diff --git a/.gitignore b/.gitignore index bddf676..cb0a0ed 100644 --- a/.gitignore +++ b/.gitignore
@@ -434,7 +434,6 @@ /third_party/sqlite4java/lib/**/*.jar /third_party/sqlite4java/lib/**/*.jnilib /third_party/sqlite4java/lib/**/*.so -/third_party/swiftshader/ /third_party/syzygy /third_party/syzygy/binaries /third_party/tsan/
diff --git a/DEPS b/DEPS index 0925519d..d6d5f96f 100644 --- a/DEPS +++ b/DEPS
@@ -36,11 +36,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': 'fc3ea41cebb8272c3f683f9cf585ff780b18f09b', + 'skia_revision': '2ab9057b31ee92060b9769ea1adfada51c11c010', # 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': '199f49c5b68b871173e3724c31288c6c33070b82', + 'v8_revision': '188b5e4e7a9e0226b816a3fc98dae0c877741dfd', # 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. @@ -56,7 +56,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': 'b6befb2ed2485a3805cddea86dc7574510178ea9', + 'pdfium_revision': '85af2a3cfcdfb2200510d337bfbf5b405858aa3b', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling openmax_dl # and whatever else without interference from each other. @@ -80,7 +80,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling NaCl # and whatever else without interference from each other. - 'nacl_revision': '5e296cb4749c3b48653eb6e5888947ad4aa86d3a', + 'nacl_revision': '2b411312ee0b4b0af6888d8b5f40b987df3b9c7c', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling freetype-android # and whatever else without interference from each other. @@ -88,11 +88,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': '462e4328f255bb41efd457a8d690427f8b7ce516', + 'catapult_revision': '49d354d564ab7571921ee15356e9949f03fd1a92', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. - 'libfuzzer_revision': '3ae6b1d1102488f26d25d045fd82208ce00a8c66', # from svn revision 272061 + 'libfuzzer_revision': '764f3890a06c04060321ede273521faf587c868f', } # Only these hosts are allowed for dependencies in this DEPS file. @@ -106,13 +106,13 @@ deps = { 'src/breakpad/src': - Var('chromium_git') + '/breakpad/breakpad/src.git' + '@' + '51db53eec7293a35cb6fc10bd2e333f22dd9d201', + Var('chromium_git') + '/breakpad/breakpad/src.git' + '@' + 'c85196f3c42b2eb8559464892a4b1749620a64d4', 'src/buildtools': Var('chromium_git') + '/chromium/buildtools.git' + '@' + Var('buildtools_revision'), 'src/sdch/open-vcdiff': - Var('chromium_git') + '/external/github.com/google/open-vcdiff.git' + '@' + '21d7d0b9c3d0c3ccbdb221c85ae889373f0a2a58', + Var('chromium_git') + '/external/github.com/google/open-vcdiff.git' + '@' + '2b9bd1fe548520e9355e457a134bab7e2f9c56c0', 'src/testing/gtest': Var('chromium_git') + '/external/github.com/google/googletest.git' + '@' + '6f8a66431cb592dad629028a50b3dd418a408c87', @@ -136,7 +136,7 @@ Var('chromium_git') + '/external/colorama.git' + '@' + '799604a1041e9b3bc5d2789ecbd7e8db2e18e6b8', 'src/third_party/icu': - Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'ef5c735307d0f86c7622f69620994c9468beba99', + Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '53ce631655a61aaaa42b43b4d64abe23e9b8d71f', 'src/third_party/hunspell_dictionaries': Var('chromium_git') + '/chromium/deps/hunspell_dictionaries.git' + '@' + 'dc6e7c25bf47cbfb466e0701fd2728b4a12e79d5', @@ -178,16 +178,16 @@ Var('chromium_git') + '/external/bidichecker/lib.git' + '@' + '97f2aa645b74c28c57eca56992235c79850fa9e0', 'src/third_party/webgl/src': - Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '46ec84c307584e6ffebc327958d56d89c36e6c27', + Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '3020b310a31cb1ede919e9915c3968b9aa8696a5', 'src/third_party/webdriver/pylib': Var('chromium_git') + '/external/selenium/py.git' + '@' + '5fd78261a75fe08d27ca4835fb6c5ce4b42275bd', 'src/third_party/libvpx/source/libvpx': - Var('chromium_git') + '/webm/libvpx.git' + '@' + '82070ae9393b1e79559d81fcf1aa89c2e4aa58ee', + Var('chromium_git') + '/webm/libvpx.git' + '@' + '2d1e63d0c50cc0088e6b851ec86fdc79f0476ac8', 'src/third_party/ffmpeg': - Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '4e878f7f64d7a9f06ba076d0a2611d7f8b33d793', + Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '75976ae026fdbedb14f006eec6cd9119c543aa7f', 'src/third_party/usrsctp/usrsctplib': Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + '9a3e5465e9d96d8a7f78f1e996412d6235d7a359', @@ -214,7 +214,7 @@ Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067', 'src/third_party/webrtc': - Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '8891ea62b26f1992ceb426d4645c59dbb7d622ac', # commit position 13667 + Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + 'dab9f13aa05550dd690be8bb37082fe78776d737', # commit position 13696 'src/third_party/openmax_dl': Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' + Var('openmax_dl_revision'),
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn index 80e32bd..f0a3b53 100644 --- a/android_webview/BUILD.gn +++ b/android_webview/BUILD.gn
@@ -132,18 +132,26 @@ disable_compression = true } -android_assets("assets") { +# These assets are needed by both monochrome and stand alone WebView, but not by +# Chrome. +android_assets("monochrome_webview_assets") { sources = [ webview_license_path, ] deps = [ ":generate_webview_license_notice", - ":pak_file_assets", "//third_party/icu:icu_assets", "//v8:v8_external_startup_data_assets", ] } +android_assets("assets") { + deps = [ + ":monochrome_webview_assets", + ":pak_file_assets", + ] +} + action("generate_webview_license_notice") { script = "tools/webview_licenses.py" inputs = exec_script("//android_webview/tools/webview_licenses.py",
diff --git a/android_webview/browser/aw_browser_main_parts.cc b/android_webview/browser/aw_browser_main_parts.cc index b5e62b2..56c9374 100644 --- a/android_webview/browser/aw_browser_main_parts.cc +++ b/android_webview/browser/aw_browser_main_parts.cc
@@ -108,10 +108,18 @@ // Try to directly mmap the webviewchromium.pak from the apk. Fall back to // load from file, using PATH_SERVICE, otherwise. - base::FilePath pak_file_path; - PathService::Get(ui::DIR_RESOURCE_PAKS_ANDROID, &pak_file_path); - pak_file_path = pak_file_path.AppendASCII("webviewchromium.pak"); - ui::LoadMainAndroidPackFile("assets/webviewchromium.pak", pak_file_path); + base::FilePath base_pak_file_path; + PathService::Get(ui::DIR_RESOURCE_PAKS_ANDROID, &base_pak_file_path); + // If Webview is a separate APK from Chrome then it uses webviewchromium.pak + base::FilePath webview_pak_file_path = base_pak_file_path.AppendASCII( + "webviewchromium.pak"); + if (!ui::LoadMainAndroidPackFile("assets/webviewchromium.pak", + webview_pak_file_path)) { + // If it the same APK as Chrome (Monochrome) then it shares resources.pak + base::FilePath chromium_pak_file_path = base_pak_file_path.AppendASCII( + "resources.pak"); + ui::LoadMainAndroidPackFile("assets/resources.pak", chromium_pak_file_path); + } base::android::MemoryPressureListenerAndroid::RegisterSystemCallback( base::android::AttachCurrentThread());
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java index 00e65f1c..e78808be 100644 --- a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java +++ b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
@@ -166,6 +166,13 @@ private WebViewDelegate mWebViewDelegate; /** + * Entry point for newer versions of Android. + */ + public static WebViewChromiumFactoryProvider create(android.webkit.WebViewDelegate delegate) { + return new WebViewChromiumFactoryProvider(delegate); + } + + /** * Constructor called by the API 21 version of {@link WebViewFactory} and earlier. */ public WebViewChromiumFactoryProvider() {
diff --git a/ash/app_list/app_list_presenter_delegate.cc b/ash/app_list/app_list_presenter_delegate.cc index 6d557d3..8023dd7 100644 --- a/ash/app_list/app_list_presenter_delegate.cc +++ b/ash/app_list/app_list_presenter_delegate.cc
@@ -336,6 +336,11 @@ view_->SetBubbleArrow(GetBubbleArrow(view_->GetWidget()->GetNativeView())); } +void AppListPresenterDelegate::OnOverviewModeStarting() { + if (is_visible_) + presenter_->Dismiss(); +} + void AppListPresenterDelegate::OnMaximizeModeStarted() { // The "fullscreen" app-list is initialized as in a different type of window, // therefore we can't switch between the fullscreen status and the normal
diff --git a/ash/app_list/app_list_presenter_delegate.h b/ash/app_list/app_list_presenter_delegate.h index 2ea0154..01d5088 100644 --- a/ash/app_list/app_list_presenter_delegate.h +++ b/ash/app_list/app_list_presenter_delegate.h
@@ -72,6 +72,7 @@ // ShellObserver overrides: void OnShelfAlignmentChanged(WmWindow* root_window) override; + void OnOverviewModeStarting() override; void OnMaximizeModeStarted() override; void OnMaximizeModeEnded() override;
diff --git a/ash/ash.gyp b/ash/ash.gyp index 836c99d..958b0e5ea 100644 --- a/ash/ash.gyp +++ b/ash/ash.gyp
@@ -503,7 +503,6 @@ 'common/wm/workspace/workspace_layout_manager.cc', 'common/wm/workspace/workspace_layout_manager.h', 'common/wm/workspace/workspace_layout_manager_backdrop_delegate.h', - 'common/wm/workspace/workspace_layout_manager_delegate.h', 'common/wm/workspace/workspace_types.h', 'common/wm/workspace/workspace_window_resizer.cc', 'common/wm/workspace/workspace_window_resizer.h',
diff --git a/ash/aura/wm_root_window_controller_aura.cc b/ash/aura/wm_root_window_controller_aura.cc index af1a4b8..58a6459 100644 --- a/ash/aura/wm_root_window_controller_aura.cc +++ b/ash/aura/wm_root_window_controller_aura.cc
@@ -135,17 +135,6 @@ observers_.RemoveObserver(observer); } -void WmRootWindowControllerAura::OnFullscreenStateChanged( - bool is_fullscreen, - WmWindow* root_window) { - if (WmWindowAura::GetAuraWindow(root_window) != - root_window_controller_->GetRootWindow()) - return; - - FOR_EACH_OBSERVER(WmRootWindowControllerObserver, observers_, - OnFullscreenStateChanged(is_fullscreen)); -} - void WmRootWindowControllerAura::OnShelfAlignmentChanged( WmWindow* root_window) { if (WmWindowAura::GetAuraWindow(root_window) !=
diff --git a/ash/aura/wm_root_window_controller_aura.h b/ash/aura/wm_root_window_controller_aura.h index fad0c5c..f4029809 100644 --- a/ash/aura/wm_root_window_controller_aura.h +++ b/ash/aura/wm_root_window_controller_aura.h
@@ -54,8 +54,6 @@ void RemoveObserver(WmRootWindowControllerObserver* observer) override; // ShellObserver: - void OnFullscreenStateChanged(bool is_fullscreen, - WmWindow* root_window) override; void OnShelfAlignmentChanged(WmWindow* root_window) override; // DisplayObserver:
diff --git a/ash/aura/wm_shelf_aura.cc b/ash/aura/wm_shelf_aura.cc index 84c7892d..4b4d5cb 100644 --- a/ash/aura/wm_shelf_aura.cc +++ b/ash/aura/wm_shelf_aura.cc
@@ -7,6 +7,7 @@ #include "ash/aura/wm_window_aura.h" #include "ash/common/shelf/wm_shelf_observer.h" #include "ash/common/wm_window.h" +#include "ash/shelf/dimmer_view.h" #include "ash/shelf/shelf.h" #include "ash/shelf/shelf_layout_manager.h" #include "ash/shell.h" @@ -14,6 +15,37 @@ namespace ash { +// WmShelfAura::AutoHideEventHandler ------------------------------------------- + +// Forwards mouse and gesture events to ShelfLayoutManager for auto-hide. +// TODO(mash): Add similar event handling support for mash. +class WmShelfAura::AutoHideEventHandler : public ui::EventHandler { + public: + explicit AutoHideEventHandler(ShelfLayoutManager* shelf_layout_manager) + : shelf_layout_manager_(shelf_layout_manager) { + Shell::GetInstance()->AddPreTargetHandler(this); + } + ~AutoHideEventHandler() override { + Shell::GetInstance()->RemovePreTargetHandler(this); + } + + // Overridden from ui::EventHandler: + void OnMouseEvent(ui::MouseEvent* event) override { + shelf_layout_manager_->UpdateAutoHideForMouseEvent( + event, WmWindowAura::Get(static_cast<aura::Window*>(event->target()))); + } + void OnGestureEvent(ui::GestureEvent* event) override { + shelf_layout_manager_->UpdateAutoHideForGestureEvent( + event, WmWindowAura::Get(static_cast<aura::Window*>(event->target()))); + } + + private: + ShelfLayoutManager* shelf_layout_manager_; + DISALLOW_COPY_AND_ASSIGN(AutoHideEventHandler); +}; + +// WmShelfAura ----------------------------------------------------------------- + WmShelfAura::WmShelfAura() {} WmShelfAura::~WmShelfAura() {} @@ -48,6 +80,7 @@ void WmShelfAura::ResetShelfLayoutManager() { if (!shelf_layout_manager_) return; + auto_hide_event_handler_.reset(); shelf_layout_manager_->RemoveObserver(this); shelf_layout_manager_ = nullptr; } @@ -88,6 +121,10 @@ return shelf_layout_manager_->shelf_widget()->GetBackgroundType(); } +WmDimmerView* WmShelfAura::CreateDimmerView(bool disable_animations_for_test) { + return DimmerView::Create(this, disable_animations_for_test); +} + bool WmShelfAura::IsDimmed() const { return shelf_layout_manager_->shelf_widget()->GetDimsShelf(); } @@ -107,7 +144,8 @@ } void WmShelfAura::UpdateVisibilityState() { - shelf_layout_manager_->UpdateVisibilityState(); + if (shelf_layout_manager_) + shelf_layout_manager_->UpdateVisibilityState(); } ShelfVisibilityState WmShelfAura::GetVisibilityState() const { @@ -140,18 +178,6 @@ return shelf_layout_manager_->ProcessGestureEvent(event); } -void WmShelfAura::UpdateAutoHideForMouseEvent(ui::MouseEvent* event) { - // Auto-hide support for ash_sysui. - if (Shell::GetInstance()->in_mus() && shelf_layout_manager_) - shelf_layout_manager_->UpdateAutoHideForMouseEvent(event); -} - -void WmShelfAura::UpdateAutoHideForGestureEvent(ui::GestureEvent* event) { - // Auto-hide support for ash_sysui. - if (Shell::GetInstance()->in_mus() && shelf_layout_manager_) - shelf_layout_manager_->UpdateAutoHideForGestureEvent(event); -} - void WmShelfAura::AddObserver(WmShelfObserver* observer) { observers_.AddObserver(observer); } @@ -188,6 +214,13 @@ void WmShelfAura::WillChangeVisibilityState(ShelfVisibilityState new_state) { FOR_EACH_OBSERVER(WmShelfObserver, observers_, WillChangeVisibilityState(new_state)); + + if (new_state != SHELF_AUTO_HIDE) { + auto_hide_event_handler_.reset(); + } else if (!auto_hide_event_handler_) { + auto_hide_event_handler_.reset( + new AutoHideEventHandler(shelf_layout_manager_)); + } } void WmShelfAura::OnAutoHideStateChanged(ShelfAutoHideState new_state) {
diff --git a/ash/aura/wm_shelf_aura.h b/ash/aura/wm_shelf_aura.h index ff6439a5..86d5186 100644 --- a/ash/aura/wm_shelf_aura.h +++ b/ash/aura/wm_shelf_aura.h
@@ -35,6 +35,8 @@ static Shelf* GetShelf(WmShelf* shelf); private: + class AutoHideEventHandler; + void ResetShelfLayoutManager(); // WmShelf: @@ -46,6 +48,7 @@ ShelfAutoHideState GetAutoHideState() const override; void UpdateAutoHideState() override; ShelfBackgroundType GetBackgroundType() const override; + WmDimmerView* CreateDimmerView(bool disable_animations_for_test) override; bool IsDimmed() const override; bool IsShowingOverflowBubble() const override; void SchedulePaint() override; @@ -57,8 +60,6 @@ void UpdateIconPositionForWindow(WmWindow* window) override; gfx::Rect GetScreenBoundsOfItemIconForWindow(WmWindow* window) override; bool ProcessGestureEvent(const ui::GestureEvent& event) override; - void UpdateAutoHideForMouseEvent(ui::MouseEvent* event) override; - void UpdateAutoHideForGestureEvent(ui::GestureEvent* event) override; void AddObserver(WmShelfObserver* observer) override; void RemoveObserver(WmShelfObserver* observer) override; void SetKeyboardBoundsForTesting(const gfx::Rect& bounds) override; @@ -83,6 +84,9 @@ base::ObserverList<WmShelfObserver> observers_; + // Forwards mouse and gesture events to ShelfLayoutManager for auto-hide. + std::unique_ptr<AutoHideEventHandler> auto_hide_event_handler_; + DISALLOW_COPY_AND_ASSIGN(WmShelfAura); };
diff --git a/ash/aura/wm_window_aura.cc b/ash/aura/wm_window_aura.cc index 5d925ba..ade4df5 100644 --- a/ash/aura/wm_window_aura.cc +++ b/ash/aura/wm_window_aura.cc
@@ -690,9 +690,7 @@ } std::unique_ptr<views::View> WmWindowAura::CreateViewWithRecreatedLayers() { - std::unique_ptr<wm::WindowMirrorView> view(new wm::WindowMirrorView(this)); - view->Init(); - return std::move(view); + return base::WrapUnique(new wm::WindowMirrorView(this)); } void WmWindowAura::AddObserver(WmWindowObserver* observer) {
diff --git a/ash/common/frame/custom_frame_view_ash.cc b/ash/common/frame/custom_frame_view_ash.cc index 723d4bf..0f2f4ce 100644 --- a/ash/common/frame/custom_frame_view_ash.cc +++ b/ash/common/frame/custom_frame_view_ash.cc
@@ -506,6 +506,11 @@ header_view_->SizeConstraintsChanged(); } +void CustomFrameViewAsh::ActivationChanged(bool active) { + // The icons differ between active and inactive. + header_view_->SchedulePaint(); +} + //////////////////////////////////////////////////////////////////////////////// // CustomFrameViewAsh, views::View overrides:
diff --git a/ash/common/frame/custom_frame_view_ash.h b/ash/common/frame/custom_frame_view_ash.h index 049e030..fd9d6b1 100644 --- a/ash/common/frame/custom_frame_view_ash.h +++ b/ash/common/frame/custom_frame_view_ash.h
@@ -57,6 +57,7 @@ void UpdateWindowIcon() override; void UpdateWindowTitle() override; void SizeConstraintsChanged() override; + void ActivationChanged(bool active) override; // views::View: gfx::Size GetPreferredSize() const override;
diff --git a/ash/common/frame/header_painter_util.cc b/ash/common/frame/header_painter_util.cc index dfd5454..f9e1595 100644 --- a/ash/common/frame/header_painter_util.cc +++ b/ash/common/frame/header_painter_util.cc
@@ -84,7 +84,8 @@ // TODO(sky): Expose a better way to determine this rather than assuming the // parent is a toplevel container. WmWindow* window = WmLookup::Get()->GetWindowForWidget(widget); - if (!window || !window->GetParent()) + // TODO(sky): GetParent()->GetLayer() is for mash until animations ported. + if (!window || !window->GetParent() || !window->GetParent()->GetLayer()) return true; ui::LayerAnimator* parent_layer_animator =
diff --git a/ash/common/shelf/app_list_button.cc b/ash/common/shelf/app_list_button.cc index 1cd900e..0803ff8 100644 --- a/ash/common/shelf/app_list_button.cc +++ b/ash/common/shelf/app_list_button.cc
@@ -21,7 +21,6 @@ #include "ui/app_list/app_list_switches.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" -#include "ui/base/ui_base_switches_util.h" #include "ui/gfx/canvas.h" #include "ui/gfx/paint_vector_icon.h" #include "ui/gfx/vector_icons_public.h" @@ -103,14 +102,12 @@ void AppListButton::OnGestureEvent(ui::GestureEvent* event) { const bool is_material = ash::MaterialDesignController::IsShelfMaterial(); - const bool touch_feedback = - !is_material && switches::IsTouchFeedbackEnabled(); switch (event->type()) { case ui::ET_GESTURE_SCROLL_BEGIN: - if (touch_feedback) - SetDrawBackgroundAsActive(false); - else if (is_material) + if (is_material) AnimateInkDrop(views::InkDropState::HIDDEN, event); + else + SetDrawBackgroundAsActive(false); shelf_view_->PointerPressedOnButton(this, ShelfView::TOUCH, *event); event->SetHandled(); return; @@ -124,15 +121,15 @@ event->SetHandled(); return; case ui::ET_GESTURE_TAP_DOWN: - if (touch_feedback) + if (!is_material) SetDrawBackgroundAsActive(true); - else if (is_material && !WmShell::Get()->IsApplistVisible()) + else if (!WmShell::Get()->IsApplistVisible()) AnimateInkDrop(views::InkDropState::ACTION_PENDING, event); ImageButton::OnGestureEvent(event); break; case ui::ET_GESTURE_TAP_CANCEL: case ui::ET_GESTURE_TAP: - if (touch_feedback) + if (!is_material) SetDrawBackgroundAsActive(false); ImageButton::OnGestureEvent(event); break;
diff --git a/ash/common/shelf/overflow_bubble.cc b/ash/common/shelf/overflow_bubble.cc index 74e59be6..aaf84ca 100644 --- a/ash/common/shelf/overflow_bubble.cc +++ b/ash/common/shelf/overflow_bubble.cc
@@ -71,16 +71,12 @@ } } -void OverflowBubble::OnMousePressed(const ui::MouseEvent& event, - const gfx::Point& location_in_screen, - views::Widget* target) { - ProcessPressedEvent(location_in_screen); -} - -void OverflowBubble::OnTouchPressed(const ui::TouchEvent& event, - const gfx::Point& location_in_screen, - views::Widget* target) { - ProcessPressedEvent(location_in_screen); +void OverflowBubble::OnPointerEventObserved( + const ui::PointerEvent& event, + const gfx::Point& location_in_screen, + views::Widget* target) { + if (event.type() == ui::ET_POINTER_DOWN) + ProcessPressedEvent(location_in_screen); } void OverflowBubble::OnWidgetDestroying(views::Widget* widget) {
diff --git a/ash/common/shelf/overflow_bubble.h b/ash/common/shelf/overflow_bubble.h index 7e35260..1e99bbc 100644 --- a/ash/common/shelf/overflow_bubble.h +++ b/ash/common/shelf/overflow_bubble.h
@@ -10,7 +10,7 @@ #include "ui/views/widget/widget_observer.h" namespace ui { -class LocatedEvent; +class PointerEvent; } namespace views { @@ -49,12 +49,9 @@ void ProcessPressedEvent(const gfx::Point& event_location_in_screen); // views::PointerWatcher: - void OnMousePressed(const ui::MouseEvent& event, - const gfx::Point& location_in_screen, - views::Widget* target) override; - void OnTouchPressed(const ui::TouchEvent& event, - const gfx::Point& location_in_screen, - views::Widget* target) override; + void OnPointerEventObserved(const ui::PointerEvent& event, + const gfx::Point& location_in_screen, + views::Widget* target) override; // Overridden from views::WidgetObserver: void OnWidgetDestroying(views::Widget* widget) override;
diff --git a/ash/common/shelf/shelf_tooltip_manager.cc b/ash/common/shelf/shelf_tooltip_manager.cc index 85028953..adf34ca9 100644 --- a/ash/common/shelf/shelf_tooltip_manager.cc +++ b/ash/common/shelf/shelf_tooltip_manager.cc
@@ -198,18 +198,13 @@ } } -void ShelfTooltipManager::OnMousePressed(const ui::MouseEvent& event, - const gfx::Point& location_in_screen, - views::Widget* target) { - // Close on any mouse press events inside or outside the tooltip. - Close(); -} - -void ShelfTooltipManager::OnTouchPressed(const ui::TouchEvent& event, - const gfx::Point& location_in_screen, - views::Widget* target) { - // Close on any touch press events inside or outside the tooltip. - Close(); +void ShelfTooltipManager::OnPointerEventObserved( + const ui::PointerEvent& event, + const gfx::Point& location_in_screen, + views::Widget* target) { + // Close on any press events inside or outside the tooltip. + if (event.type() == ui::ET_POINTER_DOWN) + Close(); } void ShelfTooltipManager::OnMouseEvent(ui::MouseEvent* event) {
diff --git a/ash/common/shelf/shelf_tooltip_manager.h b/ash/common/shelf/shelf_tooltip_manager.h index 2bc6943..c68a1b0 100644 --- a/ash/common/shelf/shelf_tooltip_manager.h +++ b/ash/common/shelf/shelf_tooltip_manager.h
@@ -58,12 +58,9 @@ void OnMouseEvent(ui::MouseEvent* event) override; // views::PointerWatcher overrides: - void OnMousePressed(const ui::MouseEvent& event, - const gfx::Point& location_in_screen, - views::Widget* target) override; - void OnTouchPressed(const ui::TouchEvent& event, - const gfx::Point& location_in_screen, - views::Widget* target) override; + void OnPointerEventObserved(const ui::PointerEvent& event, + const gfx::Point& location_in_screen, + views::Widget* target) override; // WmShelfObserver overrides: void WillChangeVisibilityState(ShelfVisibilityState new_state) override;
diff --git a/ash/common/shelf/wm_dimmer_view.h b/ash/common/shelf/wm_dimmer_view.h new file mode 100644 index 0000000..379d3722 --- /dev/null +++ b/ash/common/shelf/wm_dimmer_view.h
@@ -0,0 +1,37 @@ +// 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_COMMON_SHELF_WM_DIMMER_VIEW_H_ +#define ASH_COMMON_SHELF_WM_DIMMER_VIEW_H_ + +namespace views { +class Widget; +} + +namespace ash { + +// An interface around a widget and view that dim shelf items slightly when a +// window is maximized and visible. See DimmerView for details. This interface +// exists to avoid dependencies between ash common shelf code and the aura-only +// implementation of DimmerView. +// TODO(jamescook): Delete this after material design ships, as MD will not +// require shelf dimming. http://crbug.com/614453 +class WmDimmerView { + public: + // Returns the widget that holds the dimmer view. + virtual views::Widget* GetDimmerWidget() = 0; + + // Force the dimmer to be undimmed (e.g. by an open context menu). + virtual void ForceUndimming(bool force) = 0; + + // Returns the current alpha used by the dimming bar. + virtual int GetDimmingAlphaForTest() = 0; + + protected: + virtual ~WmDimmerView() {} +}; + +} // namespace ash + +#endif // ASH_COMMON_SHELF_WM_DIMMER_VIEW_H_
diff --git a/ash/common/shelf/wm_shelf.h b/ash/common/shelf/wm_shelf.h index 30607d04..df9f5c1 100644 --- a/ash/common/shelf/wm_shelf.h +++ b/ash/common/shelf/wm_shelf.h
@@ -14,13 +14,13 @@ namespace ui { class GestureEvent; -class MouseEvent; } namespace ash { class ShelfLockingManager; class ShelfView; +class WmDimmerView; class WmShelfObserver; class WmWindow; @@ -53,7 +53,15 @@ virtual ShelfBackgroundType GetBackgroundType() const = 0; + // Creates a view that dims shelf items. The returned view is owned by its + // widget. Returns null if shelf dimming is not supported (e.g. on mus). + // TODO(jamescook): Delete this after material design ships, as MD will not + // require shelf dimming. http://crbug.com/614453 + virtual WmDimmerView* CreateDimmerView(bool disable_animations_for_test) = 0; + // Shelf items are slightly dimmed (e.g. when a window is maximized). + // TODO(jamescook): Delete this after material design ships, as MD will not + // require shelf dimming. http://crbug.com/614453 virtual bool IsDimmed() const = 0; // Whether the shelf item overflow bubble is visible. @@ -91,10 +99,6 @@ // Returns true if the event was handled. virtual bool ProcessGestureEvent(const ui::GestureEvent& event) = 0; - // TODO(jamescook): Nuke when ash_sysui is removed. http://crbug.com/621112 - virtual void UpdateAutoHideForMouseEvent(ui::MouseEvent* event) = 0; - virtual void UpdateAutoHideForGestureEvent(ui::GestureEvent* event) = 0; - virtual void AddObserver(WmShelfObserver* observer) = 0; virtual void RemoveObserver(WmShelfObserver* observer) = 0;
diff --git a/ash/common/system/audio/volume_view.cc b/ash/common/system/audio/volume_view.cc index 01e96d41..6435bac 100644 --- a/ash/common/system/audio/volume_view.cc +++ b/ash/common/system/audio/volume_view.cc
@@ -5,6 +5,7 @@ #include "ash/common/system/audio/volume_view.h" #include "ash/common/ash_constants.h" +#include "ash/common/material_design/material_design_controller.h" #include "ash/common/metrics/user_metrics_action.h" #include "ash/common/system/audio/tray_audio.h" #include "ash/common/system/audio/tray_audio_delegate.h" @@ -17,6 +18,8 @@ #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/canvas.h" #include "ui/gfx/image/image_skia_operations.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/gfx/vector_icons_public.h" #include "ui/views/background.h" #include "ui/views/border.h" #include "ui/views/controls/button/image_button.h" @@ -152,9 +155,16 @@ more_ = new views::ImageView; more_->EnableCanvasFlippingForRTLUI(true); - more_->SetImage(ui::ResourceBundle::GetSharedInstance() - .GetImageNamed(IDR_AURA_UBER_TRAY_MORE) - .ToImageSkia()); + + if (MaterialDesignController::IsSystemTrayMenuMaterial()) { + more_->SetImage(gfx::CreateVectorIcon( + gfx::VectorIconId::SYSTEM_MENU_ARROW_RIGHT, kMenuIconColor)); + } else { + more_->SetImage(ui::ResourceBundle::GetSharedInstance() + .GetImageNamed(IDR_AURA_UBER_TRAY_MORE) + .ToImageSkia()); + } + more_region_->AddChildView(more_); set_background(views::Background::CreateSolidBackground(kBackgroundColor));
diff --git a/ash/common/system/cast/tray_cast.cc b/ash/common/system/cast/tray_cast.cc index f2f2aa44..eab2437 100644 --- a/ash/common/system/cast/tray_cast.cc +++ b/ash/common/system/cast/tray_cast.cc
@@ -353,8 +353,8 @@ void CastTrayView::UpdateAlignment(ShelfAlignment alignment) { // Center the item dependent on the orientation of the shelf. views::BoxLayout::Orientation layout = IsHorizontalAlignment(alignment) - ? views::BoxLayout::kVertical - : views::BoxLayout::kHorizontal; + ? views::BoxLayout::kHorizontal + : views::BoxLayout::kVertical; SetLayoutManager(new views::BoxLayout(layout, 0, 0, 0)); Layout(); }
diff --git a/ash/common/system/chromeos/bluetooth/tray_bluetooth.cc b/ash/common/system/chromeos/bluetooth/tray_bluetooth.cc index 16d683f6..bd967e1 100644 --- a/ash/common/system/chromeos/bluetooth/tray_bluetooth.cc +++ b/ash/common/system/chromeos/bluetooth/tray_bluetooth.cc
@@ -4,6 +4,7 @@ #include "ash/common/system/chromeos/bluetooth/tray_bluetooth.h" +#include "ash/common/material_design/material_design_controller.h" #include "ash/common/session/session_state_delegate.h" #include "ash/common/system/tray/fixed_sized_scroll_view.h" #include "ash/common/system/tray/hover_highlight_view.h" @@ -22,6 +23,8 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/image/image.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/gfx/vector_icons_public.h" #include "ui/views/controls/image_view.h" #include "ui/views/controls/label.h" #include "ui/views/layout/box_layout.h" @@ -67,21 +70,32 @@ public: BluetoothDefaultView(SystemTrayItem* owner, bool show_more) : TrayItemMore(owner, show_more) { - ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); - SetImage(bundle.GetImageNamed(IDR_AURA_UBER_TRAY_BLUETOOTH).ToImageSkia()); - UpdateLabel(); + if (!MaterialDesignController::IsSystemTrayMenuMaterial()) { + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); + SetImage( + bundle.GetImageNamed(IDR_AURA_UBER_TRAY_BLUETOOTH).ToImageSkia()); + } + Update(); } ~BluetoothDefaultView() override {} - void UpdateLabel() { + void Update() { SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); + const bool enabled = delegate->GetBluetoothEnabled(); + if (MaterialDesignController::IsSystemTrayMenuMaterial()) { + gfx::VectorIconId icon_id = + enabled ? gfx::VectorIconId::SYSTEM_MENU_BLUETOOTH + : gfx::VectorIconId::SYSTEM_MENU_BLUETOOTH_DISABLED; + gfx::ImageSkia image = gfx::CreateVectorIcon(icon_id, kMenuIconColor); + SetImage(&image); + } + if (delegate->GetBluetoothAvailable()) { ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - const base::string16 label = - rb.GetLocalizedString(delegate->GetBluetoothEnabled() - ? IDS_ASH_STATUS_TRAY_BLUETOOTH_ENABLED - : IDS_ASH_STATUS_TRAY_BLUETOOTH_DISABLED); + const base::string16 label = rb.GetLocalizedString( + enabled ? IDS_ASH_STATUS_TRAY_BLUETOOTH_ENABLED + : IDS_ASH_STATUS_TRAY_BLUETOOTH_DISABLED); SetLabel(label); SetAccessibleName(label); SetVisible(true); @@ -440,7 +454,7 @@ void TrayBluetooth::OnBluetoothRefresh() { if (default_) - default_->UpdateLabel(); + default_->Update(); else if (detailed_) detailed_->Update(); }
diff --git a/ash/common/system/chromeos/virtual_keyboard/virtual_keyboard_tray.cc b/ash/common/system/chromeos/virtual_keyboard/virtual_keyboard_tray.cc index 39eae98..205af04 100644 --- a/ash/common/system/chromeos/virtual_keyboard/virtual_keyboard_tray.cc +++ b/ash/common/system/chromeos/virtual_keyboard/virtual_keyboard_tray.cc
@@ -98,6 +98,10 @@ } void VirtualKeyboardTray::SetIconBorderForShelfAlignment() { + // Every time shelf alignment is updated, StatusAreaWidgetDelegate resets the + // border to a non-null border. So, we need to remove it. + tray_container()->SetBorder(views::Border::NullBorder()); + const gfx::ImageSkia& image = icon_->GetImage(); const int size = GetTrayConstant(VIRTUAL_KEYBOARD_BUTTON_SIZE); const int vertical_padding = (size - image.height()) / 2;
diff --git a/ash/common/system/date/date_view.cc b/ash/common/system/date/date_view.cc index 613d62e..e1434d80 100644 --- a/ash/common/system/date/date_view.cc +++ b/ash/common/system/date/date_view.cc
@@ -18,7 +18,6 @@ #include "third_party/icu/source/i18n/unicode/smpdtfmt.h" #include "ui/accessibility/ax_view_state.h" #include "ui/base/l10n/l10n_util.h" -#include "ui/base/ui_base_switches_util.h" #include "ui/views/border.h" #include "ui/views/controls/label.h" #include "ui/views/layout/box_layout.h" @@ -212,13 +211,11 @@ } void DateView::OnGestureEvent(ui::GestureEvent* event) { - if (switches::IsTouchFeedbackEnabled()) { - if (event->type() == ui::ET_GESTURE_TAP_DOWN) { - SetActive(true); - } else if (event->type() == ui::ET_GESTURE_TAP_CANCEL || - event->type() == ui::ET_GESTURE_END) { - SetActive(false); - } + if (event->type() == ui::ET_GESTURE_TAP_DOWN) { + SetActive(true); + } else if (event->type() == ui::ET_GESTURE_TAP_CANCEL || + event->type() == ui::ET_GESTURE_END) { + SetActive(false); } BaseDateTimeView::OnGestureEvent(event); }
diff --git a/ash/common/system/status_area_widget.cc b/ash/common/system/status_area_widget.cc index ada0972c0..34d04a6 100644 --- a/ash/common/system/status_area_widget.cc +++ b/ash/common/system/status_area_widget.cc
@@ -144,16 +144,6 @@ status_area_widget_delegate_->SetPaneFocusAndFocusDefault(); } -void StatusAreaWidget::OnMouseEvent(ui::MouseEvent* event) { - Widget::OnMouseEvent(event); - wm_shelf_->UpdateAutoHideForMouseEvent(event); -} - -void StatusAreaWidget::OnGestureEvent(ui::GestureEvent* event) { - Widget::OnGestureEvent(event); - wm_shelf_->UpdateAutoHideForGestureEvent(event); -} - void StatusAreaWidget::UpdateShelfItemBackground(int alpha) { web_notification_tray_->UpdateShelfItemBackground(alpha); system_tray_->UpdateShelfItemBackground(alpha);
diff --git a/ash/common/system/status_area_widget.h b/ash/common/system/status_area_widget.h index 5629496..9ee9143 100644 --- a/ash/common/system/status_area_widget.h +++ b/ash/common/system/status_area_widget.h
@@ -79,8 +79,6 @@ // Overridden from views::Widget: void OnNativeWidgetActivationChanged(bool active) override; - void OnMouseEvent(ui::MouseEvent* event) override; - void OnGestureEvent(ui::GestureEvent* event) override; // ShelfBackgroundAnimatorObserver: void UpdateShelfItemBackground(int alpha) override;
diff --git a/ash/common/system/tray/hover_highlight_view.cc b/ash/common/system/tray/hover_highlight_view.cc index e420455..05668ce6 100644 --- a/ash/common/system/tray/hover_highlight_view.cc +++ b/ash/common/system/tray/hover_highlight_view.cc
@@ -9,7 +9,6 @@ #include "ash/common/system/tray/view_click_listener.h" #include "ui/accessibility/ax_view_state.h" #include "ui/base/resource/resource_bundle.h" -#include "ui/base/ui_base_switches_util.h" #include "ui/gfx/canvas.h" #include "ui/gfx/font_list.h" #include "ui/resources/grit/ui_resources.h" @@ -241,13 +240,11 @@ } void HoverHighlightView::OnGestureEvent(ui::GestureEvent* event) { - if (switches::IsTouchFeedbackEnabled()) { - if (event->type() == ui::ET_GESTURE_TAP_DOWN) { - SetHoverHighlight(true); - } else if (event->type() == ui::ET_GESTURE_TAP_CANCEL || - event->type() == ui::ET_GESTURE_TAP) { - SetHoverHighlight(false); - } + if (event->type() == ui::ET_GESTURE_TAP_DOWN) { + SetHoverHighlight(true); + } else if (event->type() == ui::ET_GESTURE_TAP_CANCEL || + event->type() == ui::ET_GESTURE_TAP) { + SetHoverHighlight(false); } ActionableView::OnGestureEvent(event); }
diff --git a/ash/common/system/tray/tray_background_view.cc b/ash/common/system/tray/tray_background_view.cc index 3e26c506..4d209a5 100644 --- a/ash/common/system/tray/tray_background_view.cc +++ b/ash/common/system/tray/tray_background_view.cc
@@ -18,7 +18,6 @@ #include "grit/ash_resources.h" #include "ui/accessibility/ax_view_state.h" #include "ui/base/nine_image_painter_factory.h" -#include "ui/base/ui_base_switches_util.h" #include "ui/compositor/layer.h" #include "ui/compositor/layer_animation_element.h" #include "ui/compositor/scoped_layer_animation_settings.h" @@ -343,13 +342,11 @@ } void TrayBackgroundView::OnGestureEvent(ui::GestureEvent* event) { - if (switches::IsTouchFeedbackEnabled()) { - if (event->type() == ui::ET_GESTURE_TAP_DOWN) { - SetDrawBackgroundAsActive(true); - } else if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN || - event->type() == ui::ET_GESTURE_TAP_CANCEL) { - SetDrawBackgroundAsActive(false); - } + if (event->type() == ui::ET_GESTURE_TAP_DOWN) { + SetDrawBackgroundAsActive(true); + } else if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN || + event->type() == ui::ET_GESTURE_TAP_CANCEL) { + SetDrawBackgroundAsActive(false); } ActionableView::OnGestureEvent(event); }
diff --git a/ash/common/system/tray/tray_event_filter.cc b/ash/common/system/tray/tray_event_filter.cc index 3b277ccf..8f83890 100644 --- a/ash/common/system/tray/tray_event_filter.cc +++ b/ash/common/system/tray/tray_event_filter.cc
@@ -34,16 +34,12 @@ WmShell::Get()->RemovePointerWatcher(this); } -void TrayEventFilter::OnMousePressed(const ui::MouseEvent& event, - const gfx::Point& location_in_screen, - views::Widget* target) { - ProcessPressedEvent(location_in_screen, target); -} - -void TrayEventFilter::OnTouchPressed(const ui::TouchEvent& event, - const gfx::Point& location_in_screen, - views::Widget* target) { - ProcessPressedEvent(location_in_screen, target); +void TrayEventFilter::OnPointerEventObserved( + const ui::PointerEvent& event, + const gfx::Point& location_in_screen, + views::Widget* target) { + if (event.type() == ui::ET_POINTER_DOWN) + ProcessPressedEvent(location_in_screen, target); } void TrayEventFilter::ProcessPressedEvent(const gfx::Point& location_in_screen,
diff --git a/ash/common/system/tray/tray_event_filter.h b/ash/common/system/tray/tray_event_filter.h index 88a5ba80..8d7b50f 100644 --- a/ash/common/system/tray/tray_event_filter.h +++ b/ash/common/system/tray/tray_event_filter.h
@@ -15,7 +15,7 @@ } namespace ui { -class LocatedEvent; +class PointerEvent; } namespace ash { @@ -32,12 +32,9 @@ void RemoveWrapper(TrayBubbleWrapper* wrapper); // views::PointerWatcher: - void OnMousePressed(const ui::MouseEvent& event, - const gfx::Point& location_in_screen, - views::Widget* target) override; - void OnTouchPressed(const ui::TouchEvent& event, - const gfx::Point& location_in_screen, - views::Widget* target) override; + void OnPointerEventObserved(const ui::PointerEvent& event, + const gfx::Point& location_in_screen, + views::Widget* target) override; private: void ProcessPressedEvent(const gfx::Point& location_in_screen,
diff --git a/ash/common/system/tray/tray_item_more.cc b/ash/common/system/tray/tray_item_more.cc index 656cb12..7d901c3 100644 --- a/ash/common/system/tray/tray_item_more.cc +++ b/ash/common/system/tray/tray_item_more.cc
@@ -4,6 +4,7 @@ #include "ash/common/system/tray/tray_item_more.h" +#include "ash/common/material_design/material_design_controller.h" #include "ash/common/system/tray/fixed_sized_image_view.h" #include "ash/common/system/tray/system_tray_item.h" #include "ash/common/system/tray/tray_constants.h" @@ -11,6 +12,8 @@ #include "ui/accessibility/ax_view_state.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/image/image.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/gfx/vector_icons_public.h" #include "ui/views/controls/image_view.h" #include "ui/views/controls/label.h" #include "ui/views/layout/box_layout.h" @@ -37,9 +40,14 @@ if (show_more) { more_ = new views::ImageView; more_->EnableCanvasFlippingForRTLUI(true); - more_->SetImage(ui::ResourceBundle::GetSharedInstance() - .GetImageNamed(IDR_AURA_UBER_TRAY_MORE) - .ToImageSkia()); + if (MaterialDesignController::IsSystemTrayMenuMaterial()) { + more_->SetImage(gfx::CreateVectorIcon( + gfx::VectorIconId::SYSTEM_MENU_ARROW_RIGHT, kMenuIconColor)); + } else { + more_->SetImage(ui::ResourceBundle::GetSharedInstance() + .GetImageNamed(IDR_AURA_UBER_TRAY_MORE) + .ToImageSkia()); + } AddChildView(more_); } }
diff --git a/ash/common/system/tray/tray_popup_item_container.cc b/ash/common/system/tray/tray_popup_item_container.cc index fd9b7fa..f342878f 100644 --- a/ash/common/system/tray/tray_popup_item_container.cc +++ b/ash/common/system/tray/tray_popup_item_container.cc
@@ -5,7 +5,6 @@ #include "ash/common/system/tray/tray_popup_item_container.h" #include "ash/common/system/tray/tray_constants.h" -#include "ui/base/ui_base_switches_util.h" #include "ui/gfx/canvas.h" #include "ui/views/layout/box_layout.h" @@ -56,8 +55,6 @@ } void TrayPopupItemContainer::OnGestureEvent(ui::GestureEvent* event) { - if (!switches::IsTouchFeedbackEnabled()) - return; if (event->type() == ui::ET_GESTURE_TAP_DOWN) { SetActive(true); } else if (event->type() == ui::ET_GESTURE_TAP_CANCEL ||
diff --git a/ash/common/system/web_notification/web_notification_tray.cc b/ash/common/system/web_notification/web_notification_tray.cc index feba9ff..9b7d7d2 100644 --- a/ash/common/system/web_notification/web_notification_tray.cc +++ b/ash/common/system/web_notification/web_notification_tray.cc
@@ -39,7 +39,6 @@ #include "ui/message_center/views/message_popup_collection.h" #include "ui/strings/grit/ui_strings.h" #include "ui/views/bubble/tray_bubble_view.h" -#include "ui/views/controls/button/custom_button.h" #include "ui/views/controls/image_view.h" #include "ui/views/controls/label.h" #include "ui/views/controls/menu/menu_runner.h" @@ -115,12 +114,9 @@ DISALLOW_COPY_AND_ASSIGN(WebNotificationBubbleWrapper); }; -class WebNotificationButton : public views::CustomButton { +class WebNotificationIcon : public views::View { public: - WebNotificationButton(views::ButtonListener* listener) - : views::CustomButton(listener), - is_bubble_visible_(false), - unread_count_(0) { + WebNotificationIcon() : is_bubble_visible_(false), unread_count_(0) { SetLayoutManager(new views::FillLayout); gfx::ImageSkia image; @@ -158,7 +154,7 @@ } protected: - // Overridden from views::ImageButton: + // Overridden from views::View: gfx::Size GetPreferredSize() const override { const int size = GetTrayConstant(TRAY_ITEM_HEIGHT_LEGACY); return gfx::Size(size, size); @@ -200,7 +196,7 @@ views::ImageView no_unread_icon_; views::Label unread_label_; - DISALLOW_COPY_AND_ASSIGN(WebNotificationButton); + DISALLOW_COPY_AND_ASSIGN(WebNotificationIcon); }; WebNotificationTray::WebNotificationTray(WmShelf* shelf, @@ -209,18 +205,15 @@ : TrayBackgroundView(shelf), status_area_window_(status_area_window), system_tray_(system_tray), - button_(nullptr), + icon_(new WebNotificationIcon), show_message_center_on_unlock_(false), should_update_tray_content_(false), should_block_shelf_auto_hide_(false) { DCHECK(shelf); DCHECK(status_area_window_); DCHECK(system_tray_); - button_ = new WebNotificationButton(this); - button_->set_triggerable_event_flags(ui::EF_LEFT_MOUSE_BUTTON | - ui::EF_RIGHT_MOUSE_BUTTON); - tray_container()->AddChildView(button_); - button_->SetFocusBehavior(FocusBehavior::NEVER); + + tray_container()->AddChildView(icon_); SetContentsBackground(); tray_container()->SetBorder(views::Border::NullBorder()); message_center_tray_.reset(new message_center::MessageCenterTray( @@ -273,7 +266,7 @@ system_tray_->SetHideNotifications(true); shelf()->UpdateAutoHideState(); - button_->SetBubbleVisible(true); + icon_->SetBubbleVisible(true); SetDrawBackgroundAsActive(true); return true; } @@ -291,7 +284,7 @@ show_message_center_on_unlock_ = false; system_tray_->SetHideNotifications(false); shelf()->UpdateAutoHideState(); - button_->SetBubbleVisible(false); + icon_->SetBubbleVisible(false); } void WebNotificationTray::SetTrayBubbleHeight(int height) { @@ -349,6 +342,8 @@ if (alignment == shelf_alignment()) return; TrayBackgroundView::SetShelfAlignment(alignment); + // Every time shelf alignment is updated, StatusAreaWidgetDelegate resets the + // border to a non-null border. So, we need to remove it. tray_container()->SetBorder(views::Border::NullBorder()); // Destroy any existing bubble so that it will be rebuilt correctly. message_center_tray_->HideMessageCenterBubble(); @@ -460,12 +455,6 @@ message_center()->EnterQuietModeWithExpire(expires_in); } -void WebNotificationTray::ButtonPressed(views::Button* sender, - const ui::Event& event) { - DCHECK_EQ(button_, sender); - PerformAction(event); -} - void WebNotificationTray::OnMessageCenterTrayChanged() { // Do not update the tray contents directly. Multiple change events can happen // consecutively, and calling Update in the middle of those events will show @@ -483,11 +472,7 @@ message_center::MessageCenter* message_center = message_center_tray_->message_center(); - button_->SetUnreadCount(message_center->UnreadNotificationCount()); - if (IsMessageCenterBubbleVisible()) - button_->SetState(views::CustomButton::STATE_PRESSED); - else - button_->SetState(views::CustomButton::STATE_NORMAL); + icon_->SetUnreadCount(message_center->UnreadNotificationCount()); SetVisible(IsLoggedIn()); Layout();
diff --git a/ash/common/system/web_notification/web_notification_tray.h b/ash/common/system/web_notification/web_notification_tray.h index 6938498..1d13ffcf 100644 --- a/ash/common/system/web_notification/web_notification_tray.h +++ b/ash/common/system/web_notification/web_notification_tray.h
@@ -17,7 +17,6 @@ #include "ui/message_center/message_center_tray.h" #include "ui/message_center/message_center_tray_delegate.h" #include "ui/views/bubble/tray_bubble_view.h" -#include "ui/views/controls/button/button.h" // Status area tray for showing browser and app notifications. This hosts // a MessageCenter class which manages the notification list. This class @@ -28,7 +27,6 @@ // is controlled by StatusAreaWidget. namespace views { -class ImageButton; class MenuRunner; } @@ -43,14 +41,13 @@ class AshPopupAlignmentDelegate; class SystemTray; class WebNotificationBubbleWrapper; -class WebNotificationButton; +class WebNotificationIcon; class WmWindow; class ASH_EXPORT WebNotificationTray : public TrayBackgroundView, public views::TrayBubbleView::Delegate, public message_center::MessageCenterTrayDelegate, - public views::ButtonListener, public base::SupportsWeakPtr<WebNotificationTray>, public ui::SimpleMenuModel::Delegate { public: @@ -106,9 +103,6 @@ views::Widget::InitParams* params) const override; void HideBubble(const views::TrayBubbleView* bubble_view) override; - // Overridden from ButtonListener. - void ButtonPressed(views::Button* sender, const ui::Event& event) override; - // Overridden from MessageCenterTrayDelegate. void OnMessageCenterTrayChanged() override; bool ShowMessageCenter() override; @@ -175,7 +169,7 @@ std::unique_ptr<message_center::MessageCenterTray> message_center_tray_; std::unique_ptr<WebNotificationBubbleWrapper> message_center_bubble_; std::unique_ptr<message_center::MessagePopupCollection> popup_collection_; - WebNotificationButton* button_; + WebNotificationIcon* icon_; bool show_message_center_on_unlock_;
diff --git a/ash/common/wm/always_on_top_controller.cc b/ash/common/wm/always_on_top_controller.cc index 275a4462d..b32389c 100644 --- a/ash/common/wm/always_on_top_controller.cc +++ b/ash/common/wm/always_on_top_controller.cc
@@ -6,7 +6,6 @@ #include "ash/common/shell_window_ids.h" #include "ash/common/wm/workspace/workspace_layout_manager.h" -#include "ash/common/wm/workspace/workspace_layout_manager_delegate.h" #include "ash/common/wm_window.h" #include "ash/common/wm_window_property.h" #include "base/memory/ptr_util.h" @@ -15,8 +14,9 @@ AlwaysOnTopController::AlwaysOnTopController(WmWindow* viewport) : always_on_top_container_(viewport) { + DCHECK_NE(kShellWindowId_DefaultContainer, viewport->GetShellWindowId()); always_on_top_container_->SetLayoutManager( - base::WrapUnique(new WorkspaceLayoutManager(viewport, nullptr))); + base::MakeUnique<WorkspaceLayoutManager>(viewport)); // Container should be empty. DCHECK(always_on_top_container_->GetChildren().empty()); always_on_top_container_->AddObserver(this);
diff --git a/ash/common/wm/dock/docked_window_layout_manager.cc b/ash/common/wm/dock/docked_window_layout_manager.cc index 10c6bc20..6905634 100644 --- a/ash/common/wm/dock/docked_window_layout_manager.cc +++ b/ash/common/wm/dock/docked_window_layout_manager.cc
@@ -770,7 +770,7 @@ } //////////////////////////////////////////////////////////////////////////////// -// DockedWindowLayoutManager, ash::ShellObserver implementation: +// DockedWindowLayoutManager, WmRootWindowControllerObserver implementation: void DockedWindowLayoutManager::OnWorkAreaChanged() { Relayout(); @@ -778,32 +778,6 @@ MaybeMinimizeChildrenExcept(dragged_window_); } -void DockedWindowLayoutManager::OnFullscreenStateChanged(bool is_fullscreen) { - // Entering fullscreen mode (including immersive) hides docked windows. - in_fullscreen_ = root_window_controller_->GetWorkspaceWindowState() == - wm::WORKSPACE_WINDOW_STATE_FULL_SCREEN; - { - // prevent Relayout from getting called multiple times during this - base::AutoReset<bool> auto_reset_in_layout(&in_layout_, true); - // Use a copy of children array because a call to MinimizeDockedWindow or - // RestoreDockedWindow can change order. - for (WmWindow* window : dock_container_->GetChildren()) { - if (IsPopupOrTransient(window)) - continue; - wm::WindowState* window_state = window->GetWindowState(); - if (in_fullscreen_) { - if (window->IsVisible()) - MinimizeDockedWindow(window_state); - } else { - if (!window_state->IsMinimized()) - RestoreDockedWindow(window_state); - } - } - } - Relayout(); - UpdateDockBounds(DockedWindowLayoutManagerObserver::CHILD_CHANGED); -} - void DockedWindowLayoutManager::OnShelfAlignmentChanged() { if (!shelf_ || alignment_ == DOCKED_ALIGNMENT_NONE) return; @@ -922,7 +896,34 @@ void DockedWindowLayoutManager::OnFullscreenStateChanged( bool is_fullscreen, - WmWindow* root_window) {} + WmWindow* root_window) { + if (root_window != dock_container_->GetRootWindow()) + return; + + // Entering fullscreen mode (including immersive) hides docked windows. + in_fullscreen_ = root_window_controller_->GetWorkspaceWindowState() == + wm::WORKSPACE_WINDOW_STATE_FULL_SCREEN; + { + // prevent Relayout from getting called multiple times during this + base::AutoReset<bool> auto_reset_in_layout(&in_layout_, true); + // Use a copy of children array because a call to MinimizeDockedWindow or + // RestoreDockedWindow can change order. + for (WmWindow* window : dock_container_->GetChildren()) { + if (IsPopupOrTransient(window)) + continue; + wm::WindowState* window_state = window->GetWindowState(); + if (in_fullscreen_) { + if (window->IsVisible()) + MinimizeDockedWindow(window_state); + } else { + if (!window_state->IsMinimized()) + RestoreDockedWindow(window_state); + } + } + } + Relayout(); + UpdateDockBounds(DockedWindowLayoutManagerObserver::CHILD_CHANGED); +} void DockedWindowLayoutManager::OnOverviewModeStarting() { in_overview_ = true;
diff --git a/ash/common/wm/dock/docked_window_layout_manager.h b/ash/common/wm/dock/docked_window_layout_manager.h index 09af9b2..9fa36d9 100644 --- a/ash/common/wm/dock/docked_window_layout_manager.h +++ b/ash/common/wm/dock/docked_window_layout_manager.h
@@ -138,7 +138,6 @@ // WmRootWindowControllerObserver: void OnWorkAreaChanged() override; - void OnFullscreenStateChanged(bool is_fullscreen) override; void OnShelfAlignmentChanged() override; // wm::WindowStateObserver:
diff --git a/ash/common/wm/overview/window_selector.cc b/ash/common/wm/overview/window_selector.cc index b24142b1..db099179 100644 --- a/ash/common/wm/overview/window_selector.cc +++ b/ash/common/wm/overview/window_selector.cc
@@ -381,6 +381,10 @@ // may cause other, unrelated classes, (ie PanelLayoutManager) to make indirect // calls to restoring_minimized_windows() on a partially destructed object. void WindowSelector::Shutdown() { + // Stop observing screen metrics changes first to avoid auto-positioning + // windows in response to work area changes from window activation. + display::Screen::GetScreen()->RemoveObserver(this); + size_t remaining_items = 0; for (std::unique_ptr<WindowGrid>& window_grid : grid_list_) { for (WindowSelectorItem* window_selector_item : window_grid->window_list()) @@ -553,12 +557,8 @@ void WindowSelector::OnDisplayMetricsChanged(const display::Display& display, uint32_t metrics) { - // If only the work area changes, there is no need to reposition windows in - // overview. - if (metrics != DISPLAY_METRIC_WORK_AREA) { - PositionWindows(/* animate */ false); - RepositionTextFilterOnDisplayMetricsChange(); - } + PositionWindows(/* animate */ false); + RepositionTextFilterOnDisplayMetricsChange(); } void WindowSelector::OnWindowTreeChanged(WmWindow* window,
diff --git a/ash/common/wm/window_cycle_list.cc b/ash/common/wm/window_cycle_list.cc index 703ac18..a243819a 100644 --- a/ash/common/wm/window_cycle_list.cc +++ b/ash/common/wm/window_cycle_list.cc
@@ -16,6 +16,7 @@ #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "base/command_line.h" +#include "ui/accessibility/ax_view_state.h" #include "ui/views/background.h" #include "ui/views/border.h" #include "ui/views/controls/label.h" @@ -23,6 +24,7 @@ #include "ui/views/painter.h" #include "ui/views/view.h" #include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_delegate.h" #include "ui/wm/core/visibility_controller.h" namespace ash { @@ -117,6 +119,8 @@ AddChildView(preview_background_); AddChildView(mirror_view_); + + SetFocusBehavior(FocusBehavior::ALWAYS); } ~WindowPreviewView() override {} @@ -152,6 +156,11 @@ mirror_view_->SetPosition(preview_area_bounds.origin()); } + void GetAccessibleState(ui::AXViewState* state) override { + state->role = ui::AX_ROLE_WINDOW; + state->name = window_title_->text(); + } + private: // The maximum width of a window preview. static const int kMaxPreviewWidth = 512; @@ -212,7 +221,7 @@ }; // A view that shows a collection of windows the user can tab through. -class WindowCycleView : public views::View { +class WindowCycleView : public views::WidgetDelegateView { public: explicit WindowCycleView(const WindowCycleList::WindowList& windows) : mirror_container_(new views::View()), @@ -271,8 +280,11 @@ void SetTargetWindow(WmWindow* target) { target_window_ = target; - if (GetWidget()) + if (GetWidget()) { Layout(); + DCHECK(Contains(GetFocusManager()->GetFocusedView())); + window_view_map_[target_window_]->RequestFocus(); + } } void HandleWindowDestruction(WmWindow* destroying_window, @@ -283,7 +295,7 @@ SetTargetWindow(new_target); } - // views::View overrides: + // views::WidgetDelegateView overrides: gfx::Size GetPreferredSize() const override { return mirror_container_->GetPreferredSize(); } @@ -314,6 +326,12 @@ highlight_view_->SetBoundsRect(gfx::ToEnclosingRect(target_bounds)); } + View* GetContentsView() override { return this; } + + View* GetInitiallyFocusedView() override { + return window_view_map_[target_window_]; + } + WmWindow* target_window() { return target_window_; } private: @@ -384,9 +402,12 @@ window->AddObserver(this); if (ShouldShowUi()) { + cycle_view_ = new WindowCycleView(windows_); + WmWindow* root_window = WmShell::Get()->GetRootWindowForNewWindows(); views::Widget* widget = new views::Widget; views::Widget::InitParams params; + params.delegate = cycle_view_; params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS; params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; @@ -398,9 +419,6 @@ widget, kShellWindowId_OverlayContainer, ¶ms); widget->Init(params); - cycle_view_ = new WindowCycleView(windows_); - - widget->SetContentsView(cycle_view_); // TODO(estade): right now this just extends past the edge of the screen if // there are too many windows. Handle this more gracefully. Also, if // the display metrics change, cancel the UI.
diff --git a/ash/common/wm/workspace/workspace_layout_manager.cc b/ash/common/wm/workspace/workspace_layout_manager.cc index e1a19c7..3ea9ddb 100644 --- a/ash/common/wm/workspace/workspace_layout_manager.cc +++ b/ash/common/wm/workspace/workspace_layout_manager.cc
@@ -8,6 +8,8 @@ #include "ash/common/ash_switches.h" #include "ash/common/session/session_state_delegate.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/shell_window_ids.h" #include "ash/common/wm/always_on_top_controller.h" #include "ash/common/wm/fullscreen_window_finder.h" #include "ash/common/wm/window_positioner.h" @@ -15,7 +17,6 @@ #include "ash/common/wm/wm_event.h" #include "ash/common/wm/wm_screen_util.h" #include "ash/common/wm/workspace/workspace_layout_manager_backdrop_delegate.h" -#include "ash/common/wm/workspace/workspace_layout_manager_delegate.h" #include "ash/common/wm_root_window_controller.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" @@ -27,14 +28,11 @@ namespace ash { -WorkspaceLayoutManager::WorkspaceLayoutManager( - WmWindow* window, - std::unique_ptr<wm::WorkspaceLayoutManagerDelegate> delegate) +WorkspaceLayoutManager::WorkspaceLayoutManager(WmWindow* window) : window_(window), root_window_(window->GetRootWindow()), root_window_controller_(root_window_->GetRootWindowController()), shell_(window_->GetShell()), - delegate_(std::move(delegate)), work_area_in_parent_(wm::GetDisplayWorkAreaBounds(window_)), is_fullscreen_(wm::GetWindowForFullscreenMode(window) != nullptr) { shell_->AddShellObserver(this); @@ -58,10 +56,6 @@ shell_->RemoveShellObserver(this); } -void WorkspaceLayoutManager::DeleteDelegate() { - delegate_.reset(); -} - void WorkspaceLayoutManager::SetMaximizeBackdropDelegate( std::unique_ptr<WorkspaceLayoutManagerBackdropDelegate> delegate) { backdrop_delegate_.reset(delegate.release()); @@ -192,22 +186,6 @@ backdrop_delegate_->OnDisplayWorkAreaInsetsChanged(); } -void WorkspaceLayoutManager::OnFullscreenStateChanged(bool is_fullscreen) { - if (is_fullscreen_ == is_fullscreen) - return; - - is_fullscreen_ = is_fullscreen; - if (WmShell::Get()->IsPinned()) { - // If this is in pinned mode, then this event does not trigger the - // always-on-top state change, because it is kept disabled regardless of - // the fullscreen state change. - return; - } - - UpdateAlwaysOnTop(is_fullscreen_ ? wm::GetWindowForFullscreenMode(window_) - : nullptr); -} - ////////////////////////////////////////////////////////////////////////////// // WorkspaceLayoutManager, aura::WindowObserver implementation: @@ -306,6 +284,23 @@ ////////////////////////////////////////////////////////////////////////////// // WorkspaceLayoutManager, ShellObserver implementation: +void WorkspaceLayoutManager::OnFullscreenStateChanged(bool is_fullscreen, + WmWindow* root_window) { + if (root_window != root_window_ || is_fullscreen_ == is_fullscreen) + return; + + is_fullscreen_ = is_fullscreen; + if (WmShell::Get()->IsPinned()) { + // If this is in pinned mode, then this event does not trigger the + // always-on-top state change, because it is kept disabled regardless of + // the fullscreen state change. + return; + } + + UpdateAlwaysOnTop(is_fullscreen_ ? wm::GetWindowForFullscreenMode(window_) + : nullptr); +} + void WorkspaceLayoutManager::OnPinnedStateChanged(WmWindow* pinned_window) { if (!WmShell::Get()->IsPinned() && is_fullscreen_) { // On exiting from pinned mode, if the workspace is still in fullscreen @@ -345,8 +340,8 @@ } void WorkspaceLayoutManager::UpdateShelfVisibility() { - if (delegate_) - delegate_->UpdateShelfVisibility(); + if (root_window_controller_->HasShelf()) + root_window_controller_->GetShelf()->UpdateVisibilityState(); } void WorkspaceLayoutManager::UpdateFullscreenState() { @@ -355,11 +350,11 @@ // only windows in the default workspace container will go fullscreen but // this should really be tracked by the RootWindowController since // technically any container could get a fullscreen window. - if (!delegate_) + if (window_->GetShellWindowId() != kShellWindowId_DefaultContainer) return; bool is_fullscreen = wm::GetWindowForFullscreenMode(window_) != nullptr; if (is_fullscreen != is_fullscreen_) { - delegate_->OnFullscreenStateChanged(is_fullscreen); + WmShell::Get()->NotifyFullscreenStateChanged(is_fullscreen, root_window_); is_fullscreen_ = is_fullscreen; } }
diff --git a/ash/common/wm/workspace/workspace_layout_manager.h b/ash/common/wm/workspace/workspace_layout_manager.h index a91fc615..e11a782 100644 --- a/ash/common/wm/workspace/workspace_layout_manager.h +++ b/ash/common/wm/workspace/workspace_layout_manager.h
@@ -26,7 +26,6 @@ class WorkspaceLayoutManagerBackdropDelegate; namespace wm { -class WorkspaceLayoutManagerDelegate; class WMEvent; } @@ -40,14 +39,10 @@ public ShellObserver, public wm::WindowStateObserver { public: - WorkspaceLayoutManager( - WmWindow* window, - std::unique_ptr<wm::WorkspaceLayoutManagerDelegate> delegate); - + // |window| is the container for this layout manager. + explicit WorkspaceLayoutManager(WmWindow* window); ~WorkspaceLayoutManager() override; - void DeleteDelegate(); - // A delegate which can be set to add a backdrop behind the top most visible // window. With the call the ownership of the delegate will be transferred to // the WorkspaceLayoutManager. @@ -65,7 +60,6 @@ // WmRootWindowControllerObserver overrides: void OnWorkAreaChanged() override; - void OnFullscreenStateChanged(bool is_fullscreen) override; // Overriden from WmWindowObserver: void OnWindowTreeChanged( @@ -91,12 +85,8 @@ wm::WindowStateType old_type) override; // ShellObserver overrides: - void OnFullscreenStateChanged(bool is_fullscreen, WmWindow* root) override { - // Do nothing. Fullscreen state change is observed by the - // WmRootWindowControllerObserver::OnFullscreenStateChanged(). - // Because the name is conflicting, some compiler warns because this is - // hidden. To avoid it, we define it here, with empty body. - } + void OnFullscreenStateChanged(bool is_fullscreen, + WmWindow* root_window) override; void OnPinnedStateChanged(WmWindow* pinned_window) override; private: @@ -127,8 +117,6 @@ WmRootWindowController* root_window_controller_; WmShell* shell_; - std::unique_ptr<wm::WorkspaceLayoutManagerDelegate> delegate_; - // Set of windows we're listening to. WindowSet windows_;
diff --git a/ash/common/wm/workspace/workspace_layout_manager_delegate.h b/ash/common/wm/workspace/workspace_layout_manager_delegate.h deleted file mode 100644 index 9a573d0..0000000 --- a/ash/common/wm/workspace/workspace_layout_manager_delegate.h +++ /dev/null
@@ -1,28 +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_COMMON_WM_WORKSPACE_WORKSPACE_LAYOUT_MANAGER_DELEGATE_H_ -#define ASH_COMMON_WM_WORKSPACE_WORKSPACE_LAYOUT_MANAGER_DELEGATE_H_ - -#include "ash/ash_export.h" - -namespace ash { -namespace wm { - -class ASH_EXPORT WorkspaceLayoutManagerDelegate { - public: - virtual ~WorkspaceLayoutManagerDelegate() {} - - // Called when the visibility of the shelf needs to be updated. - // TODO(jamescook): Eliminate this and use WmShelf directly. - virtual void UpdateShelfVisibility() = 0; - - // Called when the fullscreen state has changed to |is_fullscreen|. - virtual void OnFullscreenStateChanged(bool is_fullscreen) = 0; -}; - -} // namespace wm -} // namespace ash - -#endif // ASH_COMMON_WM_WORKSPACE_WORKSPACE_LAYOUT_MANAGER_DELEGATE_H_
diff --git a/ash/common/wm_root_window_controller_observer.h b/ash/common/wm_root_window_controller_observer.h index 86f90d1..dd959f1 100644 --- a/ash/common/wm_root_window_controller_observer.h +++ b/ash/common/wm_root_window_controller_observer.h
@@ -15,7 +15,6 @@ class ASH_EXPORT WmRootWindowControllerObserver { public: virtual void OnWorkAreaChanged() {} - virtual void OnFullscreenStateChanged(bool is_fullscreen) {} virtual void OnShelfAlignmentChanged() {} protected:
diff --git a/ash/common/wm_shell.cc b/ash/common/wm_shell.cc index 6d629cb..5941e28 100644 --- a/ash/common/wm_shell.cc +++ b/ash/common/wm_shell.cc
@@ -98,6 +98,12 @@ FOR_EACH_OBSERVER(ShellObserver, shell_observers_, OnMaximizeModeEnded()); } +void WmShell::NotifyFullscreenStateChanged(bool is_fullscreen, + WmWindow* root_window) { + FOR_EACH_OBSERVER(ShellObserver, shell_observers_, + OnFullscreenStateChanged(is_fullscreen, root_window)); +} + void WmShell::NotifyPinnedStateChanged(WmWindow* pinned_window) { FOR_EACH_OBSERVER(ShellObserver, shell_observers_, OnPinnedStateChanged(pinned_window));
diff --git a/ash/common/wm_shell.h b/ash/common/wm_shell.h index 02dbdfc..8dd3d7e 100644 --- a/ash/common/wm_shell.h +++ b/ash/common/wm_shell.h
@@ -283,6 +283,9 @@ // Called after overview mode has ended. virtual void OnOverviewModeEnded() = 0; + // Notifies observers after toggling fullscreen mode in |root_window|. + void NotifyFullscreenStateChanged(bool is_fullscreen, WmWindow* root_window); + // Notifies |observers_| when entering or exiting pinned mode for // |pinned_window|. Entering or exiting can be checked by looking at // |pinned_window|'s window state.
diff --git a/ash/mus/BUILD.gn b/ash/mus/BUILD.gn index 073dc85..5778e5f 100644 --- a/ash/mus/BUILD.gn +++ b/ash/mus/BUILD.gn
@@ -38,24 +38,10 @@ "disconnected_app_handler.h", "drag_window_resizer.cc", "drag_window_resizer.h", - "frame/caption_buttons/caption_button_types.h", - "frame/caption_buttons/frame_caption_button.cc", - "frame/caption_buttons/frame_caption_button.h", - "frame/caption_buttons/frame_caption_button_container_view.cc", - "frame/caption_buttons/frame_caption_button_container_view.h", - "frame/default_header_painter.cc", - "frame/default_header_painter.h", - "frame/frame_border_hit_test_controller.cc", - "frame/frame_border_hit_test_controller.h", - "frame/header_painter.h", - "frame/header_painter_util.cc", - "frame/header_painter_util.h", - "frame/move_event_handler.cc", - "frame/move_event_handler.h", - "frame/non_client_frame_view_mash.cc", - "frame/non_client_frame_view_mash.h", "layout_manager.cc", "layout_manager.h", + "move_event_handler.cc", + "move_event_handler.h", "new_window_delegate_mus.cc", "new_window_delegate_mus.h", "non_client_frame_controller.cc", @@ -70,8 +56,6 @@ "shadow.h", "shadow_controller.cc", "shadow_controller.h", - "shelf_layout_impl.cc", - "shelf_layout_impl.h", "shelf_layout_manager.cc", "shelf_layout_manager.h", "shelf_layout_manager_delegate.h", @@ -79,8 +63,6 @@ "shell_delegate_mus.h", "status_layout_manager.cc", "status_layout_manager.h", - "user_window_controller_impl.cc", - "user_window_controller_impl.h", "window_manager.cc", "window_manager.h", "window_manager_application.cc", @@ -90,13 +72,13 @@ deps = [ "//components/user_manager", + "//mash/shelf/public/interfaces", "//ui/app_list/presenter", "//ui/message_center", ] public_deps = [ "//ash", - "//ash/mus/resources", "//ash/public/interfaces", "//base", "//mash/session/public/interfaces", @@ -161,7 +143,6 @@ output = "$root_out_dir/ash_mus_resources.pak" sources = [ "$root_gen_dir/ash/common/strings/ash_strings_en-US.pak", - "$root_gen_dir/ash/mus/resources/ash_mus_resources_100_percent.pak", "$root_gen_dir/ash/resources/ash_resources_100_percent.pak", "$root_gen_dir/ui/resources/ui_resources_100_percent.pak", "$root_gen_dir/ui/strings/app_locale_settings_en-US.pak", @@ -170,7 +151,6 @@ ] deps = [ "//ash/common/strings", - "//ash/mus/resources", "//ash/resources", "//ui/resources", "//ui/strings", @@ -189,6 +169,7 @@ "accelerators/accelerator_registrar_unittest.cc", "app_launch_unittest.cc", "bridge/wm_shell_mus_test_api.h", + "bridge/wm_window_mus_test_api.h", "layout_manager_unittest.cc", "root_window_controller_unittest.cc", "test/wm_test_base.cc",
diff --git a/ash/mus/bridge/wm_root_window_controller_mus.cc b/ash/mus/bridge/wm_root_window_controller_mus.cc index fe98ba7..46bd642 100644 --- a/ash/mus/bridge/wm_root_window_controller_mus.cc +++ b/ash/mus/bridge/wm_root_window_controller_mus.cc
@@ -55,12 +55,6 @@ return window->GetRoot()->GetLocalProperty(kWmRootWindowControllerKey); } -void WmRootWindowControllerMus::NotifyFullscreenStateChange( - bool is_fullscreen) { - FOR_EACH_OBSERVER(WmRootWindowControllerObserver, observers_, - OnFullscreenStateChanged(is_fullscreen)); -} - gfx::Point WmRootWindowControllerMus::ConvertPointToScreen( const WmWindowMus* source, const gfx::Point& point) const {
diff --git a/ash/mus/bridge/wm_root_window_controller_mus.h b/ash/mus/bridge/wm_root_window_controller_mus.h index 4ed1c34..0671820 100644 --- a/ash/mus/bridge/wm_root_window_controller_mus.h +++ b/ash/mus/bridge/wm_root_window_controller_mus.h
@@ -41,8 +41,6 @@ return root_window_controller_; } - void NotifyFullscreenStateChange(bool is_fullscreen); - // Screen conversion functions. gfx::Point ConvertPointToScreen(const WmWindowMus* source, const gfx::Point& point) const;
diff --git a/ash/mus/bridge/wm_shelf_mus.cc b/ash/mus/bridge/wm_shelf_mus.cc index 39e10de..f56328c7 100644 --- a/ash/mus/bridge/wm_shelf_mus.cc +++ b/ash/mus/bridge/wm_shelf_mus.cc
@@ -64,8 +64,13 @@ return SHELF_BACKGROUND_DEFAULT; } +WmDimmerView* WmShelfMus::CreateDimmerView(bool disable_animations_for_test) { + // mus does not dim shelf items. + return nullptr; +} + bool WmShelfMus::IsDimmed() const { - NOTIMPLEMENTED(); + // mus does not dim shelf items. return false; } @@ -116,14 +121,6 @@ return false; } -void WmShelfMus::UpdateAutoHideForMouseEvent(ui::MouseEvent* event) { - NOTIMPLEMENTED(); -} - -void WmShelfMus::UpdateAutoHideForGestureEvent(ui::GestureEvent* event) { - NOTIMPLEMENTED(); -} - void WmShelfMus::AddObserver(WmShelfObserver* observer) { observers_.AddObserver(observer); }
diff --git a/ash/mus/bridge/wm_shelf_mus.h b/ash/mus/bridge/wm_shelf_mus.h index 985cc08..d670d18b 100644 --- a/ash/mus/bridge/wm_shelf_mus.h +++ b/ash/mus/bridge/wm_shelf_mus.h
@@ -33,6 +33,7 @@ ShelfAutoHideState GetAutoHideState() const override; void UpdateAutoHideState() override; ShelfBackgroundType GetBackgroundType() const override; + WmDimmerView* CreateDimmerView(bool disable_animations_for_test) override; bool IsDimmed() const override; bool IsShowingOverflowBubble() const override; void SchedulePaint() override; @@ -44,8 +45,6 @@ void UpdateIconPositionForWindow(WmWindow* window) override; gfx::Rect GetScreenBoundsOfItemIconForWindow(WmWindow* window) override; bool ProcessGestureEvent(const ui::GestureEvent& event) override; - void UpdateAutoHideForMouseEvent(ui::MouseEvent* event) override; - void UpdateAutoHideForGestureEvent(ui::GestureEvent* event) override; void AddObserver(WmShelfObserver* observer) override; void RemoveObserver(WmShelfObserver* observer) override; void SetKeyboardBoundsForTesting(const gfx::Rect& bounds) override;
diff --git a/ash/mus/bridge/wm_window_mus.cc b/ash/mus/bridge/wm_window_mus.cc index 1b8db8e..d779cf4 100644 --- a/ash/mus/bridge/wm_window_mus.cc +++ b/ash/mus/bridge/wm_window_mus.cc
@@ -272,7 +272,9 @@ } gfx::Size WmWindowMus::GetMinimumSize() const { - return widget_ ? widget_->GetMinimumSize() : gfx::Size(); + return widget_ && !use_empty_minimum_size_for_testing_ + ? widget_->GetMinimumSize() + : gfx::Size(); } gfx::Size WmWindowMus::GetMaximumSize() const { @@ -356,6 +358,12 @@ return; } + if (key == WmWindowProperty::TOP_VIEW_INSET) { + // TODO: need support for TOP_VIEW_INSET: http://crbug.com/615100. + NOTIMPLEMENTED(); + return; + } + NOTREACHED(); }
diff --git a/ash/mus/bridge/wm_window_mus.h b/ash/mus/bridge/wm_window_mus.h index 3e94c97..cecb7e7 100644 --- a/ash/mus/bridge/wm_window_mus.h +++ b/ash/mus/bridge/wm_window_mus.h
@@ -27,6 +27,7 @@ class MusLayoutManagerAdapter; class WmRootWindowControllerMus; +class WmWindowMusTestApi; // WmWindow implementation for mus. // @@ -229,6 +230,8 @@ void RemoveLimitedPreTargetHandler(ui::EventHandler* handler) override; private: + friend class WmWindowMusTestApi; + // ui::WindowObserver: void OnTreeChanging(const TreeChangeParams& params) override; void OnTreeChanged(const TreeChangeParams& params) override; @@ -278,6 +281,9 @@ base::ObserverList<WmTransientWindowObserver, true> transient_observers_; + // If true the minimum size is 0x0, default is minimum size comes from widget. + bool use_empty_minimum_size_for_testing_ = false; + DISALLOW_COPY_AND_ASSIGN(WmWindowMus); };
diff --git a/ash/mus/bridge/wm_window_mus_test_api.h b/ash/mus/bridge/wm_window_mus_test_api.h new file mode 100644 index 0000000..aa064861 --- /dev/null +++ b/ash/mus/bridge/wm_window_mus_test_api.h
@@ -0,0 +1,33 @@ +// 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_MUS_BRIDGE_WM_WINDOW_MUS_TEST_API_H_ +#define ASH_MUS_BRIDGE_WM_WINDOW_MUS_TEST_API_H_ + +#include "ash/mus/bridge/wm_window_mus.h" + +namespace ash { +namespace mus { + +class WmWindowMusTestApi { + public: + explicit WmWindowMusTestApi(WmWindow* window) + : WmWindowMusTestApi(WmWindowMus::AsWmWindowMus(window)) {} + explicit WmWindowMusTestApi(WmWindowMus* window) : window_(window) {} + ~WmWindowMusTestApi() {} + + void set_use_empty_minimum_size(bool value) { + window_->use_empty_minimum_size_for_testing_ = true; + } + + private: + WmWindowMus* window_; + + DISALLOW_COPY_AND_ASSIGN(WmWindowMusTestApi); +}; + +} // namespace mus +} // namespace ash + +#endif // ASH_MUS_BRIDGE_WM_WINDOW_MUS_TEST_API_H_
diff --git a/ash/mus/frame/caption_buttons/caption_button_types.h b/ash/mus/frame/caption_buttons/caption_button_types.h deleted file mode 100644 index b72588859..0000000 --- a/ash/mus/frame/caption_buttons/caption_button_types.h +++ /dev/null
@@ -1,27 +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_MUS_FRAME_CAPTION_BUTTONS_CAPTION_BUTTON_TYPES_H_ -#define ASH_MUS_FRAME_CAPTION_BUTTONS_CAPTION_BUTTON_TYPES_H_ - -namespace ash { -namespace mus { - -// These are the icon types that a caption button can have. The size button's -// action (SnapType) can be different from its icon. -enum CaptionButtonIcon { - CAPTION_BUTTON_ICON_MINIMIZE, - CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE, - CAPTION_BUTTON_ICON_CLOSE, - CAPTION_BUTTON_ICON_LEFT_SNAPPED, - CAPTION_BUTTON_ICON_RIGHT_SNAPPED, - CAPTION_BUTTON_ICON_BACK, - CAPTION_BUTTON_ICON_LOCATION, - CAPTION_BUTTON_ICON_COUNT -}; - -} // namespace mus -} // namespace ash - -#endif // ASH_MUS_FRAME_CAPTION_BUTTONS_CAPTION_BUTTON_TYPES_H_
diff --git a/ash/mus/frame/caption_buttons/frame_caption_button.cc b/ash/mus/frame/caption_buttons/frame_caption_button.cc deleted file mode 100644 index 48eb471..0000000 --- a/ash/mus/frame/caption_buttons/frame_caption_button.cc +++ /dev/null
@@ -1,193 +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/mus/frame/caption_buttons/frame_caption_button.h" - -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/animation/slide_animation.h" -#include "ui/gfx/animation/throb_animation.h" -#include "ui/gfx/canvas.h" - -namespace ash { -namespace mus { - -namespace { - -// The duration of the crossfade animation when swapping the button's images. -const int kSwapImagesAnimationDurationMs = 200; - -// The duration of the fade out animation of the old icon during a crossfade -// animation as a ratio of |kSwapImagesAnimationDurationMs|. -const float kFadeOutRatio = 0.5f; - -// The alpha to draw inactive icons with. -const float kInactiveIconAlpha = 0.2f; - -} // namespace - -// static -const char FrameCaptionButton::kViewClassName[] = "FrameCaptionButton"; - -FrameCaptionButton::FrameCaptionButton(views::ButtonListener* listener, - CaptionButtonIcon icon) - : CustomButton(listener), - icon_(icon), - paint_as_active_(false), - alpha_(255), - icon_image_id_(-1), - hovered_background_image_id_(-1), - pressed_background_image_id_(-1), - swap_images_animation_(new gfx::SlideAnimation(this)) { - swap_images_animation_->Reset(1); - - // Do not flip the gfx::Canvas passed to the OnPaint() method. The snap left - // and snap right button icons should not be flipped. The other icons are - // horizontally symmetrical. -} - -FrameCaptionButton::~FrameCaptionButton() {} - -void FrameCaptionButton::SetImages(CaptionButtonIcon icon, - Animate animate, - int icon_image_id, - int hovered_background_image_id, - int pressed_background_image_id) { - // The early return is dependant on |animate| because callers use SetImages() - // with ANIMATE_NO to progress the crossfade animation to the end. - if (icon == icon_ && - (animate == ANIMATE_YES || !swap_images_animation_->is_animating()) && - icon_image_id == icon_image_id_ && - hovered_background_image_id == hovered_background_image_id_ && - pressed_background_image_id == pressed_background_image_id_) { - return; - } - - if (animate == ANIMATE_YES) - crossfade_icon_image_ = icon_image_; - - icon_ = icon; - icon_image_id_ = icon_image_id; - // TODO(sky): it doesn't seem like these are used. - hovered_background_image_id_ = hovered_background_image_id; - pressed_background_image_id_ = pressed_background_image_id; - - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - icon_image_ = *rb.GetImageSkiaNamed(icon_image_id); - hovered_background_image_ = - *rb.GetImageSkiaNamed(hovered_background_image_id); - pressed_background_image_ = - *rb.GetImageSkiaNamed(pressed_background_image_id); - - if (animate == ANIMATE_YES) { - swap_images_animation_->Reset(0); - swap_images_animation_->SetSlideDuration(kSwapImagesAnimationDurationMs); - swap_images_animation_->Show(); - } else { - swap_images_animation_->Reset(1); - } - PreferredSizeChanged(); - SchedulePaint(); -} - -bool FrameCaptionButton::IsAnimatingImageSwap() const { - return swap_images_animation_->is_animating(); -} - -void FrameCaptionButton::SetAlpha(int alpha) { - if (alpha_ != alpha) { - alpha_ = alpha; - SchedulePaint(); - } -} - -gfx::Size FrameCaptionButton::GetPreferredSize() const { - return hovered_background_image_.isNull() ? gfx::Size() - : hovered_background_image_.size(); -} - -const char* FrameCaptionButton::GetClassName() const { - return kViewClassName; -} - -void FrameCaptionButton::OnPaint(gfx::Canvas* canvas) { - if (hover_animation().is_animating() || state() == STATE_HOVERED) { - int hovered_background_alpha = - hover_animation().CurrentValueBetween(0, 255); - SkPaint paint; - paint.setAlpha(hovered_background_alpha); - canvas->DrawImageInt(hovered_background_image_, 0, 0, paint); - } else if (state() == STATE_PRESSED) { - canvas->DrawImageInt(pressed_background_image_, 0, 0); - } - - int icon_alpha = swap_images_animation_->CurrentValueBetween(0, 255); - int crossfade_icon_alpha = 0; - if (icon_alpha < static_cast<int>(kFadeOutRatio * 255)) - crossfade_icon_alpha = static_cast<int>(255 - icon_alpha / kFadeOutRatio); - - if (crossfade_icon_alpha > 0 && !crossfade_icon_image_.isNull()) { - gfx::Canvas icon_canvas(icon_image_.size(), canvas->image_scale(), false); - SkPaint paint; - paint.setAlpha(icon_alpha); - icon_canvas.DrawImageInt(icon_image_, 0, 0, paint); - - paint.setAlpha(crossfade_icon_alpha); - paint.setXfermodeMode(SkXfermode::kPlus_Mode); - icon_canvas.DrawImageInt(crossfade_icon_image_, 0, 0, paint); - - PaintCentered(canvas, gfx::ImageSkia(icon_canvas.ExtractImageRep()), - alpha_); - } else { - if (!swap_images_animation_->is_animating()) - icon_alpha = alpha_; - PaintCentered(canvas, icon_image_, icon_alpha); - } -} - -void FrameCaptionButton::OnGestureEvent(ui::GestureEvent* event) { - // CustomButton does not become pressed when the user drags off and then back - // onto the button. Make FrameCaptionButton pressed in this case because this - // behavior is more consistent with AlternateFrameSizeButton. - if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN || - event->type() == ui::ET_GESTURE_SCROLL_UPDATE) { - if (HitTestPoint(event->location())) { - SetState(STATE_PRESSED); - RequestFocus(); - event->StopPropagation(); - } else { - SetState(STATE_NORMAL); - } - } else if (event->type() == ui::ET_GESTURE_SCROLL_END) { - if (HitTestPoint(event->location())) { - SetState(STATE_HOVERED); - NotifyClick(*event); - event->StopPropagation(); - } - } - CustomButton::OnGestureEvent(event); -} - -void FrameCaptionButton::PaintCentered(gfx::Canvas* canvas, - const gfx::ImageSkia& to_center, - int alpha) { - if (!paint_as_active_) { - // Paint icons as active when they are hovered over or pressed. - double inactive_alpha = kInactiveIconAlpha; - if (hover_animation().is_animating()) { - inactive_alpha = - hover_animation().CurrentValueBetween(inactive_alpha, 1.0f); - } else if (state() == STATE_PRESSED || state() == STATE_HOVERED) { - inactive_alpha = 1.0f; - } - alpha *= inactive_alpha; - } - - SkPaint paint; - paint.setAlpha(alpha); - canvas->DrawImageInt(to_center, (width() - to_center.width()) / 2, - (height() - to_center.height()) / 2, paint); -} - -} // namespace mus -} // namespace ash
diff --git a/ash/mus/frame/caption_buttons/frame_caption_button.h b/ash/mus/frame/caption_buttons/frame_caption_button.h deleted file mode 100644 index 8c3bff1..0000000 --- a/ash/mus/frame/caption_buttons/frame_caption_button.h +++ /dev/null
@@ -1,103 +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_MUS_FRAME_CAPTION_BUTTONS_FRAME_CAPTION_BUTTON_H_ -#define ASH_MUS_FRAME_CAPTION_BUTTONS_FRAME_CAPTION_BUTTON_H_ - -#include <memory> - -#include "ash/mus/frame/caption_buttons/caption_button_types.h" -#include "base/macros.h" -#include "ui/gfx/image/image_skia.h" -#include "ui/views/controls/button/custom_button.h" - -namespace gfx { -class SlideAnimation; -} - -namespace ash { -namespace mus { - -// Base class for the window caption buttons (minimize, maximize, restore, -// close). -class FrameCaptionButton : public views::CustomButton { - public: - enum Animate { ANIMATE_YES, ANIMATE_NO }; - - static const char kViewClassName[]; - - FrameCaptionButton(views::ButtonListener* listener, CaptionButtonIcon icon); - ~FrameCaptionButton() override; - - // Sets the images to use to paint the button. If |animate| is ANIMATE_YES, - // the button crossfades to the new visuals. If the image ids match those - // currently used by the button and |animate| is ANIMATE_NO the crossfade - // animation is progressed to the end. - void SetImages(CaptionButtonIcon icon, - Animate animate, - int icon_image_id, - int hovered_background_image_id, - int pressed_background_image_id); - - // Returns true if the button is crossfading to new visuals set in - // SetImages(). - bool IsAnimatingImageSwap() const; - - // Sets the alpha to use for painting. Used to animate visibility changes. - void SetAlpha(int alpha); - - // views::View overrides: - gfx::Size GetPreferredSize() const override; - const char* GetClassName() const override; - void OnPaint(gfx::Canvas* canvas) override; - - void set_paint_as_active(bool paint_as_active) { - paint_as_active_ = paint_as_active; - } - - CaptionButtonIcon icon() const { return icon_; } - - int icon_image_id() const { return icon_image_id_; } - - protected: - // views::CustomButton override: - void OnGestureEvent(ui::GestureEvent* event) override; - - private: - // Paints |to_center| centered within the button with |alpha|. - void PaintCentered(gfx::Canvas* canvas, - const gfx::ImageSkia& to_center, - int alpha); - - // The button's current icon. - CaptionButtonIcon icon_; - - // Whether the button should be painted as active. - bool paint_as_active_; - - // Current alpha to use for painting. - int alpha_; - - // The images and image ids used to paint the button. - int icon_image_id_; - int hovered_background_image_id_; - int pressed_background_image_id_; - gfx::ImageSkia icon_image_; - gfx::ImageSkia hovered_background_image_; - gfx::ImageSkia pressed_background_image_; - - // The icon image to crossfade from. - gfx::ImageSkia crossfade_icon_image_; - - // Crossfade animation started when the button's images are changed by - // SetImages(). - std::unique_ptr<gfx::SlideAnimation> swap_images_animation_; - - DISALLOW_COPY_AND_ASSIGN(FrameCaptionButton); -}; - -} // namespace mus -} // namespace ash - -#endif // ASH_MUS_FRAME_CAPTION_BUTTONS_FRAME_CAPTION_BUTTON_H_
diff --git a/ash/mus/frame/caption_buttons/frame_caption_button_container_view.cc b/ash/mus/frame/caption_buttons/frame_caption_button_container_view.cc deleted file mode 100644 index 7f98c43e..0000000 --- a/ash/mus/frame/caption_buttons/frame_caption_button_container_view.cc +++ /dev/null
@@ -1,356 +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/mus/frame/caption_buttons/frame_caption_button_container_view.h" - -#include <stddef.h> - -#include <cmath> -#include <map> - -#include "ash/mus/frame/caption_buttons/frame_caption_button.h" -#include "base/macros.h" -#include "ui/base/hit_test.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/gfx/animation/slide_animation.h" -#include "ui/gfx/animation/tween.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/geometry/insets.h" -#include "ui/gfx/geometry/point.h" -#include "ui/strings/grit/ui_strings.h" // Accessibility names -#include "ui/views/widget/widget.h" -#include "ui/views/widget/widget_delegate.h" - -namespace ash { -namespace mus { - -namespace { - -// Duration of the animation of the position of |minimize_button_|. -const int kPositionAnimationDurationMs = 500; - -// Duration of the animation of the alpha of |size_button_|. -const int kAlphaAnimationDurationMs = 250; - -// Delay during |maximize_mode_animation_| hide to wait before beginning to -// animate the position of |minimize_button_|. -const int kHidePositionDelayMs = 100; - -// Duration of |maximize_mode_animation_| hiding. -// Hiding size button 250 -// |------------------------| -// Delay 100 Slide minimize button 500 -// |---------|-------------------------------------------------| -const int kHideAnimationDurationMs = - kHidePositionDelayMs + kPositionAnimationDurationMs; - -// Delay during |maximize_mode_animation_| show to wait before beginning to -// animate the alpha of |size_button_|. -const int kShowAnimationAlphaDelayMs = 100; - -// Duration of |maximize_mode_animation_| showing. -// Slide minimize button 500 -// |-------------------------------------------------| -// Delay 100 Show size button 250 -// |---------|-----------------------| -const int kShowAnimationDurationMs = kPositionAnimationDurationMs; - -// Value of |maximize_mode_animation_| showing to begin animating alpha of -// |size_button_|. -float SizeButtonShowStartValue() { - return static_cast<float>(kShowAnimationAlphaDelayMs) / - kShowAnimationDurationMs; -} - -// Amount of |maximize_mode_animation_| showing to animate the alpha of -// |size_button_|. -float SizeButtonShowDuration() { - return static_cast<float>(kAlphaAnimationDurationMs) / - kShowAnimationDurationMs; -} - -// Amount of |maximize_mode_animation_| hiding to animate the alpha of -// |size_button_|. -float SizeButtonHideDuration() { - return static_cast<float>(kAlphaAnimationDurationMs) / - kHideAnimationDurationMs; -} - -// Value of |maximize_mode_animation_| hiding to begin animating the position of -// |minimize_button_|. -float HidePositionStartValue() { - return 1.0f - - 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. -double CapAnimationValue(double value) { - return std::min(1.0, std::max(0.0, value)); -} - -} // namespace - -// static -const char FrameCaptionButtonContainerView::kViewClassName[] = - "FrameCaptionButtonContainerView"; - -FrameCaptionButtonContainerView::FrameCaptionButtonContainerView( - views::Widget* frame) - : frame_(frame), - minimize_button_(NULL), - size_button_(NULL), - close_button_(NULL) { - const bool size_button_visibility = ShouldSizeButtonBeVisible(); - maximize_mode_animation_.reset(new gfx::SlideAnimation(this)); - maximize_mode_animation_->SetTweenType(gfx::Tween::LINEAR); - - // Ensure animation tracks visibility of size button. - if (size_button_visibility) - maximize_mode_animation_->Reset(1.0f); - - // Insert the buttons left to right. - minimize_button_ = new FrameCaptionButton(this, CAPTION_BUTTON_ICON_MINIMIZE); - minimize_button_->SetAccessibleName( - l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MINIMIZE)); - minimize_button_->SetVisible(frame_->widget_delegate()->CanMinimize()); - AddChildView(minimize_button_); - - size_button_ = - new FrameCaptionButton(this, CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE); - size_button_->SetAccessibleName( - l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MAXIMIZE)); - size_button_->SetVisible(size_button_visibility); - AddChildView(size_button_); - - close_button_ = new FrameCaptionButton(this, CAPTION_BUTTON_ICON_CLOSE); - close_button_->SetAccessibleName( - l10n_util::GetStringUTF16(IDS_APP_ACCNAME_CLOSE)); - AddChildView(close_button_); -} - -FrameCaptionButtonContainerView::~FrameCaptionButtonContainerView() {} - -void FrameCaptionButtonContainerView::SetButtonImages( - CaptionButtonIcon icon, - int icon_image_id, - int hovered_background_image_id, - int pressed_background_image_id) { - button_icon_id_map_[icon] = ButtonIconIds( - icon_image_id, hovered_background_image_id, pressed_background_image_id); - FrameCaptionButton* buttons[] = {minimize_button_, size_button_, - close_button_}; - for (size_t i = 0; i < arraysize(buttons); ++i) { - if (buttons[i]->icon() == icon) { - buttons[i]->SetImages(icon, FrameCaptionButton::ANIMATE_NO, icon_image_id, - hovered_background_image_id, - pressed_background_image_id); - } - } -} - -void FrameCaptionButtonContainerView::SetPaintAsActive(bool paint_as_active) { - minimize_button_->set_paint_as_active(paint_as_active); - size_button_->set_paint_as_active(paint_as_active); - close_button_->set_paint_as_active(paint_as_active); -} - -void FrameCaptionButtonContainerView::ResetWindowControls() { - 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; - } - return HTNOWHERE; -} - -void FrameCaptionButtonContainerView::UpdateSizeButtonVisibility() { - bool visible = ShouldSizeButtonBeVisible(); - if (visible) { - size_button_->SetVisible(true); - maximize_mode_animation_->SetSlideDuration(kShowAnimationDurationMs); - maximize_mode_animation_->Show(); - } else { - maximize_mode_animation_->SetSlideDuration(kHideAnimationDurationMs); - maximize_mode_animation_->Hide(); - } -} - -gfx::Size FrameCaptionButtonContainerView::GetPreferredSize() const { - int width = 0; - for (int i = 0; i < child_count(); ++i) { - const views::View* child = child_at(i); - if (child->visible()) - width += child_at(i)->GetPreferredSize().width(); - } - return gfx::Size(width, close_button_->GetPreferredSize().height()); -} - -void FrameCaptionButtonContainerView::Layout() { - int x = 0; - for (int i = 0; i < child_count(); ++i) { - views::View* child = child_at(i); - if (!child->visible()) - continue; - - gfx::Size size = child->GetPreferredSize(); - child->SetBounds(x, 0, size.width(), size.height()); - x += size.width(); - } - if (maximize_mode_animation_->is_animating()) { - AnimationProgressed(maximize_mode_animation_.get()); - } -} - -const char* FrameCaptionButtonContainerView::GetClassName() const { - return kViewClassName; -} - -void FrameCaptionButtonContainerView::AnimationEnded( - const gfx::Animation* animation) { - // Ensure that position is calculated at least once. - AnimationProgressed(animation); - - double current_value = maximize_mode_animation_->GetCurrentValue(); - if (current_value == 0.0) { - size_button_->SetVisible(false); - PreferredSizeChanged(); - } -} - -void FrameCaptionButtonContainerView::AnimationProgressed( - const gfx::Animation* animation) { - double current_value = animation->GetCurrentValue(); - int size_alpha = 0; - int minimize_x = 0; - if (maximize_mode_animation_->IsShowing()) { - double scaled_value = - CapAnimationValue((current_value - SizeButtonShowStartValue()) / - SizeButtonShowDuration()); - double tweened_value_alpha = - gfx::Tween::CalculateValue(gfx::Tween::EASE_OUT, scaled_value); - size_alpha = gfx::Tween::LinearIntValueBetween(tweened_value_alpha, 0, 255); - - double tweened_value_slide = - gfx::Tween::CalculateValue(gfx::Tween::EASE_OUT, current_value); - minimize_x = gfx::Tween::LinearIntValueBetween(tweened_value_slide, - size_button_->x(), 0); - } else { - double scaled_value_alpha = - CapAnimationValue((1.0f - current_value) / SizeButtonHideDuration()); - double tweened_value_alpha = - gfx::Tween::CalculateValue(gfx::Tween::EASE_IN, scaled_value_alpha); - size_alpha = gfx::Tween::LinearIntValueBetween(tweened_value_alpha, 255, 0); - - double scaled_value_position = CapAnimationValue( - (HidePositionStartValue() - current_value) / HidePositionStartValue()); - double tweened_value_position = - gfx::Tween::CalculateValue(gfx::Tween::EASE_OUT, scaled_value_position); - minimize_x = gfx::Tween::LinearIntValueBetween(tweened_value_position, 0, - size_button_->x()); - } - size_button_->SetAlpha(size_alpha); - minimize_button_->SetX(minimize_x); -} - -void FrameCaptionButtonContainerView::SetButtonIcon(FrameCaptionButton* button, - CaptionButtonIcon icon, - Animate animate) { - // The early return is dependant on |animate| because callers use - // SetButtonIcon() with ANIMATE_NO to progress |button|'s crossfade animation - // to the end. - if (button->icon() == icon && - (animate == ANIMATE_YES || !button->IsAnimatingImageSwap())) { - return; - } - - FrameCaptionButton::Animate fcb_animate = - (animate == ANIMATE_YES) ? FrameCaptionButton::ANIMATE_YES - : FrameCaptionButton::ANIMATE_NO; - std::map<CaptionButtonIcon, ButtonIconIds>::const_iterator it = - button_icon_id_map_.find(icon); - if (it != button_icon_id_map_.end()) { - button->SetImages(icon, fcb_animate, it->second.icon_image_id, - it->second.hovered_background_image_id, - it->second.pressed_background_image_id); - } -} - -bool FrameCaptionButtonContainerView::ShouldSizeButtonBeVisible() const { - return frame_->widget_delegate()->CanMaximize(); -} - -void FrameCaptionButtonContainerView::SetButtonsToNormal(Animate animate) { - SetButtonIcons(CAPTION_BUTTON_ICON_MINIMIZE, CAPTION_BUTTON_ICON_CLOSE, - animate); - minimize_button_->SetState(views::Button::STATE_NORMAL); - size_button_->SetState(views::Button::STATE_NORMAL); - close_button_->SetState(views::Button::STATE_NORMAL); -} - -void FrameCaptionButtonContainerView::SetButtonIcons( - CaptionButtonIcon minimize_button_icon, - CaptionButtonIcon close_button_icon, - Animate animate) { - SetButtonIcon(minimize_button_, minimize_button_icon, animate); - SetButtonIcon(close_button_, close_button_icon, animate); -} - -void FrameCaptionButtonContainerView::ButtonPressed(views::Button* sender, - const ui::Event& event) { - // Abort any animations of the button icons. - SetButtonsToNormal(ANIMATE_NO); - - if (sender == minimize_button_) { - frame_->Minimize(); - } else if (sender == size_button_) { - if (frame_->IsFullscreen()) { // Can be clicked in immersive fullscreen. - frame_->Restore(); - } else if (frame_->IsMaximized()) { - frame_->Restore(); - } else { - frame_->Maximize(); - } - } else if (sender == close_button_) { - frame_->Close(); - } -} - -FrameCaptionButtonContainerView::ButtonIconIds::ButtonIconIds() - : icon_image_id(-1), - hovered_background_image_id(-1), - pressed_background_image_id(-1) {} - -FrameCaptionButtonContainerView::ButtonIconIds::ButtonIconIds( - int icon_id, - int hovered_background_id, - int pressed_background_id) - : icon_image_id(icon_id), - hovered_background_image_id(hovered_background_id), - pressed_background_image_id(pressed_background_id) {} - -FrameCaptionButtonContainerView::ButtonIconIds::~ButtonIconIds() {} - -} // namespace mus -} // namespace ash
diff --git a/ash/mus/frame/caption_buttons/frame_caption_button_container_view.h b/ash/mus/frame/caption_buttons/frame_caption_button_container_view.h deleted file mode 100644 index 8f52f53..0000000 --- a/ash/mus/frame/caption_buttons/frame_caption_button_container_view.h +++ /dev/null
@@ -1,136 +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_MUS_FRAME_CAPTION_BUTTONS_FRAME_CAPTION_BUTTON_CONTAINER_VIEW_H_ -#define ASH_MUS_FRAME_CAPTION_BUTTONS_FRAME_CAPTION_BUTTON_CONTAINER_VIEW_H_ - -#include <map> -#include <memory> - -#include "ash/mus/frame/caption_buttons/caption_button_types.h" -#include "base/macros.h" -#include "ui/gfx/animation/animation_delegate.h" -#include "ui/views/controls/button/button.h" -#include "ui/views/view.h" - -namespace gfx { -class SlideAnimation; -} - -namespace views { -class Widget; -} - -namespace ash { -namespace mus { - -class FrameCaptionButton; - -// Container view for the frame caption buttons. It performs the appropriate -// action when a caption button is clicked. -class FrameCaptionButtonContainerView : public views::View, - public views::ButtonListener, - public gfx::AnimationDelegate { - public: - enum Animate { ANIMATE_YES, ANIMATE_NO }; - - static const char kViewClassName[]; - - // |frame| is the views::Widget that the caption buttons act on. - explicit FrameCaptionButtonContainerView(views::Widget* frame); - ~FrameCaptionButtonContainerView() override; - - // Sets the resource ids of the images to paint the button for |icon|. The - // FrameCaptionButtonContainerView will keep track of the images to use for - // |icon| even if none of the buttons currently use |icon|. - void SetButtonImages(CaptionButtonIcon icon, - int icon_image_id, - int hovered_background_image_id, - int pressed_background_image_id); - - // Sets whether the buttons should be painted as active. Does not schedule - // a repaint. - void SetPaintAsActive(bool paint_as_active); - - // 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 size button's visibility based on whether |frame_| can be - // maximized and if maximize mode is enabled. A parent view should relayout - // to reflect the change in visibility. - void UpdateSizeButtonVisibility(); - - // views::View: - gfx::Size GetPreferredSize() const override; - void Layout() override; - const char* GetClassName() const override; - - // Overridden from gfx::AnimationDelegate: - void AnimationEnded(const gfx::Animation* animation) override; - void AnimationProgressed(const gfx::Animation* animation) override; - - private: - friend class FrameCaptionButtonContainerViewTest; - - struct ButtonIconIds { - ButtonIconIds(); - ButtonIconIds(int icon_id, - int hovered_background_id, - int pressed_background_id); - ~ButtonIconIds(); - - int icon_image_id; - int hovered_background_image_id; - int pressed_background_image_id; - }; - - // Sets |button|'s icon to |icon|. If |animate| is ANIMATE_YES, the button - // will crossfade to the new icon. If |animate| is ANIMATE_NO and - // |icon| == |button|->icon(), the crossfade animation is progressed to the - // end. - void SetButtonIcon(FrameCaptionButton* button, - CaptionButtonIcon icon, - Animate animate); - - // Returns true if maximize mode is not enabled, and |frame_| widget delegate - // can be maximized. - bool ShouldSizeButtonBeVisible() const; - - void SetButtonsToNormal(Animate animate); - void SetButtonIcons(CaptionButtonIcon minimize_button_icon, - CaptionButtonIcon close_button_icon, - Animate animate); - - // views::ButtonListener: - void ButtonPressed(views::Button* sender, const ui::Event& event) override; - - // The widget that the buttons act on. - views::Widget* frame_; - - // The buttons. In the normal button style, at most one of |minimize_button_| - // and |size_button_| is visible. - FrameCaptionButton* minimize_button_; - FrameCaptionButton* size_button_; - FrameCaptionButton* close_button_; - - // Mapping of the images needed to paint a button for each of the values of - // CaptionButtonIcon. - std::map<CaptionButtonIcon, ButtonIconIds> button_icon_id_map_; - - // Animation that affects the position of |minimize_button_| and the - // visibility of |size_button_|. - std::unique_ptr<gfx::SlideAnimation> maximize_mode_animation_; - - DISALLOW_COPY_AND_ASSIGN(FrameCaptionButtonContainerView); -}; - -} // namespace mus -} // namespace ash - -#endif // ASH_MUS_FRAME_CAPTION_BUTTONS_FRAME_CAPTION_BUTTON_CONTAINER_VIEW_H_
diff --git a/ash/mus/frame/default_header_painter.cc b/ash/mus/frame/default_header_painter.cc deleted file mode 100644 index 40c14e9..0000000 --- a/ash/mus/frame/default_header_painter.cc +++ /dev/null
@@ -1,337 +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/mus/frame/default_header_painter.h" - -#include "ash/mus/frame/caption_buttons/frame_caption_button_container_view.h" -#include "ash/mus/frame/header_painter_util.h" -#include "base/debug/leak_annotations.h" -#include "base/logging.h" -#include "grit/ash_mus_resources.h" -#include "third_party/skia/include/core/SkPaint.h" -#include "third_party/skia/include/core/SkPath.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/animation/slide_animation.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/color_utils.h" -#include "ui/gfx/font_list.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/image/image.h" -#include "ui/gfx/scoped_canvas.h" -#include "ui/gfx/skia_util.h" -#include "ui/views/view.h" -#include "ui/views/widget/native_widget_aura.h" -#include "ui/views/widget/widget.h" -#include "ui/views/widget/widget_delegate.h" - -using views::Widget; - -namespace { - -// Color for the window title text. -const SkColor kTitleTextColor = SkColorSetRGB(40, 40, 40); -// Color of the active window header/content separator line. -const SkColor kHeaderContentSeparatorColor = SkColorSetRGB(150, 150, 152); -// Color of the inactive window header/content separator line. -const SkColor kHeaderContentSeparatorInactiveColor = - SkColorSetRGB(180, 180, 182); -// The default color of the frame. -const SkColor kDefaultFrameColor = SkColorSetRGB(242, 242, 242); -// Duration of crossfade animation for activating and deactivating frame. -const int kActivationCrossfadeDurationMs = 200; - -// Tiles an image into an area, rounding the top corners. -void TileRoundRect(gfx::Canvas* canvas, - const SkPaint& paint, - const gfx::Rect& bounds, - int corner_radius) { - SkRect rect = gfx::RectToSkRect(bounds); - const SkScalar corner_radius_scalar = SkIntToScalar(corner_radius); - SkScalar radii[8] = {corner_radius_scalar, - corner_radius_scalar, // top-left - corner_radius_scalar, - corner_radius_scalar, // top-right - 0, - 0, // bottom-right - 0, - 0}; // bottom-left - SkPath path; - path.addRoundRect(rect, radii, SkPath::kCW_Direction); - canvas->DrawPath(path, paint); -} - -// Returns the FontList to use for the title. -const gfx::FontList& GetTitleFontList() { - static const gfx::FontList* title_font_list = - new gfx::FontList(views::NativeWidgetAura::GetWindowTitleFontList()); - ANNOTATE_LEAKING_OBJECT_PTR(title_font_list); - return *title_font_list; -} - -} // namespace - -namespace ash { -namespace mus { - -/////////////////////////////////////////////////////////////////////////////// -// DefaultHeaderPainter, public: - -DefaultHeaderPainter::DefaultHeaderPainter() - : frame_(NULL), - view_(NULL), - left_header_view_(NULL), - active_frame_color_(kDefaultFrameColor), - inactive_frame_color_(kDefaultFrameColor), - caption_button_container_(NULL), - painted_height_(0), - mode_(MODE_INACTIVE), - initial_paint_(true), - activation_animation_(new gfx::SlideAnimation(this)) {} - -DefaultHeaderPainter::~DefaultHeaderPainter() {} - -void DefaultHeaderPainter::Init( - views::Widget* frame, - views::View* header_view, - FrameCaptionButtonContainerView* caption_button_container) { - DCHECK(frame); - DCHECK(header_view); - DCHECK(caption_button_container); - frame_ = frame; - view_ = header_view; - caption_button_container_ = caption_button_container; - UpdateAllButtonImages(); -} - -int DefaultHeaderPainter::GetMinimumHeaderWidth() const { - // Ensure we have enough space for the window icon and buttons. We allow - // the title string to collapse to zero width. - return GetTitleBounds().x() + - caption_button_container_->GetMinimumSize().width(); -} - -void DefaultHeaderPainter::PaintHeader(gfx::Canvas* canvas, Mode mode) { - Mode old_mode = mode_; - mode_ = mode; - - if (mode_ != old_mode) { - UpdateAllButtonImages(); - if (!initial_paint_ && HeaderPainterUtil::CanAnimateActivation(frame_)) { - activation_animation_->SetSlideDuration(kActivationCrossfadeDurationMs); - if (mode_ == MODE_ACTIVE) - activation_animation_->Show(); - else - activation_animation_->Hide(); - } else { - if (mode_ == MODE_ACTIVE) - activation_animation_->Reset(1); - else - activation_animation_->Reset(0); - } - initial_paint_ = false; - } - - int corner_radius = (frame_->IsMaximized() || frame_->IsFullscreen()) - ? 0 - : HeaderPainterUtil::GetTopCornerRadiusWhenRestored(); - - SkPaint paint; - int active_alpha = activation_animation_->CurrentValueBetween(0, 255); - paint.setColor(color_utils::AlphaBlend(active_frame_color_, - inactive_frame_color_, active_alpha)); - - TileRoundRect(canvas, paint, GetLocalBounds(), corner_radius); - - if (!frame_->IsMaximized() && !frame_->IsFullscreen() && - mode_ == MODE_INACTIVE && !UsesCustomFrameColors()) { - PaintHighlightForInactiveRestoredWindow(canvas); - } - if (frame_->widget_delegate() && - frame_->widget_delegate()->ShouldShowWindowTitle()) { - PaintTitleBar(canvas); - } - if (!UsesCustomFrameColors()) - PaintHeaderContentSeparator(canvas); -} - -void DefaultHeaderPainter::LayoutHeader() { - UpdateSizeButtonImages(ShouldUseLightImages()); - caption_button_container_->Layout(); - - gfx::Size caption_button_container_size = - caption_button_container_->GetPreferredSize(); - caption_button_container_->SetBounds( - view_->width() - caption_button_container_size.width(), 0, - caption_button_container_size.width(), - caption_button_container_size.height()); - - if (left_header_view_) { - // Vertically center the left header view with respect to the caption button - // container. - // Floor when computing the center of |caption_button_container_|. - gfx::Size size = left_header_view_->GetPreferredSize(); - int icon_offset_y = - caption_button_container_->height() / 2 - size.height() / 2; - left_header_view_->SetBounds(HeaderPainterUtil::GetLeftViewXInset(), - icon_offset_y, size.width(), size.height()); - } - - // The header/content separator line overlays the caption buttons. - SetHeaderHeightForPainting(caption_button_container_->height()); -} - -int DefaultHeaderPainter::GetHeaderHeight() const { - return caption_button_container_->height(); -} - -int DefaultHeaderPainter::GetHeaderHeightForPainting() const { - return painted_height_; -} - -void DefaultHeaderPainter::SetHeaderHeightForPainting(int height) { - painted_height_ = height; -} - -void DefaultHeaderPainter::SchedulePaintForTitle() { - view_->SchedulePaintInRect(GetTitleBounds()); -} - -void DefaultHeaderPainter::SetFrameColors(SkColor active_frame_color, - SkColor inactive_frame_color) { - active_frame_color_ = active_frame_color; - inactive_frame_color_ = inactive_frame_color; - UpdateAllButtonImages(); -} - -void DefaultHeaderPainter::UpdateLeftHeaderView(views::View* left_header_view) { - left_header_view_ = left_header_view; -} - -/////////////////////////////////////////////////////////////////////////////// -// gfx::AnimationDelegate overrides: - -void DefaultHeaderPainter::AnimationProgressed( - const gfx::Animation* animation) { - view_->SchedulePaintInRect(GetLocalBounds()); -} - -/////////////////////////////////////////////////////////////////////////////// -// DefaultHeaderPainter, private: - -void DefaultHeaderPainter::PaintHighlightForInactiveRestoredWindow( - gfx::Canvas* canvas) { - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - gfx::ImageSkia top_edge = - *rb.GetImageSkiaNamed(IDR_ASH_MUS_WINDOW_HEADER_SHADE_INACTIVE_TOP); - gfx::ImageSkia left_edge = - *rb.GetImageSkiaNamed(IDR_ASH_MUS_WINDOW_HEADER_SHADE_INACTIVE_LEFT); - gfx::ImageSkia right_edge = - *rb.GetImageSkiaNamed(IDR_ASH_MUS_WINDOW_HEADER_SHADE_INACTIVE_RIGHT); - gfx::ImageSkia bottom_edge = - *rb.GetImageSkiaNamed(IDR_ASH_MUS_WINDOW_HEADER_SHADE_INACTIVE_BOTTOM); - - int left_edge_width = left_edge.width(); - int right_edge_width = right_edge.width(); - canvas->DrawImageInt(left_edge, 0, 0); - canvas->DrawImageInt(right_edge, view_->width() - right_edge_width, 0); - canvas->TileImageInt(top_edge, left_edge_width, 0, - view_->width() - left_edge_width - right_edge_width, - top_edge.height()); - - DCHECK_EQ(left_edge.height(), right_edge.height()); - int bottom = left_edge.height(); - int bottom_height = bottom_edge.height(); - canvas->TileImageInt(bottom_edge, left_edge_width, bottom - bottom_height, - view_->width() - left_edge_width - right_edge_width, - bottom_height); -} - -void DefaultHeaderPainter::PaintTitleBar(gfx::Canvas* canvas) { - // The window icon is painted by its own views::View. - gfx::Rect title_bounds = GetTitleBounds(); - title_bounds.set_x(view_->GetMirroredXForRect(title_bounds)); - canvas->DrawStringRectWithFlags( - frame_->widget_delegate()->GetWindowTitle(), GetTitleFontList(), - kTitleTextColor, title_bounds, gfx::Canvas::NO_SUBPIXEL_RENDERING); -} - -void DefaultHeaderPainter::PaintHeaderContentSeparator(gfx::Canvas* canvas) { - gfx::ScopedCanvas scoped_canvas(canvas); - const float scale = canvas->UndoDeviceScaleFactor(); - gfx::RectF rect(0, painted_height_ * scale - 1, view_->width() * scale, 1); - SkPaint paint; - paint.setColor((mode_ == MODE_ACTIVE) ? kHeaderContentSeparatorColor - : kHeaderContentSeparatorInactiveColor); - canvas->sk_canvas()->drawRect(gfx::RectFToSkRect(rect), paint); -} - -bool DefaultHeaderPainter::ShouldUseLightImages() { - return color_utils::IsDark(mode_ == MODE_INACTIVE ? inactive_frame_color_ - : active_frame_color_); -} - -void DefaultHeaderPainter::UpdateAllButtonImages() { - bool use_light_images = ShouldUseLightImages(); - caption_button_container_->SetButtonImages( - CAPTION_BUTTON_ICON_MINIMIZE, - use_light_images ? IDR_ASH_MUS_WINDOW_CONTROL_ICON_MINIMIZE_WHITE - : IDR_ASH_MUS_WINDOW_CONTROL_ICON_MINIMIZE, - IDR_ASH_MUS_WINDOW_CONTROL_BACKGROUND_H, - IDR_ASH_MUS_WINDOW_CONTROL_BACKGROUND_P); - - UpdateSizeButtonImages(use_light_images); - - caption_button_container_->SetButtonImages( - CAPTION_BUTTON_ICON_CLOSE, - use_light_images ? IDR_ASH_MUS_WINDOW_CONTROL_ICON_CLOSE_WHITE - : IDR_ASH_MUS_WINDOW_CONTROL_ICON_CLOSE, - IDR_ASH_MUS_WINDOW_CONTROL_BACKGROUND_H, - IDR_ASH_MUS_WINDOW_CONTROL_BACKGROUND_P); - - caption_button_container_->SetButtonImages( - CAPTION_BUTTON_ICON_LEFT_SNAPPED, - use_light_images ? IDR_ASH_MUS_WINDOW_CONTROL_ICON_LEFT_SNAPPED_WHITE - : IDR_ASH_MUS_WINDOW_CONTROL_ICON_LEFT_SNAPPED, - IDR_ASH_MUS_WINDOW_CONTROL_BACKGROUND_H, - IDR_ASH_MUS_WINDOW_CONTROL_BACKGROUND_P); - - caption_button_container_->SetButtonImages( - CAPTION_BUTTON_ICON_RIGHT_SNAPPED, - use_light_images ? IDR_ASH_MUS_WINDOW_CONTROL_ICON_RIGHT_SNAPPED_WHITE - : IDR_ASH_MUS_WINDOW_CONTROL_ICON_RIGHT_SNAPPED, - IDR_ASH_MUS_WINDOW_CONTROL_BACKGROUND_H, - IDR_ASH_MUS_WINDOW_CONTROL_BACKGROUND_P); -} - -void DefaultHeaderPainter::UpdateSizeButtonImages(bool use_light_images) { - int icon_id = 0; - if (frame_->IsMaximized() || frame_->IsFullscreen()) { - icon_id = use_light_images ? IDR_ASH_MUS_WINDOW_CONTROL_ICON_RESTORE_WHITE - : IDR_ASH_MUS_WINDOW_CONTROL_ICON_RESTORE; - } else { - icon_id = use_light_images ? IDR_ASH_MUS_WINDOW_CONTROL_ICON_MAXIMIZE_WHITE - : IDR_ASH_MUS_WINDOW_CONTROL_ICON_MAXIMIZE; - } - caption_button_container_->SetButtonImages( - CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE, icon_id, - IDR_ASH_MUS_WINDOW_CONTROL_BACKGROUND_H, - IDR_ASH_MUS_WINDOW_CONTROL_BACKGROUND_P); -} - -gfx::Rect DefaultHeaderPainter::GetLocalBounds() const { - return gfx::Rect(view_->width(), painted_height_); -} - -gfx::Rect DefaultHeaderPainter::GetTitleBounds() const { - return HeaderPainterUtil::GetTitleBounds( - left_header_view_, caption_button_container_, GetTitleFontList()); -} - -bool DefaultHeaderPainter::UsesCustomFrameColors() const { - return active_frame_color_ != kDefaultFrameColor || - inactive_frame_color_ != kDefaultFrameColor; -} - -} // namespace mus -} // namespace ash
diff --git a/ash/mus/frame/default_header_painter.h b/ash/mus/frame/default_header_painter.h deleted file mode 100644 index dccd03c..0000000 --- a/ash/mus/frame/default_header_painter.h +++ /dev/null
@@ -1,117 +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_MUS_FRAME_DEFAULT_HEADER_PAINTER_H_ -#define ASH_MUS_FRAME_DEFAULT_HEADER_PAINTER_H_ - -#include <memory> - -#include "ash/mus/frame/header_painter.h" -#include "base/macros.h" -#include "third_party/skia/include/core/SkColor.h" -#include "ui/gfx/animation/animation_delegate.h" - -namespace gfx { -class ImageSkia; -class Rect; -class SlideAnimation; -} -namespace views { -class View; -class Widget; -} - -namespace ash { -namespace mus { - -class FrameCaptionButtonContainerView; - -// Helper class for painting the default window header. -class DefaultHeaderPainter : public HeaderPainter, - public gfx::AnimationDelegate { - public: - DefaultHeaderPainter(); - ~DefaultHeaderPainter() override; - - // DefaultHeaderPainter does not take ownership of any of the parameters. - void Init(views::Widget* frame, - views::View* header_view, - FrameCaptionButtonContainerView* caption_button_container); - - // HeaderPainter overrides: - int GetMinimumHeaderWidth() const override; - void PaintHeader(gfx::Canvas* canvas, Mode mode) override; - void LayoutHeader() override; - int GetHeaderHeight() const override; - int GetHeaderHeightForPainting() const override; - void SetHeaderHeightForPainting(int height) override; - void SchedulePaintForTitle() override; - - // Sets the left header view for the header. Passing NULL removes the view. - void UpdateLeftHeaderView(views::View* left_header_view); - - // Sets the active and inactive frame colors. Note the inactive frame color - // will have some transparency added when the frame is drawn. - void SetFrameColors(SkColor active_frame_color, SkColor inactive_frame_color); - - private: - // gfx::AnimationDelegate override: - void AnimationProgressed(const gfx::Animation* animation) override; - - // Paints highlight around the edge of the header for inactive restored - // windows. - void PaintHighlightForInactiveRestoredWindow(gfx::Canvas* canvas); - - // Paints the title bar, primarily the title string. - void PaintTitleBar(gfx::Canvas* canvas); - - // Paints the header/content separator. - void PaintHeaderContentSeparator(gfx::Canvas* canvas); - - // Whether light caption images should be used. This is the case when the - // background of the frame is dark. - bool ShouldUseLightImages(); - - // Update all the images in the caption buttons. - void UpdateAllButtonImages(); - - // Updates the size button's images. - void UpdateSizeButtonImages(bool use_light_images); - - // Returns the header bounds in the coordinates of |view_|. The header is - // assumed to be positioned at the top left corner of |view_| and to have the - // same width as |view_|. - gfx::Rect GetLocalBounds() const; - - // Returns the bounds for the title. - gfx::Rect GetTitleBounds() const; - - // Returns whether the frame uses custom frame coloring. - bool UsesCustomFrameColors() const; - - views::Widget* frame_; - views::View* view_; - views::View* left_header_view_; // May be NULL. - SkColor active_frame_color_; - SkColor inactive_frame_color_; - FrameCaptionButtonContainerView* caption_button_container_; - - // The height of the header to paint. - int painted_height_; - - // Whether the header should be painted as active. - Mode mode_; - - // Whether the header is painted for the first time. - bool initial_paint_; - - std::unique_ptr<gfx::SlideAnimation> activation_animation_; - - DISALLOW_COPY_AND_ASSIGN(DefaultHeaderPainter); -}; - -} // namespace mus -} // namespace ash - -#endif // ASH_MUS_FRAME_DEFAULT_HEADER_PAINTER_H_
diff --git a/ash/mus/frame/frame_border_hit_test_controller.cc b/ash/mus/frame/frame_border_hit_test_controller.cc deleted file mode 100644 index 0beee5d..0000000 --- a/ash/mus/frame/frame_border_hit_test_controller.cc +++ /dev/null
@@ -1,89 +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/mus/frame/frame_border_hit_test_controller.h" - -#include "ash/mus/frame/caption_buttons/frame_caption_button_container_view.h" -#include "ui/aura/env.h" -#include "ui/aura/window.h" -#include "ui/base/hit_test.h" -#include "ui/gfx/geometry/insets.h" -#include "ui/views/widget/widget.h" -#include "ui/views/widget/widget_delegate.h" -#include "ui/views/window/non_client_view.h" - -namespace ash { -namespace mus { - -// In the window corners, the resize areas don't actually expand bigger, but the -// 16 px at the end of each edge triggers diagonal resizing. -const int kResizeAreaCornerSize = 16; - -// Windows do not have a traditional visible window frame. Window content -// extends to the edge of the window. We consider a small region outside the -// window bounds and an even smaller region overlapping the window to be the -// "non-client" area and use it for resizing. -const int kResizeOutsideBoundsSize = 6; -const int kResizeOutsideBoundsScaleForTouch = 5; -const int kResizeInsideBoundsSize = 1; - -// static -gfx::Insets FrameBorderHitTestController::GetResizeOutsideBoundsSize() { - return gfx::Insets(kResizeOutsideBoundsSize, kResizeOutsideBoundsSize, - kResizeOutsideBoundsSize, kResizeOutsideBoundsSize); -} - -// static -int FrameBorderHitTestController::NonClientHitTest( - views::NonClientFrameView* view, - FrameCaptionButtonContainerView* caption_button_container, - 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* 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; - } - - // Caption is a safe default. - return HTCAPTION; -} - -} // namespace mus -} // namespace ash
diff --git a/ash/mus/frame/frame_border_hit_test_controller.h b/ash/mus/frame/frame_border_hit_test_controller.h deleted file mode 100644 index aeb4d01..0000000 --- a/ash/mus/frame/frame_border_hit_test_controller.h +++ /dev/null
@@ -1,45 +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_MUS_FRAME_FRAME_BORDER_HIT_TEST_CONTROLLER_H_ -#define ASH_MUS_FRAME_FRAME_BORDER_HIT_TEST_CONTROLLER_H_ - -#include "base/macros.h" - -namespace gfx { -class Insets; -class Point; -} - -namespace views { -class NonClientFrameView; -class Widget; -} - -namespace ash { -namespace mus { -class FrameCaptionButtonContainerView; - -// Class which manages the hittest override bounds for |frame|. -class FrameBorderHitTestController { - public: - // Returns the amount of space resizes are allowed to occur outside the - // bounds of windows. - static gfx::Insets GetResizeOutsideBoundsSize(); - - // Does the non client hit test on behalf of |view|. |point_in_widget| must be - // in the coordinates of |view|'s widget. - static int NonClientHitTest( - views::NonClientFrameView* view, - FrameCaptionButtonContainerView* caption_button_container, - const gfx::Point& point_in_widget); - - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(FrameBorderHitTestController); -}; - -} // namespace mus -} // namespace ash - -#endif // ASH_MUS_FRAME_FRAME_BORDER_HIT_TEST_CONTROLLER_H_
diff --git a/ash/mus/frame/header_painter.h b/ash/mus/frame/header_painter.h deleted file mode 100644 index 3c075f5ac..0000000 --- a/ash/mus/frame/header_painter.h +++ /dev/null
@@ -1,49 +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_MUS_FRAME_HEADER_PAINTER_H_ -#define ASH_MUS_FRAME_HEADER_PAINTER_H_ - -namespace gfx { -class Canvas; -} - -namespace ash { -namespace mus { - -// Helper class for painting the window header. -// TODO(sky): keep this only if we're going to actually need different -// subclasses. -class HeaderPainter { - public: - enum Mode { MODE_ACTIVE, MODE_INACTIVE }; - - virtual ~HeaderPainter() {} - - // Returns the header's minimum width. - virtual int GetMinimumHeaderWidth() const = 0; - - // Paints the header. - virtual void PaintHeader(gfx::Canvas* canvas, Mode mode) = 0; - - // Performs layout for the header. - virtual void LayoutHeader() = 0; - - // Get the height of the header. - virtual int GetHeaderHeight() const = 0; - - // Gets / sets how much of the header is painted. This allows the header to - // paint under things (like the tabstrip) which have transparent / - // non-painting sections. This height does not affect LayoutHeader(). - virtual int GetHeaderHeightForPainting() const = 0; - virtual void SetHeaderHeightForPainting(int height_for_painting) = 0; - - // Schedule a re-paint of the entire title. - virtual void SchedulePaintForTitle() = 0; -}; - -} // namespace mus -} // namespace ash - -#endif // ASH_MUS_FRAME_HEADER_PAINTER_H_
diff --git a/ash/mus/frame/header_painter_util.cc b/ash/mus/frame/header_painter_util.cc deleted file mode 100644 index 2c9e9b3..0000000 --- a/ash/mus/frame/header_painter_util.cc +++ /dev/null
@@ -1,80 +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/mus/frame/header_painter_util.h" - -#include <algorithm> - -#include "ui/gfx/font_list.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/views/view.h" -#include "ui/views/widget/widget.h" - -namespace { - -// Radius of the header's top corners when the window is restored. -const int kTopCornerRadiusWhenRestored = 2; - -// Distance between left edge of the window and the leftmost view. -const int kLeftViewXInset = 9; - -// Space between the title text and the caption buttons. -const int kTitleCaptionButtonSpacing = 5; - -// Space between window icon and title text. -const int kTitleIconOffsetX = 5; - -// Space between window edge and title text, when there is no icon. -const int kTitleNoIconOffsetX = 8; - -// In the pre-Ash era the web content area had a frame along the left edge, so -// user-generated theme images for the new tab page assume they are shifted -// right relative to the header. Now that we have removed the left edge frame -// we need to copy the theme image for the window header from a few pixels -// inset to preserve alignment with the NTP image, or else we'll break a bunch -// of existing themes. We do something similar on OS X for the same reason. -const int kThemeFrameImageInsetX = 5; - -} // namespace - -namespace ash { -namespace mus { - -// static -int HeaderPainterUtil::GetTopCornerRadiusWhenRestored() { - return kTopCornerRadiusWhenRestored; -} - -// static -int HeaderPainterUtil::GetLeftViewXInset() { - return kLeftViewXInset; -} - -// static -int HeaderPainterUtil::GetThemeBackgroundXInset() { - return kThemeFrameImageInsetX; -} - -// static -gfx::Rect HeaderPainterUtil::GetTitleBounds( - const views::View* left_view, - const views::View* right_view, - const gfx::FontList& title_font_list) { - int x = left_view ? left_view->bounds().right() + kTitleIconOffsetX - : kTitleNoIconOffsetX; - int height = title_font_list.GetHeight(); - // Floor when computing the center of |caption_button_container| and when - // computing the center of the text. - int y = std::max(0, (right_view->height() / 2) - (height / 2)); - int width = std::max(0, right_view->x() - kTitleCaptionButtonSpacing - x); - return gfx::Rect(x, y, width, height); -} - -// static -bool HeaderPainterUtil::CanAnimateActivation(views::Widget* widget) { - return true; -} - -} // namespace mus -} // namespace ash
diff --git a/ash/mus/frame/header_painter_util.h b/ash/mus/frame/header_painter_util.h deleted file mode 100644 index 18abc0e..0000000 --- a/ash/mus/frame/header_painter_util.h +++ /dev/null
@@ -1,56 +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_MUS_FRAME_HEADER_PAINTER_UTIL_H_ -#define ASH_MUS_FRAME_HEADER_PAINTER_UTIL_H_ - -#include "base/macros.h" - -namespace gfx { -class FontList; -class Rect; -} -namespace views { -class View; -class Widget; -} - -namespace ash { -namespace mus { - -// Static-only helper class for functionality used accross multiple -// implementations of HeaderPainter. -class HeaderPainterUtil { - public: - // Returns the radius of the header's corners when the window is restored. - static int GetTopCornerRadiusWhenRestored(); - - // Returns the default distance between the left edge of the window and the - // leftmost view in the header. - static int GetLeftViewXInset(); - - // Returns the amount that the frame background is inset from the left edge of - // the window. - static int GetThemeBackgroundXInset(); - - // Returns the bounds for the header's title given the views to the left and - // right of the title, and the font used. - // |left_view| should be NULL if there is no view to the left of the title. - static gfx::Rect GetTitleBounds(const views::View* left_view, - const views::View* right_view, - const gfx::FontList& title_font_list); - - // Returns true if the header for |widget| can animate to new visuals when the - // widget's activation changes. Returns false if the header should switch to - // new visuals instantaneously. - static bool CanAnimateActivation(views::Widget* widget); - - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(HeaderPainterUtil); -}; - -} // namespace mus -} // namespace ash - -#endif // ASH_MUS_FRAME_HEADER_PAINTER_UTIL_H_
diff --git a/ash/mus/frame/move_event_handler.cc b/ash/mus/frame/move_event_handler.cc deleted file mode 100644 index ea3bd42..0000000 --- a/ash/mus/frame/move_event_handler.cc +++ /dev/null
@@ -1,139 +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/mus/frame/move_event_handler.h" - -#include "ash/mus/bridge/wm_window_mus.h" -#include "services/ui/public/cpp/window.h" -#include "services/ui/public/cpp/window_manager_delegate.h" -#include "services/ui/public/cpp/window_property.h" -#include "services/ui/public/interfaces/cursor.mojom.h" -#include "ui/aura/window.h" -#include "ui/base/hit_test.h" -#include "ui/events/event.h" - -MUS_DECLARE_WINDOW_PROPERTY_TYPE(ash::mus::MoveEventHandler*) - -namespace { - -// Key used for storing identifier sent to clients for windows. -MUS_DEFINE_LOCAL_WINDOW_PROPERTY_KEY(ash::mus::MoveEventHandler*, - kWmMoveEventHandler, - nullptr); - -} // namespace - -namespace ash { -namespace mus { -namespace { - -ui::mojom::Cursor CursorForWindowComponent(int window_component) { - switch (window_component) { - case HTBOTTOM: - return ui::mojom::Cursor::SOUTH_RESIZE; - case HTBOTTOMLEFT: - return ui::mojom::Cursor::SOUTH_WEST_RESIZE; - case HTBOTTOMRIGHT: - return ui::mojom::Cursor::SOUTH_EAST_RESIZE; - case HTLEFT: - return ui::mojom::Cursor::WEST_RESIZE; - case HTRIGHT: - return ui::mojom::Cursor::EAST_RESIZE; - case HTTOP: - return ui::mojom::Cursor::NORTH_RESIZE; - case HTTOPLEFT: - return ui::mojom::Cursor::NORTH_WEST_RESIZE; - case HTTOPRIGHT: - return ui::mojom::Cursor::NORTH_EAST_RESIZE; - default: - return ui::mojom::Cursor::CURSOR_NULL; - } -} - -void OnMoveLoopCompleted(const base::Callback<void(bool success)>& end_closure, - wm::WmToplevelWindowEventHandler::DragResult result) { - end_closure.Run(result == - wm::WmToplevelWindowEventHandler::DragResult::SUCCESS); -} - -} // namespace - -MoveEventHandler::MoveEventHandler( - ui::Window* mus_window, - ui::WindowManagerClient* window_manager_client, - aura::Window* aura_window) - : wm_window_(WmWindowMus::Get(mus_window)), - window_manager_client_(window_manager_client), - root_window_(aura_window->GetRootWindow()), - toplevel_window_event_handler_(wm_window_->GetShell()) { - root_window_->AddObserver(this); - root_window_->AddPreTargetHandler(this); - - mus_window->SetLocalProperty(kWmMoveEventHandler, this); -} - -MoveEventHandler::~MoveEventHandler() { - Detach(); -} - -// static -MoveEventHandler* MoveEventHandler::GetForWindow(WmWindow* wm_window) { - return WmWindowMus::GetMusWindow(wm_window)->GetLocalProperty( - kWmMoveEventHandler); -} - -void MoveEventHandler::AttemptToStartDrag( - const gfx::Point& point_in_parent, - int window_component, - aura::client::WindowMoveSource source, - const base::Callback<void(bool success)>& end_closure) { - toplevel_window_event_handler_.AttemptToStartDrag( - wm_window_, point_in_parent, window_component, source, - base::Bind(&OnMoveLoopCompleted, end_closure)); -} - -bool MoveEventHandler::IsDragInProgress() { - return toplevel_window_event_handler_.is_drag_in_progress(); -} - -void MoveEventHandler::RevertDrag() { - toplevel_window_event_handler_.RevertDrag(); -} - -void MoveEventHandler::Detach() { - if (!root_window_) - return; - - root_window_->RemoveObserver(this); - root_window_->RemovePreTargetHandler(this); - root_window_ = nullptr; -} - -void MoveEventHandler::OnMouseEvent(ui::MouseEvent* event) { - toplevel_window_event_handler_.OnMouseEvent(event, wm_window_); - if (!toplevel_window_event_handler_.is_drag_in_progress() && - (event->type() == ui::ET_POINTER_MOVED || - event->type() == ui::ET_MOUSE_MOVED)) { - const int hit_test_location = - wm_window_->GetNonClientComponent(event->location()); - window_manager_client_->SetNonClientCursor( - wm_window_->mus_window(), CursorForWindowComponent(hit_test_location)); - } -} - -void MoveEventHandler::OnGestureEvent(ui::GestureEvent* event) { - toplevel_window_event_handler_.OnGestureEvent(event, wm_window_); -} - -void MoveEventHandler::OnCancelMode(ui::CancelModeEvent* event) { - toplevel_window_event_handler_.RevertDrag(); -} - -void MoveEventHandler::OnWindowDestroying(aura::Window* window) { - DCHECK_EQ(root_window_, window); - Detach(); -} - -} // namespace mus -} // namespace ash
diff --git a/ash/mus/frame/move_event_handler.h b/ash/mus/frame/move_event_handler.h deleted file mode 100644 index 21d4540c..0000000 --- a/ash/mus/frame/move_event_handler.h +++ /dev/null
@@ -1,83 +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_MUS_FRAME_MOVE_EVENT_HANDLER_H_ -#define ASH_MUS_FRAME_MOVE_EVENT_HANDLER_H_ - -#include <memory> - -#include "ash/common/wm/wm_toplevel_window_event_handler.h" -#include "base/macros.h" -#include "ui/aura/window_observer.h" -#include "ui/events/event_handler.h" - -namespace aura { -class Window; -} - -namespace ui { -class CancelModeEvent; -class Window; -class WindowManagerClient; -} - -namespace ash { -namespace mus { - -class WmWindowMus; - -// EventHandler attached to windows that may be dragged and/or resized. This -// forwards to WmToplevelWindowEventHandler to handle the actual drag/resize. -class MoveEventHandler : public ui::EventHandler, public aura::WindowObserver { - public: - MoveEventHandler(ui::Window* mus_window, - ui::WindowManagerClient* window_manager_client, - aura::Window* aura_window); - ~MoveEventHandler() override; - - // Retrieves the MoveEventHandler for an existing WmWindow. - static MoveEventHandler* GetForWindow(WmWindow* wm_window); - - // Attempts to start a drag if one is not already in progress. This passes - // the call to the underlying WmToplevelWindowEventHandler. After the drag - // completes, |end_closure| will be called to return whether the drag was - // successfully completed. - void AttemptToStartDrag( - const gfx::Point& point_in_parent, - int window_component, - aura::client::WindowMoveSource source, - const base::Callback<void(bool success)>& end_closure); - - // Returns whether we're in a drag. - bool IsDragInProgress(); - - // Reverts a manually started drag started with AttemptToStartDrag(). - void RevertDrag(); - - private: - // Removes observer and EventHandler installed on |root_window_|. - void Detach(); - - // Overridden from ui::EventHandler: - void OnMouseEvent(ui::MouseEvent* event) override; - void OnGestureEvent(ui::GestureEvent* event) override; - void OnCancelMode(ui::CancelModeEvent* event) override; - - // Overridden from aura::WindowObserver: - void OnWindowDestroying(aura::Window* window) override; - - WmWindowMus* wm_window_; - ui::WindowManagerClient* window_manager_client_; - // The root window of the aura::Window supplied to the constructor. - // MoveEventHandler is added as a pre-target handler (and observer) of this. - aura::Window* root_window_; - wm::WmToplevelWindowEventHandler toplevel_window_event_handler_; - - DISALLOW_COPY_AND_ASSIGN(MoveEventHandler); -}; - -} // namespace mus -} // namespace ash - -#endif // ASH_MUS_FRAME_MOVE_EVENT_HANDLER_H_
diff --git a/ash/mus/frame/non_client_frame_view_mash.cc b/ash/mus/frame/non_client_frame_view_mash.cc deleted file mode 100644 index 32c0a62..0000000 --- a/ash/mus/frame/non_client_frame_view_mash.cc +++ /dev/null
@@ -1,368 +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/mus/frame/non_client_frame_view_mash.h" - -#include <algorithm> -#include <memory> -#include <vector> - -#include "ash/mus/frame/caption_buttons/frame_caption_button_container_view.h" -#include "ash/mus/frame/default_header_painter.h" -#include "ash/mus/frame/frame_border_hit_test_controller.h" -#include "ash/mus/frame/header_painter.h" -#include "base/macros.h" -#include "grit/ash_mus_resources.h" -#include "services/ui/public/cpp/window.h" -#include "services/ui/public/cpp/window_tree_client.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/compositor/paint_recorder.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/geometry/rect_conversions.h" -#include "ui/gfx/geometry/size.h" -#include "ui/gfx/image/image.h" -#include "ui/views/view.h" -#include "ui/views/widget/widget.h" -#include "ui/views/widget/widget_delegate.h" - -namespace ash { -namespace mus { - -/////////////////////////////////////////////////////////////////////////////// -// NonClientFrameViewMash::HeaderView - -// View which paints the header. -class NonClientFrameViewMash::HeaderView : public views::View { - public: - // |frame| is the widget that the caption buttons act on. - HeaderView(views::Widget* frame, ui::Window* window); - ~HeaderView() override; - - // Schedules a repaint for the entire title. - void SchedulePaintForTitle(); - - // Tells the window controls to reset themselves to the normal state. - void ResetWindowControls(); - - // Returns the view's preferred height. - int GetPreferredHeight() const; - - // Returns the view's minimum width. - int GetMinimumWidth() const; - - void SizeConstraintsChanged(); - - void SetFrameColors(SkColor active_frame_color, SkColor inactive_frame_color); - - // views::View: - void Layout() override; - void OnPaint(gfx::Canvas* canvas) override; - void ChildPreferredSizeChanged(views::View* child) override; - - FrameCaptionButtonContainerView* caption_button_container() { - return caption_button_container_; - } - - private: - // The widget that the caption buttons act on. - views::Widget* frame_; - - // Helper for painting the header. - std::unique_ptr<DefaultHeaderPainter> header_painter_; - - // View which contains the window caption buttons. - FrameCaptionButtonContainerView* caption_button_container_; - - ui::Window* window_; - - DISALLOW_COPY_AND_ASSIGN(HeaderView); -}; - -NonClientFrameViewMash::HeaderView::HeaderView(views::Widget* frame, - ui::Window* window) - : frame_(frame), - header_painter_(new DefaultHeaderPainter), - caption_button_container_(nullptr), - window_(window) { - caption_button_container_ = new FrameCaptionButtonContainerView(frame_); - caption_button_container_->UpdateSizeButtonVisibility(); - AddChildView(caption_button_container_); - - header_painter_->Init(frame_, this, caption_button_container_); -} - -NonClientFrameViewMash::HeaderView::~HeaderView() {} - -void NonClientFrameViewMash::HeaderView::SchedulePaintForTitle() { - header_painter_->SchedulePaintForTitle(); -} - -void NonClientFrameViewMash::HeaderView::ResetWindowControls() { - caption_button_container_->ResetWindowControls(); -} - -int NonClientFrameViewMash::HeaderView::GetPreferredHeight() const { - return header_painter_->GetHeaderHeightForPainting(); -} - -int NonClientFrameViewMash::HeaderView::GetMinimumWidth() const { - return header_painter_->GetMinimumHeaderWidth(); -} - -void NonClientFrameViewMash::HeaderView::SizeConstraintsChanged() { - caption_button_container_->ResetWindowControls(); - caption_button_container_->UpdateSizeButtonVisibility(); - Layout(); -} - -void NonClientFrameViewMash::HeaderView::SetFrameColors( - SkColor active_frame_color, - SkColor inactive_frame_color) { - header_painter_->SetFrameColors(active_frame_color, inactive_frame_color); -} - -/////////////////////////////////////////////////////////////////////////////// -// NonClientFrameViewMash::HeaderView, views::View overrides: - -void NonClientFrameViewMash::HeaderView::Layout() { - header_painter_->LayoutHeader(); -} - -void NonClientFrameViewMash::HeaderView::OnPaint(gfx::Canvas* canvas) { - const ui::Window* focused_window = window_->window_tree()->GetFocusedWindow(); - const bool paint_as_active = - focused_window && window_->Contains(focused_window); - caption_button_container_->SetPaintAsActive(paint_as_active); - - HeaderPainter::Mode header_mode = paint_as_active - ? HeaderPainter::MODE_ACTIVE - : HeaderPainter::MODE_INACTIVE; - header_painter_->PaintHeader(canvas, header_mode); -} - -void NonClientFrameViewMash::HeaderView::ChildPreferredSizeChanged( - views::View* child) { - // FrameCaptionButtonContainerView animates the visibility changes in - // UpdateSizeButtonVisibility(false). Due to this a new size is not available - // until the completion of the animation. Layout in response to the preferred - // size changes. - if (child != caption_button_container_) - return; - parent()->Layout(); -} - -//////////////////////////////////////////////////////////////////////////////// -// NonClientFrameViewMash, public: - -// static -const char NonClientFrameViewMash::kViewClassName[] = "NonClientFrameViewMash"; - -NonClientFrameViewMash::NonClientFrameViewMash(views::Widget* frame, - ui::Window* window) - : frame_(frame), - window_(window), - header_view_(new HeaderView(frame, window)) { - // |header_view_| is set as the non client view's overlay view so that it can - // overlay the web contents in immersive fullscreen. - AddChildView(header_view_); - window_->AddObserver(this); - window_->window_tree()->AddObserver(this); -} - -NonClientFrameViewMash::~NonClientFrameViewMash() { - RemoveObservers(); -} - -// static -gfx::Insets NonClientFrameViewMash::GetPreferredClientAreaInsets() { - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - const int header_height = - rb.GetImageSkiaNamed(IDR_ASH_MUS_WINDOW_CONTROL_BACKGROUND_P) - ->size() - .height(); - return gfx::Insets(header_height, 0, 0, 0); -} - -// static -int NonClientFrameViewMash::GetMaxTitleBarButtonWidth() { - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - return rb.GetImageSkiaNamed(IDR_ASH_MUS_WINDOW_CONTROL_BACKGROUND_P) - ->size() - .width() * - 3; -} - -void NonClientFrameViewMash::SetFrameColors(SkColor active_frame_color, - SkColor inactive_frame_color) { - header_view_->SetFrameColors(active_frame_color, inactive_frame_color); -} - -//////////////////////////////////////////////////////////////////////////////// -// NonClientFrameViewMash, views::NonClientFrameView overrides: - -gfx::Rect NonClientFrameViewMash::GetBoundsForClientView() const { - gfx::Rect result(GetLocalBounds()); - result.Inset(window_->client_area()); - return result; -} - -gfx::Rect NonClientFrameViewMash::GetWindowBoundsForClientBounds( - const gfx::Rect& client_bounds) const { - gfx::Rect window_bounds = client_bounds; - window_bounds.Inset( - window_->client_area().left(), window_->client_area().top(), - window_->client_area().right(), window_->client_area().bottom()); - return window_bounds; -} - -int NonClientFrameViewMash::NonClientHitTest(const gfx::Point& point) { - return FrameBorderHitTestController::NonClientHitTest( - this, header_view_->caption_button_container(), point); -} - -void NonClientFrameViewMash::GetWindowMask(const gfx::Size& size, - gfx::Path* window_mask) {} - -void NonClientFrameViewMash::ResetWindowControls() { - header_view_->ResetWindowControls(); -} - -void NonClientFrameViewMash::UpdateWindowIcon() {} - -void NonClientFrameViewMash::UpdateWindowTitle() { - header_view_->SchedulePaintForTitle(); -} - -void NonClientFrameViewMash::SizeConstraintsChanged() { - header_view_->SizeConstraintsChanged(); -} - -//////////////////////////////////////////////////////////////////////////////// -// NonClientFrameViewMash, views::View overrides: - -void NonClientFrameViewMash::Layout() { - header_view_->SetBounds(0, 0, width(), header_view_->GetPreferredHeight()); - header_view_->Layout(); -} - -gfx::Size NonClientFrameViewMash::GetPreferredSize() const { - gfx::Size pref = frame_->client_view()->GetPreferredSize(); - return frame_->non_client_view() - ->GetWindowBoundsForClientBounds(gfx::Rect(pref)) - .size(); -} - -const char* NonClientFrameViewMash::GetClassName() const { - return kViewClassName; -} - -gfx::Size NonClientFrameViewMash::GetMinimumSize() const { - // If the client area is empty we assume the client is rendering everything - // and the window can be resized to anything. - // TODO(sky): we need a minimum-size property. - if (window_->client_area().IsEmpty()) - return gfx::Size(); - - gfx::Size min_client_view_size(frame_->client_view()->GetMinimumSize()); - return gfx::Size( - std::max(header_view_->GetMinimumWidth(), min_client_view_size.width()), - NonClientTopBorderHeight() + min_client_view_size.height()); -} - -gfx::Size NonClientFrameViewMash::GetMaximumSize() const { - gfx::Size max_client_size(frame_->client_view()->GetMaximumSize()); - int width = 0; - int height = 0; - - if (max_client_size.width() > 0) - width = std::max(header_view_->GetMinimumWidth(), max_client_size.width()); - if (max_client_size.height() > 0) - height = NonClientTopBorderHeight() + max_client_size.height(); - - return gfx::Size(width, height); -} - -void NonClientFrameViewMash::OnPaint(gfx::Canvas* canvas) { - canvas->Save(); - NonClientFrameView::OnPaint(canvas); - canvas->Restore(); - - // The client app draws the client area. Make ours totally transparent so - // we only see the client apps client area. - canvas->FillRect(GetBoundsForClientView(), SK_ColorBLACK, - SkXfermode::kSrc_Mode); -} - -void NonClientFrameViewMash::PaintChildren(const ui::PaintContext& context) { - NonClientFrameView::PaintChildren(context); - - // The client app draws the client area. Make ours totally transparent so - // we only see the client apps client area. - ui::PaintRecorder recorder(context, size(), &paint_cache_); - recorder.canvas()->FillRect(GetBoundsForClientView(), SK_ColorBLACK, - SkXfermode::kSrc_Mode); -} - -void NonClientFrameViewMash::OnWindowClientAreaChanged( - ui::Window* window, - const gfx::Insets& old_client_area, - const std::vector<gfx::Rect>& old_additional_client_area) { - // Only the insets effect the rendering. - if (old_client_area == window->client_area()) - return; - - Layout(); - // NonClientView (our parent) positions the client view based on bounds from - // us. We need to layout from parent to trigger a layout of the client view. - if (parent()) - parent()->Layout(); - SchedulePaint(); -} - -void NonClientFrameViewMash::OnWindowDestroyed(ui::Window* window) { - RemoveObservers(); -} - -void NonClientFrameViewMash::OnWindowSharedPropertyChanged( - ui::Window* window, - const std::string& name, - const std::vector<uint8_t>* old_data, - const std::vector<uint8_t>* new_data) { - if (name == ui::mojom::WindowManager::kResizeBehavior_Property) - header_view_->SizeConstraintsChanged(); - else if (name == ui::mojom::WindowManager::kWindowTitle_Property) - header_view_->SchedulePaintForTitle(); -} - -views::View* NonClientFrameViewMash::GetHeaderView() { - return header_view_; -} - -//////////////////////////////////////////////////////////////////////////////// -// NonClientFrameViewMash, private: - -int NonClientFrameViewMash::NonClientTopBorderHeight() const { - return header_view_->GetPreferredHeight(); -} - -void NonClientFrameViewMash::RemoveObservers() { - if (!window_) - return; - - window_->RemoveObserver(this); - window_->window_tree()->RemoveObserver(this); - window_ = nullptr; -} - -void NonClientFrameViewMash::OnWindowTreeFocusChanged(ui::Window* gained_focus, - ui::Window* lost_focus) { - const bool had_focus = lost_focus && window_->Contains(lost_focus); - const bool has_focus = gained_focus && window_->Contains(gained_focus); - if (had_focus != has_focus) - SchedulePaint(); -} - -} // namespace mus -} // namespace ash
diff --git a/ash/mus/frame/non_client_frame_view_mash.h b/ash/mus/frame/non_client_frame_view_mash.h deleted file mode 100644 index 70f4e4e..0000000 --- a/ash/mus/frame/non_client_frame_view_mash.h +++ /dev/null
@@ -1,112 +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_MUS_FRAME_NON_CLIENT_FRAME_VIEW_MASH_H_ -#define ASH_MUS_FRAME_NON_CLIENT_FRAME_VIEW_MASH_H_ - -#include "base/macros.h" -#include "services/ui/public/cpp/window_observer.h" -#include "services/ui/public/cpp/window_tree_client_observer.h" -#include "third_party/skia/include/core/SkColor.h" -#include "ui/compositor/paint_cache.h" -#include "ui/views/window/non_client_view.h" - -namespace gfx { -class Insets; -} - -namespace ui { -class Window; -} - -namespace views { -class Widget; -} - -namespace ash { -namespace mus { - -class FrameCaptionButtonContainerView; - -class NonClientFrameViewMash : public views::NonClientFrameView, - public ui::WindowObserver, - public ui::WindowTreeClientObserver { - public: - // Internal class name. - static const char kViewClassName[]; - - NonClientFrameViewMash(views::Widget* frame, ui::Window* window); - ~NonClientFrameViewMash() override; - - static gfx::Insets GetPreferredClientAreaInsets(); - static int GetMaxTitleBarButtonWidth(); - - // Sets the active and inactive frame colors. Note the inactive frame color - // will have some transparency added when the frame is drawn. - void SetFrameColors(SkColor active_frame_color, SkColor inactive_frame_color); - - // views::NonClientFrameView: - gfx::Rect GetBoundsForClientView() const override; - gfx::Rect GetWindowBoundsForClientBounds( - const gfx::Rect& client_bounds) const override; - int NonClientHitTest(const gfx::Point& point) override; - void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask) override; - void ResetWindowControls() override; - void UpdateWindowIcon() override; - void UpdateWindowTitle() override; - void SizeConstraintsChanged() override; - - // views::View: - void Layout() override; - gfx::Size GetPreferredSize() const override; - const char* GetClassName() const override; - gfx::Size GetMinimumSize() const override; - gfx::Size GetMaximumSize() const override; - void OnPaint(gfx::Canvas* canvas) override; - void PaintChildren(const ui::PaintContext& context) override; - - // ui::WindowObserver: - void OnWindowClientAreaChanged( - ui::Window* window, - const gfx::Insets& old_client_area, - const std::vector<gfx::Rect>& old_additional_client_area) override; - void OnWindowDestroyed(ui::Window* window) override; - void OnWindowSharedPropertyChanged( - ui::Window* window, - const std::string& name, - const std::vector<uint8_t>* old_data, - const std::vector<uint8_t>* new_data) override; - - // Get the view of the header. - views::View* GetHeaderView(); - - private: - class OverlayView; - - // Height from top of window to top of client area. - int NonClientTopBorderHeight() const; - - void RemoveObservers(); - - // ui::WindowTreeClientObserver: - void OnWindowTreeFocusChanged(ui::Window* gained_focus, - ui::Window* lost_focus) override; - - // Not owned. - views::Widget* frame_; - - ui::Window* window_; - ui::PaintCache paint_cache_; - - // View which contains the title and window controls. - class HeaderView; - HeaderView* header_view_; - - DISALLOW_COPY_AND_ASSIGN(NonClientFrameViewMash); -}; - -} // namespace mus -} // namespace ash - -#endif // ASH_MUS_FRAME_NON_CLIENT_FRAME_VIEW_MASH_H_
diff --git a/ash/mus/move_event_handler.cc b/ash/mus/move_event_handler.cc new file mode 100644 index 0000000..469273b --- /dev/null +++ b/ash/mus/move_event_handler.cc
@@ -0,0 +1,139 @@ +// 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/mus/move_event_handler.h" + +#include "ash/mus/bridge/wm_window_mus.h" +#include "services/ui/public/cpp/window.h" +#include "services/ui/public/cpp/window_manager_delegate.h" +#include "services/ui/public/cpp/window_property.h" +#include "services/ui/public/interfaces/cursor.mojom.h" +#include "ui/aura/window.h" +#include "ui/base/hit_test.h" +#include "ui/events/event.h" + +MUS_DECLARE_WINDOW_PROPERTY_TYPE(ash::mus::MoveEventHandler*) + +namespace { + +// Key used for storing identifier sent to clients for windows. +MUS_DEFINE_LOCAL_WINDOW_PROPERTY_KEY(ash::mus::MoveEventHandler*, + kWmMoveEventHandler, + nullptr); + +} // namespace + +namespace ash { +namespace mus { +namespace { + +ui::mojom::Cursor CursorForWindowComponent(int window_component) { + switch (window_component) { + case HTBOTTOM: + return ui::mojom::Cursor::SOUTH_RESIZE; + case HTBOTTOMLEFT: + return ui::mojom::Cursor::SOUTH_WEST_RESIZE; + case HTBOTTOMRIGHT: + return ui::mojom::Cursor::SOUTH_EAST_RESIZE; + case HTLEFT: + return ui::mojom::Cursor::WEST_RESIZE; + case HTRIGHT: + return ui::mojom::Cursor::EAST_RESIZE; + case HTTOP: + return ui::mojom::Cursor::NORTH_RESIZE; + case HTTOPLEFT: + return ui::mojom::Cursor::NORTH_WEST_RESIZE; + case HTTOPRIGHT: + return ui::mojom::Cursor::NORTH_EAST_RESIZE; + default: + return ui::mojom::Cursor::CURSOR_NULL; + } +} + +void OnMoveLoopCompleted(const base::Callback<void(bool success)>& end_closure, + wm::WmToplevelWindowEventHandler::DragResult result) { + end_closure.Run(result == + wm::WmToplevelWindowEventHandler::DragResult::SUCCESS); +} + +} // namespace + +MoveEventHandler::MoveEventHandler( + ui::Window* mus_window, + ui::WindowManagerClient* window_manager_client, + aura::Window* aura_window) + : wm_window_(WmWindowMus::Get(mus_window)), + window_manager_client_(window_manager_client), + root_window_(aura_window->GetRootWindow()), + toplevel_window_event_handler_(wm_window_->GetShell()) { + root_window_->AddObserver(this); + root_window_->AddPreTargetHandler(this); + + mus_window->SetLocalProperty(kWmMoveEventHandler, this); +} + +MoveEventHandler::~MoveEventHandler() { + Detach(); +} + +// static +MoveEventHandler* MoveEventHandler::GetForWindow(WmWindow* wm_window) { + return WmWindowMus::GetMusWindow(wm_window)->GetLocalProperty( + kWmMoveEventHandler); +} + +void MoveEventHandler::AttemptToStartDrag( + const gfx::Point& point_in_parent, + int window_component, + aura::client::WindowMoveSource source, + const base::Callback<void(bool success)>& end_closure) { + toplevel_window_event_handler_.AttemptToStartDrag( + wm_window_, point_in_parent, window_component, source, + base::Bind(&OnMoveLoopCompleted, end_closure)); +} + +bool MoveEventHandler::IsDragInProgress() { + return toplevel_window_event_handler_.is_drag_in_progress(); +} + +void MoveEventHandler::RevertDrag() { + toplevel_window_event_handler_.RevertDrag(); +} + +void MoveEventHandler::Detach() { + if (!root_window_) + return; + + root_window_->RemoveObserver(this); + root_window_->RemovePreTargetHandler(this); + root_window_ = nullptr; +} + +void MoveEventHandler::OnMouseEvent(ui::MouseEvent* event) { + toplevel_window_event_handler_.OnMouseEvent(event, wm_window_); + if (!toplevel_window_event_handler_.is_drag_in_progress() && + (event->type() == ui::ET_POINTER_MOVED || + event->type() == ui::ET_MOUSE_MOVED)) { + const int hit_test_location = + wm_window_->GetNonClientComponent(event->location()); + window_manager_client_->SetNonClientCursor( + wm_window_->mus_window(), CursorForWindowComponent(hit_test_location)); + } +} + +void MoveEventHandler::OnGestureEvent(ui::GestureEvent* event) { + toplevel_window_event_handler_.OnGestureEvent(event, wm_window_); +} + +void MoveEventHandler::OnCancelMode(ui::CancelModeEvent* event) { + toplevel_window_event_handler_.RevertDrag(); +} + +void MoveEventHandler::OnWindowDestroying(aura::Window* window) { + DCHECK_EQ(root_window_, window); + Detach(); +} + +} // namespace mus +} // namespace ash
diff --git a/ash/mus/move_event_handler.h b/ash/mus/move_event_handler.h new file mode 100644 index 0000000..a51caf1 --- /dev/null +++ b/ash/mus/move_event_handler.h
@@ -0,0 +1,83 @@ +// 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_MUS_MOVE_EVENT_HANDLER_H_ +#define ASH_MUS_MOVE_EVENT_HANDLER_H_ + +#include <memory> + +#include "ash/common/wm/wm_toplevel_window_event_handler.h" +#include "base/macros.h" +#include "ui/aura/window_observer.h" +#include "ui/events/event_handler.h" + +namespace aura { +class Window; +} + +namespace ui { +class CancelModeEvent; +class Window; +class WindowManagerClient; +} + +namespace ash { +namespace mus { + +class WmWindowMus; + +// EventHandler attached to windows that may be dragged and/or resized. This +// forwards to WmToplevelWindowEventHandler to handle the actual drag/resize. +class MoveEventHandler : public ui::EventHandler, public aura::WindowObserver { + public: + MoveEventHandler(ui::Window* mus_window, + ui::WindowManagerClient* window_manager_client, + aura::Window* aura_window); + ~MoveEventHandler() override; + + // Retrieves the MoveEventHandler for an existing WmWindow. + static MoveEventHandler* GetForWindow(WmWindow* wm_window); + + // Attempts to start a drag if one is not already in progress. This passes + // the call to the underlying WmToplevelWindowEventHandler. After the drag + // completes, |end_closure| will be called to return whether the drag was + // successfully completed. + void AttemptToStartDrag( + const gfx::Point& point_in_parent, + int window_component, + aura::client::WindowMoveSource source, + const base::Callback<void(bool success)>& end_closure); + + // Returns whether we're in a drag. + bool IsDragInProgress(); + + // Reverts a manually started drag started with AttemptToStartDrag(). + void RevertDrag(); + + private: + // Removes observer and EventHandler installed on |root_window_|. + void Detach(); + + // Overridden from ui::EventHandler: + void OnMouseEvent(ui::MouseEvent* event) override; + void OnGestureEvent(ui::GestureEvent* event) override; + void OnCancelMode(ui::CancelModeEvent* event) override; + + // Overridden from aura::WindowObserver: + void OnWindowDestroying(aura::Window* window) override; + + WmWindowMus* wm_window_; + ui::WindowManagerClient* window_manager_client_; + // The root window of the aura::Window supplied to the constructor. + // MoveEventHandler is added as a pre-target handler (and observer) of this. + aura::Window* root_window_; + wm::WmToplevelWindowEventHandler toplevel_window_event_handler_; + + DISALLOW_COPY_AND_ASSIGN(MoveEventHandler); +}; + +} // namespace mus +} // namespace ash + +#endif // ASH_MUS_MOVE_EVENT_HANDLER_H_
diff --git a/ash/mus/non_client_frame_controller.cc b/ash/mus/non_client_frame_controller.cc index 913ba2b..1f46aa8 100644 --- a/ash/mus/non_client_frame_controller.cc +++ b/ash/mus/non_client_frame_controller.cc
@@ -10,10 +10,11 @@ #include <string> #include <vector> +#include "ash/common/ash_constants.h" +#include "ash/common/ash_layout_constants.h" +#include "ash/common/frame/custom_frame_view_ash.h" #include "ash/mus/bridge/wm_window_mus.h" -#include "ash/mus/frame/frame_border_hit_test_controller.h" -#include "ash/mus/frame/move_event_handler.h" -#include "ash/mus/frame/non_client_frame_view_mash.h" +#include "ash/mus/move_event_handler.h" #include "ash/mus/property_util.h" #include "ash/mus/shadow.h" #include "base/macros.h" @@ -124,7 +125,7 @@ window(), window_manager_client_, GetNativeView())); if (ShouldRemoveStandardFrame(window())) return new EmptyDraggableNonClientFrameView(); - return new NonClientFrameViewMash(GetWidget(), window()); + return new CustomFrameViewAsh(GetWidget()); } void InitNativeWidget(const views::Widget::InitParams& params) override { views::NativeWidgetMus::InitNativeWidget(params); @@ -142,21 +143,6 @@ window_tree_host->window()->layer()->Add(shadow_->layer()); shadow_->layer()->parent()->StackAtBottom(shadow_->layer()); } - void CenterWindow(const gfx::Size& size) override { - // Do nothing. The client controls the size, not us. - } - bool SetWindowTitle(const base::string16& title) override { - // Do nothing. The client controls the window title, not us. - return false; - } - void SetWindowIcons(const gfx::ImageSkia& window_icon, - const gfx::ImageSkia& app_icon) override { - // Do nothing. The client controls window icons, not us. - } - void UpdateClientArea() override { - // This pushes the client area to the WS. We don't want to do that as - // the client area should come from the client, not us. - } private: // The shadow, may be null. @@ -193,6 +179,13 @@ DISALLOW_COPY_AND_ASSIGN(ClientViewMus); }; +// Returns the frame insets to use when ShouldUseExtendedHitRegion() returns +// true. +gfx::Insets GetExtendedHitRegion() { + return gfx::Insets(kResizeOutsideBoundsSize, kResizeOutsideBoundsSize, + kResizeOutsideBoundsSize, kResizeOutsideBoundsSize); +} + } // namespace // static @@ -207,12 +200,20 @@ // static gfx::Insets NonClientFrameController::GetPreferredClientAreaInsets() { - return NonClientFrameViewMash::GetPreferredClientAreaInsets(); + // TODO(sky): figure out a better way to get this rather than hard coding. + // This value comes from the header (see DefaultHeaderPainter::LayoutHeader, + // which uses the preferred height of the CaptionButtonContainer, which uses + // the height of the close button). + return gfx::Insets( + GetAshLayoutSize(AshLayoutSize::NON_BROWSER_CAPTION_BUTTON).height(), 0, + 0, 0); } // static int NonClientFrameController::GetMaxTitleBarButtonWidth() { - return NonClientFrameViewMash::GetMaxTitleBarButtonWidth(); + // TODO(sky): same comment as for GetPreferredClientAreaInsets(). + return GetAshLayoutSize(AshLayoutSize::NON_BROWSER_CAPTION_BUTTON).width() * + 3; } NonClientFrameController::NonClientFrameController( @@ -244,9 +245,8 @@ const int shadow_inset = Shadow::GetInteriorInsetForStyle(Shadow::STYLE_ACTIVE); const gfx::Insets extended_hit_region = - wm_window->ShouldUseExtendedHitRegion() - ? FrameBorderHitTestController::GetResizeOutsideBoundsSize() - : gfx::Insets(); + wm_window->ShouldUseExtendedHitRegion() ? GetExtendedHitRegion() + : gfx::Insets(); window_manager_client->SetUnderlaySurfaceOffsetAndExtendedHitArea( window, gfx::Vector2d(shadow_inset, shadow_inset), extended_hit_region); }
diff --git a/ash/mus/resources/BUILD.gn b/ash/mus/resources/BUILD.gn deleted file mode 100644 index 9ae798b..0000000 --- a/ash/mus/resources/BUILD.gn +++ /dev/null
@@ -1,14 +0,0 @@ -# Copyright 2015 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import("//tools/grit/grit_rule.gni") - -grit("resources") { - source = "ash_mus_resources.grd" - outputs = [ - "grit/ash_mus_resources.h", - "ash_mus_resources_100_percent.pak", - "ash_mus_resources_200_percent.pak", - ] -}
diff --git a/ash/mus/resources/ash_mus_resources.grd b/ash/mus/resources/ash_mus_resources.grd deleted file mode 100644 index 91982be..0000000 --- a/ash/mus/resources/ash_mus_resources.grd +++ /dev/null
@@ -1,35 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<grit latest_public_release="0" current_release="1" output_all_resource_defines="false"> - <outputs> - <output filename="grit/ash_mus_resources.h" type="rc_header" context="default_100_percent"> - <emit emit_type='prepend'></emit> - </output> - <output filename="ash_mus_resources_100_percent.pak" type="data_package" context="default_100_percent" /> - <output filename="ash_mus_resources_200_percent.pak" type="data_package" context="default_200_percent" /> - </outputs> - <release seq="1"> - <structures fallback_to_low_resolution="true"> - <!-- KEEP THESE IN ALPHABETICAL ORDER! DO NOT ADD TO RANDOM PLACES JUST - BECAUSE YOUR RESOURCES ARE FUNCTIONALLY RELATED OR FALL UNDER THE - SAME CONDITIONALS. --> - <structure type="chrome_scaled_image" name="IDR_ASH_MUS_WINDOW_CONTROL_BACKGROUND_H" file="common/window_control_background_hover.png" /> - <structure type="chrome_scaled_image" name="IDR_ASH_MUS_WINDOW_CONTROL_BACKGROUND_P" file="common/window_control_background_pressed.png" /> - <structure type="chrome_scaled_image" name="IDR_ASH_MUS_WINDOW_CONTROL_ICON_CLOSE" file="common/window_control_icon_close.png" /> - <structure type="chrome_scaled_image" name="IDR_ASH_MUS_WINDOW_CONTROL_ICON_CLOSE_WHITE" file="common/window_control_icon_close_white.png" /> - <structure type="chrome_scaled_image" name="IDR_ASH_MUS_WINDOW_CONTROL_ICON_LEFT_SNAPPED" file="common/window_control_icon_left_snapped.png" /> - <structure type="chrome_scaled_image" name="IDR_ASH_MUS_WINDOW_CONTROL_ICON_LEFT_SNAPPED_WHITE" file="common/window_control_icon_left_snapped_white.png" /> - <structure type="chrome_scaled_image" name="IDR_ASH_MUS_WINDOW_CONTROL_ICON_MAXIMIZE" file="common/window_control_icon_maximize.png" /> - <structure type="chrome_scaled_image" name="IDR_ASH_MUS_WINDOW_CONTROL_ICON_MAXIMIZE_WHITE" file="common/window_control_icon_maximize_white.png" /> - <structure type="chrome_scaled_image" name="IDR_ASH_MUS_WINDOW_CONTROL_ICON_MINIMIZE" file="common/window_control_icon_minimize.png" /> - <structure type="chrome_scaled_image" name="IDR_ASH_MUS_WINDOW_CONTROL_ICON_MINIMIZE_WHITE" file="common/window_control_icon_minimize_white.png" /> - <structure type="chrome_scaled_image" name="IDR_ASH_MUS_WINDOW_CONTROL_ICON_RESTORE" file="common/window_control_icon_restore.png" /> - <structure type="chrome_scaled_image" name="IDR_ASH_MUS_WINDOW_CONTROL_ICON_RESTORE_WHITE" file="common/window_control_icon_restore_white.png" /> - <structure type="chrome_scaled_image" name="IDR_ASH_MUS_WINDOW_CONTROL_ICON_RIGHT_SNAPPED" file="common/window_control_icon_right_snapped.png" /> - <structure type="chrome_scaled_image" name="IDR_ASH_MUS_WINDOW_CONTROL_ICON_RIGHT_SNAPPED_WHITE" file="common/window_control_icon_right_snapped_white.png" /> - <structure type="chrome_scaled_image" name="IDR_ASH_MUS_WINDOW_HEADER_SHADE_INACTIVE_BOTTOM" file="common/window_header_shade_bottom_inactive.png" /> - <structure type="chrome_scaled_image" name="IDR_ASH_MUS_WINDOW_HEADER_SHADE_INACTIVE_LEFT" file="common/window_header_shade_left_inactive.png" /> - <structure type="chrome_scaled_image" name="IDR_ASH_MUS_WINDOW_HEADER_SHADE_INACTIVE_RIGHT" file="common/window_header_shade_right_inactive.png" /> - <structure type="chrome_scaled_image" name="IDR_ASH_MUS_WINDOW_HEADER_SHADE_INACTIVE_TOP" file="common/window_header_shade_top_inactive.png" /> - </structures> - </release> -</grit>
diff --git a/ash/mus/resources/default_100_percent/common/window_control_background_hover.png b/ash/mus/resources/default_100_percent/common/window_control_background_hover.png deleted file mode 100644 index f32a78ea..0000000 --- a/ash/mus/resources/default_100_percent/common/window_control_background_hover.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_100_percent/common/window_control_background_pressed.png b/ash/mus/resources/default_100_percent/common/window_control_background_pressed.png deleted file mode 100644 index 2aee9da..0000000 --- a/ash/mus/resources/default_100_percent/common/window_control_background_pressed.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_100_percent/common/window_control_icon_close.png b/ash/mus/resources/default_100_percent/common/window_control_icon_close.png deleted file mode 100644 index db26524..0000000 --- a/ash/mus/resources/default_100_percent/common/window_control_icon_close.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_100_percent/common/window_control_icon_close_white.png b/ash/mus/resources/default_100_percent/common/window_control_icon_close_white.png deleted file mode 100644 index 1bc6a84..0000000 --- a/ash/mus/resources/default_100_percent/common/window_control_icon_close_white.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_100_percent/common/window_control_icon_left_snapped.png b/ash/mus/resources/default_100_percent/common/window_control_icon_left_snapped.png deleted file mode 100644 index 4374068dfb..0000000 --- a/ash/mus/resources/default_100_percent/common/window_control_icon_left_snapped.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_100_percent/common/window_control_icon_left_snapped_white.png b/ash/mus/resources/default_100_percent/common/window_control_icon_left_snapped_white.png deleted file mode 100644 index 58be13a..0000000 --- a/ash/mus/resources/default_100_percent/common/window_control_icon_left_snapped_white.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_100_percent/common/window_control_icon_maximize.png b/ash/mus/resources/default_100_percent/common/window_control_icon_maximize.png deleted file mode 100644 index ce0cf13..0000000 --- a/ash/mus/resources/default_100_percent/common/window_control_icon_maximize.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_100_percent/common/window_control_icon_maximize_white.png b/ash/mus/resources/default_100_percent/common/window_control_icon_maximize_white.png deleted file mode 100644 index 5dc6ccb..0000000 --- a/ash/mus/resources/default_100_percent/common/window_control_icon_maximize_white.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_100_percent/common/window_control_icon_minimize.png b/ash/mus/resources/default_100_percent/common/window_control_icon_minimize.png deleted file mode 100644 index 48c262c..0000000 --- a/ash/mus/resources/default_100_percent/common/window_control_icon_minimize.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_100_percent/common/window_control_icon_minimize_white.png b/ash/mus/resources/default_100_percent/common/window_control_icon_minimize_white.png deleted file mode 100644 index b085916..0000000 --- a/ash/mus/resources/default_100_percent/common/window_control_icon_minimize_white.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_100_percent/common/window_control_icon_restore.png b/ash/mus/resources/default_100_percent/common/window_control_icon_restore.png deleted file mode 100644 index 565dae9c..0000000 --- a/ash/mus/resources/default_100_percent/common/window_control_icon_restore.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_100_percent/common/window_control_icon_restore_white.png b/ash/mus/resources/default_100_percent/common/window_control_icon_restore_white.png deleted file mode 100644 index 5b51c15..0000000 --- a/ash/mus/resources/default_100_percent/common/window_control_icon_restore_white.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_100_percent/common/window_control_icon_right_snapped.png b/ash/mus/resources/default_100_percent/common/window_control_icon_right_snapped.png deleted file mode 100644 index 53551d4f..0000000 --- a/ash/mus/resources/default_100_percent/common/window_control_icon_right_snapped.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_100_percent/common/window_control_icon_right_snapped_white.png b/ash/mus/resources/default_100_percent/common/window_control_icon_right_snapped_white.png deleted file mode 100644 index b02d33c..0000000 --- a/ash/mus/resources/default_100_percent/common/window_control_icon_right_snapped_white.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_100_percent/common/window_header_shade_bottom_inactive.png b/ash/mus/resources/default_100_percent/common/window_header_shade_bottom_inactive.png deleted file mode 100644 index 69a3e01..0000000 --- a/ash/mus/resources/default_100_percent/common/window_header_shade_bottom_inactive.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_100_percent/common/window_header_shade_left_inactive.png b/ash/mus/resources/default_100_percent/common/window_header_shade_left_inactive.png deleted file mode 100644 index 06b9749..0000000 --- a/ash/mus/resources/default_100_percent/common/window_header_shade_left_inactive.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_100_percent/common/window_header_shade_right_inactive.png b/ash/mus/resources/default_100_percent/common/window_header_shade_right_inactive.png deleted file mode 100644 index 3dcc983..0000000 --- a/ash/mus/resources/default_100_percent/common/window_header_shade_right_inactive.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_100_percent/common/window_header_shade_top_inactive.png b/ash/mus/resources/default_100_percent/common/window_header_shade_top_inactive.png deleted file mode 100644 index 0be57ba..0000000 --- a/ash/mus/resources/default_100_percent/common/window_header_shade_top_inactive.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_200_percent/common/window_control_background_hover.png b/ash/mus/resources/default_200_percent/common/window_control_background_hover.png deleted file mode 100644 index d37f619e9..0000000 --- a/ash/mus/resources/default_200_percent/common/window_control_background_hover.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_200_percent/common/window_control_background_pressed.png b/ash/mus/resources/default_200_percent/common/window_control_background_pressed.png deleted file mode 100644 index 77fcf5f..0000000 --- a/ash/mus/resources/default_200_percent/common/window_control_background_pressed.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_200_percent/common/window_control_icon_close.png b/ash/mus/resources/default_200_percent/common/window_control_icon_close.png deleted file mode 100644 index 5c14ecd..0000000 --- a/ash/mus/resources/default_200_percent/common/window_control_icon_close.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_200_percent/common/window_control_icon_close_white.png b/ash/mus/resources/default_200_percent/common/window_control_icon_close_white.png deleted file mode 100644 index 27cef0f..0000000 --- a/ash/mus/resources/default_200_percent/common/window_control_icon_close_white.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_200_percent/common/window_control_icon_left_snapped.png b/ash/mus/resources/default_200_percent/common/window_control_icon_left_snapped.png deleted file mode 100644 index f8db919..0000000 --- a/ash/mus/resources/default_200_percent/common/window_control_icon_left_snapped.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_200_percent/common/window_control_icon_left_snapped_white.png b/ash/mus/resources/default_200_percent/common/window_control_icon_left_snapped_white.png deleted file mode 100644 index 6e938b8..0000000 --- a/ash/mus/resources/default_200_percent/common/window_control_icon_left_snapped_white.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_200_percent/common/window_control_icon_maximize.png b/ash/mus/resources/default_200_percent/common/window_control_icon_maximize.png deleted file mode 100644 index a5947a59..0000000 --- a/ash/mus/resources/default_200_percent/common/window_control_icon_maximize.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_200_percent/common/window_control_icon_maximize_white.png b/ash/mus/resources/default_200_percent/common/window_control_icon_maximize_white.png deleted file mode 100644 index 5e17aaef..0000000 --- a/ash/mus/resources/default_200_percent/common/window_control_icon_maximize_white.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_200_percent/common/window_control_icon_minimize.png b/ash/mus/resources/default_200_percent/common/window_control_icon_minimize.png deleted file mode 100644 index 837b433f..0000000 --- a/ash/mus/resources/default_200_percent/common/window_control_icon_minimize.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_200_percent/common/window_control_icon_minimize_white.png b/ash/mus/resources/default_200_percent/common/window_control_icon_minimize_white.png deleted file mode 100644 index cb295d0..0000000 --- a/ash/mus/resources/default_200_percent/common/window_control_icon_minimize_white.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_200_percent/common/window_control_icon_restore.png b/ash/mus/resources/default_200_percent/common/window_control_icon_restore.png deleted file mode 100644 index 5a327bb..0000000 --- a/ash/mus/resources/default_200_percent/common/window_control_icon_restore.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_200_percent/common/window_control_icon_restore_white.png b/ash/mus/resources/default_200_percent/common/window_control_icon_restore_white.png deleted file mode 100644 index a2e02ed..0000000 --- a/ash/mus/resources/default_200_percent/common/window_control_icon_restore_white.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_200_percent/common/window_control_icon_right_snapped.png b/ash/mus/resources/default_200_percent/common/window_control_icon_right_snapped.png deleted file mode 100644 index 8eed437a..0000000 --- a/ash/mus/resources/default_200_percent/common/window_control_icon_right_snapped.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_200_percent/common/window_control_icon_right_snapped_white.png b/ash/mus/resources/default_200_percent/common/window_control_icon_right_snapped_white.png deleted file mode 100644 index d8d5cfd4..0000000 --- a/ash/mus/resources/default_200_percent/common/window_control_icon_right_snapped_white.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_200_percent/common/window_header_shade_bottom_inactive.png b/ash/mus/resources/default_200_percent/common/window_header_shade_bottom_inactive.png deleted file mode 100644 index 5c6d4ff1..0000000 --- a/ash/mus/resources/default_200_percent/common/window_header_shade_bottom_inactive.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_200_percent/common/window_header_shade_left_inactive.png b/ash/mus/resources/default_200_percent/common/window_header_shade_left_inactive.png deleted file mode 100644 index 91f40878..0000000 --- a/ash/mus/resources/default_200_percent/common/window_header_shade_left_inactive.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_200_percent/common/window_header_shade_right_inactive.png b/ash/mus/resources/default_200_percent/common/window_header_shade_right_inactive.png deleted file mode 100644 index 2ab6d846..0000000 --- a/ash/mus/resources/default_200_percent/common/window_header_shade_right_inactive.png +++ /dev/null Binary files differ
diff --git a/ash/mus/resources/default_200_percent/common/window_header_shade_top_inactive.png b/ash/mus/resources/default_200_percent/common/window_header_shade_top_inactive.png deleted file mode 100644 index 576ad9b..0000000 --- a/ash/mus/resources/default_200_percent/common/window_header_shade_top_inactive.png +++ /dev/null Binary files differ
diff --git a/ash/mus/root_window_controller.cc b/ash/mus/root_window_controller.cc index e864585..887092f 100644 --- a/ash/mus/root_window_controller.cc +++ b/ash/mus/root_window_controller.cc
@@ -21,7 +21,6 @@ #include "ash/common/wm/panels/panel_layout_manager.h" #include "ash/common/wm/root_window_layout_manager.h" #include "ash/common/wm/workspace/workspace_layout_manager.h" -#include "ash/common/wm/workspace/workspace_layout_manager_delegate.h" #include "ash/mus/bridge/wm_root_window_controller_mus.h" #include "ash/mus/bridge/wm_shelf_mus.h" #include "ash/mus/bridge/wm_shell_mus.h" @@ -50,32 +49,6 @@ namespace ash { namespace mus { -namespace { - -class WorkspaceLayoutManagerDelegateImpl - : public wm::WorkspaceLayoutManagerDelegate { - public: - explicit WorkspaceLayoutManagerDelegateImpl( - WmRootWindowControllerMus* root_window_controller) - : root_window_controller_(root_window_controller) {} - ~WorkspaceLayoutManagerDelegateImpl() override = default; - - // WorkspaceLayoutManagerDelegate: - void UpdateShelfVisibility() override { NOTIMPLEMENTED(); } - void OnFullscreenStateChanged(bool is_fullscreen) override { - // TODO(sky): this should only do something if there is a shelf, see - // implementation in ash/shell.cc. - NOTIMPLEMENTED(); - root_window_controller_->NotifyFullscreenStateChange(is_fullscreen); - } - - private: - WmRootWindowControllerMus* root_window_controller_; - - DISALLOW_COPY_AND_ASSIGN(WorkspaceLayoutManagerDelegateImpl); -}; - -} // namespace RootWindowController::RootWindowController(WindowManager* window_manager, ui::Window* root, @@ -164,17 +137,6 @@ WmWindowMus::Get(root_)->GetChildByShellWindowId(id)); } -ShelfLayoutManager* RootWindowController::GetShelfLayoutManager() { - return static_cast<ShelfLayoutManager*>( - layout_managers_[GetWindowForContainer(Container::USER_PRIVATE_SHELF)] - .get()); -} - -StatusLayoutManager* RootWindowController::GetStatusLayoutManager() { - return static_cast<StatusLayoutManager*>( - layout_managers_[GetWindowForContainer(Container::STATUS)].get()); -} - gfx::Rect RootWindowController::CalculateDefaultBounds( ui::Window* window) const { if (window->HasSharedProperty( @@ -206,13 +168,7 @@ DockedWindowLayoutManager* docked_window_layout_manager = DockedWindowLayoutManager::Get(WmWindowMus::Get(root_)); - // Following code expects the shelf to be called only once. - // TODO(sky): this check is only necessary while we have shelf hosted in - // sysui (as sysui can restart). Once that is fixed there should be a DCHECK - // that the shelf hasn't been set. - if (docked_window_layout_manager->shelf()) - return; - + DCHECK(!docked_window_layout_manager->shelf()); docked_window_layout_manager->SetShelf(wm_shelf_.get()); PanelLayoutManager::Get(WmWindowMus::Get(root_))->SetShelf(wm_shelf_.get()); @@ -247,11 +203,7 @@ GetWindowByShellWindowId(kShellWindowId_DefaultContainer); // WorkspaceLayoutManager is not a mash::wm::LayoutManager (it's a // wm::LayoutManager), so it can't be in |layout_managers_|. - std::unique_ptr<WorkspaceLayoutManagerDelegateImpl> - workspace_layout_manager_delegate(new WorkspaceLayoutManagerDelegateImpl( - wm_root_window_controller_.get())); - workspace_layout_manager_ = new WorkspaceLayoutManager( - default_container, std::move(workspace_layout_manager_delegate)); + workspace_layout_manager_ = new WorkspaceLayoutManager(default_container); default_container->SetLayoutManager( base::WrapUnique(workspace_layout_manager_));
diff --git a/ash/mus/root_window_controller.h b/ash/mus/root_window_controller.h index e00c460..ae1f013 100644 --- a/ash/mus/root_window_controller.h +++ b/ash/mus/root_window_controller.h
@@ -27,8 +27,6 @@ namespace mus { class LayoutManager; -class ShelfLayoutManager; -class StatusLayoutManager; class WindowManager; class WmRootWindowControllerMus; class WmShelfMus; @@ -64,8 +62,6 @@ const display::Display& display() const { return display_; } - ShelfLayoutManager* GetShelfLayoutManager(); - StatusLayoutManager* GetStatusLayoutManager(); WorkspaceLayoutManager* workspace_layout_manager() { return workspace_layout_manager_; }
diff --git a/ash/mus/shelf_layout_impl.cc b/ash/mus/shelf_layout_impl.cc deleted file mode 100644 index 93aab02..0000000 --- a/ash/mus/shelf_layout_impl.cc +++ /dev/null
@@ -1,34 +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/mus/shelf_layout_impl.h" - -#include "ash/mus/root_window_controller.h" -#include "ash/mus/shelf_layout_manager.h" -#include "ash/mus/status_layout_manager.h" - -namespace ash { -namespace mus { - -ShelfLayoutImpl::ShelfLayoutImpl() {} - -ShelfLayoutImpl::~ShelfLayoutImpl() {} - -void ShelfLayoutImpl::Initialize(RootWindowController* root_controller) { - root_controller_ = root_controller; -} - -void ShelfLayoutImpl::SetAlignment(mash::shelf::mojom::Alignment alignment) { - root_controller_->GetShelfLayoutManager()->SetAlignment(alignment); - root_controller_->GetStatusLayoutManager()->SetAlignment(alignment); -} - -void ShelfLayoutImpl::SetAutoHideBehavior( - mash::shelf::mojom::AutoHideBehavior auto_hide) { - root_controller_->GetShelfLayoutManager()->SetAutoHideBehavior(auto_hide); - root_controller_->GetStatusLayoutManager()->SetAutoHideBehavior(auto_hide); -} - -} // namespace mus -} // namespace ash
diff --git a/ash/mus/shelf_layout_impl.h b/ash/mus/shelf_layout_impl.h deleted file mode 100644 index 698525b..0000000 --- a/ash/mus/shelf_layout_impl.h +++ /dev/null
@@ -1,39 +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_MUS_SHELF_LAYOUT_IMPL_H_ -#define ASH_MUS_SHELF_LAYOUT_IMPL_H_ - -#include "ash/public/interfaces/shelf_layout.mojom.h" -#include "base/macros.h" - -namespace ash { -namespace mus { - -class RootWindowController; - -// Implements the ShelfLayout mojo interface to listen for layout changes from -// the system UI application. -class ShelfLayoutImpl : public mojom::ShelfLayout { - public: - ShelfLayoutImpl(); - ~ShelfLayoutImpl() override; - - void Initialize(RootWindowController* root_controller); - - private: - // Overridden from mojom::ShelfLayout: - void SetAlignment(mash::shelf::mojom::Alignment alignment) override; - void SetAutoHideBehavior( - mash::shelf::mojom::AutoHideBehavior auto_hide) override; - - RootWindowController* root_controller_ = nullptr; - - DISALLOW_COPY_AND_ASSIGN(ShelfLayoutImpl); -}; - -} // namespace mus -} // namespace ash - -#endif // ASH_MUS_SHELF_LAYOUT_IMPL_H_
diff --git a/ash/mus/user_window_controller_impl.cc b/ash/mus/user_window_controller_impl.cc deleted file mode 100644 index 56e5469..0000000 --- a/ash/mus/user_window_controller_impl.cc +++ /dev/null
@@ -1,209 +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/mus/user_window_controller_impl.h" - -#include "ash/common/shell_window_ids.h" -#include "ash/mus/bridge/wm_window_mus.h" -#include "ash/mus/property_util.h" -#include "ash/mus/root_window_controller.h" -#include "ash/public/interfaces/container.mojom.h" -#include "mojo/common/common_type_converters.h" -#include "services/ui/public/cpp/property_type_converters.h" -#include "services/ui/public/cpp/window.h" -#include "services/ui/public/cpp/window_property.h" -#include "services/ui/public/cpp/window_tree_client.h" -#include "ui/resources/grit/ui_resources.h" - -MUS_DECLARE_WINDOW_PROPERTY_TYPE(uint32_t) - -namespace { - -// Key used for storing identifier sent to clients for windows. -MUS_DEFINE_LOCAL_WINDOW_PROPERTY_KEY(uint32_t, kUserWindowIdKey, 0u); - -} // namespace - -namespace ash { -namespace mus { - -namespace { - -// Returns |window|, or an ancestor thereof, parented to |container|, or null. -ui::Window* GetTopLevelWindow(ui::Window* window, ui::Window* container) { - while (window && window->parent() != container) - window = window->parent(); - return window; -} - -// Get a UserWindow struct from a ui::Window. -mojom::UserWindowPtr GetUserWindow(ui::Window* window) { - mojom::UserWindowPtr user_window(mojom::UserWindow::New()); - DCHECK_NE(0u, window->GetLocalProperty(kUserWindowIdKey)); - user_window->window_id = window->GetLocalProperty(kUserWindowIdKey); - user_window->window_title = mojo::String::From(GetWindowTitle(window)); - user_window->window_app_icon = GetWindowAppIcon(window); - user_window->window_app_id = mojo::String::From(GetAppID(window)); - user_window->ignored_by_shelf = GetWindowIgnoredByShelf(window); - ui::Window* focused = window->window_tree()->GetFocusedWindow(); - focused = GetTopLevelWindow(focused, window->parent()); - user_window->window_has_focus = focused == window; - return user_window; -} - -} // namespace - -// Observes property changes on user windows. UserWindowControllerImpl uses -// this separate observer to avoid observing duplicate tree change -// notifications. -class WindowPropertyObserver : public ui::WindowObserver { - public: - explicit WindowPropertyObserver(UserWindowControllerImpl* controller) - : controller_(controller) {} - ~WindowPropertyObserver() override {} - - private: - // ui::WindowObserver: - void OnWindowSharedPropertyChanged( - ui::Window* window, - const std::string& name, - const std::vector<uint8_t>* old_data, - const std::vector<uint8_t>* new_data) override { - if (!controller_->user_window_observer()) - return; - if (name == ui::mojom::WindowManager::kWindowTitle_Property) { - controller_->user_window_observer()->OnUserWindowTitleChanged( - window->GetLocalProperty(kUserWindowIdKey), - mojo::String::From(GetWindowTitle(window))); - } else if (name == ui::mojom::WindowManager::kWindowAppIcon_Property) { - controller_->user_window_observer()->OnUserWindowAppIconChanged( - window->GetLocalProperty(kUserWindowIdKey), - new_data ? mojo::Array<uint8_t>::From(*new_data) - : mojo::Array<uint8_t>()); - } - } - - UserWindowControllerImpl* controller_; - DISALLOW_COPY_AND_ASSIGN(WindowPropertyObserver); -}; - -UserWindowControllerImpl::UserWindowControllerImpl() - : root_controller_(nullptr) {} - -UserWindowControllerImpl::~UserWindowControllerImpl() { - if (!root_controller_) - return; - - ui::Window* user_container = GetUserWindowContainer(); - if (!user_container) - return; - - RemoveObservers(user_container); -} - -void UserWindowControllerImpl::Initialize( - RootWindowController* root_controller) { - DCHECK(root_controller); - DCHECK(!root_controller_); - root_controller_ = root_controller; - GetUserWindowContainer()->AddObserver(this); - GetUserWindowContainer()->window_tree()->AddObserver(this); - window_property_observer_.reset(new WindowPropertyObserver(this)); - for (ui::Window* window : GetUserWindowContainer()->children()) { - AssignIdIfNecessary(window); - window->AddObserver(window_property_observer_.get()); - } -} - -void UserWindowControllerImpl::AssignIdIfNecessary(ui::Window* window) { - if (window->GetLocalProperty(kUserWindowIdKey) == 0u) - window->SetLocalProperty(kUserWindowIdKey, next_id_++); -} - -void UserWindowControllerImpl::RemoveObservers(ui::Window* user_container) { - user_container->RemoveObserver(this); - user_container->window_tree()->RemoveObserver(this); - for (auto* iter : user_container->children()) - iter->RemoveObserver(window_property_observer_.get()); -} - -ui::Window* UserWindowControllerImpl::GetUserWindowById(uint32_t id) { - for (ui::Window* window : GetUserWindowContainer()->children()) { - if (window->GetLocalProperty(kUserWindowIdKey) == id) - return window; - } - return nullptr; -} - -ui::Window* UserWindowControllerImpl::GetUserWindowContainer() const { - WmWindowMus* window = root_controller_->GetWindowByShellWindowId( - kShellWindowId_DefaultContainer); - return window ? window->mus_window() : nullptr; -} - -void UserWindowControllerImpl::OnTreeChanging(const TreeChangeParams& params) { - DCHECK(root_controller_); - if (params.new_parent == GetUserWindowContainer()) { - params.target->AddObserver(window_property_observer_.get()); - AssignIdIfNecessary(params.target); - if (user_window_observer_) - user_window_observer_->OnUserWindowAdded(GetUserWindow(params.target)); - } else if (params.old_parent == GetUserWindowContainer()) { - params.target->RemoveObserver(window_property_observer_.get()); - if (user_window_observer_) - user_window_observer_->OnUserWindowRemoved( - params.target->GetLocalProperty(kUserWindowIdKey)); - } -} - -void UserWindowControllerImpl::OnWindowDestroying(ui::Window* window) { - if (window == GetUserWindowContainer()) - RemoveObservers(window); -} - -void UserWindowControllerImpl::OnWindowTreeFocusChanged( - ui::Window* gained_focus, - ui::Window* lost_focus) { - if (!user_window_observer_) - return; - - // Treat focus in the user window hierarchy as focus of the top-level window. - gained_focus = GetTopLevelWindow(gained_focus, GetUserWindowContainer()); - lost_focus = GetTopLevelWindow(lost_focus, GetUserWindowContainer()); - if (gained_focus == lost_focus) - return; - - if (lost_focus) { - user_window_observer_->OnUserWindowFocusChanged( - lost_focus->GetLocalProperty(kUserWindowIdKey), false); - } - if (gained_focus) { - user_window_observer_->OnUserWindowFocusChanged( - gained_focus->GetLocalProperty(kUserWindowIdKey), true); - } -} - -void UserWindowControllerImpl::AddUserWindowObserver( - mojom::UserWindowObserverPtr observer) { - // TODO(msw): Support multiple observers. - user_window_observer_ = std::move(observer); - - const ui::Window::Children& windows = GetUserWindowContainer()->children(); - mojo::Array<mojom::UserWindowPtr> user_windows = - mojo::Array<mojom::UserWindowPtr>::New(windows.size()); - for (size_t i = 0; i < windows.size(); ++i) - user_windows[i] = GetUserWindow(windows[i]); - user_window_observer_->OnUserWindowObserverAdded(std::move(user_windows)); -} - -void UserWindowControllerImpl::ActivateUserWindow(uint32_t window_id) { - ui::Window* window = GetUserWindowById(window_id); - if (window) { - window->SetVisible(true); - window->SetFocus(); - } -} - -} // namespace mus -} // namespace ash
diff --git a/ash/mus/user_window_controller_impl.h b/ash/mus/user_window_controller_impl.h deleted file mode 100644 index 4fb327c2..0000000 --- a/ash/mus/user_window_controller_impl.h +++ /dev/null
@@ -1,72 +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_MUS_USER_WINDOW_CONTROLLER_IMPL_H_ -#define ASH_MUS_USER_WINDOW_CONTROLLER_IMPL_H_ - -#include <stdint.h> - -#include <memory> - -#include "ash/public/interfaces/user_window_controller.mojom.h" -#include "base/macros.h" -#include "services/ui/common/types.h" -#include "services/ui/public/cpp/window_observer.h" -#include "services/ui/public/cpp/window_tree_client_observer.h" - -namespace ash { -namespace mus { - -class RootWindowController; -class WindowPropertyObserver; - -class UserWindowControllerImpl : public mojom::UserWindowController, - public ui::WindowObserver, - public ui::WindowTreeClientObserver { - public: - UserWindowControllerImpl(); - ~UserWindowControllerImpl() override; - - mojom::UserWindowObserver* user_window_observer() const { - return user_window_observer_.get(); - } - - void Initialize(RootWindowController* root_controller); - - private: - void AssignIdIfNecessary(ui::Window* window); - - // Removes observers from the window and client. - void RemoveObservers(ui::Window* user_container); - - // Returns the window with the specified user id. - ui::Window* GetUserWindowById(uint32_t id); - - // A helper to get the container for user windows. - ui::Window* GetUserWindowContainer() const; - - // ui::WindowObserver: - void OnTreeChanging(const TreeChangeParams& params) override; - void OnWindowDestroying(ui::Window* window) override; - - // ui::WindowTreeClientObserver: - void OnWindowTreeFocusChanged(ui::Window* gained_focus, - ui::Window* lost_focus) override; - - // mojom::UserWindowController: - void AddUserWindowObserver(mojom::UserWindowObserverPtr observer) override; - void ActivateUserWindow(uint32_t window_id) override; - - RootWindowController* root_controller_; - mojom::UserWindowObserverPtr user_window_observer_; - std::unique_ptr<WindowPropertyObserver> window_property_observer_; - uint32_t next_id_ = 1u; - - DISALLOW_COPY_AND_ASSIGN(UserWindowControllerImpl); -}; - -} // namespace mus -} // namespace ash - -#endif // ASH_MUS_USER_WINDOW_CONTROLLER_IMPL_H_
diff --git a/ash/mus/window_manager.cc b/ash/mus/window_manager.cc index b64575f..da15fa8e 100644 --- a/ash/mus/window_manager.cc +++ b/ash/mus/window_manager.cc
@@ -14,7 +14,7 @@ #include "ash/mus/bridge/wm_lookup_mus.h" #include "ash/mus/bridge/wm_shell_mus.h" #include "ash/mus/bridge/wm_window_mus.h" -#include "ash/mus/frame/move_event_handler.h" +#include "ash/mus/move_event_handler.h" #include "ash/mus/non_client_frame_controller.h" #include "ash/mus/property_util.h" #include "ash/mus/root_window_controller.h" @@ -220,9 +220,9 @@ window_manager_client_ = nullptr; } -void WindowManager::OnEventObserved(const ui::Event& event, - ui::Window* target) { - // Does not use EventObservers. +void WindowManager::OnPointerEventObserved(const ui::PointerEvent& event, + ui::Window* target) { + // Does not use PointerWatchers. } void WindowManager::SetWindowManagerClient(ui::WindowManagerClient* client) {
diff --git a/ash/mus/window_manager.h b/ash/mus/window_manager.h index ca85768..8c2c243 100644 --- a/ash/mus/window_manager.h +++ b/ash/mus/window_manager.h
@@ -93,7 +93,8 @@ // WindowTreeClientDelegate: void OnEmbed(ui::Window* root) override; void OnDidDestroyClient(ui::WindowTreeClient* client) override; - void OnEventObserved(const ui::Event& event, ui::Window* target) override; + void OnPointerEventObserved(const ui::PointerEvent& event, + ui::Window* target) override; // WindowManagerDelegate: void SetWindowManagerClient(ui::WindowManagerClient* client) override;
diff --git a/ash/mus/window_manager_application.cc b/ash/mus/window_manager_application.cc index 9acd365..a24d0b6d 100644 --- a/ash/mus/window_manager_application.cc +++ b/ash/mus/window_manager_application.cc
@@ -8,9 +8,6 @@ #include "ash/common/material_design/material_design_controller.h" #include "ash/mus/accelerators/accelerator_registrar_impl.h" -#include "ash/mus/root_window_controller.h" -#include "ash/mus/shelf_layout_impl.h" -#include "ash/mus/user_window_controller_impl.h" #include "ash/mus/window_manager.h" #include "base/bind.h" #include "base/memory/ptr_util.h" @@ -21,9 +18,11 @@ #include "services/ui/common/gpu_service.h" #include "services/ui/public/cpp/window.h" #include "services/ui/public/cpp/window_tree_client.h" +#include "ui/aura/env.h" #include "ui/events/event.h" #include "ui/message_center/message_center.h" #include "ui/views/mus/aura_init.h" +#include "ui/views/mus/surface_context_factory.h" #if defined(OS_CHROMEOS) #include "ash/common/system/chromeos/power/power_status.h" @@ -92,14 +91,16 @@ InitializeComponents(); window_manager_->Init(window_tree_client); - window_manager_->AddObserver(this); } void WindowManagerApplication::OnStart(const shell::Identity& identity) { + aura_init_.reset(new views::AuraInit(connector(), "ash_mus_resources.pak")); gpu_service_ = ui::GpuService::Initialize(connector()); + compositor_context_factory_.reset(new views::SurfaceContextFactory()); + aura::Env::GetInstance()->set_context_factory( + compositor_context_factory_.get()); window_manager_.reset(new WindowManager(connector())); - aura_init_.reset(new views::AuraInit(connector(), "ash_mus_resources.pak")); MaterialDesignController::Initialize(); tracing_.Initialize(connector(), identity.name()); @@ -113,8 +114,6 @@ bool WindowManagerApplication::OnConnect(const shell::Identity& remote_identity, shell::InterfaceRegistry* registry) { - registry->AddInterface<mojom::ShelfLayout>(this); - registry->AddInterface<mojom::UserWindowController>(this); registry->AddInterface<ui::mojom::AcceleratorRegistrar>(this); if (remote_identity.name() == "mojo:mash_session") { connector()->ConnectToInterface(remote_identity, &session_); @@ -126,28 +125,6 @@ void WindowManagerApplication::Create( const shell::Identity& remote_identity, - mojo::InterfaceRequest<mojom::ShelfLayout> request) { - // TODO(msw): Handle multiple shelves (one per display). - if (!window_manager_->GetRootWindowControllers().empty()) { - shelf_layout_bindings_.AddBinding(shelf_layout_.get(), std::move(request)); - } else { - shelf_layout_requests_.push_back(std::move(request)); - } -} - -void WindowManagerApplication::Create( - const shell::Identity& remote_identity, - mojo::InterfaceRequest<mojom::UserWindowController> request) { - if (!window_manager_->GetRootWindowControllers().empty()) { - user_window_controller_bindings_.AddBinding(user_window_controller_.get(), - std::move(request)); - } else { - user_window_controller_requests_.push_back(std::move(request)); - } -} - -void WindowManagerApplication::Create( - const shell::Identity& remote_identity, mojo::InterfaceRequest<ui::mojom::AcceleratorRegistrar> request) { if (!window_manager_->window_manager_client()) return; // Can happen during shutdown. @@ -169,40 +146,5 @@ window_manager_->SetScreenLocked(locked); } -void WindowManagerApplication::OnRootWindowControllerAdded( - RootWindowController* controller) { - if (user_window_controller_) - return; - - // TODO(sky): |shelf_layout_| and |user_window_controller_| should really - // be owned by WindowManager and/or RootWindowController. But this code is - // temporary while migrating away from sysui. - - shelf_layout_.reset(new ShelfLayoutImpl); - user_window_controller_.reset(new UserWindowControllerImpl()); - - // TODO(msw): figure out if this should be per display, or global. - user_window_controller_->Initialize(controller); - for (auto& request : user_window_controller_requests_) - user_window_controller_bindings_.AddBinding(user_window_controller_.get(), - std::move(request)); - user_window_controller_requests_.clear(); - - // TODO(msw): figure out if this should be per display, or global. - shelf_layout_->Initialize(controller); - for (auto& request : shelf_layout_requests_) - shelf_layout_bindings_.AddBinding(shelf_layout_.get(), std::move(request)); - shelf_layout_requests_.clear(); -} - -void WindowManagerApplication::OnWillDestroyRootWindowController( - RootWindowController* controller) { - // TODO(msw): this isn't right, ownership should belong in WindowManager - // and/or RootWindowController. But this is temporary until we get rid of - // sysui. - shelf_layout_.reset(); - user_window_controller_.reset(); -} - } // namespace mus } // namespace ash
diff --git a/ash/mus/window_manager_application.h b/ash/mus/window_manager_application.h index b7946277..6d55d350 100644 --- a/ash/mus/window_manager_application.h +++ b/ash/mus/window_manager_application.h
@@ -10,9 +10,6 @@ #include <memory> #include <set> -#include "ash/mus/window_manager_observer.h" -#include "ash/public/interfaces/shelf_layout.mojom.h" -#include "ash/public/interfaces/user_window_controller.mojom.h" #include "base/macros.h" #include "mash/session/public/interfaces/session.mojom.h" #include "mojo/public/cpp/bindings/binding.h" @@ -24,6 +21,7 @@ namespace views { class AuraInit; +class SurfaceContextFactory; } namespace ui { @@ -36,18 +34,14 @@ namespace mus { class AcceleratorRegistrarImpl; -class RootWindowController; -class ShelfLayoutImpl; -class UserWindowControllerImpl; class WindowManager; +// Hosts the window manager and the ash system user interface for mash. +// TODO(mash): Port ash_sysui's ShelfController and WallpaperController here. class WindowManagerApplication : public shell::Service, - public shell::InterfaceFactory<mojom::ShelfLayout>, - public shell::InterfaceFactory<mojom::UserWindowController>, public shell::InterfaceFactory<ui::mojom::AcceleratorRegistrar>, - public mash::session::mojom::ScreenlockStateListener, - public WindowManagerObserver { + public mash::session::mojom::ScreenlockStateListener { public: WindowManagerApplication(); ~WindowManagerApplication() override; @@ -69,15 +63,6 @@ bool OnConnect(const shell::Identity& remote_identity, shell::InterfaceRegistry* registry) override; - // shell::InterfaceFactory<mojom::ShelfLayout>: - void Create(const shell::Identity& remote_identity, - mojo::InterfaceRequest<mojom::ShelfLayout> request) override; - - // shell::InterfaceFactory<mojom::UserWindowController>: - void Create( - const shell::Identity& remote_identity, - mojo::InterfaceRequest<mojom::UserWindowController> request) override; - // shell::InterfaceFactory<ui::mojom::AcceleratorRegistrar>: void Create( const shell::Identity& remote_identity, @@ -86,31 +71,12 @@ // session::mojom::ScreenlockStateListener: void ScreenlockStateChanged(bool locked) override; - // WindowManagerObserver: - void OnRootWindowControllerAdded(RootWindowController* controller) override; - void OnWillDestroyRootWindowController( - RootWindowController* controller) override; - tracing::Provider tracing_; std::unique_ptr<views::AuraInit> aura_init_; - // The |shelf_layout_| object is created once OnEmbed() is called. Until that - // time |shelf_layout_requests_| stores pending interface requests. - std::unique_ptr<ShelfLayoutImpl> shelf_layout_; - mojo::BindingSet<mojom::ShelfLayout> shelf_layout_bindings_; - std::vector<mojo::InterfaceRequest<mojom::ShelfLayout>> - shelf_layout_requests_; - - // |user_window_controller_| is created once OnEmbed() is called. Until that - // time |user_window_controller_requests_| stores pending interface requests. - std::unique_ptr<UserWindowControllerImpl> user_window_controller_; - mojo::BindingSet<mojom::UserWindowController> - user_window_controller_bindings_; - std::vector<mojo::InterfaceRequest<mojom::UserWindowController>> - user_window_controller_requests_; - std::unique_ptr<ui::GpuService> gpu_service_; + std::unique_ptr<views::SurfaceContextFactory> compositor_context_factory_; std::unique_ptr<WindowManager> window_manager_; std::set<AcceleratorRegistrarImpl*> accelerator_registrars_;
diff --git a/ash/mus/window_manager_unittest.cc b/ash/mus/window_manager_unittest.cc index dfe236b9..1e77c8c 100644 --- a/ash/mus/window_manager_unittest.cc +++ b/ash/mus/window_manager_unittest.cc
@@ -2,15 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <stdint.h> - #include <memory> -#include <utility> -#include "ash/public/interfaces/user_window_controller.mojom.h" #include "base/bind.h" #include "base/macros.h" -#include "base/run_loop.h" #include "services/shell/public/cpp/service_test.h" #include "services/ui/public/cpp/window.h" #include "services/ui/public/cpp/window_tree_client.h" @@ -29,7 +24,8 @@ // ui::WindowTreeClientDelegate: void OnEmbed(ui::Window* root) override {} void OnDidDestroyClient(ui::WindowTreeClient* client) override {} - void OnEventObserved(const ui::Event& event, ui::Window* target) override {} + void OnPointerEventObserved(const ui::PointerEvent& event, + ui::Window* target) override {} DISALLOW_COPY_AND_ASSIGN(WindowTreeClientDelegate); }; @@ -47,69 +43,6 @@ ASSERT_TRUE(success); } -class TestUserWindowObserver : public mojom::UserWindowObserver { - public: - explicit TestUserWindowObserver(shell::Connector* connector) - : binding_(this), window_count_(0u), expected_window_count_(0u) { - connector->ConnectToInterface("mojo:ash", &user_window_controller_); - user_window_controller_->AddUserWindowObserver( - binding_.CreateInterfacePtrAndBind()); - } - - ~TestUserWindowObserver() override {} - - bool WaitUntilWindowCountReaches(size_t expected) { - DCHECK(quit_callback_.is_null()); - if (window_count_ != expected) { - base::RunLoop loop; - quit_callback_ = loop.QuitClosure(); - expected_window_count_ = expected; - loop.Run(); - quit_callback_ = base::Closure(); - } - return window_count_ == expected; - } - - private: - void QuitIfNecessary() { - if (window_count_ == expected_window_count_ && !quit_callback_.is_null()) - quit_callback_.Run(); - } - - // mojom::UserWindowObserver: - void OnUserWindowObserverAdded( - mojo::Array<mojom::UserWindowPtr> user_windows) override { - window_count_ = user_windows.size(); - QuitIfNecessary(); - } - - void OnUserWindowAdded(mojom::UserWindowPtr user_window) override { - ++window_count_; - QuitIfNecessary(); - } - - void OnUserWindowRemoved(uint32_t window_id) override { - ASSERT_TRUE(window_count_); - --window_count_; - QuitIfNecessary(); - } - - void OnUserWindowTitleChanged(uint32_t window_id, - const mojo::String& window_title) override {} - void OnUserWindowFocusChanged(uint32_t window_id, bool has_focus) override {} - void OnUserWindowAppIconChanged(uint32_t window_id, - mojo::Array<uint8_t> app_icon) override {} - - mojom::UserWindowControllerPtr user_window_controller_; - mojo::Binding<mojom::UserWindowObserver> binding_; - - size_t window_count_; - size_t expected_window_count_; - base::Closure quit_callback_; - - DISALLOW_COPY_AND_ASSIGN(TestUserWindowObserver); -}; - TEST_F(WindowManagerTest, OpenWindow) { WindowTreeClientDelegate window_tree_delegate; @@ -137,23 +70,5 @@ ASSERT_TRUE(!child_client->GetRoots().empty()); } -TEST_F(WindowManagerTest, OpenWindowAndClose) { - connector()->Connect("mojo:ash"); - - TestUserWindowObserver observer(connector()); - - // Connect to mus and create a new top level window. - WindowTreeClientDelegate window_tree_delegate; - std::unique_ptr<ui::WindowTreeClient> client( - new ui::WindowTreeClient(&window_tree_delegate, nullptr, nullptr)); - client->ConnectViaWindowTreeFactory(connector()); - ui::Window* top_level_window = client->NewTopLevelWindow(nullptr); - ASSERT_TRUE(top_level_window); - - observer.WaitUntilWindowCountReaches(1u); - client.reset(); - observer.WaitUntilWindowCountReaches(0u); -} - } // namespace mus } // namespace ash
diff --git a/ash/mus/workspace/workspace_layout_manager_unittest.cc b/ash/mus/workspace/workspace_layout_manager_unittest.cc index bf737d5c..61a9f60 100644 --- a/ash/mus/workspace/workspace_layout_manager_unittest.cc +++ b/ash/mus/workspace/workspace_layout_manager_unittest.cc
@@ -7,13 +7,15 @@ #include <string> #include <utility> +#include "ash/common/shell_observer.h" #include "ash/common/wm/fullscreen_window_finder.h" #include "ash/common/wm/window_state.h" #include "ash/common/wm/wm_event.h" #include "ash/common/wm/wm_screen_util.h" -#include "ash/common/wm_root_window_controller_observer.h" +#include "ash/common/wm_shell.h" #include "ash/mus/bridge/wm_root_window_controller_mus.h" #include "ash/mus/bridge/wm_window_mus.h" +#include "ash/mus/bridge/wm_window_mus_test_api.h" #include "ash/mus/test/wm_test_base.h" #include "base/run_loop.h" #include "services/ui/public/cpp/tests/test_window.h" @@ -47,20 +49,16 @@ }; */ -class FullscreenObserver : public WmRootWindowControllerObserver { +class FullscreenObserver : public ShellObserver { public: - explicit FullscreenObserver(WmRootWindowController* root_window_controller) - : root_window_controller_(root_window_controller), - call_count_(0), - is_fullscreen_(false) { - root_window_controller_->AddObserver(this); + FullscreenObserver() : call_count_(0), is_fullscreen_(false) { + WmShell::Get()->AddShellObserver(this); } - ~FullscreenObserver() override { - root_window_controller_->RemoveObserver(this); - } + ~FullscreenObserver() override { WmShell::Get()->RemoveShellObserver(this); } - void OnFullscreenStateChanged(bool is_fullscreen) override { + void OnFullscreenStateChanged(bool is_fullscreen, + WmWindow* root_window) override { call_count_++; is_fullscreen_ = is_fullscreen; } @@ -70,7 +68,6 @@ bool is_fullscreen() const { return is_fullscreen_; } private: - WmRootWindowController* root_window_controller_; int call_count_; bool is_fullscreen_; @@ -87,6 +84,7 @@ TEST_F(WorkspaceLayoutManagerTest, RestoreFromMinimizeKeepsRestore) { ui::Window* mus_window = CreateTestWindow(gfx::Rect(1, 2, 3, 4)); WmWindow* window = WmWindowMus::Get(mus_window); + WmWindowMusTestApi(window).set_use_empty_minimum_size(true); gfx::Rect bounds(10, 15, 25, 35); window->SetBounds(bounds); @@ -454,8 +452,7 @@ } TEST_F(WorkspaceLayoutManagerTest, NotifyFullscreenChanges) { - FullscreenObserver observer( - WmWindowMus::Get(GetPrimaryRootWindow())->GetRootWindowController()); + FullscreenObserver observer; ui::Window* window1 = CreateTestWindow(gfx::Rect(1, 2, 30, 40)); ui::Window* window2 = CreateTestWindow(gfx::Rect(1, 2, 30, 40)); wm::WindowState* window_state1 = WmWindowMus::Get(window1)->GetWindowState(); @@ -697,11 +694,12 @@ } // Verifies that the restore bounds do not get reset when restoring to a -// maximzied state from a minimized state. +// maximized state from a minimized state. TEST_F(WorkspaceLayoutManagerSoloTest, BoundsAfterRestoringToMaximizeFromMinimize) { ui::Window* mus_window = CreateTestWindow(gfx::Rect(1, 2, 3, 4)); WmWindow* window = WmWindowMus::Get(mus_window); + WmWindowMusTestApi(window).set_use_empty_minimum_size(true); gfx::Rect bounds(10, 15, 25, 35); window->SetBounds(bounds);
diff --git a/ash/pointer_watcher_delegate_aura.cc b/ash/pointer_watcher_delegate_aura.cc index d70720d5..9e72178 100644 --- a/ash/pointer_watcher_delegate_aura.cc +++ b/ash/pointer_watcher_delegate_aura.cc
@@ -34,17 +34,27 @@ } void PointerWatcherDelegateAura::OnMouseEvent(ui::MouseEvent* event) { - if (event->type() == ui::ET_MOUSE_PRESSED) - FOR_EACH_OBSERVER(views::PointerWatcher, pointer_watchers_, - OnMousePressed(*event, GetLocationInScreen(*event), - GetTargetWidget(*event))); + // For compatibility with the mus version, don't send moves. + if (event->type() != ui::ET_MOUSE_PRESSED && + event->type() != ui::ET_MOUSE_RELEASED) + return; + ui::PointerEvent mouse_pointer_event(*event); + FOR_EACH_OBSERVER( + views::PointerWatcher, pointer_watchers_, + OnPointerEventObserved(mouse_pointer_event, GetLocationInScreen(*event), + GetTargetWidget(*event))); } void PointerWatcherDelegateAura::OnTouchEvent(ui::TouchEvent* event) { - if (event->type() == ui::ET_TOUCH_PRESSED) - FOR_EACH_OBSERVER(views::PointerWatcher, pointer_watchers_, - OnTouchPressed(*event, GetLocationInScreen(*event), - GetTargetWidget(*event))); + // For compatibility with the mus version, don't send moves. + if (event->type() != ui::ET_TOUCH_PRESSED && + event->type() != ui::ET_TOUCH_RELEASED) + return; + ui::PointerEvent touch_pointer_event(*event); + FOR_EACH_OBSERVER( + views::PointerWatcher, pointer_watchers_, + OnPointerEventObserved(touch_pointer_event, GetLocationInScreen(*event), + GetTargetWidget(*event))); } gfx::Point PointerWatcherDelegateAura::GetLocationInScreen(
diff --git a/ash/public/interfaces/BUILD.gn b/ash/public/interfaces/BUILD.gn index 47657db6..62cbcc30 100644 --- a/ash/public/interfaces/BUILD.gn +++ b/ash/public/interfaces/BUILD.gn
@@ -8,13 +8,10 @@ sources = [ "ash_window_type.mojom", "container.mojom", - "shelf_layout.mojom", - "user_window_controller.mojom", + "wallpaper.mojom", ] - public_deps = [ - "//mash/shelf/public/interfaces", + deps = [ + "//skia/public/interfaces", ] - - use_new_wrapper_types = false }
diff --git a/ash/public/interfaces/shelf_layout.mojom b/ash/public/interfaces/shelf_layout.mojom deleted file mode 100644 index 529f92f8..0000000 --- a/ash/public/interfaces/shelf_layout.mojom +++ /dev/null
@@ -1,14 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -module ash.mojom; - -import "mash/shelf/public/interfaces/shelf_constants.mojom"; - -// Used by mojo:ash_sysui to push the current shelf state to its layout manager. -interface ShelfLayout { - // TODO: Update preferred sizes with alignment to avoid flicker during layout. - SetAlignment(mash.shelf.mojom.Alignment alignment); - SetAutoHideBehavior(mash.shelf.mojom.AutoHideBehavior auto_hide); -};
diff --git a/ash/public/interfaces/user_window_controller.mojom b/ash/public/interfaces/user_window_controller.mojom deleted file mode 100644 index 0352ff07..0000000 --- a/ash/public/interfaces/user_window_controller.mojom +++ /dev/null
@@ -1,38 +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. - -module ash.mojom; - -struct UserWindow { - uint32 window_id; // The local window id, defined by UserWindowController. - string window_title; // The window title. - bool window_has_focus; // A flag; true if the window is currently focused. - array<uint8> window_app_icon; // A serialized SkBitmap. - string window_app_id; // The window application ID (ie. 'mojo:foo'). - bool ignored_by_shelf; // A flag; true to avoid showing a shelf item. -}; - -// An observer of user windows within mojom::Container::USER_WINDOWS. -// TODO(msw): Observe focus changes, title/icon changes, etc. -interface UserWindowObserver { - // Called when the observer is first added to supply the initial state. - OnUserWindowObserverAdded(array<UserWindow> user_windows); - - OnUserWindowAdded(UserWindow user_window); - OnUserWindowRemoved(uint32 window_id); - - OnUserWindowTitleChanged(uint32 window_id, string window_title); - - // |app_icon| is a serialized SkBitmap. - OnUserWindowAppIconChanged(uint32 window_id, array<uint8> app_icon); - - OnUserWindowFocusChanged(uint32 window_id, bool has_focus); -}; - -// An interface allowing system UIs to manage the set of user windows. -// TODO(msw): Add minimization, restoration, opening a chooser view, etc. -interface UserWindowController { - AddUserWindowObserver(UserWindowObserver observer); - ActivateUserWindow(uint32 window_id); -};
diff --git a/ash/public/interfaces/wallpaper.mojom b/ash/public/interfaces/wallpaper.mojom new file mode 100644 index 0000000..d2bbad3 --- /dev/null +++ b/ash/public/interfaces/wallpaper.mojom
@@ -0,0 +1,20 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module ash.mojom; + +import "skia/public/interfaces/bitmap.mojom"; + +// These values match wallpaper::WallpaperLayout. +enum WallpaperLayout { CENTER, CENTER_CROPPED, STRETCH, TILE, }; + +// Used by Chrome to set the wallpaper displayed by ash. +interface WallpaperController { + SetWallpaper(skia.mojom.Bitmap wallpaper, WallpaperLayout layout); +}; + +// Used by ash to trigger Chrome's wallpaper picker functionality. +interface WallpaperManager { + Open(); +};
diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc index 6cdc05c5..a6b4275d 100644 --- a/ash/root_window_controller.cc +++ b/ash/root_window_controller.cc
@@ -30,7 +30,6 @@ #include "ash/common/wm/switchable_windows.h" #include "ash/common/wm/window_state.h" #include "ash/common/wm/workspace/workspace_layout_manager.h" -#include "ash/common/wm/workspace/workspace_layout_manager_delegate.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/desktop_background/desktop_background_widget_controller.h" @@ -42,6 +41,7 @@ #include "ash/shelf/shelf.h" #include "ash/shelf/shelf_layout_manager.h" #include "ash/shelf/shelf_widget.h" +#include "ash/shelf/shelf_window_targeter.h" #include "ash/shell.h" #include "ash/touch/touch_hud_debug.h" #include "ash/touch/touch_hud_projection.h" @@ -280,34 +280,6 @@ DISALLOW_COPY_AND_ASSIGN(EmptyWindowDelegate); }; -class WorkspaceLayoutManagerDelegateImpl - : public wm::WorkspaceLayoutManagerDelegate { - public: - explicit WorkspaceLayoutManagerDelegateImpl(aura::Window* root_window) - : root_window_(root_window) {} - ~WorkspaceLayoutManagerDelegateImpl() override = default; - - void set_shelf(ShelfLayoutManager* shelf) { shelf_ = shelf; } - - // WorkspaceLayoutManagerDelegate: - void UpdateShelfVisibility() override { - if (shelf_) - shelf_->UpdateVisibilityState(); - } - void OnFullscreenStateChanged(bool is_fullscreen) override { - if (shelf_) { - Shell::GetInstance()->NotifyFullscreenStateChange( - is_fullscreen, WmWindowAura::Get(root_window_)); - } - } - - private: - aura::Window* root_window_; - ShelfLayoutManager* shelf_ = nullptr; - - DISALLOW_COPY_AND_ASSIGN(WorkspaceLayoutManagerDelegateImpl); -}; - } // namespace void RootWindowController::CreateForPrimaryDisplay(AshWindowTreeHost* host) { @@ -639,10 +611,8 @@ } void RootWindowController::MoveWindowsTo(aura::Window* dst) { - // Forget the shelf early so that shelf don't update itself using wrong - // display info. + // Clear the shelf first, so it doesn't update itself with wrong display info. workspace_controller_->SetShelf(nullptr); - workspace_controller_->layout_manager()->DeleteDelegate(); ReparentAllWindows(GetRootWindow(), dst); } @@ -841,26 +811,28 @@ lock_modal_container->SetLayoutManager( new SystemModalContainerLayoutManager(lock_modal_container)); - WorkspaceLayoutManagerDelegateImpl* workspace_layout_manager_delegate = - new WorkspaceLayoutManagerDelegateImpl(root_window); - workspace_controller_.reset(new WorkspaceController( - default_container, base::WrapUnique(workspace_layout_manager_delegate))); + workspace_controller_.reset(new WorkspaceController(default_container)); WmWindow* always_on_top_container = WmWindowAura::Get(GetContainer(kShellWindowId_AlwaysOnTopContainer)); always_on_top_controller_.reset( new AlwaysOnTopController(always_on_top_container)); + // Create the shelf and status area widgets. DCHECK(!shelf_widget_.get()); - WmWindow* shelf_container = - WmWindowAura::Get(GetContainer(kShellWindowId_ShelfContainer)); - WmWindow* status_container = - WmWindowAura::Get(GetContainer(kShellWindowId_StatusContainer)); - shelf_widget_.reset(new ShelfWidget(shelf_container, status_container, + aura::Window* shelf_container = GetContainer(kShellWindowId_ShelfContainer); + aura::Window* status_container = GetContainer(kShellWindowId_StatusContainer); + WmWindow* wm_shelf_container = WmWindowAura::Get(shelf_container); + WmWindow* wm_status_container = WmWindowAura::Get(status_container); + shelf_widget_.reset(new ShelfWidget(wm_shelf_container, wm_status_container, wm_shelf_aura_.get(), workspace_controller())); - workspace_layout_manager_delegate->set_shelf( - shelf_widget_->shelf_layout_manager()); + // Make it easier to resize windows that partially overlap the shelf. Must + // occur after the ShelfLayoutManager is constructed by ShelfWidget. + shelf_container->SetEventTargeter(base::MakeUnique<ShelfWindowTargeter>( + wm_shelf_container, wm_shelf_aura_.get())); + status_container->SetEventTargeter(base::MakeUnique<ShelfWindowTargeter>( + wm_status_container, wm_shelf_aura_.get())); if (!WmShell::Get() ->GetSessionStateDelegate()
diff --git a/ash/shelf/dimmer_view.cc b/ash/shelf/dimmer_view.cc index de49e040..83aee9c 100644 --- a/ash/shelf/dimmer_view.cc +++ b/ash/shelf/dimmer_view.cc
@@ -62,14 +62,6 @@ : BACKGROUND_CHANGE_ANIMATE); } -void DimmerView::ForceUndimming(bool force) { - bool previous = force_hovered_; - force_hovered_ = force; - // If the forced change does change the result we apply the change. - if (is_hovered_ || force_hovered_ != is_hovered_ || previous) - SetHovered(is_hovered_); -} - void DimmerView::OnPaintBackground(gfx::Canvas* canvas) { SkPaint paint; ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); @@ -103,6 +95,22 @@ void DimmerView::BackgroundAnimationEnded(BackgroundAnimator* animator) {} +views::Widget* DimmerView::GetDimmerWidget() { + return GetWidget(); +} + +void DimmerView::ForceUndimming(bool force) { + bool previous = force_hovered_; + force_hovered_ = force; + // If the forced change does change the result we apply the change. + if (is_hovered_ || force_hovered_ != is_hovered_ || previous) + SetHovered(is_hovered_); +} + +int DimmerView::GetDimmingAlphaForTest() { + return alpha_; +} + void DimmerView::OnWindowBoundsChanged(WmWindow* window, const gfx::Rect& old_bounds, const gfx::Rect& new_bounds) {
diff --git a/ash/shelf/dimmer_view.h b/ash/shelf/dimmer_view.h index 0a4ff07..e4b9ad02 100644 --- a/ash/shelf/dimmer_view.h +++ b/ash/shelf/dimmer_view.h
@@ -5,6 +5,7 @@ #ifndef ASH_SHELF_DIMMER_VIEW_H_ #define ASH_SHELF_DIMMER_VIEW_H_ +#include "ash/common/shelf/wm_dimmer_view.h" #include "ash/common/wm/background_animator.h" #include "ash/common/wm_window_observer.h" #include "base/macros.h" @@ -17,21 +18,22 @@ class WmShelf; // DimmerView slightly dims shelf items when a window is maximized and visible. +// TODO(jamescook): Delete this after material design ships, as MD will not +// require shelf dimming. http://crbug.com/614453 class DimmerView : public views::View, public views::WidgetDelegate, public BackgroundAnimatorDelegate, + public WmDimmerView, public WmWindowObserver { public: - // Creates and shows a DimmerView and its Widget. - // If |disable_animations_for_test| is set, all changes apply instantly. + // Creates and shows a DimmerView and its Widget. The returned view is owned + // by its widget. If |disable_animations_for_test| is set, all changes apply + // instantly. static DimmerView* Create(WmShelf* shelf, bool disable_animations_for_test); // Called by |DimmerEventFilter| when the mouse |hovered| state changes. void SetHovered(bool hovered); - // Force the dimmer to be undimmed. - void ForceUndimming(bool force); - // views::View overrides: void OnPaintBackground(gfx::Canvas* canvas) override; @@ -43,6 +45,11 @@ void UpdateBackground(BackgroundAnimator* animator, int alpha) override; void BackgroundAnimationEnded(BackgroundAnimator* animator) override; + // WmDimmerView: + views::Widget* GetDimmerWidget() override; + void ForceUndimming(bool force) override; + int GetDimmingAlphaForTest() override; + // WmWindowObserver overrides: // This will be called when the shelf itself changes its absolute position. // Since the |dimmer_| panel needs to be placed in screen coordinates it needs @@ -52,9 +59,6 @@ const gfx::Rect& old_bounds, const gfx::Rect& new_bounds) override; - // A function to test the current alpha used. - int get_dimming_alpha_for_test() { return alpha_; } - private: DimmerView(WmShelf* shelf, bool disable_animations_for_test); ~DimmerView() override;
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc index 61f1c45..4422b63 100644 --- a/ash/shelf/shelf_layout_manager.cc +++ b/ash/shelf/shelf_layout_manager.cc
@@ -39,7 +39,6 @@ #include "ui/display/display.h" #include "ui/display/screen.h" #include "ui/events/event.h" -#include "ui/events/event_handler.h" #include "ui/keyboard/keyboard_util.h" #include "ui/views/border.h" #include "ui/views/widget/widget.h" @@ -73,56 +72,6 @@ } // namespace -// ShelfLayoutManager::AutoHideEventFilter ------------------------------------- - -// Notifies ShelfLayoutManager any time the mouse moves. Not used on mash. -// TODO(jamescook): Delete this once the mash implementation handles drags on -// and off the shelf. -class ShelfLayoutManager::AutoHideEventFilter : public ui::EventHandler { - public: - explicit AutoHideEventFilter(ShelfLayoutManager* shelf); - ~AutoHideEventFilter() override; - - // Returns true if the last mouse event was a mouse drag. - bool in_mouse_drag() const { return in_mouse_drag_; } - - // Overridden from ui::EventHandler: - void OnMouseEvent(ui::MouseEvent* event) override; - void OnGestureEvent(ui::GestureEvent* event) override; - - private: - ShelfLayoutManager* shelf_; - bool in_mouse_drag_; - DISALLOW_COPY_AND_ASSIGN(AutoHideEventFilter); -}; - -ShelfLayoutManager::AutoHideEventFilter::AutoHideEventFilter( - ShelfLayoutManager* shelf) - : shelf_(shelf), in_mouse_drag_(false) { - Shell::GetInstance()->AddPreTargetHandler(this); -} - -ShelfLayoutManager::AutoHideEventFilter::~AutoHideEventFilter() { - Shell::GetInstance()->RemovePreTargetHandler(this); -} - -void ShelfLayoutManager::AutoHideEventFilter::OnMouseEvent( - ui::MouseEvent* event) { - // This also checks IsShelfWindow() to make sure we don't attempt to hide the - // shelf if the mouse down occurs on the shelf. - in_mouse_drag_ = - (event->type() == ui::ET_MOUSE_DRAGGED || - (in_mouse_drag_ && event->type() != ui::ET_MOUSE_RELEASED && - event->type() != ui::ET_MOUSE_CAPTURE_CHANGED)) && - !shelf_->IsShelfWindow(static_cast<aura::Window*>(event->target())); - shelf_->UpdateAutoHideForMouseEvent(event); -} - -void ShelfLayoutManager::AutoHideEventFilter::OnGestureEvent( - ui::GestureEvent* event) { - shelf_->UpdateAutoHideForGestureEvent(event); -} - // ShelfLayoutManager::UpdateShelfObserver ------------------------------------- // UpdateShelfObserver is used to delay updating the background until the @@ -229,7 +178,6 @@ // Clear all event filters, otherwise sometimes those filters may catch // synthesized mouse event and cause crashes during the shutdown. set_workspace_controller(NULL); - auto_hide_event_filter_.reset(); bezel_event_filter_.reset(); // Stop observing changes to avoid updating a partially destructed shelf. WmShell::Get()->RemoveActivationObserver(this); @@ -346,7 +294,15 @@ } } -void ShelfLayoutManager::UpdateAutoHideForMouseEvent(ui::MouseEvent* event) { +void ShelfLayoutManager::UpdateAutoHideForMouseEvent(ui::MouseEvent* event, + WmWindow* target) { + // This also checks IsShelfWindow() to make sure we don't attempt to hide the + // shelf if the mouse down occurs on the shelf. + in_mouse_drag_ = (event->type() == ui::ET_MOUSE_DRAGGED || + (in_mouse_drag_ && event->type() != ui::ET_MOUSE_RELEASED && + event->type() != ui::ET_MOUSE_CAPTURE_CHANGED)) && + !IsShelfWindow(target); + // Don't update during shutdown because synthetic mouse events (e.g. mouse // exit) may be generated during status area widget teardown. if (visibility_state() != SHELF_AUTO_HIDE || in_shutdown_) @@ -359,13 +315,12 @@ } } -void ShelfLayoutManager::UpdateAutoHideForGestureEvent( - ui::GestureEvent* event) { +void ShelfLayoutManager::UpdateAutoHideForGestureEvent(ui::GestureEvent* event, + WmWindow* target) { if (visibility_state() != SHELF_AUTO_HIDE || in_shutdown_) return; - aura::Window* target_window = static_cast<aura::Window*>(event->target()); - if (IsShelfWindow(target_window) && ProcessGestureEvent(*event)) + if (IsShelfWindow(target) && ProcessGestureEvent(*event)) event->StopPropagation(); } @@ -544,19 +499,6 @@ FOR_EACH_OBSERVER(ShelfLayoutManagerObserver, observers_, WillChangeVisibilityState(visibility_state)); - // mash does not support global event handlers. It uses events on the shelf - // and status area widgets to update auto-hide. - if (!Shell::GetInstance()->in_mus()) { - if (state.visibility_state == SHELF_AUTO_HIDE) { - // When state is SHELF_AUTO_HIDE we need to track when the mouse is over - // the shelf to unhide it. AutoHideEventFilter does that for us. - if (!auto_hide_event_filter_) - auto_hide_event_filter_.reset(new AutoHideEventFilter(this)); - } else { - auto_hide_event_filter_.reset(NULL); - } - } - StopAutoHideTimer(); State old_state = state_; @@ -989,7 +931,7 @@ return gesture_drag_auto_hide_state_; // Don't show if the user is dragging the mouse. - if (auto_hide_event_filter_.get() && auto_hide_event_filter_->in_mouse_drag()) + if (in_mouse_drag_) return SHELF_AUTO_HIDE_HIDDEN; // Ignore the mouse position if mouse events are disabled. @@ -1037,14 +979,14 @@ return SHELF_AUTO_HIDE_HIDDEN; } -bool ShelfLayoutManager::IsShelfWindow(aura::Window* window) { - if (!window) +bool ShelfLayoutManager::IsShelfWindow(WmWindow* window) { + if (!window || !shelf_widget_) return false; - return (shelf_widget_ && - shelf_widget_->GetNativeWindow()->Contains(window)) || - (shelf_widget_->status_area_widget() && - shelf_widget_->status_area_widget()->GetNativeWindow()->Contains( - window)); + WmWindow* shelf_window = WmLookup::Get()->GetWindowForWidget(shelf_widget_); + WmWindow* status_window = + WmLookup::Get()->GetWindowForWidget(shelf_widget_->status_area_widget()); + return (shelf_window && shelf_window->Contains(window)) || + (status_window && status_window->Contains(window)); } int ShelfLayoutManager::GetWorkAreaInsets(const State& state, int size) const {
diff --git a/ash/shelf/shelf_layout_manager.h b/ash/shelf/shelf_layout_manager.h index dfde44a..9e180ad 100644 --- a/ash/shelf/shelf_layout_manager.h +++ b/ash/shelf/shelf_layout_manager.h
@@ -98,11 +98,10 @@ // Invoked by the shelf when the auto-hide state may have changed. void UpdateAutoHideState(); - // Updates the auto-hide state for certain events. In classic ash these come - // from an EventHandler. In mash these come from events that hit the shelf - // widget and status tray widget. - void UpdateAutoHideForMouseEvent(ui::MouseEvent* event); - void UpdateAutoHideForGestureEvent(ui::GestureEvent* event); + // Updates the auto-hide state for certain events. + // TODO(mash): Add similar event handling support for mash. + void UpdateAutoHideForMouseEvent(ui::MouseEvent* event, WmWindow* target); + void UpdateAutoHideForGestureEvent(ui::GestureEvent* event, WmWindow* target); ShelfVisibilityState visibility_state() const { return state_.visibility_state; @@ -188,7 +187,6 @@ void SetChromeVoxPanelHeight(int height); private: - class AutoHideEventFilter; class RootWindowControllerObserverImpl; class UpdateShelfObserver; friend class PanelLayoutManagerTest; @@ -276,7 +274,7 @@ ShelfVisibilityState visibility_state) const; // Returns true if |window| is a descendant of the shelf. - bool IsShelfWindow(aura::Window* window); + bool IsShelfWindow(WmWindow* window); int GetWorkAreaInsets(const State& state, int size) const; @@ -307,6 +305,9 @@ bool in_shutdown_ = false; + // True if the last mouse event was a mouse drag. + bool in_mouse_drag_ = false; + // Current state. State state_; @@ -323,10 +324,6 @@ // False when neither the auto hide timer nor the timer task are running. bool mouse_over_shelf_when_auto_hide_timer_started_; - // EventFilter used to detect when user moves the mouse over the shelf to - // trigger showing the shelf. Used in classic ash. - std::unique_ptr<AutoHideEventFilter> auto_hide_event_filter_; - // EventFilter used to detect when user issues a gesture on a bezel sensor. std::unique_ptr<ShelfBezelEventFilter> bezel_event_filter_;
diff --git a/ash/shelf/shelf_widget.cc b/ash/shelf/shelf_widget.cc index f582e8b..44c0a133 100644 --- a/ash/shelf/shelf_widget.cc +++ b/ash/shelf/shelf_widget.cc
@@ -5,29 +5,26 @@ #include "ash/shelf/shelf_widget.h" #include "ash/aura/wm_shelf_aura.h" -#include "ash/aura/wm_window_aura.h" #include "ash/common/focus_cycler.h" #include "ash/common/material_design/material_design_controller.h" #include "ash/common/session/session_state_delegate.h" #include "ash/common/shelf/shelf_background_animator_observer.h" #include "ash/common/shelf/shelf_constants.h" #include "ash/common/shelf/shelf_delegate.h" +#include "ash/common/shelf/wm_dimmer_view.h" #include "ash/common/shelf/wm_shelf.h" #include "ash/common/shelf/wm_shelf_util.h" #include "ash/common/system/status_area_widget.h" #include "ash/common/system/tray/system_tray_delegate.h" #include "ash/common/wm_root_window_controller.h" #include "ash/common/wm_shell.h" -#include "ash/shelf/dimmer_view.h" +#include "ash/common/wm_window.h" #include "ash/shelf/shelf.h" #include "ash/shelf/shelf_layout_manager.h" -#include "ash/shelf/shelf_window_targeter.h" -#include "ash/shell.h" #include "ash/wm/status_area_layout_manager.h" #include "ash/wm/workspace_controller.h" #include "base/memory/ptr_util.h" #include "grit/ash_resources.h" -#include "ui/aura/window.h" #include "ui/base/resource/resource_bundle.h" #include "ui/compositor/layer.h" #include "ui/compositor/scoped_layer_animation_settings.h" @@ -106,7 +103,7 @@ } private: - ShelfWidget* shelf_; + ShelfWidget* shelf_widget_; FocusCycler* focus_cycler_; int asset_background_alpha_; // TODO(bruthig): Remove opaque_background_ (see https://crbug.com/621551). @@ -117,8 +114,9 @@ // can be used simultaneously - so no repurposing possible. ui::Layer opaque_foreground_; - // The view which does the dimming. - DimmerView* dimmer_view_; + // The interface for the view which does the dimming. Null if the shelf is not + // being dimmed, or if dimming is not supported (e.g. for mus). + WmDimmerView* dimmer_view_; // True if dimming animations should be turned off. bool disable_dimming_animations_for_test_; @@ -126,8 +124,8 @@ DISALLOW_COPY_AND_ASSIGN(DelegateView); }; -ShelfWidget::DelegateView::DelegateView(ShelfWidget* shelf) - : shelf_(shelf), +ShelfWidget::DelegateView::DelegateView(ShelfWidget* shelf_widget) + : shelf_widget_(shelf_widget), focus_cycler_(nullptr), asset_background_alpha_(0), opaque_background_(ui::LAYER_SOLID_COLOR), @@ -150,20 +148,26 @@ } void ShelfWidget::DelegateView::SetDimmed(bool dimmed) { - if (dimmed == (dimmer_view_ != nullptr)) - return; - + // When starting dimming, attempt to create a dimmer view. if (dimmed) { - dimmer_view_ = DimmerView::Create(shelf_->wm_shelf_aura_, - disable_dimming_animations_for_test_); - } else { - dimmer_view_->GetWidget()->CloseNow(); + if (!dimmer_view_) { + // The WmShelf interface is private in WmShelfAura. + WmShelf* shelf = static_cast<WmShelf*>(shelf_widget_->wm_shelf_aura_); + dimmer_view_ = + shelf->CreateDimmerView(disable_dimming_animations_for_test_); + } + return; + } + + // Close the dimmer widget when stopping dimming. + if (dimmer_view_) { + dimmer_view_->GetDimmerWidget()->CloseNow(); dimmer_view_ = nullptr; } } bool ShelfWidget::DelegateView::GetDimmed() const { - return dimmer_view_ && dimmer_view_->GetWidget()->IsVisible(); + return dimmer_view_ && dimmer_view_->GetDimmerWidget()->IsVisible(); } void ShelfWidget::DelegateView::SetParentLayer(ui::Layer* layer) { @@ -179,14 +183,15 @@ ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); gfx::ImageSkia shelf_background = *rb->GetImageSkiaNamed(IDR_ASH_SHELF_BACKGROUND); - const bool horizontal = IsHorizontalAlignment(shelf_->GetAlignment()); + const bool horizontal = IsHorizontalAlignment(shelf_widget_->GetAlignment()); if (!horizontal) { shelf_background = gfx::ImageSkiaOperations::CreateRotatedImage( - shelf_background, shelf_->GetAlignment() == SHELF_ALIGNMENT_LEFT + shelf_background, shelf_widget_->GetAlignment() == SHELF_ALIGNMENT_LEFT ? SkBitmapOperations::ROTATION_90_CW : SkBitmapOperations::ROTATION_270_CW); } - const gfx::Rect dock_bounds(shelf_->shelf_layout_manager()->dock_bounds()); + const gfx::Rect dock_bounds( + shelf_widget_->shelf_layout_manager()->dock_bounds()); SkPaint paint; paint.setAlpha(asset_background_alpha_); canvas->DrawImageInt( @@ -221,7 +226,7 @@ paint); } gfx::Rect black_rect = - shelf_->shelf_layout_manager()->SelectValueForShelfAlignment( + shelf_widget_->shelf_layout_manager()->SelectValueForShelfAlignment( gfx::Rect(0, height() - kNumBlackPixels, width(), kNumBlackPixels), gfx::Rect(0, 0, kNumBlackPixels, height()), gfx::Rect(width() - kNumBlackPixels, 0, kNumBlackPixels, height())); @@ -230,7 +235,7 @@ bool ShelfWidget::DelegateView::CanActivate() const { // Allow to activate as fallback. - if (shelf_->activating_as_fallback_) + if (shelf_widget_->activating_as_fallback_) return true; // Allow to activate from the focus cycler. if (focus_cycler_ && focus_cycler_->widget_activating() == GetWidget()) @@ -249,7 +254,7 @@ opaque_background_.SetBounds(GetLocalBounds()); opaque_foreground_.SetBounds(GetLocalBounds()); if (dimmer_view_) - dimmer_view_->GetWidget()->SetBounds(GetBoundsInScreen()); + dimmer_view_->GetDimmerWidget()->SetBounds(GetBoundsInScreen()); } void ShelfWidget::DelegateView::ForceUndimming(bool force) { @@ -259,13 +264,13 @@ int ShelfWidget::DelegateView::GetDimmingAlphaForTest() { if (GetDimmed()) - return dimmer_view_->get_dimming_alpha_for_test(); + return dimmer_view_->GetDimmingAlphaForTest(); return -1; } gfx::Rect ShelfWidget::DelegateView::GetDimmerBoundsForTest() { if (GetDimmed()) - return dimmer_view_->GetBoundsInScreen(); + return dimmer_view_->GetDimmerWidget()->GetWindowBoundsInScreen(); return gfx::Rect(); } @@ -325,11 +330,6 @@ status_container->SetLayoutManager( base::MakeUnique<StatusAreaLayoutManager>(this)); - WmWindowAura::GetAuraWindow(shelf_container)->SetEventTargeter( - base::MakeUnique<ShelfWindowTargeter>(shelf_container, wm_shelf_aura_)); - WmWindowAura::GetAuraWindow(status_container)->SetEventTargeter( - base::MakeUnique<ShelfWindowTargeter>(status_container, wm_shelf_aura_)); - views::Widget::AddObserver(this); } @@ -513,7 +513,7 @@ void ShelfWidget::DisableDimmingAnimationsForTest() { DCHECK(delegate_view_); - return delegate_view_->disable_dimming_animations_for_test(); + delegate_view_->disable_dimming_animations_for_test(); } void ShelfWidget::UpdateShelfItemBackground(int alpha) { @@ -526,16 +526,4 @@ shelf_layout_manager_ = nullptr; } -void ShelfWidget::OnMouseEvent(ui::MouseEvent* event) { - Widget::OnMouseEvent(event); - if (Shell::GetInstance()->in_mus() && shelf_layout_manager_) - shelf_layout_manager_->UpdateAutoHideForMouseEvent(event); -} - -void ShelfWidget::OnGestureEvent(ui::GestureEvent* event) { - Widget::OnGestureEvent(event); - if (Shell::GetInstance()->in_mus() && shelf_layout_manager_) - shelf_layout_manager_->UpdateAutoHideForGestureEvent(event); -} - } // namespace ash
diff --git a/ash/shelf/shelf_widget.h b/ash/shelf/shelf_widget.h index c23bffc..ebf3e02 100644 --- a/ash/shelf/shelf_widget.h +++ b/ash/shelf/shelf_widget.h
@@ -106,10 +106,6 @@ class DelegateView; friend class DelegateView; - // views::Widget: - void OnMouseEvent(ui::MouseEvent* event) override; - void OnGestureEvent(ui::GestureEvent* event) override; - WmShelfAura* wm_shelf_aura_; // Owned by the shelf container's aura::Window.
diff --git a/ash/shell.cc b/ash/shell.cc index 6f64011..3b69f661 100644 --- a/ash/shell.cc +++ b/ash/shell.cc
@@ -453,12 +453,6 @@ OnShelfAutoHideBehaviorChanged(root_window)); } -void Shell::NotifyFullscreenStateChange(bool is_fullscreen, - WmWindow* root_window) { - FOR_EACH_OBSERVER(ShellObserver, *wm_shell_->shell_observers(), - OnFullscreenStateChanged(is_fullscreen, root_window)); -} - void Shell::CreateModalBackground(aura::Window* window) { RootWindowControllerList controllers = GetAllRootWindowControllers(); for (RootWindowControllerList::iterator iter = controllers.begin();
diff --git a/ash/shell.h b/ash/shell.h index d86fd28..39ad425 100644 --- a/ash/shell.h +++ b/ash/shell.h
@@ -364,11 +364,6 @@ // TODO(jamescook): Move to Shelf. void OnShelfAutoHideBehaviorChanged(WmWindow* root_window); - // Notifies |observers_| when entering or exiting fullscreen mode in - // |root_window|. - // TODO(hidehiko): Rename this to NotifyFullscreenStateChanged. - void NotifyFullscreenStateChange(bool is_fullscreen, WmWindow* root_window); - // Creates a modal background (a partially-opaque fullscreen window) // on all displays for |window|. void CreateModalBackground(aura::Window* window);
diff --git a/ash/sysui/BUILD.gn b/ash/sysui/BUILD.gn index adf4ac8..e9afcc9a 100644 --- a/ash/sysui/BUILD.gn +++ b/ash/sysui/BUILD.gn
@@ -64,7 +64,7 @@ ] public_deps = [ - "//ash/sysui/public/interfaces", + "//ash/public/interfaces", "//mash/shelf/public/interfaces", ]
diff --git a/ash/sysui/manifest.json b/ash/sysui/manifest.json index b567316..9a6d0db 100644 --- a/ash/sysui/manifest.json +++ b/ash/sysui/manifest.json
@@ -5,14 +5,8 @@ "capabilities": { "required": { "*": { "classes": [ "app" ] }, - "mojo:ash": { - "interfaces": [ - "ash::mojom::ShelfLayout", - "ash::mojom::UserWindowController" - ] - }, "exe:chrome" : { - "interfaces": [ "ash::sysui::mojom::WallpaperManager" ], + "interfaces": [ "ash::mojom::WallpaperManager" ], "classes": [ "app_list:presenter" ] } }
diff --git a/ash/sysui/pointer_watcher_delegate_mus.cc b/ash/sysui/pointer_watcher_delegate_mus.cc index 8118237..0487af9d 100644 --- a/ash/sysui/pointer_watcher_delegate_mus.cc +++ b/ash/sysui/pointer_watcher_delegate_mus.cc
@@ -14,7 +14,8 @@ void PointerWatcherDelegateMus::AddPointerWatcher( views::PointerWatcher* watcher) { - views::WindowManagerConnection::Get()->AddPointerWatcher(watcher); + views::WindowManagerConnection::Get()->AddPointerWatcher( + watcher, false /* want_moves */); } void PointerWatcherDelegateMus::RemovePointerWatcher(
diff --git a/ash/sysui/public/interfaces/BUILD.gn b/ash/sysui/public/interfaces/BUILD.gn deleted file mode 100644 index d9fa137..0000000 --- a/ash/sysui/public/interfaces/BUILD.gn +++ /dev/null
@@ -1,17 +0,0 @@ -# Copyright 2016 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import("//mojo/public/tools/bindings/mojom.gni") - -mojom("interfaces") { - sources = [ - "wallpaper.mojom", - ] - - deps = [ - "//skia/public/interfaces", - ] - - use_new_wrapper_types = false -}
diff --git a/ash/sysui/public/interfaces/wallpaper.mojom b/ash/sysui/public/interfaces/wallpaper.mojom deleted file mode 100644 index af7b712..0000000 --- a/ash/sysui/public/interfaces/wallpaper.mojom +++ /dev/null
@@ -1,20 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -module ash.sysui.mojom; - -import "skia/public/interfaces/bitmap.mojom"; - -// These values match wallpaper::WallpaperLayout. -enum WallpaperLayout { CENTER, CENTER_CROPPED, STRETCH, TILE, }; - -// Used by Chrome to set the wallpaper displayed by ash_sysui. -interface WallpaperController { - SetWallpaper(skia.mojom.Bitmap wallpaper, WallpaperLayout layout); -}; - -// Used by ash_sysui to trigger Chrome's wallpaper picker functionality. -interface WallpaperManager { - Open(); -};
diff --git a/ash/sysui/shelf_delegate_mus.cc b/ash/sysui/shelf_delegate_mus.cc index 129cd25..82a2626 100644 --- a/ash/sysui/shelf_delegate_mus.cc +++ b/ash/sysui/shelf_delegate_mus.cc
@@ -27,18 +27,16 @@ #include "ui/resources/grit/ui_resources.h" #include "ui/views/mus/window_manager_connection.h" -using ash::mojom::UserWindowController; - namespace ash { namespace sysui { namespace { -// A ShelfItemDelegate used for pinned items and open user windows. +// A ShelfItemDelegate used for pinned items. +// TODO(mash): Support open user windows, etc. class ShelfItemDelegateMus : public ShelfItemDelegate { public: - explicit ShelfItemDelegateMus(UserWindowController* user_window_controller) - : user_window_controller_(user_window_controller) {} + ShelfItemDelegateMus() {} ~ShelfItemDelegateMus() override {} void SetDelegate( @@ -90,7 +88,7 @@ return command_id > 0; } void ExecuteCommand(int command_id, int event_flags) override { - item_delegate_->user_window_controller_->ActivateUserWindow(command_id); + NOTIMPLEMENTED(); } private: @@ -107,9 +105,8 @@ return kNewWindowCreated; } if (window_id_to_title_.size() == 1) { - user_window_controller_->ActivateUserWindow( - window_id_to_title_.begin()->first); - return kExistingWindowActivated; + // TODO(mash): Activate the window and return kExistingWindowActivated. + NOTIMPLEMENTED(); } return kNoAction; } @@ -141,7 +138,6 @@ bool pinned_ = false; std::map<uint32_t, base::string16> window_id_to_title_; base::string16 title_; - UserWindowController* user_window_controller_; DISALLOW_COPY_AND_ASSIGN(ShelfItemDelegateMus); }; @@ -175,15 +171,7 @@ } // namespace -ShelfDelegateMus::ShelfDelegateMus(ShelfModel* model) - : model_(model), binding_(this) { - ::shell::Connector* connector = - views::WindowManagerConnection::Get()->connector(); - connector->ConnectToInterface("mojo:ash", &shelf_layout_); - connector->ConnectToInterface("mojo:ash", &user_window_controller_); - user_window_controller_->AddUserWindowObserver( - binding_.CreateInterfacePtrAndBind()); -} +ShelfDelegateMus::ShelfDelegateMus(ShelfModel* model) : model_(model) {} ShelfDelegateMus::~ShelfDelegateMus() {} @@ -202,8 +190,6 @@ SetShelfPreferredSizes(shelf); mash::shelf::mojom::Alignment alignment = static_cast<mash::shelf::mojom::Alignment>(shelf->alignment()); - shelf_layout_->SetAlignment(alignment); - observers_.ForAllPtrs( [alignment](mash::shelf::mojom::ShelfObserver* observer) { observer->OnAlignmentChanged(alignment); @@ -214,8 +200,6 @@ mash::shelf::mojom::AutoHideBehavior behavior = static_cast<mash::shelf::mojom::AutoHideBehavior>( shelf->auto_hide_behavior()); - shelf_layout_->SetAutoHideBehavior(behavior); - observers_.ForAllPtrs( [behavior](mash::shelf::mojom::ShelfObserver* observer) { observer->OnAutoHideBehaviorChanged(behavior); @@ -312,7 +296,7 @@ model_->Add(shelf_item); std::unique_ptr<ShelfItemDelegateMus> item_delegate( - new ShelfItemDelegateMus(user_window_controller_.get())); + new ShelfItemDelegateMus()); item_delegate->SetDelegate(std::move(delegate)); item_delegate->set_pinned(true); item_delegate->set_title(item->app_title.To<base::string16>()); @@ -345,115 +329,6 @@ model_->Set(index, item); } -void ShelfDelegateMus::OnUserWindowObserverAdded( - mojo::Array<ash::mojom::UserWindowPtr> user_windows) { - for (size_t i = 0; i < user_windows.size(); ++i) - OnUserWindowAdded(std::move(user_windows[i])); -} - -void ShelfDelegateMus::OnUserWindowAdded( - ash::mojom::UserWindowPtr user_window) { - DCHECK(!window_id_to_shelf_id_.count(user_window->window_id)); - - if (user_window->ignored_by_shelf) - return; - - std::string app_id(user_window->window_app_id.To<std::string>()); - if (app_id_to_shelf_id_.count(app_id)) { - ShelfID shelf_id = app_id_to_shelf_id_[app_id]; - window_id_to_shelf_id_.insert( - std::make_pair(user_window->window_id, shelf_id)); - - ShelfItemDelegateMus* item_delegate = GetShelfItemDelegate(shelf_id); - item_delegate->AddWindow(user_window->window_id, - user_window->window_title.To<base::string16>()); - return; - } - - ShelfID shelf_id = model_->next_id(); - window_id_to_shelf_id_.insert( - std::make_pair(user_window->window_id, shelf_id)); - app_id_to_shelf_id_.insert(std::make_pair(app_id, shelf_id)); - shelf_id_to_app_id_.insert(std::make_pair(shelf_id, app_id)); - - ShelfItem item; - item.type = TYPE_PLATFORM_APP; - item.status = user_window->window_has_focus ? STATUS_ACTIVE : STATUS_RUNNING; - item.image = GetShelfIconFromSerializedBitmap(user_window->window_app_icon); - model_->Add(item); - - std::unique_ptr<ShelfItemDelegateMus> item_delegate( - new ShelfItemDelegateMus(user_window_controller_.get())); - item_delegate->AddWindow(user_window->window_id, - user_window->window_title.To<base::string16>()); - model_->SetShelfItemDelegate(shelf_id, std::move(item_delegate)); -} - -void ShelfDelegateMus::OnUserWindowRemoved(uint32_t window_id) { - if (!window_id_to_shelf_id_.count(window_id)) - return; - ShelfID shelf_id = window_id_to_shelf_id_[window_id]; - ShelfItemDelegateMus* item_delegate = GetShelfItemDelegate(shelf_id); - item_delegate->RemoveWindow(window_id); - window_id_to_shelf_id_.erase(window_id); - if (item_delegate->window_id_to_title().empty() && !item_delegate->pinned()) { - model_->RemoveItemAt(model_->ItemIndexByID(shelf_id)); - const std::string& app_id = shelf_id_to_app_id_[shelf_id]; - app_id_to_shelf_id_.erase(app_id); - shelf_id_to_app_id_.erase(shelf_id); - } -} - -void ShelfDelegateMus::OnUserWindowTitleChanged( - uint32_t window_id, - const mojo::String& window_title) { - if (!window_id_to_shelf_id_.count(window_id)) - return; - ShelfID shelf_id = window_id_to_shelf_id_[window_id]; - ShelfItemDelegateMus* item_delegate = GetShelfItemDelegate(shelf_id); - item_delegate->SetWindowTitle(window_id, window_title.To<base::string16>()); - - // There's nothing in the ShelfItem that needs to be updated. But we still - // need to update the ShelfModel so that the observers can pick up any - // changes. - int index = model_->ItemIndexByID(shelf_id); - DCHECK_GE(index, 0); - ShelfItems::const_iterator iter = model_->ItemByID(shelf_id); - DCHECK(iter != model_->items().end()); - model_->Set(index, *iter); -} - -void ShelfDelegateMus::OnUserWindowAppIconChanged( - uint32_t window_id, - mojo::Array<uint8_t> app_icon) { - if (!window_id_to_shelf_id_.count(window_id)) - return; - // Find the shelf ID for this window. - ShelfID shelf_id = window_id_to_shelf_id_[window_id]; - DCHECK_GT(shelf_id, 0); - - // Update the icon in the ShelfItem. - int index = model_->ItemIndexByID(shelf_id); - DCHECK_GE(index, 0); - ShelfItem item = *model_->ItemByID(shelf_id); - item.image = GetShelfIconFromSerializedBitmap(app_icon); - model_->Set(index, item); -} - -void ShelfDelegateMus::OnUserWindowFocusChanged(uint32_t window_id, - bool has_focus) { - if (!window_id_to_shelf_id_.count(window_id)) - return; - ShelfID shelf_id = window_id_to_shelf_id_[window_id]; - int index = model_->ItemIndexByID(shelf_id); - DCHECK_GE(index, 0); - ShelfItems::const_iterator iter = model_->ItemByID(shelf_id); - DCHECK(iter != model_->items().end()); - ShelfItem item = *iter; - item.status = has_focus ? STATUS_ACTIVE : STATUS_RUNNING; - model_->Set(index, item); -} - void ShelfDelegateMus::SetShelfPreferredSizes(Shelf* shelf) { ShelfWidget* widget = shelf->shelf_widget(); ShelfLayoutManager* layout_manager = widget->shelf_layout_manager();
diff --git a/ash/sysui/shelf_delegate_mus.h b/ash/sysui/shelf_delegate_mus.h index c92575d7..74b3948 100644 --- a/ash/sysui/shelf_delegate_mus.h +++ b/ash/sysui/shelf_delegate_mus.h
@@ -8,8 +8,6 @@ #include <map> #include "ash/common/shelf/shelf_delegate.h" -#include "ash/public/interfaces/shelf_layout.mojom.h" -#include "ash/public/interfaces/user_window_controller.mojom.h" #include "mash/shelf/public/interfaces/shelf.mojom.h" #include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/interface_ptr_set.h" @@ -20,11 +18,10 @@ namespace sysui { -// Manages communication between the ash_sysui shelf, the window manager, and -// the browser. +// Manages communication between the mash shelf and the browser. +// TODO(mash): Support ShelfController in mojo:ash and remove this sysui impl. class ShelfDelegateMus : public ShelfDelegate, - public mash::shelf::mojom::ShelfController, - public ash::mojom::UserWindowObserver { + public mash::shelf::mojom::ShelfController { public: explicit ShelfDelegateMus(ShelfModel* model); ~ShelfDelegateMus() override; @@ -56,27 +53,13 @@ void UnpinItem(const mojo::String& app_id) override; void SetItemImage(const mojo::String& app_id, const SkBitmap& image) override; - // ash::mojom::UserWindowObserver: - void OnUserWindowObserverAdded( - mojo::Array<ash::mojom::UserWindowPtr> user_windows) override; - void OnUserWindowAdded(ash::mojom::UserWindowPtr user_window) override; - void OnUserWindowRemoved(uint32_t window_id) override; - void OnUserWindowTitleChanged(uint32_t window_id, - const mojo::String& window_title) override; - void OnUserWindowAppIconChanged(uint32_t window_id, - mojo::Array<uint8_t> app_icon) override; - void OnUserWindowFocusChanged(uint32_t window_id, bool has_focus) override; - - // Set the Mus window preferred sizes, needed by mash::wm::ShelfLayout. + // Set the Mus window preferred sizes. void SetShelfPreferredSizes(Shelf* shelf); ShelfModel* model_; mojo::AssociatedInterfacePtrSet<mash::shelf::mojom::ShelfObserver> observers_; - ash::mojom::ShelfLayoutPtr shelf_layout_; - ash::mojom::UserWindowControllerPtr user_window_controller_; - mojo::Binding<ash::mojom::UserWindowObserver> binding_; std::map<uint32_t, ShelfID> window_id_to_shelf_id_; std::map<std::string, ShelfID> app_id_to_shelf_id_;
diff --git a/ash/sysui/sysui_application.h b/ash/sysui/sysui_application.h index 8d6d61c..a9878e06 100644 --- a/ash/sysui/sysui_application.h +++ b/ash/sysui/sysui_application.h
@@ -7,7 +7,7 @@ #include <memory> -#include "ash/sysui/public/interfaces/wallpaper.mojom.h" +#include "ash/public/interfaces/wallpaper.mojom.h" #include "base/macros.h" #include "mash/shelf/public/interfaces/shelf.mojom.h" #include "mojo/public/cpp/bindings/binding_set.h"
diff --git a/ash/sysui/user_wallpaper_delegate_mus.cc b/ash/sysui/user_wallpaper_delegate_mus.cc index eaeec81..801e5ea4 100644 --- a/ash/sysui/user_wallpaper_delegate_mus.cc +++ b/ash/sysui/user_wallpaper_delegate_mus.cc
@@ -14,15 +14,15 @@ namespace { wallpaper::WallpaperLayout WallpaperLayoutFromMojo( - ash::sysui::mojom::WallpaperLayout layout) { + ash::mojom::WallpaperLayout layout) { switch (layout) { - case ash::sysui::mojom::WallpaperLayout::CENTER: + case ash::mojom::WallpaperLayout::CENTER: return wallpaper::WALLPAPER_LAYOUT_CENTER; - case ash::sysui::mojom::WallpaperLayout::CENTER_CROPPED: + case ash::mojom::WallpaperLayout::CENTER_CROPPED: return wallpaper::WALLPAPER_LAYOUT_CENTER_CROPPED; - case ash::sysui::mojom::WallpaperLayout::STRETCH: + case ash::mojom::WallpaperLayout::STRETCH: return wallpaper::WALLPAPER_LAYOUT_STRETCH; - case ash::sysui::mojom::WallpaperLayout::TILE: + case ash::mojom::WallpaperLayout::TILE: return wallpaper::WALLPAPER_LAYOUT_TILE; } NOTREACHED();
diff --git a/ash/sysui/user_wallpaper_delegate_mus.h b/ash/sysui/user_wallpaper_delegate_mus.h index 94261048..b616d34 100644 --- a/ash/sysui/user_wallpaper_delegate_mus.h +++ b/ash/sysui/user_wallpaper_delegate_mus.h
@@ -6,7 +6,7 @@ #define ASH_SYSUI_USER_WALLPAPER_DELEGATE_MUS_H_ #include "ash/desktop_background/user_wallpaper_delegate.h" -#include "ash/sysui/public/interfaces/wallpaper.mojom.h" +#include "ash/public/interfaces/wallpaper.mojom.h" #include "base/macros.h" namespace ash {
diff --git a/ash/touch_hud/mus/touch_hud_application.cc b/ash/touch_hud/mus/touch_hud_application.cc index 7e9eb06..b211438 100644 --- a/ash/touch_hud/mus/touch_hud_application.cc +++ b/ash/touch_hud/mus/touch_hud_application.cc
@@ -14,7 +14,7 @@ #include "ui/views/mus/aura_init.h" #include "ui/views/mus/native_widget_mus.h" #include "ui/views/mus/window_manager_connection.h" -#include "ui/views/touch_event_watcher.h" +#include "ui/views/pointer_watcher.h" #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_delegate.h" @@ -25,16 +25,16 @@ // receiving touch events from ui::WindowManagerConnection, it calls // ash::TouchHudRenderer to draw out touch points. class TouchHudUI : public views::WidgetDelegateView, - public views::TouchEventWatcher { + public views::PointerWatcher { public: TouchHudUI(views::WindowManagerConnection* window_manager_connection, views::Widget* widget) : window_manager_connection_(window_manager_connection), touch_hud_renderer_(new TouchHudRenderer(widget)) { - window_manager_connection_->AddTouchEventWatcher(this); + window_manager_connection_->AddPointerWatcher(this, true /* want_moves */); } ~TouchHudUI() override { - window_manager_connection_->RemoveTouchEventWatcher(this); + window_manager_connection_->RemovePointerWatcher(this); } private: @@ -45,10 +45,12 @@ return base::ASCIIToUTF16("TouchHud"); } - // Overridden from views::TouchEventWatcher: - void OnTouchEventObserved(const ui::LocatedEvent& event, - views::Widget* target) override { - touch_hud_renderer_->HandleTouchEvent(event); + // Overridden from views::PointerWatcher: + void OnPointerEventObserved(const ui::PointerEvent& event, + const gfx::Point& location_in_screen, + views::Widget* target) override { + if (event.IsTouchPointerEvent()) + touch_hud_renderer_->HandleTouchEvent(event); } views::WindowManagerConnection* window_manager_connection_;
diff --git a/ash/wm/always_on_top_controller_unittest.cc b/ash/wm/always_on_top_controller_unittest.cc index 386f36a..61c21d2 100644 --- a/ash/wm/always_on_top_controller_unittest.cc +++ b/ash/wm/always_on_top_controller_unittest.cc
@@ -7,7 +7,6 @@ #include "ash/aura/wm_window_aura.h" #include "ash/common/shell_window_ids.h" #include "ash/common/wm/workspace/workspace_layout_manager.h" -#include "ash/common/wm/workspace/workspace_layout_manager_delegate.h" #include "ash/root_window_controller.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" @@ -39,8 +38,7 @@ class TestLayoutManager : public WorkspaceLayoutManager { public: explicit TestLayoutManager(WmWindow* window) - : WorkspaceLayoutManager(window, nullptr), - keyboard_bounds_changed_(false) {} + : WorkspaceLayoutManager(window), keyboard_bounds_changed_(false) {} ~TestLayoutManager() override {}
diff --git a/ash/wm/immersive_fullscreen_controller.cc b/ash/wm/immersive_fullscreen_controller.cc index c2882f1..13ce2d3 100644 --- a/ash/wm/immersive_fullscreen_controller.cc +++ b/ash/wm/immersive_fullscreen_controller.cc
@@ -115,17 +115,10 @@ // The height in pixels of the region below the top edge of the display in which // the mouse can trigger revealing the top-of-window views. -#if defined(OS_WIN) -// Windows 8 reserves some pixels at the top of the screen for the hand icon -// that allows you to drag a metro app off the screen, so a few additional -// pixels of space must be reserved for the mouse reveal. -const int ImmersiveFullscreenController::kMouseRevealBoundsHeight = 9; -#else // The height must be greater than 1px because the top pixel is used to trigger // moving the cursor between displays if the user has a vertical display layout // (primary display above/below secondary display). const int ImmersiveFullscreenController::kMouseRevealBoundsHeight = 3; -#endif //////////////////////////////////////////////////////////////////////////////// @@ -380,7 +373,7 @@ } else if (event->type() != ui::ET_MOUSE_CAPTURE_CHANGED) { // Trigger a reveal if the cursor pauses at the top of the screen for a // while. - UpdateTopEdgeHoverTimer(event); + UpdateTopEdgeHoverTimer(*event); } } @@ -416,7 +409,7 @@ break; case ui::ET_GESTURE_SCROLL_UPDATE: if (gesture_begun_) { - if (UpdateRevealedLocksForSwipe(GetSwipeType(event))) + if (UpdateRevealedLocksForSwipe(GetSwipeType(*event))) event->SetHandled(); gesture_begun_ = false; } @@ -553,7 +546,7 @@ } void ImmersiveFullscreenController::UpdateTopEdgeHoverTimer( - ui::MouseEvent* event) { + const ui::MouseEvent& event) { DCHECK(enabled_); DCHECK(reveal_state_ == SLIDING_CLOSED || reveal_state_ == CLOSED); @@ -562,7 +555,7 @@ // |widget_| is inactive but prevents starting the timer if the mouse is over // a portion of the top edge obscured by an unrelated widget. if (!top_edge_hover_timer_.IsRunning() && - !native_window_->Contains(static_cast<aura::Window*>(event->target()))) { + !native_window_->Contains(static_cast<aura::Window*>(event.target()))) { return; } @@ -571,7 +564,7 @@ if (aura::client::GetCaptureWindow(native_window_)) return; - gfx::Point location_in_screen = GetEventLocationInScreen(*event); + gfx::Point location_in_screen = GetEventLocationInScreen(event); if (ShouldIgnoreMouseEventAtLocation(location_in_screen)) return; @@ -605,7 +598,7 @@ } void ImmersiveFullscreenController::UpdateLocatedEventRevealedLock( - ui::LocatedEvent* event) { + const ui::LocatedEvent* event) { if (!enabled_) return; DCHECK(!event || event->IsMouseEvent() || event->IsTouchEvent()); @@ -851,16 +844,17 @@ } ImmersiveFullscreenController::SwipeType -ImmersiveFullscreenController::GetSwipeType(ui::GestureEvent* event) const { - if (event->type() != ui::ET_GESTURE_SCROLL_UPDATE) +ImmersiveFullscreenController::GetSwipeType( + const ui::GestureEvent& event) const { + if (event.type() != ui::ET_GESTURE_SCROLL_UPDATE) return SWIPE_NONE; // Make sure that it is a clear vertical gesture. - if (std::abs(event->details().scroll_y()) <= - kSwipeVerticalThresholdMultiplier * std::abs(event->details().scroll_x())) + if (std::abs(event.details().scroll_y()) <= + kSwipeVerticalThresholdMultiplier * std::abs(event.details().scroll_x())) return SWIPE_NONE; - if (event->details().scroll_y() < 0) + if (event.details().scroll_y() < 0) return SWIPE_CLOSE; - else if (event->details().scroll_y() > 0) + if (event.details().scroll_y() > 0) return SWIPE_OPEN; return SWIPE_NONE; }
diff --git a/ash/wm/immersive_fullscreen_controller.h b/ash/wm/immersive_fullscreen_controller.h index 4ea60768..25e65306 100644 --- a/ash/wm/immersive_fullscreen_controller.h +++ b/ash/wm/immersive_fullscreen_controller.h
@@ -131,12 +131,12 @@ // hovered at the top of the screen the timer is started. If the mouse moves // away from the top edge, or moves too much in the x direction, the timer is // stopped. - void UpdateTopEdgeHoverTimer(ui::MouseEvent* event); + void UpdateTopEdgeHoverTimer(const ui::MouseEvent& event); // Updates |located_event_revealed_lock_| based on the current mouse state and // the current touch state. // |event| is NULL if the source event is not known. - void UpdateLocatedEventRevealedLock(ui::LocatedEvent* event); + void UpdateLocatedEventRevealedLock(const ui::LocatedEvent* event); // Acquires |located_event_revealed_lock_| if it is not already held. void AcquireLocatedEventRevealedLock(); @@ -171,7 +171,7 @@ void OnSlideClosedAnimationCompleted(); // Returns the type of swipe given |event|. - SwipeType GetSwipeType(ui::GestureEvent* event) const; + SwipeType GetSwipeType(const ui::GestureEvent& event) const; // Returns true if a mouse event at |location_in_screen| should be ignored. // Ignored mouse events should not contribute to revealing or unrevealing the
diff --git a/ash/wm/overview/window_selector_unittest.cc b/ash/wm/overview/window_selector_unittest.cc index eef26a9..f5f53a1 100644 --- a/ash/wm/overview/window_selector_unittest.cc +++ b/ash/wm/overview/window_selector_unittest.cc
@@ -453,6 +453,27 @@ EXPECT_FALSE(aura::client::GetCursorClient(root_window)->IsCursorLocked()); } +// Tests that entering overview mode with an App-list active properly focuses +// and activates the overview text filter window. +TEST_P(WindowSelectorTest, TextFilterActive) { + gfx::Rect bounds(0, 0, 400, 400); + std::unique_ptr<aura::Window> window1(CreateWindow(bounds)); + wm::ActivateWindow(window1.get()); + + EXPECT_TRUE(wm::IsActiveWindow(window1.get())); + EXPECT_EQ(window1.get(), GetFocusedWindow()); + + WmShell::Get()->ToggleAppList(); + + // Activating overview cancels the App-list which normally would activate the + // previously active |window1|. Overview mode should properly transfer focus + // and activation to the text filter widget. + ToggleOverview(); + EXPECT_FALSE(wm::IsActiveWindow(window1.get())); + EXPECT_TRUE(wm::IsActiveWindow(GetFocusedWindow())); + EXPECT_EQ(text_filter_widget()->GetNativeWindow(), GetFocusedWindow()); +} + // Tests that the ordering of windows is near the windows' original positions. TEST_P(WindowSelectorTest, MinimizeMovement) { // With Material Design the order of windows in overview mode is MRU.
diff --git a/ash/wm/window_mirror_view.cc b/ash/wm/window_mirror_view.cc index 1c50ecb..e797dc9f 100644 --- a/ash/wm/window_mirror_view.cc +++ b/ash/wm/window_mirror_view.cc
@@ -11,6 +11,7 @@ #include "ui/aura/window.h" #include "ui/compositor/layer.h" #include "ui/compositor/layer_tree_owner.h" +#include "ui/views/widget/widget.h" namespace ash { namespace wm { @@ -34,27 +35,15 @@ } WindowMirrorView::~WindowMirrorView() {} -void WindowMirrorView::Init() { - SetPaintToLayer(true); - - layer_owner_ = ::wm::RecreateLayers(target_->aura_window(), this); - - GetMirrorLayer()->parent()->Remove(GetMirrorLayer()); - layer()->Add(GetMirrorLayer()); - - // Some extra work is needed when the target window is minimized. - if (target_->GetWindowState()->IsMinimized()) { - GetMirrorLayer()->SetVisible(true); - GetMirrorLayer()->SetOpacity(1); - EnsureAllChildrenAreVisible(GetMirrorLayer()); - } -} - gfx::Size WindowMirrorView::GetPreferredSize() const { return target_->GetBounds().size(); } void WindowMirrorView::Layout() { + // If |layer_owner_| hasn't been initialized (|this| isn't on screen), no-op. + if (!layer_owner_) + return; + // Position at 0, 0. GetMirrorLayer()->SetBounds(gfx::Rect(GetMirrorLayer()->bounds().size())); @@ -68,6 +57,15 @@ GetMirrorLayer()->SetTransform(mirror_transform); } +bool WindowMirrorView::GetNeedsNotificationWhenVisibleBoundsChange() const { + return true; +} + +void WindowMirrorView::OnVisibleBoundsChanged() { + if (!layer_owner_ && !GetVisibleBounds().IsEmpty()) + InitLayerOwner(); +} + ui::LayerDelegate* WindowMirrorView::CreateDelegate( ui::LayerDelegate* delegate) { if (!delegate) @@ -78,6 +76,24 @@ return delegates_.back().get(); } +void WindowMirrorView::InitLayerOwner() { + SetPaintToLayer(true); + + layer_owner_ = ::wm::RecreateLayers(target_->aura_window(), this); + + GetMirrorLayer()->parent()->Remove(GetMirrorLayer()); + layer()->Add(GetMirrorLayer()); + + // Some extra work is needed when the target window is minimized. + if (target_->GetWindowState()->IsMinimized()) { + GetMirrorLayer()->SetVisible(true); + GetMirrorLayer()->SetOpacity(1); + EnsureAllChildrenAreVisible(GetMirrorLayer()); + } + + Layout(); +} + ui::Layer* WindowMirrorView::GetMirrorLayer() { return layer_owner_->root(); }
diff --git a/ash/wm/window_mirror_view.h b/ash/wm/window_mirror_view.h index 268ea10..c59297f6 100644 --- a/ash/wm/window_mirror_view.h +++ b/ash/wm/window_mirror_view.h
@@ -29,16 +29,18 @@ explicit WindowMirrorView(WmWindowAura* window); ~WindowMirrorView() override; - void Init(); - // views::View: gfx::Size GetPreferredSize() const override; void Layout() override; + bool GetNeedsNotificationWhenVisibleBoundsChange() const override; + void OnVisibleBoundsChanged() override; // ::wm::LayerDelegateFactory: ui::LayerDelegate* CreateDelegate(ui::LayerDelegate* delegate) override; private: + void InitLayerOwner(); + // Gets the root of the layer tree that was lifted from |target_| (and is now // a child of |this->layer()|). ui::Layer* GetMirrorLayer(); @@ -46,7 +48,8 @@ // The original window that is being represented by |this|. WmWindowAura* target_; - // Retains ownership of the mirror layer tree. + // Retains ownership of the mirror layer tree. This is lazily initialized + // the first time the view becomes visible. std::unique_ptr<ui::LayerTreeOwner> layer_owner_; std::vector<std::unique_ptr<ForwardingLayerDelegate>> delegates_;
diff --git a/ash/wm/workspace_controller.cc b/ash/wm/workspace_controller.cc index 99c12cd2..80d1783 100644 --- a/ash/wm/workspace_controller.cc +++ b/ash/wm/workspace_controller.cc
@@ -11,7 +11,6 @@ #include "ash/common/wm/window_state.h" #include "ash/common/wm/workspace/workspace_layout_manager.h" #include "ash/common/wm/workspace/workspace_layout_manager_backdrop_delegate.h" -#include "ash/common/wm/workspace/workspace_layout_manager_delegate.h" #include "ash/root_window_controller.h" #include "ash/shelf/shelf_layout_manager.h" #include "ash/shell.h" @@ -44,14 +43,11 @@ } // namespace -WorkspaceController::WorkspaceController( - aura::Window* viewport, - std::unique_ptr<wm::WorkspaceLayoutManagerDelegate> delegate) +WorkspaceController::WorkspaceController(aura::Window* viewport) : viewport_(viewport), shelf_(NULL), event_handler_(new WorkspaceEventHandler), - layout_manager_(new WorkspaceLayoutManager(WmWindowAura::Get(viewport), - std::move(delegate))) { + layout_manager_(new WorkspaceLayoutManager(WmWindowAura::Get(viewport))) { SetWindowVisibilityAnimationTransition(viewport_, ::wm::ANIMATE_NONE); WmWindowAura::Get(viewport_)->SetLayoutManager(
diff --git a/ash/wm/workspace_controller.h b/ash/wm/workspace_controller.h index ec111a2..fb8e3c3 100644 --- a/ash/wm/workspace_controller.h +++ b/ash/wm/workspace_controller.h
@@ -22,17 +22,11 @@ class WorkspaceLayoutManager; class WorkspaceLayoutManagerBackdropDelegate; -namespace wm { -class WorkspaceLayoutManagerDelegate; -} - // WorkspaceController acts as a central place that ties together all the // various workspace pieces. class ASH_EXPORT WorkspaceController { public: - WorkspaceController( - aura::Window* viewport, - std::unique_ptr<wm::WorkspaceLayoutManagerDelegate> delegate); + explicit WorkspaceController(aura::Window* viewport); virtual ~WorkspaceController(); // Returns the current window state.
diff --git a/base/BUILD.gn b/base/BUILD.gn index bf7092f..ae1159a 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -1487,10 +1487,20 @@ sources = [ "base_switches.cc", "base_switches.h", + "task_scheduler/switches.cc", + "task_scheduler/switches.h", "win/pe_image.cc", "win/pe_image.h", ] + if (is_win) { + # Disable sanitizer coverage in win/pe_image.cc. It is called by the sandbox + # before sanitizer coverage can initialize. http://crbug.com/484711 + configs -= [ "//build/config/sanitizers:default_sanitizer_flags" ] + configs += + [ "//build/config/sanitizers:default_sanitizer_flags_but_coverage" ] + } + if (!is_debug) { configs -= [ "//build/config/compiler:default_optimization" ] configs += [ "//build/config/compiler:optimize_max" ] @@ -1511,12 +1521,12 @@ "i18n/case_conversion.h", "i18n/char_iterator.cc", "i18n/char_iterator.h", + "i18n/encoding_detection.cc", + "i18n/encoding_detection.h", "i18n/file_util_icu.cc", "i18n/file_util_icu.h", "i18n/i18n_constants.cc", "i18n/i18n_constants.h", - "i18n/icu_encoding_detection.cc", - "i18n/icu_encoding_detection.h", "i18n/icu_string_conversions.cc", "i18n/icu_string_conversions.h", "i18n/icu_util.cc", @@ -1543,6 +1553,7 @@ defines = [ "BASE_I18N_IMPLEMENTATION" ] configs += [ "//build/config/compiler:wexit_time_destructors" ] public_deps = [ + "//third_party/ced", "//third_party/icu", ] deps = [
diff --git a/base/DEPS b/base/DEPS index c0e95a0..4b25f3f 100644 --- a/base/DEPS +++ b/base/DEPS
@@ -2,6 +2,7 @@ "+jni", "+third_party/ashmem", "+third_party/apple_apsl", + "+third_party/ced", "+third_party/lss", "+third_party/modp_b64", "+third_party/tcmalloc",
diff --git a/base/android/java/src/org/chromium/base/SecureRandomInitializer.java b/base/android/java/src/org/chromium/base/SecureRandomInitializer.java index 457e2ef..be1c18c5 100644 --- a/base/android/java/src/org/chromium/base/SecureRandomInitializer.java +++ b/base/android/java/src/org/chromium/base/SecureRandomInitializer.java
@@ -16,27 +16,20 @@ public class SecureRandomInitializer { private static final int NUM_RANDOM_BYTES = 16; - private static byte[] sSeedBytes = new byte[NUM_RANDOM_BYTES]; - /** * Safely initializes the random number generator, by seeding it with data from /dev/urandom. */ public static void initialize(SecureRandom generator) throws IOException { FileInputStream fis = null; try { + byte[] seedBytes = new byte[NUM_RANDOM_BYTES]; fis = new FileInputStream("/dev/urandom"); - if (fis.read(sSeedBytes) != sSeedBytes.length) { + if (fis.read(seedBytes) != seedBytes.length) { throw new IOException("Failed to get enough random data."); } - generator.setSeed(sSeedBytes); + generator.setSeed(seedBytes); } finally { - try { - if (fis != null) { - fis.close(); - } - } catch (IOException e) { - // Ignore exception closing the device. - } + StreamUtil.closeQuietly(fis); } } }
diff --git a/base/android/jni_generator/jni_generator_helper.h b/base/android/jni_generator/jni_generator_helper.h index 9075d3c..56a2ec8 100644 --- a/base/android/jni_generator/jni_generator_helper.h +++ b/base/android/jni_generator/jni_generator_helper.h
@@ -34,7 +34,4 @@ } // namespace jni_generator -using base::android::ScopedJavaLocalRef; -using base::android::JavaParamRef; - #endif // BASE_ANDROID_JNI_GENERATOR_JNI_GENERATOR_HELPER_H_
diff --git a/base/base.gyp b/base/base.gyp index 427a960c..6a036c4 100644 --- a/base/base.gyp +++ b/base/base.gyp
@@ -276,6 +276,7 @@ 'dependencies': [ 'base', 'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', + '../third_party/ced/ced.gyp:ced', '../third_party/icu/icu.gyp:icui18n', '../third_party/icu/icu.gyp:icuuc', ], @@ -634,6 +635,7 @@ 'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', '../testing/gmock.gyp:gmock', '../testing/gtest.gyp:gtest', + '../third_party/ced/ced.gyp:ced', '../third_party/icu/icu.gyp:icui18n', '../third_party/icu/icu.gyp:icuuc', ],
diff --git a/base/base.gypi b/base/base.gypi index ad2e3cea..a511ed5 100644 --- a/base/base.gypi +++ b/base/base.gypi
@@ -1083,12 +1083,12 @@ 'i18n/case_conversion.h', 'i18n/char_iterator.cc', 'i18n/char_iterator.h', + 'i18n/encoding_detection.cc', + 'i18n/encoding_detection.h', 'i18n/file_util_icu.cc', 'i18n/file_util_icu.h', 'i18n/i18n_constants.cc', 'i18n/i18n_constants.h', - 'i18n/icu_encoding_detection.cc', - 'i18n/icu_encoding_detection.h', 'i18n/icu_string_conversions.cc', 'i18n/icu_string_conversions.h', 'i18n/icu_util.cc',
diff --git a/base/base_nacl.gyp b/base/base_nacl.gyp index 30763d4..686bb6d 100644 --- a/base/base_nacl.gyp +++ b/base/base_nacl.gyp
@@ -67,6 +67,7 @@ 'dependencies': [ 'allocator/allocator.gyp:allocator_features#target', 'base.gyp:base_build_date', + '../third_party/ced/ced_nacl.gyp:ced_nacl', '../third_party/icu/icu_nacl.gyp:icudata_nacl', '../third_party/icu/icu_nacl.gyp:icui18n_nacl', '../third_party/icu/icu_nacl.gyp:icuuc_nacl',
diff --git a/base/containers/small_map.h b/base/containers/small_map.h index 9a96f6a..ed96caf 100644 --- a/base/containers/small_map.h +++ b/base/containers/small_map.h
@@ -510,8 +510,8 @@ size_ = 0; } - // Invalidates iterators. - void erase(const iterator& position) { + // Invalidates iterators. Returns iterator following the last removed element. + iterator erase(const iterator& position) { if (size_ >= 0) { int i = position.array_iter_ - array_; array_[i].Destroy(); @@ -519,10 +519,11 @@ if (i != size_) { array_[i].InitFromMove(std::move(array_[size_])); array_[size_].Destroy(); + return iterator(array_ + i); } - } else { - map_->erase(position.hash_iter_); + return end(); } + return iterator(map_->erase(position.hash_iter_)); } size_t erase(const key_type& key) {
diff --git a/base/containers/small_map_unittest.cc b/base/containers/small_map_unittest.cc index d76d93a9..47889e96 100644 --- a/base/containers/small_map_unittest.cc +++ b/base/containers/small_map_unittest.cc
@@ -331,6 +331,36 @@ EXPECT_TRUE(m.empty()); } +TEST(SmallMap, EraseReturnsIteratorFollowingRemovedElement) { + SmallMap<hash_map<std::string, int> > m; + SmallMap<hash_map<std::string, int> >::iterator iter; + + m["a"] = 0; + m["b"] = 1; + m["c"] = 2; + + // Erase first item. + auto following_iter = m.erase(m.begin()); + EXPECT_EQ(m.begin(), following_iter); + EXPECT_EQ(2u, m.size()); + EXPECT_EQ(m.count("a"), 0u); + EXPECT_EQ(m.count("b"), 1u); + EXPECT_EQ(m.count("c"), 1u); + + // Iterate to last item and erase it. + ++following_iter; + following_iter = m.erase(following_iter); + ASSERT_EQ(1u, m.size()); + EXPECT_EQ(m.end(), following_iter); + EXPECT_EQ(m.count("b"), 0u); + EXPECT_EQ(m.count("c"), 1u); + + // Erase remaining item. + following_iter = m.erase(m.begin()); + EXPECT_TRUE(m.empty()); + EXPECT_EQ(m.end(), following_iter); +} + TEST(SmallMap, NonHashMap) { SmallMap<std::map<int, int>, 4, std::equal_to<int> > m; EXPECT_TRUE(m.empty());
diff --git a/base/debug/stack_trace_posix.cc b/base/debug/stack_trace_posix.cc index fc3ee14..27a656e6 100644 --- a/base/debug/stack_trace_posix.cc +++ b/base/debug/stack_trace_posix.cc
@@ -444,8 +444,6 @@ StackTrace stack_trace; } -} // namespace - #if defined(USE_SYMBOLIZE) // class SandboxSymbolizeHelper. @@ -461,7 +459,8 @@ public: // Returns the singleton instance. static SandboxSymbolizeHelper* GetInstance() { - return Singleton<SandboxSymbolizeHelper>::get(); + return Singleton<SandboxSymbolizeHelper, + LeakySingletonTraits<SandboxSymbolizeHelper>>::get(); } private: @@ -677,6 +676,8 @@ }; #endif // USE_SYMBOLIZE +} // namespace + bool EnableInProcessStackDumping() { #if defined(USE_SYMBOLIZE) SandboxSymbolizeHelper::GetInstance();
diff --git a/base/i18n/encoding_detection.cc b/base/i18n/encoding_detection.cc new file mode 100644 index 0000000..5658251 --- /dev/null +++ b/base/i18n/encoding_detection.cc
@@ -0,0 +1,41 @@ +// 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 "base/i18n/encoding_detection.h" + +#include "third_party/ced/src/compact_enc_det/compact_enc_det.h" + +namespace base { + +bool DetectEncoding(const std::string& text, std::string* encoding) { + int consumed_bytes; + bool is_reliable; + Encoding enc = CompactEncDet::DetectEncoding( + text.c_str(), text.length(), nullptr, nullptr, nullptr, + UNKNOWN_ENCODING, + UNKNOWN_LANGUAGE, + CompactEncDet::QUERY_CORPUS, // plain text + false, // Include 7-bit encodings + &consumed_bytes, + &is_reliable); + + if (enc == UNKNOWN_ENCODING) + return false; + + // 7-bit encodings (except ISO-2022-JP) are not supported in web standard. + // Mark them as ascii to keep the raw bytes intact. + switch (enc) { + case HZ_GB_2312: + case ISO_2022_KR: + case ISO_2022_CN: + case UTF7: + enc = ASCII_7BIT; + break; + default: + break; + } + *encoding = MimeEncodingName(enc); + return true; +} +} // namespace base
diff --git a/base/i18n/encoding_detection.h b/base/i18n/encoding_detection.h new file mode 100644 index 0000000..c8e660c4 --- /dev/null +++ b/base/i18n/encoding_detection.h
@@ -0,0 +1,21 @@ +// 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 BASE_I18N_ENCODING_DETECTION_H_ +#define BASE_I18N_ENCODING_DETECTION_H_ + +#include <string> + +#include "base/compiler_specific.h" +#include "base/i18n/base_i18n_export.h" + +namespace base { + +// Detect encoding of |text| and put the name of encoding in |encoding|. +// Returns true on success. +BASE_I18N_EXPORT bool DetectEncoding(const std::string& text, + std::string* encoding) WARN_UNUSED_RESULT; +} // namespace base + +#endif // BASE_I18N_ENCODING_DETECTION_H_
diff --git a/base/i18n/icu_encoding_detection.cc b/base/i18n/icu_encoding_detection.cc deleted file mode 100644 index 04df0758..0000000 --- a/base/i18n/icu_encoding_detection.cc +++ /dev/null
@@ -1,100 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/i18n/icu_encoding_detection.h" - -#include <stdint.h> - -#include <set> - -#include "base/strings/string_util.h" -#include "third_party/icu/source/i18n/unicode/ucsdet.h" - -namespace base { - -bool DetectEncoding(const std::string& text, std::string* encoding) { - if (IsStringASCII(text)) { - *encoding = std::string(); - return true; - } - - UErrorCode status = U_ZERO_ERROR; - UCharsetDetector* detector = ucsdet_open(&status); - ucsdet_setText(detector, text.data(), static_cast<int32_t>(text.length()), - &status); - const UCharsetMatch* match = ucsdet_detect(detector, &status); - if (match != nullptr) - *encoding = ucsdet_getName(match, &status); - ucsdet_close(detector); - return (match != nullptr) && !!U_SUCCESS(status); -} - -bool DetectAllEncodings(const std::string& text, - std::vector<std::string>* encodings) { - UErrorCode status = U_ZERO_ERROR; - UCharsetDetector* detector = ucsdet_open(&status); - ucsdet_setText(detector, text.data(), static_cast<int32_t>(text.length()), - &status); - int matches_count = 0; - const UCharsetMatch** matches = ucsdet_detectAll(detector, - &matches_count, - &status); - if (U_FAILURE(status)) { - ucsdet_close(detector); - return false; - } - - // ICU has some heuristics for encoding detection, such that the more likely - // encodings should be returned first. However, it doesn't always return - // all encodings that properly decode |text|, so we'll append more encodings - // later. To make that efficient, keep track of encodings sniffed in this - // first phase. - std::set<std::string> sniffed_encodings; - - encodings->clear(); - for (int i = 0; i < matches_count; i++) { - UErrorCode get_name_status = U_ZERO_ERROR; - const char* encoding_name = ucsdet_getName(matches[i], &get_name_status); - - // If we failed to get the encoding's name, ignore the error. - if (U_FAILURE(get_name_status)) - continue; - - int32_t confidence = ucsdet_getConfidence(matches[i], &get_name_status); - - // We also treat this error as non-fatal. - if (U_FAILURE(get_name_status)) - continue; - - // A confidence level >= 10 means that the encoding is expected to properly - // decode the text. Drop all encodings with lower confidence level. - if (confidence < 10) - continue; - - encodings->push_back(encoding_name); - sniffed_encodings.insert(encoding_name); - } - - // Append all encodings not included earlier, in arbitrary order. - // TODO(jshin): This shouldn't be necessary, possible ICU bug. - // See also http://crbug.com/65917. - UEnumeration* detectable_encodings = ucsdet_getAllDetectableCharsets(detector, - &status); - int detectable_count = uenum_count(detectable_encodings, &status); - for (int i = 0; i < detectable_count; i++) { - int name_length; - const char* name_raw = uenum_next(detectable_encodings, - &name_length, - &status); - std::string name(name_raw, name_length); - if (sniffed_encodings.find(name) == sniffed_encodings.end()) - encodings->push_back(name); - } - uenum_close(detectable_encodings); - - ucsdet_close(detector); - return !encodings->empty(); -} - -} // namespace base
diff --git a/base/i18n/icu_encoding_detection.h b/base/i18n/icu_encoding_detection.h deleted file mode 100644 index 6d1e71c..0000000 --- a/base/i18n/icu_encoding_detection.h +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_I18N_ICU_ENCODING_DETECTION_H_ -#define BASE_I18N_ICU_ENCODING_DETECTION_H_ - -#include <string> -#include <vector> - -#include "base/i18n/base_i18n_export.h" - -namespace base { - -// Detect encoding of |text| and put the name of encoding (as returned by ICU) -// in |encoding|. For ASCII texts |encoding| will be set to an empty string. -// Returns true on success. -BASE_I18N_EXPORT bool DetectEncoding(const std::string& text, - std::string* encoding); - -// Detect all possible encodings of |text| and put their names -// (as returned by ICU) in |encodings|. Returns true on success. -// Note: this function may return encodings that may fail to decode |text|, -// the caller is responsible for handling that. -BASE_I18N_EXPORT bool DetectAllEncodings(const std::string& text, - std::vector<std::string>* encodings); - -} // namespace base - -#endif // BASE_I18N_ICU_ENCODING_DETECTION_H_
diff --git a/base/optional.h b/base/optional.h index b468964..98cd9585 100644 --- a/base/optional.h +++ b/base/optional.h
@@ -163,6 +163,8 @@ constexpr explicit operator bool() const { return !storage_.is_null_; } + constexpr bool has_value() const { return !storage_.is_null_; } + // TODO(mlamouri): using 'constexpr' here breaks compiler that assume it was // meant to be 'constexpr const'. T& value() & { @@ -231,6 +233,10 @@ swap(**this, *other); } + void reset() { + FreeIfNeeded(); + } + template <class... Args> void emplace(Args&&... args) { FreeIfNeeded();
diff --git a/base/optional_unittest.cc b/base/optional_unittest.cc index d6bf263..565b6cd6 100644 --- a/base/optional_unittest.cc +++ b/base/optional_unittest.cc
@@ -1298,4 +1298,49 @@ EXPECT_NE(setOptInt.end(), setOptInt.find(3)); } +TEST(OptionalTest, HasValue) { + Optional<int> a; + EXPECT_FALSE(a.has_value()); + + a = 42; + EXPECT_TRUE(a.has_value()); + + a = nullopt; + EXPECT_FALSE(a.has_value()); + + a = 0; + EXPECT_TRUE(a.has_value()); + + a = Optional<int>(); + EXPECT_FALSE(a.has_value()); +} + +TEST(OptionalTest, Reset_int) { + Optional<int> a(0); + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(0, a.value()); + + a.reset(); + EXPECT_FALSE(a.has_value()); + EXPECT_EQ(-1, a.value_or(-1)); +} + +TEST(OptionalTest, Reset_Object) { + Optional<TestObject> a(TestObject(0, 0.1)); + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(TestObject(0, 0.1), a.value()); + + a.reset(); + EXPECT_FALSE(a.has_value()); + EXPECT_EQ(TestObject(42, 0.0), a.value_or(TestObject(42, 0.0))); +} + +TEST(OptionalTest, Reset_NoOp) { + Optional<int> a; + EXPECT_FALSE(a.has_value()); + + a.reset(); + EXPECT_FALSE(a.has_value()); +} + } // namespace base
diff --git a/base/sequence_token.cc b/base/sequence_token.cc index 153d180..1178181 100644 --- a/base/sequence_token.cc +++ b/base/sequence_token.cc
@@ -15,13 +15,18 @@ base::StaticAtomicSequenceNumber g_sequence_token_generator; -LazyInstance<ThreadLocalPointer<ScopedSetSequenceTokenForCurrentThread>>::Leaky +base::StaticAtomicSequenceNumber g_task_token_generator; + +LazyInstance<ThreadLocalPointer<const SequenceToken>>::Leaky tls_current_sequence_token = LAZY_INSTANCE_INITIALIZER; +LazyInstance<ThreadLocalPointer<const TaskToken>>::Leaky + tls_current_task_token = LAZY_INSTANCE_INITIALIZER; + } // namespace bool SequenceToken::operator==(const SequenceToken& other) const { - return token_ == other.token_ && token_ != kInvalidSequenceToken; + return token_ == other.token_ && IsValid(); } bool SequenceToken::operator!=(const SequenceToken& other) const { @@ -37,23 +42,47 @@ } SequenceToken SequenceToken::GetForCurrentThread() { - const ScopedSetSequenceTokenForCurrentThread* current_sequence_token = + const SequenceToken* current_sequence_token = tls_current_sequence_token.Get().Get(); - return current_sequence_token ? current_sequence_token->token_ - : SequenceToken(); + return current_sequence_token ? *current_sequence_token : SequenceToken(); +} + +bool TaskToken::operator==(const TaskToken& other) const { + return token_ == other.token_ && IsValid(); +} + +bool TaskToken::operator!=(const TaskToken& other) const { + return !(*this == other); +} + +bool TaskToken::IsValid() const { + return token_ != kInvalidTaskToken; +} + +TaskToken TaskToken::Create() { + return TaskToken(g_task_token_generator.GetNext()); +} + +TaskToken TaskToken::GetForCurrentThread() { + const TaskToken* current_task_token = tls_current_task_token.Get().Get(); + return current_task_token ? *current_task_token : TaskToken(); } ScopedSetSequenceTokenForCurrentThread::ScopedSetSequenceTokenForCurrentThread( - const SequenceToken& token) - : token_(token) { + const SequenceToken& sequence_token) + : sequence_token_(sequence_token), task_token_(TaskToken::Create()) { DCHECK(!tls_current_sequence_token.Get().Get()); - tls_current_sequence_token.Get().Set(this); + DCHECK(!tls_current_task_token.Get().Get()); + tls_current_sequence_token.Get().Set(&sequence_token_); + tls_current_task_token.Get().Set(&task_token_); } ScopedSetSequenceTokenForCurrentThread:: ~ScopedSetSequenceTokenForCurrentThread() { - DCHECK_EQ(tls_current_sequence_token.Get().Get(), this); + DCHECK_EQ(tls_current_sequence_token.Get().Get(), &sequence_token_); + DCHECK_EQ(tls_current_task_token.Get().Get(), &task_token_); tls_current_sequence_token.Get().Set(nullptr); + tls_current_task_token.Get().Set(nullptr); } } // namespace base
diff --git a/base/sequence_token.h b/base/sequence_token.h index 8d1398ea..80340c0 100644 --- a/base/sequence_token.h +++ b/base/sequence_token.h
@@ -39,23 +39,69 @@ static SequenceToken GetForCurrentThread(); private: - SequenceToken(int token) : token_(token) {} + explicit SequenceToken(int token) : token_(token) {} static constexpr int kInvalidSequenceToken = -1; int token_ = kInvalidSequenceToken; }; -// Throughout its lifetime, determines the value returned by -// SequenceToken::GetForCurrentThread(). +// A token that identifies a task. +// +// This is used by ThreadCheckerImpl to determine whether calls to +// CalledOnValidThread() come from the same task and hence are deterministically +// single-threaded (vs. calls coming from different sequenced or parallel tasks, +// which may or may not run on the same thread). +class BASE_EXPORT TaskToken { + public: + // Instantiates an invalid TaskToken. + TaskToken() = default; + + // Explicitly allow copy. + TaskToken(const TaskToken& other) = default; + TaskToken& operator=(const TaskToken& other) = default; + + // An invalid TaskToken is not equal to any other TaskToken, including + // other invalid TaskTokens. + bool operator==(const TaskToken& other) const; + bool operator!=(const TaskToken& other) const; + + // Returns true if this is a valid TaskToken. + bool IsValid() const; + + // In the scope of a ScopedSetSequenceTokenForCurrentThread, returns a valid + // TaskToken which isn't equal to any TaskToken returned in the scope of a + // different ScopedSetSequenceTokenForCurrentThread. Otherwise, returns an + // invalid TaskToken. + static TaskToken GetForCurrentThread(); + + private: + friend class ScopedSetSequenceTokenForCurrentThread; + + explicit TaskToken(int token) : token_(token) {} + + // Returns a valid TaskToken which isn't equal to any previously returned + // TaskToken. This is private as it only meant to be instantiated by + // ScopedSetSequenceTokenForCurrentThread. + static TaskToken Create(); + + static constexpr int kInvalidTaskToken = -1; + int token_ = kInvalidTaskToken; +}; + +// Instantiate this in the scope where a single task runs. class BASE_EXPORT ScopedSetSequenceTokenForCurrentThread { public: - ScopedSetSequenceTokenForCurrentThread(const SequenceToken& token); + // Throughout the lifetime of the constructed object, + // SequenceToken::GetForCurrentThread() will return |sequence_token| and + // TaskToken::GetForCurrentThread() will return a TaskToken which is not equal + // to any TaskToken returned in the scope of another + // ScopedSetSequenceTokenForCurrentThread. + ScopedSetSequenceTokenForCurrentThread(const SequenceToken& sequence_token); ~ScopedSetSequenceTokenForCurrentThread(); private: - friend class SequenceToken; - - const SequenceToken token_; + const SequenceToken sequence_token_; + const TaskToken task_token_; DISALLOW_COPY_AND_ASSIGN(ScopedSetSequenceTokenForCurrentThread); };
diff --git a/base/sequence_token_unittest.cc b/base/sequence_token_unittest.cc index ff8725e..23e6283e 100644 --- a/base/sequence_token_unittest.cc +++ b/base/sequence_token_unittest.cc
@@ -62,4 +62,64 @@ EXPECT_FALSE(SequenceToken::GetForCurrentThread().IsValid()); } +// Expect a default-constructed TaskToken to be invalid and not equal to +// another invalid TaskToken. +TEST(TaskTokenTest, InvalidDefaultConstructed) { + EXPECT_FALSE(TaskToken().IsValid()); + EXPECT_NE(TaskToken(), TaskToken()); +} + +// Expect a TaskToken returned by TaskToken::GetForCurrentThread() outside the +// scope of a ScopedSetSequenceTokenForCurrentThread to be invalid. +TEST(TaskTokenTest, InvalidOutsideScope) { + EXPECT_FALSE(TaskToken::GetForCurrentThread().IsValid()); +} + +// Expect an invalid TaskToken not to be equal with a valid TaskToken. +TEST(TaskTokenTest, ValidNotEqualsInvalid) { + ScopedSetSequenceTokenForCurrentThread + scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); + TaskToken valid = TaskToken::GetForCurrentThread(); + TaskToken invalid; + EXPECT_NE(valid, invalid); +} + +// Expect TaskTokens returned by TaskToken::GetForCurrentThread() in the scope +// of the same ScopedSetSequenceTokenForCurrentThread instance to be +// valid and equal with each other. +TEST(TaskTokenTest, EqualInSameScope) { + ScopedSetSequenceTokenForCurrentThread + scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); + + const TaskToken token_a = TaskToken::GetForCurrentThread(); + const TaskToken token_b = TaskToken::GetForCurrentThread(); + + EXPECT_TRUE(token_a.IsValid()); + EXPECT_TRUE(token_b.IsValid()); + EXPECT_EQ(token_a, token_b); +} + +// Expect TaskTokens returned by TaskToken::GetForCurrentThread() in the scope +// of different ScopedSetSequenceTokenForCurrentThread instances to be +// valid but not equal to each other. +TEST(TaskTokenTest, NotEqualInDifferentScopes) { + TaskToken token_a; + TaskToken token_b; + + { + ScopedSetSequenceTokenForCurrentThread + scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); + token_a = TaskToken::GetForCurrentThread(); + } + { + ScopedSetSequenceTokenForCurrentThread + scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); + token_b = TaskToken::GetForCurrentThread(); + } + + EXPECT_TRUE(token_a.IsValid()); + EXPECT_TRUE(token_b.IsValid()); + EXPECT_NE(token_a, token_b); +} + } // namespace base
diff --git a/base/stl_util.h b/base/stl_util.h index 12e226a..8882ac9 100644 --- a/base/stl_util.h +++ b/base/stl_util.h
@@ -15,6 +15,8 @@ #include "base/logging.h" +namespace base { + // Clears internal memory of an STL object. // STL clear()/reserve(0) does not always free internal memory allocated // This function uses swap/destructor to ensure the internal memory is freed. @@ -198,8 +200,6 @@ collection.end(); } -namespace base { - // Returns true if the container is sorted. template <typename Container> bool STLIsSorted(const Container& cont) { @@ -259,4 +259,20 @@ } // namespace base +// TODO(skyostil): Remove these global aliases once all call sites have been +// fixed. +using base::ContainsKey; +using base::ContainsValue; +using base::STLClearObject; +using base::STLCount; +using base::STLDeleteContainerPairFirstPointers; +using base::STLDeleteContainerPairPointers; +using base::STLDeleteContainerPairSecondPointers; +using base::STLDeleteContainerPointers; +using base::STLDeleteElements; +using base::STLDeleteValues; +using base::STLElementDeleter; +using base::STLValueDeleter; +using base::string_as_array; + #endif // BASE_STL_UTIL_H_
diff --git a/base/task_scheduler/switches.cc b/base/task_scheduler/switches.cc new file mode 100644 index 0000000..4dd3bbc --- /dev/null +++ b/base/task_scheduler/switches.cc
@@ -0,0 +1,12 @@ +// 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 "base/task_scheduler/switches.h" + +namespace switches { + +const char kDisableBrowserTaskScheduler[] = "disable-browser-task-scheduler"; +const char kEnableBrowserTaskScheduler[] = "enable-browser-task-scheduler"; + +} // namespace switches
diff --git a/base/task_scheduler/switches.h b/base/task_scheduler/switches.h new file mode 100644 index 0000000..967c726 --- /dev/null +++ b/base/task_scheduler/switches.h
@@ -0,0 +1,15 @@ +// 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 BASE_TASK_SCHEDULER_SWITCHES_H_ +#define BASE_TASK_SCHEDULER_SWITCHES_H_ + +namespace switches { + +extern const char kDisableBrowserTaskScheduler[]; +extern const char kEnableBrowserTaskScheduler[]; + +} // namespace switches + +#endif // BASE_TASK_SCHEDULER_SWITCHES_H_
diff --git a/base/task_scheduler/task_tracker_unittest.cc b/base/task_scheduler/task_tracker_unittest.cc index bbfff42..fedb215 100644 --- a/base/task_scheduler/task_tracker_unittest.cc +++ b/base/task_scheduler/task_tracker_unittest.cc
@@ -382,13 +382,11 @@ tracker.RunNextTaskInSequence( CreateSequenceWithTask(std::move(task)).get()); } else { -#if !defined(OS_LINUX) // http://crbug.com/634552 EXPECT_DCHECK_DEATH( { tracker.RunNextTaskInSequence( CreateSequenceWithTask(std::move(task)).get()); }); -#endif // !defined(OS_LINUX) } }
diff --git a/base/threading/thread_checker.h b/base/threading/thread_checker.h index 5b64880..1d4eb1c 100644 --- a/base/threading/thread_checker.h +++ b/base/threading/thread_checker.h
@@ -57,9 +57,7 @@ // tasks posted to SingleThreadTaskRunners bound to different sequences, even if // the tasks happen to run on the same thread (e.g. two independent TaskRunners // with ExecutionMode::SINGLE_THREADED on the TaskScheduler that happen to share -// a thread). Also, CalledOnValidThread() returns false when called from a non- -// single-threaded task which is associated with a SequenceToken (e.g. a task -// posted with ExecutionMode::SEQUENCED to the TaskScheduler). +// a thread). // // In Release mode, CalledOnValidThread will always return true. #if DCHECK_IS_ON()
diff --git a/base/threading/thread_checker_impl.cc b/base/threading/thread_checker_impl.cc index 11c2b95..d5ccbdb 100644 --- a/base/threading/thread_checker_impl.cc +++ b/base/threading/thread_checker_impl.cc
@@ -19,6 +19,11 @@ AutoLock auto_lock(lock_); EnsureAssigned(); + // Always return true when called from the task from which this + // ThreadCheckerImpl was assigned to a thread. + if (task_token_ == TaskToken::GetForCurrentThread()) + return true; + // If this ThreadCheckerImpl is bound to a valid SequenceToken, it must be // equal to the current SequenceToken and there must be a registered // ThreadTaskRunnerHandle. Otherwise, the fact that the current task runs on @@ -35,6 +40,7 @@ void ThreadCheckerImpl::DetachFromThread() { AutoLock auto_lock(lock_); thread_id_ = PlatformThreadRef(); + task_token_ = TaskToken(); sequence_token_ = SequenceToken(); } @@ -44,6 +50,7 @@ return; thread_id_ = PlatformThread::CurrentRef(); + task_token_ = TaskToken::GetForCurrentThread(); sequence_token_ = SequenceToken::GetForCurrentThread(); }
diff --git a/base/threading/thread_checker_impl.h b/base/threading/thread_checker_impl.h index 3e46316b..13193d12 100644 --- a/base/threading/thread_checker_impl.h +++ b/base/threading/thread_checker_impl.h
@@ -42,6 +42,14 @@ // Thread on which CalledOnValidThread() may return true. mutable PlatformThreadRef thread_id_; + // TaskToken for which CalledOnValidThread() always returns true. This allows + // CalledOnValidThread() to return true when called multiple times from the + // same task, even if it's not running in a single-threaded context itself + // (allowing usage of ThreadChecker/NonThreadSafe objects on the stack in the + // scope of one-off tasks). Note: CalledOnValidThread() may return true even + // if the current TaskToken is not equal to this. + mutable TaskToken task_token_; + // SequenceToken for which CalledOnValidThread() may return true. Used to // ensure that CalledOnValidThread() doesn't return true for TaskScheduler // tasks that happen to run on the same thread but weren't posted to the same
diff --git a/base/threading/thread_checker_unittest.cc b/base/threading/thread_checker_unittest.cc index d806c0c75..96455e6 100644 --- a/base/threading/thread_checker_unittest.cc +++ b/base/threading/thread_checker_unittest.cc
@@ -69,15 +69,34 @@ } // namespace -TEST(ThreadCheckerTest, CallsAllowedSameThreadNoSequenceToken) { +TEST(ThreadCheckerTest, AllowedSameThreadNoSequenceToken) { ThreadCheckerImpl thread_checker; EXPECT_TRUE(thread_checker.CalledOnValidThread()); } TEST(ThreadCheckerTest, - CallsAllowedSameThreadSameSequenceTokenWithThreadTaskRunnerHandle) { + AllowedSameThreadAndSequenceDifferentTasksWithThreadTaskRunnerHandle) { ThreadTaskRunnerHandle thread_task_runner_handle( make_scoped_refptr(new TestSimpleTaskRunner)); + + std::unique_ptr<ThreadCheckerImpl> thread_checker; + const SequenceToken sequence_token = SequenceToken::Create(); + + { + ScopedSetSequenceTokenForCurrentThread + scoped_set_sequence_token_for_current_thread(sequence_token); + thread_checker.reset(new ThreadCheckerImpl); + } + + { + ScopedSetSequenceTokenForCurrentThread + scoped_set_sequence_token_for_current_thread(sequence_token); + EXPECT_TRUE(thread_checker->CalledOnValidThread()); + } +} + +TEST(ThreadCheckerTest, + AllowedSameThreadSequenceAndTaskNoThreadTaskRunnerHandle) { ScopedSetSequenceTokenForCurrentThread scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); ThreadCheckerImpl thread_checker; @@ -85,20 +104,29 @@ } TEST(ThreadCheckerTest, - CallsDisallowedSameThreadSameSequenceTokenNoThreadTaskRunnerHandle) { - ScopedSetSequenceTokenForCurrentThread - scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); - ThreadCheckerImpl thread_checker; - EXPECT_FALSE(thread_checker.CalledOnValidThread()); + DisallowedSameThreadAndSequenceDifferentTasksNoThreadTaskRunnerHandle) { + std::unique_ptr<ThreadCheckerImpl> thread_checker; + + { + ScopedSetSequenceTokenForCurrentThread + scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); + thread_checker.reset(new ThreadCheckerImpl); + } + + { + ScopedSetSequenceTokenForCurrentThread + scoped_set_sequence_token_for_current_thread(SequenceToken::Create()); + EXPECT_FALSE(thread_checker->CalledOnValidThread()); + } } -TEST(ThreadCheckerTest, CallsDisallowedOnDifferentThreadsNoSequenceToken) { +TEST(ThreadCheckerTest, DisallowedDifferentThreadsNoSequenceToken) { ThreadCheckerImpl thread_checker; RunCallbackOnNewThreadSynchronously( Bind(&ExpectNotCalledOnValidThread, Unretained(&thread_checker))); } -TEST(ThreadCheckerTest, CallsDisallowedOnDifferentThreadsSameSequenceToken) { +TEST(ThreadCheckerTest, DisallowedDifferentThreadsSameSequence) { ThreadTaskRunnerHandle thread_task_runner_handle( make_scoped_refptr(new TestSimpleTaskRunner)); const SequenceToken sequence_token(SequenceToken::Create()); @@ -113,7 +141,7 @@ Unretained(&thread_checker), sequence_token)); } -TEST(ThreadCheckerTest, CallsDisallowedSameThreadDifferentSequenceToken) { +TEST(ThreadCheckerTest, DisallowedSameThreadDifferentSequence) { std::unique_ptr<ThreadCheckerImpl> thread_checker; ThreadTaskRunnerHandle thread_task_runner_handle(
diff --git a/blimp/client/BUILD.gn b/blimp/client/BUILD.gn index 093c711..52e0fd9 100644 --- a/blimp/client/BUILD.gn +++ b/blimp/client/BUILD.gn
@@ -91,14 +91,14 @@ source_set("feature") { sources = [ + "core/contents/tab_control_feature.cc", + "core/contents/tab_control_feature.h", "feature/ime_feature.cc", "feature/ime_feature.h", "feature/render_widget_feature.cc", "feature/render_widget_feature.h", "feature/settings_feature.cc", "feature/settings_feature.h", - "feature/tab_control_feature.cc", - "feature/tab_control_feature.h", ] deps = [ @@ -193,9 +193,9 @@ testonly = true sources = [ + "core/contents/tab_control_feature_unittest.cc", "feature/compositor/blimp_compositor_manager_unittest.cc", "feature/render_widget_feature_unittest.cc", - "feature/tab_control_feature_unittest.cc", ] deps = [ @@ -390,8 +390,6 @@ "app/android/java/src/org/chromium/blimp/toolbar/ToolbarMenu.java", "app/android/java/src/org/chromium/blimp/toolbar/UrlBar.java", ] - - srcjar_deps = [ "//blimp/client/core/session:java_enums_srcjar" ] } android_library("blimp_test_java") {
diff --git a/blimp/client/app/android/blimp_client_session_android.cc b/blimp/client/app/android/blimp_client_session_android.cc index 4f9e410..18e0f554 100644 --- a/blimp/client/app/android/blimp_client_session_android.cc +++ b/blimp/client/app/android/blimp_client_session_android.cc
@@ -10,9 +10,9 @@ #include "base/android/scoped_java_ref.h" #include "base/threading/thread_task_runner_handle.h" #include "blimp/client/app/user_agent.h" +#include "blimp/client/core/contents/tab_control_feature.h" #include "blimp/client/core/session/assignment_source.h" #include "blimp/client/feature/settings_feature.h" -#include "blimp/client/feature/tab_control_feature.h" #include "components/version_info/version_info.h" #include "jni/BlimpClientSession_jni.h" #include "net/base/net_errors.h" @@ -102,7 +102,7 @@ } void BlimpClientSessionAndroid::OnAssignmentConnectionAttempted( - AssignmentSource::Result result, + AssignmentRequestResult result, const Assignment& assignment) { // Notify the front end of the assignment result. std::string engine_ip = IPAddressToStringWithPort(
diff --git a/blimp/client/app/android/blimp_client_session_android.h b/blimp/client/app/android/blimp_client_session_android.h index 38d14f5..77f12f5 100644 --- a/blimp/client/app/android/blimp_client_session_android.h +++ b/blimp/client/app/android/blimp_client_session_android.h
@@ -8,6 +8,7 @@ #include "base/android/jni_android.h" #include "base/android/jni_array.h" #include "base/macros.h" +#include "blimp/client/public/session/assignment.h" #include "blimp/client/session/blimp_client_session.h" namespace blimp { @@ -44,7 +45,7 @@ ~BlimpClientSessionAndroid() override; // BlimpClientSession implementation. - void OnAssignmentConnectionAttempted(AssignmentSource::Result result, + void OnAssignmentConnectionAttempted(AssignmentRequestResult result, const Assignment& assignment) override; // NetworkEventObserver implementation.
diff --git a/blimp/client/app/android/java/src/org/chromium/blimp/session/BlimpClientSession.java b/blimp/client/app/android/java/src/org/chromium/blimp/session/BlimpClientSession.java index 7ac9ba7..d719956 100644 --- a/blimp/client/app/android/java/src/org/chromium/blimp/session/BlimpClientSession.java +++ b/blimp/client/app/android/java/src/org/chromium/blimp/session/BlimpClientSession.java
@@ -7,7 +7,7 @@ import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; import org.chromium.blimp.R; -import org.chromium.blimp.core.session.assignment.Result; +import org.chromium.blimp_public.session.AssignmentRequestResult; import java.util.ArrayList; import java.util.List; @@ -109,37 +109,37 @@ int resultMessageResourceId = R.string.assignment_failure_unknown; switch (result) { - case Result.OK: + case AssignmentRequestResult.OK: resultMessageResourceId = R.string.assignment_success; break; - case Result.BAD_REQUEST: + case AssignmentRequestResult.BAD_REQUEST: resultMessageResourceId = R.string.assignment_failure_bad_request; break; - case Result.BAD_RESPONSE: + case AssignmentRequestResult.BAD_RESPONSE: resultMessageResourceId = R.string.assignment_failure_bad_response; break; - case Result.INVALID_PROTOCOL_VERSION: + case AssignmentRequestResult.INVALID_PROTOCOL_VERSION: resultMessageResourceId = R.string.assignment_failure_bad_version; break; - case Result.EXPIRED_ACCESS_TOKEN: + case AssignmentRequestResult.EXPIRED_ACCESS_TOKEN: resultMessageResourceId = R.string.assignment_failure_expired_token; break; - case Result.USER_INVALID: + case AssignmentRequestResult.USER_INVALID: resultMessageResourceId = R.string.assignment_failure_user_invalid; break; - case Result.OUT_OF_VMS: + case AssignmentRequestResult.OUT_OF_VMS: resultMessageResourceId = R.string.assignment_failure_out_of_vms; break; - case Result.SERVER_ERROR: + case AssignmentRequestResult.SERVER_ERROR: resultMessageResourceId = R.string.assignment_failure_server_error; break; - case Result.SERVER_INTERRUPTED: + case AssignmentRequestResult.SERVER_INTERRUPTED: resultMessageResourceId = R.string.assignment_failure_server_interrupted; break; - case Result.NETWORK_FAILURE: + case AssignmentRequestResult.NETWORK_FAILURE: resultMessageResourceId = R.string.assignment_failure_network; break; - case Result.UNKNOWN: + case AssignmentRequestResult.UNKNOWN: default: resultMessageResourceId = R.string.assignment_failure_unknown; break;
diff --git a/blimp/client/app/android/tab_control_feature_android.cc b/blimp/client/app/android/tab_control_feature_android.cc index c19c25f..4266a2a 100644 --- a/blimp/client/app/android/tab_control_feature_android.cc +++ b/blimp/client/app/android/tab_control_feature_android.cc
@@ -5,7 +5,7 @@ #include "blimp/client/app/android/tab_control_feature_android.h" #include "blimp/client/app/android/blimp_client_session_android.h" -#include "blimp/client/feature/tab_control_feature.h" +#include "blimp/client/core/contents/tab_control_feature.h" #include "jni/TabControlFeature_jni.h" #include "ui/gfx/geometry/size.h"
diff --git a/blimp/client/app/linux/blimp_display_manager.cc b/blimp/client/app/linux/blimp_display_manager.cc index 6550ac8..e6f9f85 100644 --- a/blimp/client/app/linux/blimp_display_manager.cc +++ b/blimp/client/app/linux/blimp_display_manager.cc
@@ -4,8 +4,8 @@ #include "blimp/client/app/linux/blimp_display_manager.h" +#include "blimp/client/core/contents/tab_control_feature.h" #include "blimp/client/feature/render_widget_feature.h" -#include "blimp/client/feature/tab_control_feature.h" #include "ui/events/event.h" #include "ui/gfx/geometry/size.h" #include "ui/platform_window/platform_window.h"
diff --git a/blimp/client/app/linux/blimp_main.cc b/blimp/client/app/linux/blimp_main.cc index 8245eceb..37c7c95 100644 --- a/blimp/client/app/linux/blimp_main.cc +++ b/blimp/client/app/linux/blimp_main.cc
@@ -12,8 +12,8 @@ #include "blimp/client/app/blimp_startup.h" #include "blimp/client/app/linux/blimp_client_session_linux.h" #include "blimp/client/core/contents/navigation_feature.h" +#include "blimp/client/core/contents/tab_control_feature.h" #include "blimp/client/core/session/assignment_source.h" -#include "blimp/client/feature/tab_control_feature.h" #include "ui/gfx/x/x11_connection.h" namespace {
diff --git a/blimp/client/core/BUILD.gn b/blimp/client/core/BUILD.gn index 94a51ae..dc2a174 100644 --- a/blimp/client/core/BUILD.gn +++ b/blimp/client/core/BUILD.gn
@@ -93,6 +93,7 @@ "//blimp/client/core/contents", "//blimp/client/core/session", "//blimp/client/public:public_headers", + "//url", ] if (is_android) { @@ -184,7 +185,10 @@ android_library("settings_java") { visibility = [ "//blimp/client/*" ] - java_files = [ "android/java/src/org/chromium/blimp/core/settings/AboutBlimpPreferences.java" ] + java_files = [ + "android/java/src/org/chromium/blimp/core/settings/AboutBlimpPreferences.java", + "android/java/src/org/chromium/blimp/core/settings/PreferencesUtil.java", + ] # TODO(xingliu): Remove android support v7 dependency and move android resources to Chrome # after Blimp merge to Chrome.
diff --git a/blimp/client/core/android/blimp_client_context_impl_android.cc b/blimp/client/core/android/blimp_client_context_impl_android.cc index 24ec524..3eb10d66 100644 --- a/blimp/client/core/android/blimp_client_context_impl_android.cc +++ b/blimp/client/core/android/blimp_client_context_impl_android.cc
@@ -5,6 +5,7 @@ #include "blimp/client/core/android/blimp_client_context_impl_android.h" #include "base/android/jni_android.h" +#include "base/android/jni_string.h" #include "base/android/scoped_java_ref.h" #include "blimp/client/core/contents/blimp_contents_impl.h" #include "blimp/client/public/blimp_client_context.h" @@ -39,8 +40,9 @@ } BlimpClientContextImplAndroid::BlimpClientContextImplAndroid( - scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner) - : BlimpClientContextImpl(io_thread_task_runner) { + scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner) + : BlimpClientContextImpl(io_thread_task_runner, file_thread_task_runner) { JNIEnv* env = base::android::AttachCurrentThread(); java_obj_.Reset(env, Java_BlimpClientContextImpl_create( @@ -69,5 +71,14 @@ return blimp_contents_impl->GetJavaBlimpContentsImpl(); } +GURL BlimpClientContextImplAndroid::GetAssignerURL() { + JNIEnv* env = base::android::AttachCurrentThread(); + base::android::ScopedJavaLocalRef<jstring> jurl = + Java_BlimpClientContextImpl_getAssignerUrl(env, java_obj_.obj()); + GURL assigner_url = GURL(ConvertJavaStringToUTF8(env, jurl)); + DCHECK(assigner_url.is_valid()); + return assigner_url; +} + } // namespace client } // namespace blimp
diff --git a/blimp/client/core/android/blimp_client_context_impl_android.h b/blimp/client/core/android/blimp_client_context_impl_android.h index e3cf8d4..eb4a3b5 100644 --- a/blimp/client/core/android/blimp_client_context_impl_android.h +++ b/blimp/client/core/android/blimp_client_context_impl_android.h
@@ -21,8 +21,11 @@ // The |io_thread_task_runner| must be the task runner to use for IO // operations. + // The |file_thread_task_runner| must be the task runner to use for file + // operations. explicit BlimpClientContextImplAndroid( - scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner); + scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner); ~BlimpClientContextImplAndroid() override; base::android::ScopedJavaLocalRef<jobject> GetJavaObject(); @@ -31,6 +34,10 @@ JNIEnv* env, jobject jobj); + protected: + // BlimpClientContextImpl implementation. + GURL GetAssignerURL() override; + private: base::android::ScopedJavaGlobalRef<jobject> java_obj_;
diff --git a/blimp/client/core/android/java/src/org/chromium/blimp/core/BlimpClientContextImpl.java b/blimp/client/core/android/java/src/org/chromium/blimp/core/BlimpClientContextImpl.java index a71d95be..29f17a3 100644 --- a/blimp/client/core/android/java/src/org/chromium/blimp/core/BlimpClientContextImpl.java +++ b/blimp/client/core/android/java/src/org/chromium/blimp/core/BlimpClientContextImpl.java
@@ -9,6 +9,7 @@ import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; import org.chromium.blimp.core.settings.AboutBlimpPreferences; +import org.chromium.blimp.core.settings.PreferencesUtil; import org.chromium.blimp_public.BlimpClientContext; import org.chromium.blimp_public.BlimpClientContextDelegate; import org.chromium.blimp_public.BlimpSettingsCallbacks; @@ -83,6 +84,11 @@ return mNativeBlimpClientContextImplAndroid; } + @CalledByNative + private String getAssignerUrl() { + return PreferencesUtil.getLastUsedAssigner(); + } + private native BlimpContents nativeCreateBlimpContentsJava( long nativeBlimpClientContextImplAndroid); }
diff --git a/blimp/client/core/blimp_client_context_impl.cc b/blimp/client/core/blimp_client_context_impl.cc index 076fc78f..289602a 100644 --- a/blimp/client/core/blimp_client_context_impl.cc +++ b/blimp/client/core/blimp_client_context_impl.cc
@@ -9,6 +9,7 @@ #include "base/message_loop/message_loop.h" #include "base/threading/sequenced_task_runner_handle.h" #include "blimp/client/core/contents/blimp_contents_impl.h" +#include "blimp/client/core/contents/blimp_contents_manager.h" #include "blimp/client/core/session/cross_thread_network_event_observer.h" #include "blimp/client/public/blimp_client_context_delegate.h" @@ -19,24 +20,35 @@ namespace blimp { namespace client { +namespace { +const char kDefaultAssignerUrl[] = + "https://blimp-pa.googleapis.com/v1/assignment"; +} // namespace + // This function is declared in //blimp/client/public/blimp_client_context.h, // and either this function or the one in // //blimp/client/core/dummy_blimp_client_context.cc should be linked in to // any binary using BlimpClientContext::Create. // static BlimpClientContext* BlimpClientContext::Create( - scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner) { + scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner) { #if defined(OS_ANDROID) - return new BlimpClientContextImplAndroid(io_thread_task_runner); + return new BlimpClientContextImplAndroid(io_thread_task_runner, + file_thread_task_runner); #else - return new BlimpClientContextImpl(io_thread_task_runner); + return new BlimpClientContextImpl(io_thread_task_runner, + file_thread_task_runner); #endif // defined(OS_ANDROID) } BlimpClientContextImpl::BlimpClientContextImpl( - scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner) + scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner) : BlimpClientContext(), io_thread_task_runner_(io_thread_task_runner), + file_thread_task_runner_(file_thread_task_runner), + blimp_contents_manager_(new BlimpContentsManager), weak_factory_(this) { blimp_connection_statistics_ = new BlimpConnectionStatistics(); net_components_.reset(new ClientNetworkComponents( @@ -66,14 +78,51 @@ std::unique_ptr<BlimpContents> BlimpClientContextImpl::CreateBlimpContents() { std::unique_ptr<BlimpContents> blimp_contents = - base::MakeUnique<BlimpContentsImpl>(); + blimp_contents_manager_->CreateBlimpContents(); delegate_->AttachBlimpContentsHelpers(blimp_contents.get()); return blimp_contents; } +void BlimpClientContextImpl::Connect(const std::string& client_auth_token) { + if (!assignment_source_) { + assignment_source_.reset(new AssignmentSource( + GetAssignerURL(), io_thread_task_runner_, file_thread_task_runner_)); + } + + VLOG(1) << "Trying to get assignment."; + assignment_source_->GetAssignment( + client_auth_token, + base::Bind(&BlimpClientContextImpl::ConnectWithAssignment, + weak_factory_.GetWeakPtr())); +} + void BlimpClientContextImpl::OnConnected() {} void BlimpClientContextImpl::OnDisconnected(int result) {} +GURL BlimpClientContextImpl::GetAssignerURL() { + return GURL(kDefaultAssignerUrl); +} + +void BlimpClientContextImpl::ConnectWithAssignment( + AssignmentRequestResult result, + const Assignment& assignment) { + VLOG(1) << "Assignment result: " << result; + + if (delegate_) { + delegate_->OnAssignmentConnectionAttempted(result, assignment); + } + + if (result != ASSIGNMENT_REQUEST_RESULT_OK) { + LOG(ERROR) << "Assignment failed, reason: " << result; + return; + } + + io_thread_task_runner_->PostTask( + FROM_HERE, + base::Bind(&ClientNetworkComponents::ConnectWithAssignment, + base::Unretained(net_components_.get()), assignment)); +} + } // namespace client } // namespace blimp
diff --git a/blimp/client/core/blimp_client_context_impl.h b/blimp/client/core/blimp_client_context_impl.h index e108782..dfc184b 100644 --- a/blimp/client/core/blimp_client_context_impl.h +++ b/blimp/client/core/blimp_client_context_impl.h
@@ -16,12 +16,16 @@ #include "blimp/client/core/session/network_event_observer.h" #include "blimp/client/public/blimp_client_context.h" #include "blimp/client/public/contents/blimp_contents.h" +#include "blimp/client/public/session/assignment.h" #include "blimp/net/blimp_connection_statistics.h" #include "blimp/net/thread_pipe_manager.h" +#include "url/gurl.h" namespace blimp { namespace client { +class BlimpContentsManager; + // BlimpClientContextImpl is the implementation of the main context-class for // the blimp client. class BlimpClientContextImpl : public BlimpClientContext, @@ -29,29 +33,52 @@ public: // The |io_thread_task_runner| must be the task runner to use for IO // operations. - explicit BlimpClientContextImpl( - scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner); + // The |file_thread_task_runner| must be the task runner to use for file + // operations. + BlimpClientContextImpl( + scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner); ~BlimpClientContextImpl() override; // BlimpClientContext implementation. void SetDelegate(BlimpClientContextDelegate* delegate) override; std::unique_ptr<BlimpContents> CreateBlimpContents() override; + void Connect(const std::string& client_auth_token) override; // NetworkEventObserver implementation. void OnConnected() override; void OnDisconnected(int result) override; + protected: + // Returns the URL to use for connections to the assigner. Used to construct + // the AssignmentSource. + virtual GURL GetAssignerURL(); + private: + // The AssignmentCallback for when an assignment is ready. This will trigger + // a connection to the engine. + virtual void ConnectWithAssignment(AssignmentRequestResult result, + const Assignment& assignment); + // Provides functionality from the embedder. - BlimpClientContextDelegate* delegate_; + BlimpClientContextDelegate* delegate_ = nullptr; // The task runner to use for IO operations. scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner_; + // The task runner to use for file operations. + scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner_; + + // The AssignmentSource is used when the user of BlimpClientContextImpl calls + // Connect() to get a valid assignment and later connect to the engine. + std::unique_ptr<AssignmentSource> assignment_source_; + // Collects details of network, such as number of commits and bytes // transferred over network. Owned by ClientNetworkComponents. BlimpConnectionStatistics* blimp_connection_statistics_; + std::unique_ptr<BlimpContentsManager> blimp_contents_manager_; + // Container struct for network components. // Must be deleted on the IO thread. std::unique_ptr<ClientNetworkComponents> net_components_;
diff --git a/blimp/client/core/blimp_client_context_impl_unittest.cc b/blimp/client/core/blimp_client_context_impl_unittest.cc index 57c768f..55acec3 100644 --- a/blimp/client/core/blimp_client_context_impl_unittest.cc +++ b/blimp/client/core/blimp_client_context_impl_unittest.cc
@@ -35,18 +35,17 @@ } protected: - // The thread to use for IO related tasks. base::Thread io_thread_; private: - // Message loop for the test thread. base::MessageLoop message_loop_; DISALLOW_COPY_AND_ASSIGN(BlimpClientContextImplTest); }; TEST_F(BlimpClientContextImplTest, CreatedBlimpContentsGetsHelpersAttached) { - BlimpClientContextImpl blimp_client_context(io_thread_.task_runner()); + BlimpClientContextImpl blimp_client_context(io_thread_.task_runner(), + io_thread_.task_runner()); TestBlimpClientContextDelegate delegate; blimp_client_context.SetDelegate(&delegate);
diff --git a/blimp/client/core/contents/BUILD.gn b/blimp/client/core/contents/BUILD.gn index c3f8ab8b..e5f57fb4 100644 --- a/blimp/client/core/contents/BUILD.gn +++ b/blimp/client/core/contents/BUILD.gn
@@ -13,6 +13,8 @@ sources = [ "blimp_contents_impl.cc", "blimp_contents_impl.h", + "blimp_contents_manager.cc", + "blimp_contents_manager.h", "blimp_navigation_controller_delegate.h", "blimp_navigation_controller_impl.cc", "blimp_navigation_controller_impl.h", @@ -80,6 +82,8 @@ sources = [ "blimp_contents_impl_unittest.cc", + "blimp_contents_manager_unittest.cc", + "blimp_contents_observer_unittest.cc", "blimp_navigation_controller_impl_unittest.cc", "navigation_feature_unittest.cc", ]
diff --git a/blimp/client/core/contents/android/blimp_contents_factory.cc b/blimp/client/core/contents/android/blimp_contents_factory.cc index 92a2ec9..ae3df18b 100644 --- a/blimp/client/core/contents/android/blimp_contents_factory.cc +++ b/blimp/client/core/contents/android/blimp_contents_factory.cc
@@ -12,6 +12,10 @@ using base::android::JavaParamRef; +namespace { +const int kDummyTabId = 0; +} + namespace blimp { namespace client { @@ -20,7 +24,7 @@ const JavaParamRef<jclass>& clazz) { // To delete |blimp_contents_impl|, the Java caller must call the // destroy() method on BlimpContents. - BlimpContentsImpl* blimp_contents_impl = new BlimpContentsImpl; + BlimpContentsImpl* blimp_contents_impl = new BlimpContentsImpl(kDummyTabId); return blimp_contents_impl->GetJavaBlimpContentsImpl(); }
diff --git a/blimp/client/core/contents/android/blimp_contents_observer_proxy.cc b/blimp/client/core/contents/android/blimp_contents_observer_proxy.cc index 61d668fc..e53c09f 100644 --- a/blimp/client/core/contents/android/blimp_contents_observer_proxy.cc +++ b/blimp/client/core/contents/android/blimp_contents_observer_proxy.cc
@@ -33,9 +33,9 @@ JNIEnv* env, jobject obj, BlimpContentsImplAndroid* blimp_contents_impl_android) - : blimp_contents_impl_android_(blimp_contents_impl_android) { + : BlimpContentsObserver(blimp_contents_impl_android->blimp_contents_impl()), + blimp_contents_impl_android_(blimp_contents_impl_android) { java_obj_.Reset(env, obj); - blimp_contents_impl_android_->blimp_contents_impl()->AddObserver(this); } BlimpContentsObserverProxy::~BlimpContentsObserverProxy() {}
diff --git a/blimp/client/core/contents/blimp_contents_impl.cc b/blimp/client/core/contents/blimp_contents_impl.cc index bc4047e3..bfbbca3 100644 --- a/blimp/client/core/contents/blimp_contents_impl.cc +++ b/blimp/client/core/contents/blimp_contents_impl.cc
@@ -22,10 +22,12 @@ #endif // OS_ANDROID } -BlimpContentsImpl::BlimpContentsImpl() - : navigation_controller_(this, nullptr) {} +BlimpContentsImpl::BlimpContentsImpl(int id) + : navigation_controller_(this, nullptr), id_(id) {} -BlimpContentsImpl::~BlimpContentsImpl() {} +BlimpContentsImpl::~BlimpContentsImpl() { + FOR_EACH_OBSERVER(BlimpContentsObserver, observers_, BlimpContentsDying()); +} #if defined(OS_ANDROID) @@ -59,6 +61,10 @@ observers_.RemoveObserver(observer); } +bool BlimpContentsImpl::HasObserver(BlimpContentsObserver* observer) { + return observers_.HasObserver(observer); +} + void BlimpContentsImpl::OnNavigationStateChanged() { FOR_EACH_OBSERVER(BlimpContentsObserver, observers_, OnNavigationStateChanged());
diff --git a/blimp/client/core/contents/blimp_contents_impl.h b/blimp/client/core/contents/blimp_contents_impl.h index 38c457b..1110ccd 100644 --- a/blimp/client/core/contents/blimp_contents_impl.h +++ b/blimp/client/core/contents/blimp_contents_impl.h
@@ -29,7 +29,7 @@ class BlimpContentsImpl : public BlimpContents, public BlimpNavigationControllerDelegate { public: - BlimpContentsImpl(); + explicit BlimpContentsImpl(int id); ~BlimpContentsImpl() override; #if defined(OS_ANDROID) @@ -42,9 +42,14 @@ void AddObserver(BlimpContentsObserver* observer) override; void RemoveObserver(BlimpContentsObserver* observer) override; + // Check if some observer is in the observer list. + bool HasObserver(BlimpContentsObserver* observer); + // BlimpNavigationControllerDelegate implementation. void OnNavigationStateChanged() override; + int id() { return id_; } + private: // Handles the back/forward list and loading URLs. BlimpNavigationControllerImpl navigation_controller_; @@ -52,6 +57,10 @@ // A list of all the observers of this BlimpContentsImpl. base::ObserverList<BlimpContentsObserver> observers_; + // The id is assigned during contents creation. It is used by + // BlimpContentsManager to control the life time of the its observer. + int id_; + DISALLOW_COPY_AND_ASSIGN(BlimpContentsImpl); };
diff --git a/blimp/client/core/contents/blimp_contents_impl_unittest.cc b/blimp/client/core/contents/blimp_contents_impl_unittest.cc index 555cbbe..98fa2066 100644 --- a/blimp/client/core/contents/blimp_contents_impl_unittest.cc +++ b/blimp/client/core/contents/blimp_contents_impl_unittest.cc
@@ -17,10 +17,12 @@ const char kExampleURL[] = "https://www.example.com/"; const char kOtherExampleURL[] = "https://www.otherexample.com/"; +const int kDummyTabId = 0; class MockBlimpContentsObserver : public BlimpContentsObserver { public: - MockBlimpContentsObserver() = default; + explicit MockBlimpContentsObserver(BlimpContents* blimp_contents) + : BlimpContentsObserver(blimp_contents) {} ~MockBlimpContentsObserver() override = default; MOCK_METHOD0(OnNavigationStateChanged, void()); @@ -31,7 +33,7 @@ TEST(BlimpContentsImplTest, LoadURLAndNotifyObservers) { base::MessageLoop loop; - BlimpContentsImpl blimp_contents; + BlimpContentsImpl blimp_contents(kDummyTabId); BlimpNavigationControllerImpl& navigation_controller = blimp_contents.GetNavigationController(); @@ -39,10 +41,8 @@ feature.SetDelegate(1, &navigation_controller); navigation_controller.SetNavigationFeatureForTesting(&feature); - testing::StrictMock<MockBlimpContentsObserver> observer1; - blimp_contents.AddObserver(&observer1); - testing::StrictMock<MockBlimpContentsObserver> observer2; - blimp_contents.AddObserver(&observer2); + testing::StrictMock<MockBlimpContentsObserver> observer1(&blimp_contents); + testing::StrictMock<MockBlimpContentsObserver> observer2(&blimp_contents); EXPECT_CALL(observer1, OnNavigationStateChanged()); EXPECT_CALL(observer2, OnNavigationStateChanged()).Times(2);
diff --git a/blimp/client/core/contents/blimp_contents_manager.cc b/blimp/client/core/contents/blimp_contents_manager.cc new file mode 100644 index 0000000..f0a1f6bf --- /dev/null +++ b/blimp/client/core/contents/blimp_contents_manager.cc
@@ -0,0 +1,95 @@ +// 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 "blimp/client/core/contents/blimp_contents_manager.h" + +#include "base/bind.h" +#include "base/memory/ptr_util.h" +#include "base/threading/thread_task_runner_handle.h" +#include "blimp/client/public/contents/blimp_contents_observer.h" + +namespace { +const int kDummyTabId = 0; +} + +namespace blimp { +namespace client { + +class BlimpContentsManager::BlimpContentsDeletionObserver + : public BlimpContentsObserver { + public: + BlimpContentsDeletionObserver(BlimpContentsManager* blimp_contents_manager, + BlimpContentsImpl* blimp_contents); + + void OnContentsDestroyed() override; + + private: + // The BlimpContentsManager containing this BlimpContentsDeletionObserver + BlimpContentsManager* blimp_contents_manager_; + + DISALLOW_COPY_AND_ASSIGN(BlimpContentsDeletionObserver); +}; + +BlimpContentsManager::BlimpContentsDeletionObserver:: + BlimpContentsDeletionObserver(BlimpContentsManager* blimp_contents_manager, + BlimpContentsImpl* blimp_contents) + : BlimpContentsObserver(blimp_contents), + blimp_contents_manager_(blimp_contents_manager) {} + +void BlimpContentsManager::BlimpContentsDeletionObserver:: + OnContentsDestroyed() { + BlimpContents* contents = blimp_contents(); + int id = static_cast<BlimpContentsImpl*>(contents)->id(); + DCHECK(base::ThreadTaskRunnerHandle::Get()); + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(&BlimpContentsManager::EraseObserverFromMap, + blimp_contents_manager_->GetWeakPtr(), id)); +} + +BlimpContentsManager::BlimpContentsManager() : weak_ptr_factory_(this) {} + +BlimpContentsManager::~BlimpContentsManager() {} + +std::unique_ptr<BlimpContentsImpl> BlimpContentsManager::CreateBlimpContents() { + int id = CreateBlimpContentsId(); + std::unique_ptr<BlimpContentsImpl> new_contents = + base::MakeUnique<BlimpContentsImpl>(id); + std::unique_ptr<BlimpContentsDeletionObserver> observer = + base::MakeUnique<BlimpContentsDeletionObserver>(this, new_contents.get()); + observer_map_.insert( + std::pair<int, std::unique_ptr<BlimpContentsDeletionObserver>>( + id, std::move(observer))); + return new_contents; +} + +BlimpContentsImpl* BlimpContentsManager::GetBlimpContents(int id) { + if (observer_map_.find(id) == observer_map_.end()) return nullptr; + + BlimpContentsDeletionObserver* observer = observer_map_.at(id).get(); + // If the BlimpContents that the observer tracks is empty, it means + // OnContentsDestroyed was called on this observer, but the task to erase + // the observer from the map hasn't been run. + if (observer->blimp_contents()) + return static_cast<BlimpContentsImpl*>(observer->blimp_contents()); + + return nullptr; +} + +int BlimpContentsManager::CreateBlimpContentsId() { + // TODO(mlliu): currently, Blimp only supports a single tab, so returning a + // dummy tab id. Need to return real case id when Blimp supports multiple + // tabs. + return kDummyTabId; +} + +void BlimpContentsManager::EraseObserverFromMap(int id) { + observer_map_.erase(id); +} + +base::WeakPtr<BlimpContentsManager> BlimpContentsManager::GetWeakPtr() { + return weak_ptr_factory_.GetWeakPtr(); +} + +} // namespace client +} // namespace blimp
diff --git a/blimp/client/core/contents/blimp_contents_manager.h b/blimp/client/core/contents/blimp_contents_manager.h new file mode 100644 index 0000000..ea70960 --- /dev/null +++ b/blimp/client/core/contents/blimp_contents_manager.h
@@ -0,0 +1,51 @@ +// 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 BLIMP_CLIENT_CORE_CONTENTS_BLIMP_CONTENTS_MANAGER_H_ +#define BLIMP_CLIENT_CORE_CONTENTS_BLIMP_CONTENTS_MANAGER_H_ + +#include "blimp/client/core/contents/blimp_contents_impl.h" + +namespace blimp { +namespace client { + +// BlimpContentsManager does the real work of creating BlimpContentsImpl, and +// then passes the ownership to the caller. It also owns the observers to +// monitor the life time of the contents it creates. +class BlimpContentsManager { + public: + BlimpContentsManager(); + ~BlimpContentsManager(); + + std::unique_ptr<BlimpContentsImpl> CreateBlimpContents(); + + // The caller can query the contents through its id. + BlimpContentsImpl* GetBlimpContents(int id); + + private: + class BlimpContentsDeletionObserver; + friend class BlimpContentsDeletionObserver; + + // When creating the BlimpContentsImpl, an id is created for the content. + int CreateBlimpContentsId(); + + // When a BlimpContentsImpl is destroyed, its observer is able to retrieve the + // id, and use this to destroy the observer entry from the observer_map_. + void EraseObserverFromMap(int id); + base::WeakPtr<BlimpContentsManager> GetWeakPtr(); + + // BlimpContentsManager owns the BlimpContentsDeletionObserver for the + // contents it creates, with the content id being the key to help manage the + // lifetime of the observers. + std::map<int, std::unique_ptr<BlimpContentsDeletionObserver>> observer_map_; + + base::WeakPtrFactory<BlimpContentsManager> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(BlimpContentsManager); +}; + +} // namespace client +} // namespace blimp + +#endif // BLIMP_CLIENT_CORE_CONTENTS_BLIMP_CONTENTS_MANAGER_H_
diff --git a/blimp/client/core/contents/blimp_contents_manager_unittest.cc b/blimp/client/core/contents/blimp_contents_manager_unittest.cc new file mode 100644 index 0000000..422b771 --- /dev/null +++ b/blimp/client/core/contents/blimp_contents_manager_unittest.cc
@@ -0,0 +1,59 @@ +// 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 "blimp/client/core/contents/blimp_contents_manager.h" + +#include "base/memory/ptr_util.h" +#include "base/message_loop/message_loop.h" +#include "blimp/client/core/contents/blimp_contents_impl.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { +const int kDummyTabId = 0; +} + +namespace blimp { +namespace client { +namespace { + +TEST(BlimpContentsManagerUnittest, GetExistingBlimpContents) { + base::MessageLoop loop; + BlimpContentsManager blimp_contents_manager; + + std::unique_ptr<BlimpContentsImpl> blimp_contents = + blimp_contents_manager.CreateBlimpContents(); + int id = blimp_contents->id(); + BlimpContentsImpl* existing_contents = + blimp_contents_manager.GetBlimpContents(id); + EXPECT_EQ(blimp_contents.get(), existing_contents); +} + +TEST(BlimpContentsManagerUnittest, GetNonExistingBlimpContents) { + BlimpContentsManager blimp_contents_manager; + + BlimpContentsImpl* existing_contents = + blimp_contents_manager.GetBlimpContents(kDummyTabId); + EXPECT_EQ(nullptr, existing_contents); +} + +TEST(BlimpContentsManagerUnittest, GetDestroyedBlimpContents) { + base::MessageLoop loop; + BlimpContentsManager blimp_contents_manager; + int id; + + std::unique_ptr<BlimpContentsImpl> blimp_contents = + blimp_contents_manager.CreateBlimpContents(); + id = blimp_contents.get()->id(); + BlimpContentsImpl* existing_contents = + blimp_contents_manager.GetBlimpContents(id); + EXPECT_EQ(blimp_contents.get(), existing_contents); + blimp_contents.reset(); + + loop.RunUntilIdle(); + EXPECT_EQ(nullptr, blimp_contents_manager.GetBlimpContents(id)); +} + +} // namespace +} // namespace client +} // namespace blimp
diff --git a/blimp/client/core/contents/blimp_contents_observer_unittest.cc b/blimp/client/core/contents/blimp_contents_observer_unittest.cc new file mode 100644 index 0000000..cf23333 --- /dev/null +++ b/blimp/client/core/contents/blimp_contents_observer_unittest.cc
@@ -0,0 +1,60 @@ +// 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 "blimp/client/public/contents/blimp_contents_observer.h" + +#include "base/memory/ptr_util.h" +#include "blimp/client/core/contents/blimp_contents_impl.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { +const int kDummyTabId = 0; +} + +namespace blimp { +namespace client { + +namespace { + +class BlimpContentsObserverTest : public BlimpContentsObserver { + public: + explicit BlimpContentsObserverTest(BlimpContents* blimp_contents) + : BlimpContentsObserver(blimp_contents) {} + + MOCK_METHOD0(OnContentsDestroyed, void()); + + private: + DISALLOW_COPY_AND_ASSIGN(BlimpContentsObserverTest); +}; + +TEST(BlimpContentsObserverUnittests, ObserverDies) { + BlimpContentsImpl contents(kDummyTabId); + + std::unique_ptr<BlimpContentsObserver> observer = + base::MakeUnique<BlimpContentsObserverTest>(&contents); + BlimpContentsObserver* observer_ptr = observer.get(); + EXPECT_TRUE(contents.HasObserver(observer_ptr)); + observer.reset(); + + EXPECT_FALSE(contents.HasObserver(observer_ptr)); +} + +TEST(BlimpContentsObserverUnittests, ContentsDies) { + std::unique_ptr<BlimpContentsObserverTest> observer; + + std::unique_ptr<BlimpContentsImpl> contents = + base::MakeUnique<BlimpContentsImpl>(kDummyTabId); + observer.reset(new BlimpContentsObserverTest(contents.get())); + EXPECT_CALL(*observer, OnContentsDestroyed()).Times(1); + EXPECT_EQ(observer->blimp_contents(), contents.get()); + contents.reset(); + + EXPECT_EQ(observer->blimp_contents(), nullptr); +} + +} // namespace + +} // namespace client +} // namespace blimp
diff --git a/blimp/client/core/contents/tab_control_feature.cc b/blimp/client/core/contents/tab_control_feature.cc new file mode 100644 index 0000000..b438763 --- /dev/null +++ b/blimp/client/core/contents/tab_control_feature.cc
@@ -0,0 +1,72 @@ +// 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 "blimp/client/core/contents/tab_control_feature.h" + +#include "blimp/common/create_blimp_message.h" +#include "blimp/common/proto/blimp_message.pb.h" +#include "blimp/common/proto/tab_control.pb.h" +#include "blimp/net/blimp_message_processor.h" +#include "net/base/net_errors.h" + +namespace blimp { +namespace client { + +TabControlFeature::TabControlFeature() {} + +TabControlFeature::~TabControlFeature() {} + +void TabControlFeature::set_outgoing_message_processor( + std::unique_ptr<BlimpMessageProcessor> processor) { + outgoing_message_processor_ = std::move(processor); +} + +void TabControlFeature::SetSizeAndScale(const gfx::Size& size, + float device_pixel_ratio) { + if (last_size_ == size && last_device_pixel_ratio_ == device_pixel_ratio) { + return; + } + + last_size_ = size; + last_device_pixel_ratio_ = device_pixel_ratio; + + SizeMessage* size_details; + std::unique_ptr<BlimpMessage> message = CreateBlimpMessage(&size_details); + size_details->set_width(size.width()); + size_details->set_height(size.height()); + size_details->set_device_pixel_ratio(device_pixel_ratio); + + // TODO(dtrainor): Don't keep sending size events to the server. Wait for a + // CompletionCallback to return before sending future size updates. + outgoing_message_processor_->ProcessMessage(std::move(message), + net::CompletionCallback()); +} + +void TabControlFeature::CreateTab(int tab_id) { + TabControlMessage* tab_control; + std::unique_ptr<BlimpMessage> message = CreateBlimpMessage(&tab_control); + tab_control->mutable_create_tab(); + outgoing_message_processor_->ProcessMessage(std::move(message), + net::CompletionCallback()); +} + +void TabControlFeature::CloseTab(int tab_id) { + TabControlMessage* tab_control; + std::unique_ptr<BlimpMessage> message = CreateBlimpMessage(&tab_control); + tab_control->mutable_close_tab(); + outgoing_message_processor_->ProcessMessage(std::move(message), + net::CompletionCallback()); +} + +void TabControlFeature::ProcessMessage( + std::unique_ptr<BlimpMessage> message, + const net::CompletionCallback& callback) { + DCHECK(!callback.is_null()); + callback.Run(net::OK); + + NOTIMPLEMENTED(); +} + +} // namespace client +} // namespace blimp
diff --git a/blimp/client/core/contents/tab_control_feature.h b/blimp/client/core/contents/tab_control_feature.h new file mode 100644 index 0000000..15b066a --- /dev/null +++ b/blimp/client/core/contents/tab_control_feature.h
@@ -0,0 +1,56 @@ +// 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 BLIMP_CLIENT_CORE_CONTENTS_TAB_CONTROL_FEATURE_H_ +#define BLIMP_CLIENT_CORE_CONTENTS_TAB_CONTROL_FEATURE_H_ + +#include <memory> + +#include "base/macros.h" +#include "blimp/net/blimp_message_processor.h" +#include "ui/gfx/geometry/size.h" + +namespace gfx { +class Size; +} + +namespace blimp { +namespace client { + +class TabControlFeature : public BlimpMessageProcessor { + public: + TabControlFeature(); + ~TabControlFeature() override; + + // Set the BlimpMessageProcessor that will be used to send + // BlimpMessage::TAB_CONTROL messages to the engine. + void set_outgoing_message_processor( + std::unique_ptr<BlimpMessageProcessor> processor); + + // Pushes the current size and scale information to the engine, which will + // affect the web content display area for all tabs. + void SetSizeAndScale(const gfx::Size& size, float device_pixel_ratio); + + void CreateTab(int tab_id); + void CloseTab(int tab_id); + + // BlimpMessageProcessor implementation. + void ProcessMessage(std::unique_ptr<BlimpMessage> message, + const net::CompletionCallback& callback) override; + + private: + // Used to send BlimpMessage::TAB_CONTROL messages to the engine. + std::unique_ptr<BlimpMessageProcessor> outgoing_message_processor_; + + // Used to avoid sending unnecessary messages to engine. + gfx::Size last_size_; + float last_device_pixel_ratio_ = -1; + + DISALLOW_COPY_AND_ASSIGN(TabControlFeature); +}; + +} // namespace client +} // namespace blimp + +#endif // BLIMP_CLIENT_CORE_CONTENTS_TAB_CONTROL_FEATURE_H_
diff --git a/blimp/client/core/contents/tab_control_feature_unittest.cc b/blimp/client/core/contents/tab_control_feature_unittest.cc new file mode 100644 index 0000000..69acd60f --- /dev/null +++ b/blimp/client/core/contents/tab_control_feature_unittest.cc
@@ -0,0 +1,93 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "blimp/client/core/contents/tab_control_feature.h" + +#include <memory> + +#include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "blimp/common/proto/blimp_message.pb.h" +#include "blimp/common/proto/tab_control.pb.h" +#include "blimp/net/test_common.h" +#include "net/base/net_errors.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/geometry/size.h" + +using testing::_; + +namespace blimp { +namespace client { + +MATCHER_P3(EqualsSizeMessage, width, height, dp_to_px, "") { + return arg.tab_control().tab_control_case() == TabControlMessage::kSize && + arg.tab_control().size().width() == width && + arg.tab_control().size().height() == height && + arg.tab_control().size().device_pixel_ratio() == dp_to_px; +} + +class TabControlFeatureTest : public testing::Test { + public: + TabControlFeatureTest() : out_processor_(nullptr) {} + + void SetUp() override { + out_processor_ = new MockBlimpMessageProcessor(); + feature_.set_outgoing_message_processor(base::WrapUnique(out_processor_)); + } + + protected: + // This is a raw pointer to a class that is owned by the ControlFeature. + MockBlimpMessageProcessor* out_processor_; + + TabControlFeature feature_; +}; + +TEST_F(TabControlFeatureTest, CreatesCorrectSizeMessage) { + uint64_t width = 10; + uint64_t height = 15; + float dp_to_px = 1.23f; + + EXPECT_CALL( + *out_processor_, + MockableProcessMessage(EqualsSizeMessage(width, height, dp_to_px), _)) + .Times(1); + feature_.SetSizeAndScale(gfx::Size(width, height), dp_to_px); +} + +TEST_F(TabControlFeatureTest, NoDuplicateSizeMessage) { + uint64_t width = 10; + uint64_t height = 15; + float dp_to_px = 1.23f; + + EXPECT_CALL( + *out_processor_, + MockableProcessMessage(EqualsSizeMessage(width, height, dp_to_px), _)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL( + *out_processor_, + MockableProcessMessage(EqualsSizeMessage(width, height, dp_to_px + 1), _)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*out_processor_, + MockableProcessMessage( + EqualsSizeMessage(width + 1, height, dp_to_px + 1), _)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*out_processor_, + MockableProcessMessage( + EqualsSizeMessage(width + 1, height + 1, dp_to_px + 1), _)) + .Times(1) + .RetiresOnSaturation(); + + feature_.SetSizeAndScale(gfx::Size(width, height), dp_to_px); + feature_.SetSizeAndScale(gfx::Size(width, height), dp_to_px); + feature_.SetSizeAndScale(gfx::Size(width, height), dp_to_px + 1); + feature_.SetSizeAndScale(gfx::Size(width + 1, height), dp_to_px + 1); + feature_.SetSizeAndScale(gfx::Size(width + 1, height + 1), dp_to_px + 1); +} + +} // namespace client +} // namespace blimp
diff --git a/blimp/client/core/dummy_blimp_client_context.cc b/blimp/client/core/dummy_blimp_client_context.cc index 10db782..8c0f250 100644 --- a/blimp/client/core/dummy_blimp_client_context.cc +++ b/blimp/client/core/dummy_blimp_client_context.cc
@@ -4,6 +4,7 @@ #include "blimp/client/core/dummy_blimp_client_context.h" +#include "base/logging.h" #include "base/memory/ref_counted.h" #include "base/single_thread_task_runner.h" @@ -20,7 +21,8 @@ // any binary using BlimpClientContext::Create. // static BlimpClientContext* BlimpClientContext::Create( - scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner) { + scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner) { #if defined(OS_ANDROID) return new DummyBlimpClientContextAndroid(); #else @@ -39,5 +41,9 @@ return nullptr; } +void DummyBlimpClientContext::Connect(const std::string& client_auth_token) { + NOTREACHED(); +} + } // namespace client } // namespace blimp
diff --git a/blimp/client/core/dummy_blimp_client_context.h b/blimp/client/core/dummy_blimp_client_context.h index 92f6e31..207579e 100644 --- a/blimp/client/core/dummy_blimp_client_context.h +++ b/blimp/client/core/dummy_blimp_client_context.h
@@ -12,7 +12,10 @@ namespace blimp { namespace client { -// A dummy implementation of the BlimpClientContext. +// A dummy implementation of the BlimpClientContext which is in use by +// embedders that do not set the GN argument |enable_blimp_client| to true. +// It exists so that it is possible for an embedder to still have code depending +// on the public APIs of blimp, without in fact linking in all the core code. class DummyBlimpClientContext : public BlimpClientContext { public: DummyBlimpClientContext(); @@ -21,6 +24,7 @@ // BlimpClientContext implementation. void SetDelegate(BlimpClientContextDelegate* delegate) override; std::unique_ptr<BlimpContents> CreateBlimpContents() override; + void Connect(const std::string& client_auth_token) override; private: DISALLOW_COPY_AND_ASSIGN(DummyBlimpClientContext);
diff --git a/blimp/client/core/session/BUILD.gn b/blimp/client/core/session/BUILD.gn index f013214..6af914abb 100644 --- a/blimp/client/core/session/BUILD.gn +++ b/blimp/client/core/session/BUILD.gn
@@ -25,6 +25,7 @@ public_deps = [ "//base", + "//blimp/client/public:public_headers", "//blimp/net", "//components/safe_json", "//net", @@ -72,13 +73,3 @@ ] } } - -if (is_android) { - java_cpp_enum("java_enums_srcjar") { - visibility = [ "//blimp/client/*" ] - - sources = [ - "assignment_source.h", - ] - } -}
diff --git a/blimp/client/core/session/assignment_source.cc b/blimp/client/core/session/assignment_source.cc index e2c2824..52bcfa54 100644 --- a/blimp/client/core/session/assignment_source.cc +++ b/blimp/client/core/session/assignment_source.cc
@@ -168,23 +168,6 @@ } // namespace -Assignment::Assignment() : transport_protocol(TransportProtocol::UNKNOWN) {} - -Assignment::Assignment(const Assignment& other) = default; - -Assignment::~Assignment() {} - -bool Assignment::IsValid() const { - if (engine_endpoint.address().empty() || engine_endpoint.port() == 0 || - transport_protocol == TransportProtocol::UNKNOWN) { - return false; - } - if (transport_protocol == TransportProtocol::SSL && !cert) { - return false; - } - return true; -} - AssignmentSource::AssignmentSource( const GURL& assigner_endpoint, const scoped_refptr<base::SingleThreadTaskRunner>& network_task_runner, @@ -221,7 +204,7 @@ // If GetAssignmentFromCommandLine succeeded, then return its output. if (parsed_assignment.IsValid()) { base::ResetAndReturn(&callback_) - .Run(AssignmentSource::RESULT_OK, parsed_assignment); + .Run(ASSIGNMENT_REQUEST_RESULT_OK, parsed_assignment); return; } @@ -259,7 +242,7 @@ DVLOG(1) << "Assignment request failed due to network error: " << net::ErrorToString(source->GetStatus().error()); base::ResetAndReturn(&callback_) - .Run(AssignmentSource::Result::RESULT_NETWORK_FAILURE, Assignment()); + .Run(ASSIGNMENT_REQUEST_RESULT_NETWORK_FAILURE, Assignment()); return; } @@ -269,28 +252,29 @@ break; case net::HTTP_BAD_REQUEST: base::ResetAndReturn(&callback_) - .Run(AssignmentSource::Result::RESULT_BAD_REQUEST, Assignment()); + .Run(ASSIGNMENT_REQUEST_RESULT_BAD_REQUEST, Assignment()); break; case net::HTTP_UNAUTHORIZED: base::ResetAndReturn(&callback_) - .Run(AssignmentSource::Result::RESULT_EXPIRED_ACCESS_TOKEN, - Assignment()); + .Run(ASSIGNMENT_REQUEST_RESULT_EXPIRED_ACCESS_TOKEN, Assignment()); break; case net::HTTP_FORBIDDEN: base::ResetAndReturn(&callback_) - .Run(AssignmentSource::Result::RESULT_USER_INVALID, Assignment()); + .Run(ASSIGNMENT_REQUEST_RESULT_USER_INVALID, Assignment()); break; case 429: // Too Many Requests base::ResetAndReturn(&callback_) - .Run(AssignmentSource::Result::RESULT_OUT_OF_VMS, Assignment()); + .Run(ASSIGNMENT_REQUEST_RESULT_OUT_OF_VMS, Assignment()); break; case net::HTTP_INTERNAL_SERVER_ERROR: base::ResetAndReturn(&callback_) - .Run(AssignmentSource::Result::RESULT_SERVER_ERROR, Assignment()); + .Run(ASSIGNMENT_REQUEST_RESULT_SERVER_ERROR, Assignment()); break; default: + LOG(WARNING) << "Defaulting to BAD_RESPONSE for HTTP response code " + << source->GetResponseCode(); base::ResetAndReturn(&callback_) - .Run(AssignmentSource::Result::RESULT_BAD_RESPONSE, Assignment()); + .Run(ASSIGNMENT_REQUEST_RESULT_BAD_RESPONSE, Assignment()); break; } } @@ -303,8 +287,9 @@ // Grab the response from the assigner request. std::string response; if (!url_fetcher_->GetResponseAsString(&response)) { + LOG(WARNING) << "Unable to retrieve response as string from URLFetcher."; base::ResetAndReturn(&callback_) - .Run(AssignmentSource::Result::RESULT_BAD_RESPONSE, Assignment()); + .Run(ASSIGNMENT_REQUEST_RESULT_BAD_RESPONSE, Assignment()); return; } @@ -318,8 +303,9 @@ void AssignmentSource::OnJsonParsed(std::unique_ptr<base::Value> json) { const base::DictionaryValue* dict; if (!json->GetAsDictionary(&dict)) { + LOG(WARNING) << "Unable to parse JSON data as a dictionary."; base::ResetAndReturn(&callback_) - .Run(AssignmentSource::Result::RESULT_BAD_RESPONSE, Assignment()); + .Run(ASSIGNMENT_REQUEST_RESULT_BAD_RESPONSE, Assignment()); return; } @@ -331,21 +317,24 @@ if (!(dict->GetString(kClientTokenKey, &client_token) && dict->GetString(kHostKey, &host) && dict->GetInteger(kPortKey, &port) && dict->GetString(kCertificateKey, &cert_str))) { + LOG(WARNING) << "Not all fields present in assignment JSON data."; base::ResetAndReturn(&callback_) - .Run(AssignmentSource::Result::RESULT_BAD_RESPONSE, Assignment()); + .Run(ASSIGNMENT_REQUEST_RESULT_BAD_RESPONSE, Assignment()); return; } net::IPAddress ip_address; if (!ip_address.AssignFromIPLiteral(host)) { + LOG(WARNING) << "Unable to assign IP address from string literal " << host; base::ResetAndReturn(&callback_) - .Run(AssignmentSource::Result::RESULT_BAD_RESPONSE, Assignment()); + .Run(ASSIGNMENT_REQUEST_RESULT_BAD_RESPONSE, Assignment()); return; } if (!base::IsValueInRangeForNumericType<uint16_t>(port)) { + LOG(WARNING) << "Assignment port number not in range for uint16_t"; base::ResetAndReturn(&callback_) - .Run(AssignmentSource::Result::RESULT_BAD_RESPONSE, Assignment()); + .Run(ASSIGNMENT_REQUEST_RESULT_BAD_RESPONSE, Assignment()); return; } @@ -355,7 +344,7 @@ net::X509Certificate::FORMAT_PEM_CERT_SEQUENCE); if (cert_list.size() != 1) { base::ResetAndReturn(&callback_) - .Run(AssignmentSource::Result::RESULT_INVALID_CERT, Assignment()); + .Run(ASSIGNMENT_REQUEST_RESULT_INVALID_CERT, Assignment()); return; } @@ -368,13 +357,13 @@ assignment.cert = std::move(cert_list[0]); base::ResetAndReturn(&callback_) - .Run(AssignmentSource::Result::RESULT_OK, assignment); + .Run(ASSIGNMENT_REQUEST_RESULT_OK, assignment); } void AssignmentSource::OnJsonParseError(const std::string& error) { DLOG(ERROR) << "Error while parsing assigner JSON: " << error; base::ResetAndReturn(&callback_) - .Run(AssignmentSource::Result::RESULT_BAD_RESPONSE, Assignment()); + .Run(ASSIGNMENT_REQUEST_RESULT_BAD_RESPONSE, Assignment()); } } // namespace client
diff --git a/blimp/client/core/session/assignment_source.h b/blimp/client/core/session/assignment_source.h index 13ea11d..a7551f5 100644 --- a/blimp/client/core/session/assignment_source.h +++ b/blimp/client/core/session/assignment_source.h
@@ -9,7 +9,7 @@ #include "base/callback.h" #include "base/memory/weak_ptr.h" -#include "net/base/ip_endpoint.h" +#include "blimp/client/public/session/assignment.h" #include "net/url_request/url_fetcher_delegate.h" #include "url/gurl.h" @@ -22,64 +22,16 @@ namespace net { class URLFetcher; class URLRequestContextGetter; -class X509Certificate; } namespace blimp { namespace client { -// An Assignment contains the configuration data needed for a client -// to connect to the engine. -struct Assignment { - enum TransportProtocol { - UNKNOWN = 0, - SSL = 1, - TCP = 2, - }; - - Assignment(); - Assignment(const Assignment& other); - ~Assignment(); - - // Returns true if the net::IPEndPoint has an unspecified IP, port, or - // transport protocol. - bool IsValid() const; - - // Specifies the transport to use to connect to the engine. - TransportProtocol transport_protocol; - - // Specifies the IP address and port on which to reach the engine. - net::IPEndPoint engine_endpoint; - - // Used to authenticate to the specified engine. - std::string client_token; - - // Specifies the X.509 certificate that the engine must report. - scoped_refptr<net::X509Certificate> cert; -}; - // AssignmentSource provides functionality to find out how a client should // connect to an engine. class AssignmentSource : public net::URLFetcherDelegate { public: - // A Java counterpart will be generated for this enum. - // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.blimp.core.session.assignment - enum Result { - RESULT_UNKNOWN = 0, - RESULT_OK = 1, - RESULT_BAD_REQUEST = 2, - RESULT_BAD_RESPONSE = 3, - RESULT_INVALID_PROTOCOL_VERSION = 4, - RESULT_EXPIRED_ACCESS_TOKEN = 5, - RESULT_USER_INVALID = 6, - RESULT_OUT_OF_VMS = 7, - RESULT_SERVER_ERROR = 8, - RESULT_SERVER_INTERRUPTED = 9, - RESULT_NETWORK_FAILURE = 10, - RESULT_INVALID_CERT = 11, - }; - - typedef base::Callback<void(AssignmentSource::Result, const Assignment&)> + typedef base::Callback<void(AssignmentRequestResult, const Assignment&)> AssignmentCallback; // |assigner_endpoint|: The URL of the Assigner service to query.
diff --git a/blimp/client/core/session/assignment_source_unittest.cc b/blimp/client/core/session/assignment_source_unittest.cc index 734784d..4513012d 100644 --- a/blimp/client/core/session/assignment_source_unittest.cc +++ b/blimp/client/core/session/assignment_source_unittest.cc
@@ -150,7 +150,7 @@ } MOCK_METHOD2(AssignmentResponse, - void(AssignmentSource::Result, const Assignment&)); + void(AssignmentRequestResult, const Assignment&)); protected: Assignment BuildSslAssignment(); @@ -221,7 +221,7 @@ CHECK_EQ("MyVoiceIsMyPassport", assignment.client_token); - EXPECT_CALL(*this, AssignmentResponse(AssignmentSource::Result::RESULT_OK, + EXPECT_CALL(*this, AssignmentResponse(ASSIGNMENT_REQUEST_RESULT_OK, AssignmentEquals(assignment))) .Times(1); @@ -245,7 +245,7 @@ assignment.client_token = GetClientToken(*cmd_line); - EXPECT_CALL(*this, AssignmentResponse(AssignmentSource::Result::RESULT_OK, + EXPECT_CALL(*this, AssignmentResponse(ASSIGNMENT_REQUEST_RESULT_OK, AssignmentEquals(assignment))) .Times(1); @@ -255,7 +255,7 @@ TEST_F(AssignmentSourceTest, TestSuccess) { Assignment assignment = BuildSslAssignment(); - EXPECT_CALL(*this, AssignmentResponse(AssignmentSource::Result::RESULT_OK, + EXPECT_CALL(*this, AssignmentResponse(ASSIGNMENT_REQUEST_RESULT_OK, AssignmentEquals(assignment))) .Times(1); @@ -268,12 +268,12 @@ InSequence sequence; Assignment assignment = BuildSslAssignment(); - EXPECT_CALL(*this, AssignmentResponse( - AssignmentSource::Result::RESULT_NETWORK_FAILURE, _)) + EXPECT_CALL(*this, + AssignmentResponse(ASSIGNMENT_REQUEST_RESULT_NETWORK_FAILURE, _)) .Times(1) .RetiresOnSaturation(); - EXPECT_CALL(*this, AssignmentResponse(AssignmentSource::Result::RESULT_OK, + EXPECT_CALL(*this, AssignmentResponse(ASSIGNMENT_REQUEST_RESULT_OK, AssignmentEquals(assignment))) .Times(1) .RetiresOnSaturation(); @@ -288,54 +288,53 @@ } TEST_F(AssignmentSourceTest, TestNetworkFailure) { - EXPECT_CALL(*this, AssignmentResponse( - AssignmentSource::Result::RESULT_NETWORK_FAILURE, _)); + EXPECT_CALL(*this, + AssignmentResponse(ASSIGNMENT_REQUEST_RESULT_NETWORK_FAILURE, _)); GetNetworkAssignmentAndWaitForResponse(net::HTTP_OK, net::Error::ERR_INSUFFICIENT_RESOURCES, "", kTestAuthToken, kProtocolVersion); } TEST_F(AssignmentSourceTest, TestBadRequest) { - EXPECT_CALL(*this, AssignmentResponse( - AssignmentSource::Result::RESULT_BAD_REQUEST, _)); + EXPECT_CALL(*this, + AssignmentResponse(ASSIGNMENT_REQUEST_RESULT_BAD_REQUEST, _)); GetNetworkAssignmentAndWaitForResponse(net::HTTP_BAD_REQUEST, net::Error::OK, "", kTestAuthToken, kProtocolVersion); } TEST_F(AssignmentSourceTest, TestUnauthorized) { - EXPECT_CALL(*this, - AssignmentResponse( - AssignmentSource::Result::RESULT_EXPIRED_ACCESS_TOKEN, _)); + EXPECT_CALL(*this, AssignmentResponse( + ASSIGNMENT_REQUEST_RESULT_EXPIRED_ACCESS_TOKEN, _)); GetNetworkAssignmentAndWaitForResponse(net::HTTP_UNAUTHORIZED, net::Error::OK, "", kTestAuthToken, kProtocolVersion); } TEST_F(AssignmentSourceTest, TestForbidden) { - EXPECT_CALL(*this, AssignmentResponse( - AssignmentSource::Result::RESULT_USER_INVALID, _)); + EXPECT_CALL(*this, + AssignmentResponse(ASSIGNMENT_REQUEST_RESULT_USER_INVALID, _)); GetNetworkAssignmentAndWaitForResponse(net::HTTP_FORBIDDEN, net::Error::OK, "", kTestAuthToken, kProtocolVersion); } TEST_F(AssignmentSourceTest, TestTooManyRequests) { - EXPECT_CALL(*this, AssignmentResponse( - AssignmentSource::Result::RESULT_OUT_OF_VMS, _)); + EXPECT_CALL(*this, + AssignmentResponse(ASSIGNMENT_REQUEST_RESULT_OUT_OF_VMS, _)); GetNetworkAssignmentAndWaitForResponse(static_cast<net::HttpStatusCode>(429), net::Error::OK, "", kTestAuthToken, kProtocolVersion); } TEST_F(AssignmentSourceTest, TestInternalServerError) { - EXPECT_CALL(*this, AssignmentResponse( - AssignmentSource::Result::RESULT_SERVER_ERROR, _)); + EXPECT_CALL(*this, + AssignmentResponse(ASSIGNMENT_REQUEST_RESULT_SERVER_ERROR, _)); GetNetworkAssignmentAndWaitForResponse(net::HTTP_INTERNAL_SERVER_ERROR, net::Error::OK, "", kTestAuthToken, kProtocolVersion); } TEST_F(AssignmentSourceTest, TestUnexpectedNetCodeFallback) { - EXPECT_CALL(*this, AssignmentResponse( - AssignmentSource::Result::RESULT_BAD_RESPONSE, _)); + EXPECT_CALL(*this, + AssignmentResponse(ASSIGNMENT_REQUEST_RESULT_BAD_RESPONSE, _)); GetNetworkAssignmentAndWaitForResponse(net::HTTP_NOT_IMPLEMENTED, net::Error::OK, "", kTestAuthToken, kProtocolVersion); @@ -348,8 +347,8 @@ std::string response = ValueToString(*BuildAssignerResponse()); response = response.substr(response.size() / 2); - EXPECT_CALL(*this, AssignmentResponse( - AssignmentSource::Result::RESULT_BAD_RESPONSE, _)); + EXPECT_CALL(*this, + AssignmentResponse(ASSIGNMENT_REQUEST_RESULT_BAD_RESPONSE, _)); GetNetworkAssignmentAndWaitForResponse(net::HTTP_OK, net::Error::OK, response, kTestAuthToken, kProtocolVersion); } @@ -357,8 +356,8 @@ TEST_F(AssignmentSourceTest, TestMissingResponsePort) { std::unique_ptr<base::DictionaryValue> response = BuildAssignerResponse(); response->Remove("port", nullptr); - EXPECT_CALL(*this, AssignmentResponse( - AssignmentSource::Result::RESULT_BAD_RESPONSE, _)); + EXPECT_CALL(*this, + AssignmentResponse(ASSIGNMENT_REQUEST_RESULT_BAD_RESPONSE, _)); GetNetworkAssignmentAndWaitForResponse(net::HTTP_OK, net::Error::OK, ValueToString(*response), kTestAuthToken, kProtocolVersion); @@ -368,8 +367,8 @@ std::unique_ptr<base::DictionaryValue> response = BuildAssignerResponse(); response->SetString("host", "happywhales.test"); - EXPECT_CALL(*this, AssignmentResponse( - AssignmentSource::Result::RESULT_BAD_RESPONSE, _)); + EXPECT_CALL(*this, + AssignmentResponse(ASSIGNMENT_REQUEST_RESULT_BAD_RESPONSE, _)); GetNetworkAssignmentAndWaitForResponse(net::HTTP_OK, net::Error::OK, ValueToString(*response), kTestAuthToken, kProtocolVersion); @@ -378,8 +377,8 @@ TEST_F(AssignmentSourceTest, TestMissingCert) { std::unique_ptr<base::DictionaryValue> response = BuildAssignerResponse(); response->Remove("certificate", nullptr); - EXPECT_CALL(*this, AssignmentResponse( - AssignmentSource::Result::RESULT_BAD_RESPONSE, _)); + EXPECT_CALL(*this, + AssignmentResponse(ASSIGNMENT_REQUEST_RESULT_BAD_RESPONSE, _)); GetNetworkAssignmentAndWaitForResponse(net::HTTP_OK, net::Error::OK, ValueToString(*response), kTestAuthToken, kProtocolVersion); @@ -388,8 +387,8 @@ TEST_F(AssignmentSourceTest, TestInvalidCert) { std::unique_ptr<base::DictionaryValue> response = BuildAssignerResponse(); response->SetString("certificate", "h4x0rz!"); - EXPECT_CALL(*this, AssignmentResponse( - AssignmentSource::Result::RESULT_INVALID_CERT, _)); + EXPECT_CALL(*this, + AssignmentResponse(ASSIGNMENT_REQUEST_RESULT_INVALID_CERT, _)); GetNetworkAssignmentAndWaitForResponse(net::HTTP_OK, net::Error::OK, ValueToString(*response), kTestAuthToken, kProtocolVersion);
diff --git a/blimp/client/feature/tab_control_feature.cc b/blimp/client/feature/tab_control_feature.cc deleted file mode 100644 index 285d525e..0000000 --- a/blimp/client/feature/tab_control_feature.cc +++ /dev/null
@@ -1,72 +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 "blimp/client/feature/tab_control_feature.h" - -#include "blimp/common/create_blimp_message.h" -#include "blimp/common/proto/blimp_message.pb.h" -#include "blimp/common/proto/tab_control.pb.h" -#include "blimp/net/blimp_message_processor.h" -#include "net/base/net_errors.h" - -namespace blimp { -namespace client { - -TabControlFeature::TabControlFeature() {} - -TabControlFeature::~TabControlFeature() {} - -void TabControlFeature::set_outgoing_message_processor( - std::unique_ptr<BlimpMessageProcessor> processor) { - outgoing_message_processor_ = std::move(processor); -} - -void TabControlFeature::SetSizeAndScale(const gfx::Size& size, - float device_pixel_ratio) { - if (last_size_ == size && last_device_pixel_ratio_ == device_pixel_ratio) { - return; - } - - last_size_ = size; - last_device_pixel_ratio_ = device_pixel_ratio; - - SizeMessage* size_details; - std::unique_ptr<BlimpMessage> message = CreateBlimpMessage(&size_details); - size_details->set_width(size.width()); - size_details->set_height(size.height()); - size_details->set_device_pixel_ratio(device_pixel_ratio); - - // TODO(dtrainor): Don't keep sending size events to the server. Wait for a - // CompletionCallback to return before sending future size updates. - outgoing_message_processor_->ProcessMessage(std::move(message), - net::CompletionCallback()); -} - -void TabControlFeature::CreateTab(int tab_id) { - TabControlMessage* tab_control; - std::unique_ptr<BlimpMessage> message = CreateBlimpMessage(&tab_control); - tab_control->mutable_create_tab(); - outgoing_message_processor_->ProcessMessage(std::move(message), - net::CompletionCallback()); -} - -void TabControlFeature::CloseTab(int tab_id) { - TabControlMessage* tab_control; - std::unique_ptr<BlimpMessage> message = CreateBlimpMessage(&tab_control); - tab_control->mutable_close_tab(); - outgoing_message_processor_->ProcessMessage(std::move(message), - net::CompletionCallback()); -} - -void TabControlFeature::ProcessMessage( - std::unique_ptr<BlimpMessage> message, - const net::CompletionCallback& callback) { - DCHECK(!callback.is_null()); - callback.Run(net::OK); - - NOTIMPLEMENTED(); -} - -} // namespace client -} // namespace blimp
diff --git a/blimp/client/feature/tab_control_feature.h b/blimp/client/feature/tab_control_feature.h deleted file mode 100644 index 962d0c2..0000000 --- a/blimp/client/feature/tab_control_feature.h +++ /dev/null
@@ -1,56 +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 BLIMP_CLIENT_FEATURE_TAB_CONTROL_FEATURE_H_ -#define BLIMP_CLIENT_FEATURE_TAB_CONTROL_FEATURE_H_ - -#include <memory> - -#include "base/macros.h" -#include "blimp/net/blimp_message_processor.h" -#include "ui/gfx/geometry/size.h" - -namespace gfx { -class Size; -} - -namespace blimp { -namespace client { - -class TabControlFeature : public BlimpMessageProcessor { - public: - TabControlFeature(); - ~TabControlFeature() override; - - // Set the BlimpMessageProcessor that will be used to send - // BlimpMessage::TAB_CONTROL messages to the engine. - void set_outgoing_message_processor( - std::unique_ptr<BlimpMessageProcessor> processor); - - // Pushes the current size and scale information to the engine, which will - // affect the web content display area for all tabs. - void SetSizeAndScale(const gfx::Size& size, float device_pixel_ratio); - - void CreateTab(int tab_id); - void CloseTab(int tab_id); - - // BlimpMessageProcessor implementation. - void ProcessMessage(std::unique_ptr<BlimpMessage> message, - const net::CompletionCallback& callback) override; - - private: - // Used to send BlimpMessage::TAB_CONTROL messages to the engine. - std::unique_ptr<BlimpMessageProcessor> outgoing_message_processor_; - - // Used to avoid sending unnecessary messages to engine. - gfx::Size last_size_; - float last_device_pixel_ratio_ = -1; - - DISALLOW_COPY_AND_ASSIGN(TabControlFeature); -}; - -} // namespace client -} // namespace blimp - -#endif // BLIMP_CLIENT_FEATURE_TAB_CONTROL_FEATURE_H_
diff --git a/blimp/client/feature/tab_control_feature_unittest.cc b/blimp/client/feature/tab_control_feature_unittest.cc deleted file mode 100644 index 471719e3..0000000 --- a/blimp/client/feature/tab_control_feature_unittest.cc +++ /dev/null
@@ -1,93 +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 "blimp/client/feature/tab_control_feature.h" - -#include <memory> - -#include "base/logging.h" -#include "base/memory/ptr_util.h" -#include "blimp/common/proto/blimp_message.pb.h" -#include "blimp/common/proto/tab_control.pb.h" -#include "blimp/net/test_common.h" -#include "net/base/net_errors.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/gfx/geometry/size.h" - -using testing::_; - -namespace blimp { -namespace client { - -MATCHER_P3(EqualsSizeMessage, width, height, dp_to_px, "") { - return arg.tab_control().tab_control_case() == TabControlMessage::kSize && - arg.tab_control().size().width() == width && - arg.tab_control().size().height() == height && - arg.tab_control().size().device_pixel_ratio() == dp_to_px; -} - -class TabControlFeatureTest : public testing::Test { - public: - TabControlFeatureTest() : out_processor_(nullptr) {} - - void SetUp() override { - out_processor_ = new MockBlimpMessageProcessor(); - feature_.set_outgoing_message_processor(base::WrapUnique(out_processor_)); - } - - protected: - // This is a raw pointer to a class that is owned by the ControlFeature. - MockBlimpMessageProcessor* out_processor_; - - TabControlFeature feature_; -}; - -TEST_F(TabControlFeatureTest, CreatesCorrectSizeMessage) { - uint64_t width = 10; - uint64_t height = 15; - float dp_to_px = 1.23f; - - EXPECT_CALL( - *out_processor_, - MockableProcessMessage(EqualsSizeMessage(width, height, dp_to_px), _)) - .Times(1); - feature_.SetSizeAndScale(gfx::Size(width, height), dp_to_px); -} - -TEST_F(TabControlFeatureTest, NoDuplicateSizeMessage) { - uint64_t width = 10; - uint64_t height = 15; - float dp_to_px = 1.23f; - - EXPECT_CALL( - *out_processor_, - MockableProcessMessage(EqualsSizeMessage(width, height, dp_to_px), _)) - .Times(1) - .RetiresOnSaturation(); - EXPECT_CALL( - *out_processor_, - MockableProcessMessage(EqualsSizeMessage(width, height, dp_to_px + 1), _)) - .Times(1) - .RetiresOnSaturation(); - EXPECT_CALL(*out_processor_, - MockableProcessMessage( - EqualsSizeMessage(width + 1, height, dp_to_px + 1), _)) - .Times(1) - .RetiresOnSaturation(); - EXPECT_CALL(*out_processor_, - MockableProcessMessage( - EqualsSizeMessage(width + 1, height + 1, dp_to_px + 1), _)) - .Times(1) - .RetiresOnSaturation(); - - feature_.SetSizeAndScale(gfx::Size(width, height), dp_to_px); - feature_.SetSizeAndScale(gfx::Size(width, height), dp_to_px); - feature_.SetSizeAndScale(gfx::Size(width, height), dp_to_px + 1); - feature_.SetSizeAndScale(gfx::Size(width + 1, height), dp_to_px + 1); - feature_.SetSizeAndScale(gfx::Size(width + 1, height + 1), dp_to_px + 1); -} - -} // namespace client -} // namespace blimp
diff --git a/blimp/client/public/BUILD.gn b/blimp/client/public/BUILD.gn index 3b787909..b9023b1 100644 --- a/blimp/client/public/BUILD.gn +++ b/blimp/client/public/BUILD.gn
@@ -30,13 +30,17 @@ "blimp_client_context.h", "blimp_client_context_delegate.h", "contents/blimp_contents.h", + "contents/blimp_contents_observer.cc", "contents/blimp_contents_observer.h", "contents/blimp_navigation_controller.h", + "session/assignment.cc", + "session/assignment.h", ] public_deps = [ "//base", "//components/keyed_service/core", + "//net", "//url", ] @@ -75,5 +79,21 @@ "android/java/src/org/chromium/blimp_public/BlimpClientContextDelegate.java", "android/java/src/org/chromium/blimp_public/BlimpSettingsCallbacks.java", ] + + deps = [ + "//third_party/android_tools:android_support_annotations_java", + ] + + # The enums are added here for convenience for embedders, so they can still + # only depend on :public_java. + srcjar_deps = [ ":public_headers_java_enums_srcjar" ] + } + + java_cpp_enum("public_headers_java_enums_srcjar") { + visibility = [ ":*" ] + + sources = [ + "session/assignment.h", + ] } }
diff --git a/blimp/client/public/blimp_client_context.h b/blimp/client/public/blimp_client_context.h index e43e739..8b8638f0 100644 --- a/blimp/client/public/blimp_client_context.h +++ b/blimp/client/public/blimp_client_context.h
@@ -6,6 +6,7 @@ #define BLIMP_CLIENT_PUBLIC_BLIMP_CLIENT_CONTEXT_H_ #include <memory> +#include <string> #include "base/memory/ref_counted.h" #include "base/single_thread_task_runner.h" @@ -41,8 +42,11 @@ // linked in. // The |io_thread_task_runner| must be the task runner to use for IO // operations. + // The |file_thread_task_runner| must be the task runner to use for file + // operations. static BlimpClientContext* Create( - scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner); + scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner); // The delegate provides all the required functionality from the embedder. virtual void SetDelegate(BlimpClientContextDelegate* delegate) = 0; @@ -50,6 +54,9 @@ // Creates a new BlimpContents. virtual std::unique_ptr<BlimpContents> CreateBlimpContents() = 0; + // Initiates the process for connecting to the engine. + virtual void Connect(const std::string& client_auth_token) = 0; + protected: BlimpClientContext() = default;
diff --git a/blimp/client/public/blimp_client_context_delegate.h b/blimp/client/public/blimp_client_context_delegate.h index 506d948..ea51f19 100644 --- a/blimp/client/public/blimp_client_context_delegate.h +++ b/blimp/client/public/blimp_client_context_delegate.h
@@ -6,6 +6,7 @@ #define BLIMP_CLIENT_PUBLIC_BLIMP_CLIENT_CONTEXT_DELEGATE_H_ #include "base/macros.h" +#include "blimp/client/public/session/assignment.h" namespace blimp { namespace client { @@ -20,6 +21,16 @@ // Attaches any required base::SupportsUserData::Data to the BlimpContents. virtual void AttachBlimpContentsHelpers(BlimpContents* blimp_contents) = 0; + // Called whenever an assignment request has finished and the resulting + // Assignment is ready to be used in an attempt to connect to the engine. The + // |result| is the result for the assignment request itself, not for the + // connection attempt. Only when |result| is ASSIGNMENT_REQUEST_RESULT_OK + // will an attempt actually be made to connect to the engine using the + // Assignment. + virtual void OnAssignmentConnectionAttempted( + AssignmentRequestResult result, + const Assignment& assignment) = 0; + protected: BlimpClientContextDelegate() = default;
diff --git a/blimp/client/public/contents/blimp_contents_observer.cc b/blimp/client/public/contents/blimp_contents_observer.cc new file mode 100644 index 0000000..edf48fd --- /dev/null +++ b/blimp/client/public/contents/blimp_contents_observer.cc
@@ -0,0 +1,29 @@ +// 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 "blimp/client/public/contents/blimp_contents_observer.h" + +#include "blimp/client/public/contents/blimp_contents.h" + +namespace blimp { +namespace client { + +BlimpContentsObserver::BlimpContentsObserver(BlimpContents* blimp_contents) + : contents_(blimp_contents) { + blimp_contents->AddObserver(this); +} + +BlimpContentsObserver::~BlimpContentsObserver() { + if (contents_) + contents_->RemoveObserver(this); +} + +void BlimpContentsObserver::BlimpContentsDying() { + DCHECK(contents_); + OnContentsDestroyed(); + contents_ = nullptr; +} + +} // namespace client +} // namespace blimp
diff --git a/blimp/client/public/contents/blimp_contents_observer.h b/blimp/client/public/contents/blimp_contents_observer.h index dc3e1ec89..a70c577 100644 --- a/blimp/client/public/contents/blimp_contents_observer.h +++ b/blimp/client/public/contents/blimp_contents_observer.h
@@ -11,19 +11,33 @@ namespace blimp { namespace client { +class BlimpContents; + // An observer API implemented by classes which are interested in various events // related to BlimpContents. class BlimpContentsObserver { public: - virtual ~BlimpContentsObserver() = default; + virtual ~BlimpContentsObserver(); // Invoked when the navigation state of the BlimpContents has changed. virtual void OnNavigationStateChanged() {} + // Called by BlimpContentsDying(). + virtual void OnContentsDestroyed() {} + + // Invoke when the destructor of blimp contents is called. This will clear + // the contents_ to nullptr. + void BlimpContentsDying(); + + BlimpContents* blimp_contents() { return contents_; } + protected: - BlimpContentsObserver() {} + explicit BlimpContentsObserver(BlimpContents* blimp_contents); private: + // The BlimpContents being tracked by this BlimpContentsObserver. + BlimpContents* contents_; + DISALLOW_COPY_AND_ASSIGN(BlimpContentsObserver); };
diff --git a/blimp/client/public/session/assignment.cc b/blimp/client/public/session/assignment.cc new file mode 100644 index 0000000..333875f --- /dev/null +++ b/blimp/client/public/session/assignment.cc
@@ -0,0 +1,30 @@ +// 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 "blimp/client/public/session/assignment.h" + +#include "net/cert/x509_certificate.h" + +namespace blimp { +namespace client { + +Assignment::Assignment() : transport_protocol(TransportProtocol::UNKNOWN) {} + +Assignment::Assignment(const Assignment& other) = default; + +Assignment::~Assignment() {} + +bool Assignment::IsValid() const { + if (engine_endpoint.address().empty() || engine_endpoint.port() == 0 || + transport_protocol == TransportProtocol::UNKNOWN) { + return false; + } + if (transport_protocol == TransportProtocol::SSL && !cert) { + return false; + } + return true; +} + +} // namespace client +} // namespace blimp
diff --git a/blimp/client/public/session/assignment.h b/blimp/client/public/session/assignment.h new file mode 100644 index 0000000..ea755158 --- /dev/null +++ b/blimp/client/public/session/assignment.h
@@ -0,0 +1,70 @@ +// 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 BLIMP_CLIENT_PUBLIC_SESSION_ASSIGNMENT_H_ +#define BLIMP_CLIENT_PUBLIC_SESSION_ASSIGNMENT_H_ + +#include <string> + +#include "base/memory/ref_counted.h" +#include "net/base/ip_endpoint.h" + +namespace net { +class X509Certificate; +} + +namespace blimp { +namespace client { + +// A Java counterpart will be generated for this enum. +// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.blimp_public.session +enum AssignmentRequestResult { + ASSIGNMENT_REQUEST_RESULT_UNKNOWN = 0, + ASSIGNMENT_REQUEST_RESULT_OK = 1, + ASSIGNMENT_REQUEST_RESULT_BAD_REQUEST = 2, + ASSIGNMENT_REQUEST_RESULT_BAD_RESPONSE = 3, + ASSIGNMENT_REQUEST_RESULT_INVALID_PROTOCOL_VERSION = 4, + ASSIGNMENT_REQUEST_RESULT_EXPIRED_ACCESS_TOKEN = 5, + ASSIGNMENT_REQUEST_RESULT_USER_INVALID = 6, + ASSIGNMENT_REQUEST_RESULT_OUT_OF_VMS = 7, + ASSIGNMENT_REQUEST_RESULT_SERVER_ERROR = 8, + ASSIGNMENT_REQUEST_RESULT_SERVER_INTERRUPTED = 9, + ASSIGNMENT_REQUEST_RESULT_NETWORK_FAILURE = 10, + ASSIGNMENT_REQUEST_RESULT_INVALID_CERT = 11, +}; + +// An Assignment contains the configuration data needed for a client +// to connect to the engine. +struct Assignment { + enum TransportProtocol { + UNKNOWN = 0, + SSL = 1, + TCP = 2, + }; + + Assignment(); + Assignment(const Assignment& other); + ~Assignment(); + + // Returns false if the net::IPEndPoint has an unspecified IP, port, or + // transport protocol. + bool IsValid() const; + + // Specifies the transport to use to connect to the engine. + TransportProtocol transport_protocol; + + // Specifies the IP address and port on which to reach the engine. + net::IPEndPoint engine_endpoint; + + // Used to authenticate to the specified engine. + std::string client_token; + + // Specifies the engine's X.509 certificate. + scoped_refptr<net::X509Certificate> cert; +}; + +} // namespace client +} // namespace blimp + +#endif // BLIMP_CLIENT_PUBLIC_SESSION_ASSIGNMENT_H_
diff --git a/blimp/client/session/blimp_client_session.cc b/blimp/client/session/blimp_client_session.cc index 7c69dd00..65dbad9 100644 --- a/blimp/client/session/blimp_client_session.cc +++ b/blimp/client/session/blimp_client_session.cc
@@ -17,12 +17,12 @@ #include "base/threading/thread_task_runner_handle.h" #include "blimp/client/core/blimp_client_switches.h" #include "blimp/client/core/contents/navigation_feature.h" +#include "blimp/client/core/contents/tab_control_feature.h" #include "blimp/client/core/session/client_network_components.h" #include "blimp/client/core/session/cross_thread_network_event_observer.h" #include "blimp/client/feature/ime_feature.h" #include "blimp/client/feature/render_widget_feature.h" #include "blimp/client/feature/settings_feature.h" -#include "blimp/client/feature/tab_control_feature.h" #include "blimp/common/blob_cache/in_memory_blob_cache.h" #include "blimp/net/blimp_message_thread_pipe.h" #include "blimp/net/blob_channel/blob_channel_receiver.h" @@ -82,11 +82,11 @@ weak_factory_.GetWeakPtr())); } -void BlimpClientSession::ConnectWithAssignment(AssignmentSource::Result result, +void BlimpClientSession::ConnectWithAssignment(AssignmentRequestResult result, const Assignment& assignment) { OnAssignmentConnectionAttempted(result, assignment); - if (result != AssignmentSource::Result::RESULT_OK) { + if (result != ASSIGNMENT_REQUEST_RESULT_OK) { LOG(ERROR) << "Assignment failed, reason: " << result; return; } @@ -100,7 +100,7 @@ } void BlimpClientSession::OnAssignmentConnectionAttempted( - AssignmentSource::Result result, + AssignmentRequestResult result, const Assignment& assignment) {} void BlimpClientSession::RegisterFeatures() {
diff --git a/blimp/client/session/blimp_client_session.h b/blimp/client/session/blimp_client_session.h index 7b94faf..10951470c 100644 --- a/blimp/client/session/blimp_client_session.h +++ b/blimp/client/session/blimp_client_session.h
@@ -15,6 +15,7 @@ #include "blimp/client/core/compositor/blob_image_serialization_processor.h" #include "blimp/client/core/session/assignment_source.h" #include "blimp/client/core/session/network_event_observer.h" +#include "blimp/client/public/session/assignment.h" #include "blimp/common/proto/blimp_message.pb.h" #include "blimp/net/blimp_connection_statistics.h" #include "blimp/net/blimp_message_processor.h" @@ -73,7 +74,7 @@ // The AssignmentCallback for when an assignment is ready. This will trigger // a connection to the engine. - virtual void ConnectWithAssignment(AssignmentSource::Result result, + virtual void ConnectWithAssignment(AssignmentRequestResult result, const Assignment& assignment); protected: @@ -81,7 +82,7 @@ // Notified every time the AssignmentSource returns the result of an attempted // assignment request. - virtual void OnAssignmentConnectionAttempted(AssignmentSource::Result result, + virtual void OnAssignmentConnectionAttempted(AssignmentRequestResult result, const Assignment& assignment); private:
diff --git a/blimp/client/test/test_blimp_client_context_delegate.h b/blimp/client/test/test_blimp_client_context_delegate.h index 8062245e..16b18fe 100644 --- a/blimp/client/test/test_blimp_client_context_delegate.h +++ b/blimp/client/test/test_blimp_client_context_delegate.h
@@ -21,6 +21,8 @@ // BlimpClientContextDelegate implementation. MOCK_METHOD1(AttachBlimpContentsHelpers, void(BlimpContents*)); + MOCK_METHOD2(OnAssignmentConnectionAttempted, + void(AssignmentRequestResult, const Assignment&)); private: DISALLOW_COPY_AND_ASSIGN(TestBlimpClientContextDelegate);
diff --git a/blimp/docs/build.md b/blimp/docs/build.md index 0df09d756..b984f0a 100644 --- a/blimp/docs/build.md +++ b/blimp/docs/build.md
@@ -13,7 +13,20 @@ ## Building There are two different build configurations depending on what you want to -build: +build, either the client or the engine. + +Regardless of which you build, it is helpful to setup the following +environment variable in your shell to get a better view of how the build is +progressing: + +```bash +export NINJA_STATUS="[%r %f/%s/%u/%t] " +``` + +It will give you a count for the following values: +`[RUNNING FINISHED/STARTED/NOT_STARTED/TOTAL]`. See the +[ninja manual](https://ninja-build.org/manual.html#_environment_variables) +for a full list of template values. ### Android client
diff --git a/blimp/engine/browser_tests/engine_browsertest.cc b/blimp/engine/browser_tests/engine_browsertest.cc index f10f100..369adcf 100644 --- a/blimp/engine/browser_tests/engine_browsertest.cc +++ b/blimp/engine/browser_tests/engine_browsertest.cc
@@ -5,12 +5,13 @@ #include "base/memory/ptr_util.h" #include "blimp/client/core/contents/mock_navigation_feature_delegate.h" #include "blimp/client/core/contents/navigation_feature.h" +#include "blimp/client/core/contents/tab_control_feature.h" #include "blimp/client/core/session/assignment_source.h" #include "blimp/client/feature/ime_feature.h" #include "blimp/client/feature/mock_ime_feature_delegate.h" #include "blimp/client/feature/mock_render_widget_feature_delegate.h" #include "blimp/client/feature/render_widget_feature.h" -#include "blimp/client/feature/tab_control_feature.h" +#include "blimp/client/public/session/assignment.h" #include "blimp/client/session/test_client_session.h" #include "blimp/engine/browser_tests/blimp_browser_test.h" #include "content/public/test/browser_test.h" @@ -72,8 +73,8 @@ .WillOnce(InvokeWithoutArgs(this, &EngineBrowserTest::QuitRunLoop)); // Skip assigner. Engine info is already available. - client_session_->ConnectWithAssignment( - client::AssignmentSource::Result::RESULT_OK, GetAssignment()); + client_session_->ConnectWithAssignment(client::ASSIGNMENT_REQUEST_RESULT_OK, + GetAssignment()); client_session_->GetTabControlFeature()->SetSizeAndScale(gfx::Size(100, 100), 1); client_session_->GetTabControlFeature()->CreateTab(kDummyTabId);
diff --git a/blimp/tools/client_engine_integration.py b/blimp/tools/client_engine_integration.py index 75235ae..f1807f3 100755 --- a/blimp/tools/client_engine_integration.py +++ b/blimp/tools/client_engine_integration.py
@@ -294,6 +294,10 @@ blacklist_file = args.blacklist_file serial = args.device else: + if not _IsNonEmptyFile(json_file_path): + logging.error('Cannot find json file: %s' + json_file_path) + logging.error('Run `client_engine_integration.py {run,start}` first.') + sys.exit(1) with open(json_file_path, 'r') as f: file_lines = f.readlines() jsonarg = json.loads(file_lines[0], object_hook=_FromJson)
diff --git a/build/android/pylib/gtest/filter/content_browsertests_disabled b/build/android/pylib/gtest/filter/content_browsertests_disabled index b18be439..d4fe3b6 100644 --- a/build/android/pylib/gtest/filter/content_browsertests_disabled +++ b/build/android/pylib/gtest/filter/content_browsertests_disabled
@@ -34,7 +34,7 @@ RenderViewImplTest.OnHandleKeyboardEvent RenderViewImplTest.OnNavStateChanged # ZoomLevel is not used on Android -RenderFrameImplTest.ZoomLimit +RenderViewImplTest.ZoomLimit RendererAccessibilityTest.SendFullAccessibilityTreeOnReload RendererAccessibilityTest.HideAccessibilityObject RendererAccessibilityTest.ShowAccessibilityObject
diff --git a/build/android/pylib/perf/perf_test_instance.py b/build/android/pylib/perf/perf_test_instance.py index 426ffaf..5643682 100644 --- a/build/android/pylib/perf/perf_test_instance.py +++ b/build/android/pylib/perf/perf_test_instance.py
@@ -79,7 +79,9 @@ ' '.join(args.single_step_command) if args.single_step else None) self._steps = args.steps self._test_filter = args.test_filter - self._write_buildbot_json = args.write_buildbot_json + # TODO(perezju): Read the value from the command line option when bot + # recipes have been updated to supply it. + self._write_buildbot_json = True # args.write_buildbot_json def SetUp(self): pass
diff --git a/build/android/pylib/results/flakiness_dashboard/results_uploader.py b/build/android/pylib/results/flakiness_dashboard/results_uploader.py index 71fbee1..b68a898b 100644 --- a/build/android/pylib/results/flakiness_dashboard/results_uploader.py +++ b/build/android/pylib/results/flakiness_dashboard/results_uploader.py
@@ -86,22 +86,17 @@ """Handles uploading buildbot tests results to the flakiness dashboard.""" def __init__(self, tests_type): self._build_number = os.environ.get('BUILDBOT_BUILDNUMBER') + self._master_name = os.environ.get('BUILDBOT_MASTERNAME') self._builder_name = os.environ.get('BUILDBOT_BUILDERNAME') self._tests_type = tests_type + self._build_name = None if not self._build_number or not self._builder_name: raise Exception('You should not be uploading tests results to the server' 'from your local machine.') upstream = (tests_type != 'Chromium_Android_Instrumentation') - if upstream: - # TODO(frankf): Use factory properties (see buildbot/bb_device_steps.py) - # This requires passing the actual master name (e.g. 'ChromiumFYI' not - # 'chromium.fyi'). - from slave import slave_utils # pylint: disable=F0401 - self._build_name = slave_utils.SlaveBuildName(host_paths.DIR_SOURCE_ROOT) - self._master_name = slave_utils.GetActiveMaster() - else: + if not upstream: self._build_name = 'chromium-android' buildbot_branch = os.environ.get('BUILDBOT_BRANCH') if not buildbot_branch:
diff --git a/build/config/ios/codesign.py b/build/config/ios/codesign.py index 364640e..3d66b24 100644 --- a/build/config/ios/codesign.py +++ b/build/config/ios/codesign.py
@@ -268,6 +268,9 @@ parser.add_argument( '--disable-code-signature', action='store_false', dest='sign', help='disable code signature') + parser.add_argument( + '--platform', '-t', required=True, + help='platform the signed bundle is targetting') parser.set_defaults(sign=True) @staticmethod @@ -283,7 +286,7 @@ provisioning_profile_required = args.identity != '-' provisioning_profile = FindProvisioningProfile( bundle.identifier, provisioning_profile_required) - if provisioning_profile: + if provisioning_profile and args.platform != 'iphonesimulator': provisioning_profile.Install(bundle) # Delete existing code signature. @@ -306,7 +309,7 @@ # Embeds entitlements into the code signature (if code signing identify has # been provided). codesign_extra_args = [] - if provisioning_profile: + if provisioning_profile and args.platform != 'iphonesimulator': temporary_entitlements_file = tempfile.NamedTemporaryFile(suffix='.xcent') codesign_extra_args.extend( ['--entitlements', temporary_entitlements_file.name])
diff --git a/build/config/ios/rules.gni b/build/config/ios/rules.gni index c670170..5a9b209 100644 --- a/build/config/ios/rules.gni +++ b/build/config/ios/rules.gni
@@ -480,6 +480,7 @@ } code_signing_args = [ "code-sign-bundle", + "-t=" + ios_sdk_name, "-i=" + ios_code_signing_identity, "-e=" + rebase_path(_entitlements_path, root_build_dir), "-b=" + rebase_path("$target_out_dir/$_output_name", root_build_dir), @@ -835,6 +836,7 @@ "assert_no_deps", "bundle_deps", "data_deps", + "enable_code_signing", "info_plist", "info_plist_target", "output_name", @@ -984,6 +986,7 @@ "assert_no_deps", "bundle_deps", "data_deps", + "enable_code_signing", "info_plist", "info_plist_target", "output_name", @@ -1139,8 +1142,8 @@ } bundle_root_dir = _framework_root_dir - bundle_resources_dir = "$bundle_root_dir/Resources" - bundle_executable_dir = "$bundle_root_dir" + bundle_resources_dir = _framework_root_dir + bundle_executable_dir = _framework_root_dir if (!defined(deps)) { deps = [] @@ -1152,13 +1155,18 @@ _entitlements_path = invoker.entitlements_path } + _ios_enable_code_signing = ios_enable_code_signing + if (defined(invoker.enable_code_signing)) { + _ios_enable_code_signing = invoker.enable_code_signing + } + code_signing_script = _code_signing_script_path code_signing_sources = [ _entitlements_path, "$_shared_library_dir/$_output_name", ] code_signing_outputs = [ "$bundle_root_dir/$_output_name" ] - if (ios_enable_code_signing) { + if (_ios_enable_code_signing) { code_signing_outputs += [ "$bundle_root_dir/_CodeSignature/CodeResources" ] } @@ -1167,13 +1175,14 @@ } code_signing_args = [ "code-sign-bundle", + "-t=" + ios_sdk_name, "-i=" + ios_code_signing_identity, "-e=" + rebase_path(_entitlements_path, root_build_dir), "-b=" + rebase_path("$_shared_library_dir/$_output_name", root_build_dir), rebase_path(bundle_root_dir, root_build_dir), ] - if (!ios_enable_code_signing) { + if (!_ios_enable_code_signing) { code_signing_args += [ "--disable-code-signature" ] } } @@ -1408,6 +1417,7 @@ } code_signing_args = [ "code-sign-bundle", + "-t=" + ios_sdk_name, "-i=" + ios_code_signing_identity, "-e=" + rebase_path(_entitlements_path, root_build_dir), "-b=" + rebase_path("$target_out_dir/$_xctest_output", root_build_dir),
diff --git a/build/config/mac/mac_sdk.gni b/build/config/mac/mac_sdk.gni index eb0fdda6..587f43dd 100644 --- a/build/config/mac/mac_sdk.gni +++ b/build/config/mac/mac_sdk.gni
@@ -25,8 +25,20 @@ mac_sdk_name = "macosx" } +# Check that the version of macOS SDK used is the one requested when building +# a version of Chrome shipped to the users. Disable the check if building for +# iOS as the version macOS SDK used is not relevant for the tool build for the +# host (they are not shipped) --- this is required as Chrome on iOS is usually +# build with the latest version of Xcode that may not ship with the version of +# the macOS SDK used to build Chrome on mac. +# TODO(crbug.com/635745): the check for target_os should be replaced by a +# check that current_toolchain is default_toolchain, and the file should +# assert that current_os is "mac" once this file is no longer included by +# iOS toolchains. +_verify_sdk = is_chrome_branded && is_official_build && target_os != "ios" + find_sdk_args = [ "--print_sdk_path" ] -if (is_chrome_branded && is_official_build) { +if (_verify_sdk) { find_sdk_args += [ "--verify", mac_sdk_min,
diff --git a/build/config/mac/symbols.gni b/build/config/mac/symbols.gni index 8cec695..2cb0b8f0 100644 --- a/build/config/mac/symbols.gni +++ b/build/config/mac/symbols.gni
@@ -3,6 +3,7 @@ # found in the LICENSE file. import("//build/config/chrome_build.gni") +import("//build/config/sanitizers/sanitizers.gni") # This file declares arguments and configs that control whether dSYM debug # info is produced and whether build products are stripped. @@ -13,14 +14,14 @@ # the //build/toolchain/mac/linker_driver.py. Enabling this will result in # all shared library, loadable module, and executable targets having a dSYM # generated. - enable_dsyms = is_official_build + enable_dsyms = (is_official_build && is_chrome_branded) || using_sanitizer # Strip symbols from linked targets by default. If this is enabled, the # //build/config/mac:strip_all config will be applied to all linked targets. - # If custom stripping paramters are required, remove that config from a + # If custom stripping parameters are required, remove that config from a # linked target and apply custom -Wcrl,strip flags. See # //build/toolchain/mac/linker_driver.py for more information. - enable_stripping = is_official_build + enable_stripping = is_official_build && is_chrome_branded } # Save unstripped copies of targets with a ".unstripped" suffix. This is
diff --git a/build/config/sanitizers/BUILD.gn b/build/config/sanitizers/BUILD.gn index cf518962..3768cb93 100644 --- a/build/config/sanitizers/BUILD.gn +++ b/build/config/sanitizers/BUILD.gn
@@ -231,6 +231,12 @@ if (using_sanitizer) { assert(is_clang, "sanitizers only supported with clang") cflags += [ "-gline-tables-only" ] + if (is_win) { + # Just -gline-tables-only currently causes clang-cl to emit debug info + # in DWARF format. + # TODO(thakis): Remove this once we have a clang at LLVM r278139+ + cflags += [ "/Z7" ] + } } # Common options for AddressSanitizer, LeakSanitizer, ThreadSanitizer,
diff --git a/build/config/win/BUILD.gn b/build/config/win/BUILD.gn index 90be9952..5e621ba 100644 --- a/build/config/win/BUILD.gn +++ b/build/config/win/BUILD.gn
@@ -16,6 +16,9 @@ # warnings, so normally this is done on a build machine and only the new # warnings are examined. use_vs_code_analysis = false + + # Turn this on to have the linker output extra timing information. + win_linker_timing = false } # This is included by reference in the //build/config/compiler config that @@ -267,13 +270,10 @@ "/maxilksize:0x7ff00000", ] - # Flags not supported in version 2013. - if (visual_studio_version != "2013" && visual_studio_version != "2013e") { - ldflags += [ - # Tell the linker to crash on failures. - "/fastfail", - ] - } + ldflags += [ + # Tell the linker to crash on failures. + "/fastfail", + ] # ASLR makes debugging with windbg difficult because Chrome.exe and # Chrome.dll share the same base name. As result, windbg will name the @@ -286,6 +286,13 @@ } else { ldflags += [ "/DYNAMICBASE" ] } + + if (win_linker_timing) { + ldflags += [ + "/time", + "/verbose:incr", + ] + } } # Subsystem --------------------------------------------------------------------
diff --git a/build/landmine_utils.py b/build/landmine_utils.py index ef949d72..57dfe3f2 100644 --- a/build/landmine_utils.py +++ b/build/landmine_utils.py
@@ -33,7 +33,7 @@ @memoize() def IsLinux(): - return sys.platform.startswith(('linux', 'freebsd', 'openbsd')) + return sys.platform.startswith(('linux', 'freebsd', 'netbsd', 'openbsd')) @memoize()
diff --git a/build/toolchain/android/BUILD.gn b/build/toolchain/android/BUILD.gn index 4a1a29f..917c4691 100644 --- a/build/toolchain/android/BUILD.gn +++ b/build/toolchain/android/BUILD.gn
@@ -10,8 +10,6 @@ # wrapper around gcc_toolchain to avoid duplication of logic. # # Parameters: -# - toolchain_cpu -# Same as gcc_toolchain. # - toolchain_root # Path to cpu-specific toolchain within the ndk. # - sysroot @@ -22,9 +20,10 @@ # Prefix of compiler executables. template("android_gcc_toolchain") { gcc_toolchain(target_name) { - is_clang = invoker.is_clang - toolchain_cpu = invoker.toolchain_cpu - toolchain_os = "android" + assert(defined(invoker.toolchain_args), + "toolchain_args must be defined for android_gcc_toolchain()") + toolchain_args = invoker.toolchain_args + toolchain_args.current_os = "android" # Make our manually injected libs relative to the build dir. _ndk_lib = @@ -42,7 +41,15 @@ # The tools should be run relative to the build dir. _tool_prefix = rebase_path("$_android_tool_prefix", root_build_dir) - if (is_clang) { + # Use the clang specified by the toolchain if there is one. Otherwise fall + # back to the global flag. + if (defined(toolchain_args.is_clang)) { + toolchain_uses_clang = toolchain_args.is_clang + } else { + toolchain_uses_clang = is_clang + } + + if (toolchain_uses_clang) { _prefix = rebase_path("$clang_base_path/bin", root_build_dir) cc = "$_prefix/clang" cxx = "$_prefix/clang++" @@ -65,58 +72,71 @@ template("android_gcc_toolchains_helper") { android_gcc_toolchain(target_name) { forward_variables_from(invoker, "*") + toolchain_args.is_clang = false } android_gcc_toolchain("clang_$target_name") { forward_variables_from(invoker, "*") - is_clang = true + toolchain_args.is_clang = true } } android_gcc_toolchains_helper("x86") { - toolchain_cpu = "x86" toolchain_root = x86_android_toolchain_root sysroot = "$android_ndk_root/$x86_android_sysroot_subdir" lib_dir = "usr/lib" binary_prefix = "i686-linux-android" + toolchain_args = { + current_cpu = "x86" + } } android_gcc_toolchains_helper("arm") { - toolchain_cpu = "arm" toolchain_root = arm_android_toolchain_root sysroot = "$android_ndk_root/$arm_android_sysroot_subdir" lib_dir = "usr/lib" binary_prefix = "arm-linux-androideabi" + toolchain_args = { + current_cpu = "arm" + } } android_gcc_toolchains_helper("mipsel") { - toolchain_cpu = "mipsel" toolchain_root = mips_android_toolchain_root sysroot = "$android_ndk_root/$mips_android_sysroot_subdir" lib_dir = "usr/lib" binary_prefix = "mipsel-linux-android" + toolchain_args = { + current_cpu = "mipsel" + } } android_gcc_toolchains_helper("x64") { - toolchain_cpu = "x86_64" toolchain_root = x86_64_android_toolchain_root sysroot = "$android_ndk_root/$x86_64_android_sysroot_subdir" lib_dir = "usr/lib64" binary_prefix = "x86_64-linux-android" + toolchain_args = { + current_cpu = "x64" + } } android_gcc_toolchains_helper("arm64") { - toolchain_cpu = "arm64" toolchain_root = arm64_android_toolchain_root sysroot = "$android_ndk_root/$arm64_android_sysroot_subdir" lib_dir = "usr/lib" binary_prefix = "aarch64-linux-android" + toolchain_args = { + current_cpu = "arm64" + } } android_gcc_toolchains_helper("mips64el") { - toolchain_cpu = "mips64el" toolchain_root = mips64_android_toolchain_root sysroot = "$android_ndk_root/$mips64_android_sysroot_subdir" lib_dir = "usr/lib64" binary_prefix = "mips64el-linux-android" + toolchain_args = { + current_cpu = "mips64el" + } }
diff --git a/build/toolchain/cc_wrapper.gni b/build/toolchain/cc_wrapper.gni index 1fa1850..0a03dde 100644 --- a/build/toolchain/cc_wrapper.gni +++ b/build/toolchain/cc_wrapper.gni
@@ -2,6 +2,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/toolchain/goma.gni") + # Defines the configuration of cc wrapper # ccache: a c/c++ compiler cache which can greatly reduce recompilation times. # icecc, distcc: it takes compile jobs from a build and distributes them among @@ -33,3 +35,6 @@ # Set to "ccache", "icecc" or "distcc". Probably doesn't work on windows. cc_wrapper = "" } + +assert(!use_goma || cc_wrapper == "", + "use_goma and cc_wrapper can not be used together.")
diff --git a/build/toolchain/cros/BUILD.gn b/build/toolchain/cros/BUILD.gn index c45779df..56a408b 100644 --- a/build/toolchain/cros/BUILD.gn +++ b/build/toolchain/cros/BUILD.gn
@@ -8,17 +8,9 @@ import("//build/toolchain/cros_toolchain.gni") template("cros_target_toolchain") { - if (defined(invoker.use_debug_fission)) { - use_debug_fission = invoker.use_debug_fission - } - if (defined(invoker.use_gold)) { - use_gold = invoker.use_gold - } - if (defined(invoker.use_sysroot)) { - use_sysroot = invoker.use_sysroot - } - gcc_toolchain(target_name) { + assert(defined(invoker.toolchain_args)) + # These are args for the template. ar = cros_target_ar cc = cros_target_cc @@ -38,20 +30,27 @@ extra_cxxflags = cros_target_extra_cxxflags extra_ldflags = cros_target_extra_ldflags - # These are passed through as toolchain_args. - cc_wrapper = "" - is_clang = is_clang - toolchain_cpu = target_cpu - toolchain_os = "chromeos" + toolchain_args = { + forward_variables_from(invoker.toolchain_args, "*") - use_debug_fission = use_debug_fission - use_gold = use_gold - use_sysroot = use_sysroot + cc_wrapper = "" + + # This will override the default computation for is_clang in the + # secondary toolchain with the value of is_clang in the current toolchain + # (the current toolchain will always be the default toolchain here). + is_clang = is_clang + current_cpu = target_cpu + current_os = "chromeos" + use_debug_fission = use_debug_fission + use_sysroot = use_sysroot + } } } # This is the normal toolchain for most targets. cros_target_toolchain("target") { + toolchain_args = { + } } # This is a special toolchain needed just for the nacl_bootstrap target in @@ -59,9 +58,11 @@ # to ":target" except that it forces use_debug_fission, use_gold, and # use_sysroot off. cros_target_toolchain("nacl_bootstrap") { - use_debug_fission = false - use_gold = false - use_sysroot = false + toolchain_args = { + use_debug_fission = false + use_gold = false + use_sysroot = false + } } gcc_toolchain("host") { @@ -84,12 +85,13 @@ extra_cxxflags = cros_host_extra_cxxflags extra_ldflags = cros_host_extra_ldflags - # These are passed through as toolchain_args. - cc_wrapper = "" - is_clang = cros_host_is_clang - toolchain_cpu = host_cpu - toolchain_os = "linux" - use_sysroot = false + toolchain_args = { + cc_wrapper = "" + is_clang = cros_host_is_clang + current_cpu = host_cpu + current_os = "linux" + use_sysroot = false + } } gcc_toolchain("v8_snapshot") { @@ -112,15 +114,16 @@ extra_cxxflags = cros_v8_snapshot_extra_cxxflags extra_ldflags = cros_v8_snapshot_extra_ldflags - # These are passed through as toolchain_args. - cc_wrapper = "" - is_clang = cros_v8_snapshot_is_clang - if (target_cpu == "x86" || target_cpu == "arm" || target_cpu == "mipsel") { - toolchain_cpu = "x86" - } else { - toolchain_cpu = "x64" + toolchain_args = { + cc_wrapper = "" + is_clang = cros_v8_snapshot_is_clang + if (target_cpu == "x86" || target_cpu == "arm" || target_cpu == "mipsel") { + current_cpu = "x86" + } else { + current_cpu = "x64" + } + v8_current_cpu = v8_target_cpu + current_os = "linux" + use_sysroot = false } - v8_toolchain_cpu = v8_target_cpu - toolchain_os = "linux" - use_sysroot = false }
diff --git a/build/toolchain/gcc_toolchain.gni b/build/toolchain/gcc_toolchain.gni index 0045411..ad2d1339 100644 --- a/build/toolchain/gcc_toolchain.gni +++ b/build/toolchain/gcc_toolchain.gni
@@ -18,11 +18,6 @@ # - cc # - cxx # - ld -# and the following which is used in the toolchain_args -# - toolchain_cpu (What "current_cpu" should be set to when invoking a -# build using this toolchain.) -# - toolchain_os (What "current_os" should be set to when invoking a -# build using this toolchain.) # # Optional parameters that control the tools: # @@ -72,61 +67,12 @@ # Location of the strip executable. When specified, strip will be run on # all shared libraries and executables as they are built. The pre-stripped # artifacts will be put in lib.unstripped/ and exe.unstripped/. -# -# Optional build argument controls. -# -# - clear_sanitizers -# When set to true, is_asan, is_msan, etc.will all be set to false. Often -# secondary toolchains do not want to run with sanitizers. -# - is_clang -# Whether to use clang instead of gcc. -# - is_component_build -# Whether to forcibly enable or disable component builds for this -# toolchain; if not specified, the toolchain will inherit the -# default setting. -# - is_nacl_glibc -# Whether NaCl code is built using Glibc instead of Newlib. -# - cc_wrapper -# Override the global cc_wrapper setting. e.g. "ccache" or "icecc". -# useful to opt-out of cc_wrapper in a particular toolchain by setting -# cc_wrapper = "" in it. -# - use_debug_fission -# Override the global use_debug_fission setting, useful if the particular -# toolchain should not be generating split-dwarf code. -# - use_goma -# Override the global use_goma setting, useful to opt-out of goma in a -# particular toolchain by setting use_gome = false in it. -# - use_gold -# Override the global use_gold setting, useful if the particular -# toolchain has a custom link step that is not actually using Gold. -# - v8_toolchain_cpu -# If defined, set v8_current_cpu to this, else set v8_current_cpu -# to current_cpu. template("gcc_toolchain") { toolchain(target_name) { assert(defined(invoker.ar), "gcc_toolchain() must specify a \"ar\" value") assert(defined(invoker.cc), "gcc_toolchain() must specify a \"cc\" value") assert(defined(invoker.cxx), "gcc_toolchain() must specify a \"cxx\" value") assert(defined(invoker.ld), "gcc_toolchain() must specify a \"ld\" value") - assert(defined(invoker.toolchain_cpu), - "gcc_toolchain() must specify a \"toolchain_cpu\"") - assert(defined(invoker.toolchain_os), - "gcc_toolchain() must specify a \"toolchain_os\"") - - if (defined(invoker.cc_wrapper)) { - cc_wrapper = invoker.cc_wrapper - } - if (defined(invoker.use_goma)) { - use_goma = invoker.use_goma - } - if (use_goma) { - assert(cc_wrapper == "", "Goma and cc_wrapper can't be used together.") - compiler_prefix = "$goma_dir/gomacc " - } else if (cc_wrapper != "") { - compiler_prefix = cc_wrapper + " " - } else { - compiler_prefix = "" - } # This define changes when the toolchain changes, forcing a rebuild. # Nothing should ever use this define. @@ -136,6 +82,60 @@ rebuild_string = "" } + # GN's syntax can't handle more than one scope dereference at once, like + # "invoker.toolchain_args.foo", so make a temporary to hold the toolchain + # args so we can do "invoker_toolchain_args.foo". + assert(defined(invoker.toolchain_args), + "Toolchains must specify toolchain_args") + invoker_toolchain_args = invoker.toolchain_args + assert(defined(invoker_toolchain_args.current_cpu), + "toolchain_args must specify a current_cpu") + assert(defined(invoker_toolchain_args.current_os), + "toolchain_args must specify a current_os") + + # When invoking this toolchain not as the default one, these args will be + # passed to the build. They are ignored when this is the default toolchain. + toolchain_args = { + # Populate toolchain args from the invoker. + forward_variables_from(invoker_toolchain_args, "*") + + # The host toolchain value computed by the default toolchain's setup + # needs to be passed through unchanged to all secondary toolchains to + # ensure that it's always the same, regardless of the values that may be + # set on those toolchains. + host_toolchain = host_toolchain + + if (!defined(invoker_toolchain_args.v8_current_cpu)) { + v8_current_cpu = invoker_toolchain_args.current_cpu + } + } + + # When the invoker has explicitly overridden use_goma or cc_wrapper in the + # toolchain args, use those values, otherwise default to the global one. + # This works because the only reasonable override that toolchains might + # supply for these values are to force-disable them. + if (defined(toolchain_args.use_goma)) { + toolchain_uses_goma = toolchain_args.use_goma + } else { + toolchain_uses_goma = use_goma + } + if (defined(toolchain_args.cc_wrapper)) { + toolchain_cc_wrapper = toolchain_args.cc_wrapper + } else { + toolchain_cc_wrapper = cc_wrapper + } + + # Compute the compiler prefix. + if (toolchain_uses_goma) { + assert(toolchain_cc_wrapper == "", + "Goma and cc_wrapper can't be used together.") + compiler_prefix = "$goma_dir/gomacc " + } else if (toolchain_cc_wrapper != "") { + compiler_prefix = toolchain_cc_wrapper + " " + } else { + compiler_prefix = "" + } + cc = compiler_prefix + invoker.cc cxx = compiler_prefix + invoker.cxx ar = invoker.ar @@ -434,64 +434,18 @@ description = copy_description } - # When invoking this toolchain not as the default one, these args will be - # passed to the build. They are ignored when this is the default toolchain. - toolchain_args() { - current_cpu = invoker.toolchain_cpu - current_os = invoker.toolchain_os - - # These values need to be passed through unchanged. - host_toolchain = host_toolchain - target_os = target_os - target_cpu = target_cpu - - if (defined(invoker.is_clang)) { - is_clang = invoker.is_clang - } - if (defined(invoker.is_component_build)) { - is_component_build = invoker.is_component_build - } - if (defined(invoker.is_nacl_glibc)) { - is_nacl_glibc = invoker.is_nacl_glibc - } - if (defined(invoker.symbol_level)) { - symbol_level = invoker.symbol_level - } - if (defined(invoker.use_allocator)) { - use_allocator = invoker.use_allocator - } - if (defined(invoker.use_debug_fission)) { - use_debug_fission = invoker.use_debug_fission - } - if (defined(invoker.use_gold)) { - use_gold = invoker.use_gold - } - if (defined(invoker.use_sysroot)) { - use_sysroot = invoker.use_sysroot - } - if (defined(invoker.v8_toolchain_cpu)) { - v8_current_cpu = invoker.v8_toolchain_cpu - } else { - v8_current_cpu = current_cpu - } - } - forward_variables_from(invoker, [ "deps" ]) } } -# This is a shorthand for gcc_toolchain instances based on the -# Chromium-built version of Clang. Only the toolchain_cpu and -# toolchain_os variables need to be specified by the invoker, and -# optionally toolprefix if it's a cross-compile case. Note that for -# a cross-compile case this toolchain requires a config to pass the -# appropriate -target option, or else it will actually just be doing -# a native compile. The invoker can optionally override use_gold too. +# This is a shorthand for gcc_toolchain instances based on the Chromium-built +# version of Clang. Only the toolchain_cpu and toolchain_os variables need to +# be specified by the invoker, and optionally toolprefix if it's a +# cross-compile case. Note that for a cross-compile case this toolchain +# requires a config to pass the appropriate -target option, or else it will +# actually just be doing a native compile. The invoker can optionally override +# use_gold too. template("clang_toolchain") { - assert(defined(invoker.toolchain_cpu), - "clang_toolchain() must specify a \"toolchain_cpu\"") - assert(defined(invoker.toolchain_os), - "clang_toolchain() must specify a \"toolchain_os\"") if (defined(invoker.toolprefix)) { toolprefix = invoker.toolprefix } else { @@ -503,23 +457,41 @@ cc = "$prefix/clang" cxx = "$prefix/clang++" ld = cxx - is_clang = true readelf = "${toolprefix}readelf" ar = "${toolprefix}ar" nm = "${toolprefix}nm" - forward_variables_from(invoker, - [ - "strip", - "toolchain_cpu", - "toolchain_os", - "use_gold", - "v8_toolchain_cpu", - ]) + forward_variables_from(invoker, [ "strip" ]) + toolchain_args = { + if (defined(invoker.toolchain_args)) { + forward_variables_from(invoker.toolchain_args, "*") + } + is_clang = true + } + + # Backwards-compatible handling for toolchain definitions in the Native + # Client repo. + # + # TODO(brettw) bug 634446 remove this when + # //native_client/src/trusted/service_runtime/linux/BUILD.gn is updated to + # use the new-style toolchain_args. + if (defined(invoker.toolchain_cpu)) { + assert(!defined(toolchain_args.current_cpu)) + toolchain_args.current_cpu = invoker.toolchain_cpu + } + if (defined(invoker.toolchain_os)) { + assert(!defined(toolchain_args.current_os)) + toolchain_args.current_os = invoker.toolchain_os + } if (defined(invoker.use_debug_fission)) { - use_debug_fission = invoker.use_debug_fission + assert(!defined(toolchain_args.use_debug_fission)) + toolchain_args.use_debug_fission = invoker.use_debug_fission + } + if (defined(invoker.use_gold)) { + assert(!defined(toolchain_args.use_gold)) + toolchain_args.use_gold = invoker.use_gold } } }
diff --git a/build/toolchain/goma.gni b/build/toolchain/goma.gni index 86ac0e9..cb25cfd8 100644 --- a/build/toolchain/goma.gni +++ b/build/toolchain/goma.gni
@@ -3,9 +3,6 @@ # found in the LICENSE file. # Defines the configuration of Goma. -# -# This is currently designed to match the GYP build exactly, so as not to break -# people during the transition. declare_args() { # Set to true to enable distributed compilation using Goma.
diff --git a/build/toolchain/linux/BUILD.gn b/build/toolchain/linux/BUILD.gn index c7a8794..548722d39 100644 --- a/build/toolchain/linux/BUILD.gn +++ b/build/toolchain/linux/BUILD.gn
@@ -6,15 +6,19 @@ import("//build/toolchain/gcc_toolchain.gni") clang_toolchain("clang_arm") { - toolchain_cpu = "arm" - toolchain_os = "linux" toolprefix = "arm-linux-gnueabihf-" + toolchain_args = { + current_cpu = "arm" + current_os = "linux" + } } clang_toolchain("clang_arm64") { - toolchain_cpu = "arm64" - toolchain_os = "linux" toolprefix = "aarch64-linux-gnu-" + toolchain_args = { + current_cpu = "arm64" + current_os = "linux" + } } gcc_toolchain("arm") { @@ -28,26 +32,34 @@ readelf = "${toolprefix}readelf" nm = "${toolprefix}nm" - toolchain_cpu = "arm" - toolchain_os = "linux" - is_clang = false + toolchain_args = { + current_cpu = "arm" + current_os = "linux" + is_clang = false + } } clang_toolchain("clang_x86") { - toolchain_cpu = "x86" - toolchain_os = "linux" + toolchain_args = { + current_cpu = "x86" + current_os = "linux" + } } clang_toolchain("clang_x86_v8_arm") { - toolchain_cpu = "x86" - v8_toolchain_cpu = "arm" - toolchain_os = "linux" + toolchain_args = { + current_cpu = "x86" + v8_current_cpu = "arm" + current_os = "linux" + } } clang_toolchain("clang_x86_v8_mipsel") { - toolchain_cpu = "x86" - v8_toolchain_cpu = "mipsel" - toolchain_os = "linux" + toolchain_args = { + current_cpu = "x86" + v8_current_cpu = "mipsel" + current_os = "linux" + } } gcc_toolchain("x86") { @@ -59,26 +71,34 @@ ar = "ar" ld = cxx - toolchain_cpu = "x86" - toolchain_os = "linux" - is_clang = false + toolchain_args = { + current_cpu = "x86" + current_os = "linux" + is_clang = false + } } clang_toolchain("clang_x64") { - toolchain_cpu = "x64" - toolchain_os = "linux" + toolchain_args = { + current_cpu = "x64" + current_os = "linux" + } } clang_toolchain("clang_x64_v8_arm64") { - toolchain_cpu = "x64" - v8_toolchain_cpu = "arm64" - toolchain_os = "linux" + toolchain_args = { + current_cpu = "x64" + v8_current_cpu = "arm64" + current_os = "linux" + } } clang_toolchain("clang_x64_v8_mips64el") { - toolchain_cpu = "x64" - v8_toolchain_cpu = "mips64el" - toolchain_os = "linux" + toolchain_args = { + current_cpu = "x64" + v8_current_cpu = "mips64el" + current_os = "linux" + } } gcc_toolchain("x64") { @@ -90,14 +110,18 @@ ar = "ar" ld = cxx - toolchain_cpu = "x64" - toolchain_os = "linux" - is_clang = false + toolchain_args = { + current_cpu = "x64" + current_os = "linux" + is_clang = false + } } clang_toolchain("clang_mipsel") { - toolchain_cpu = "mipsel" - toolchain_os = "linux" + toolchain_args = { + current_cpu = "mipsel" + current_os = "linux" + } } gcc_toolchain("mipsel") { @@ -108,9 +132,11 @@ readelf = "mipsel-linux-gnu-readelf" nm = "mipsel-linux-gnu-nm" - toolchain_cpu = "mipsel" - toolchain_os = "linux" - is_clang = false - cc_wrapper = "" - use_goma = false + toolchain_args = { + cc_wrapper = "" + current_cpu = "mipsel" + current_os = "linux" + is_clang = false + use_goma = false + } }
diff --git a/build/toolchain/mac/BUILD.gn b/build/toolchain/mac/BUILD.gn index 348c3b36..44cf56d4 100644 --- a/build/toolchain/mac/BUILD.gn +++ b/build/toolchain/mac/BUILD.gn
@@ -61,30 +61,57 @@ # Work around for unused variable warning in template https://crbug.com/395883. assert(tool_versions != "") -# Shared toolchain definition. Invocations should set toolchain_os to set the +# Shared toolchain definition. Invocations should set current_os to set the # build args in this definition. template("mac_toolchain") { toolchain(target_name) { - assert(defined(invoker.toolchain_cpu), - "mac_toolchain() must specify a \"toolchain_cpu\"") - assert(defined(invoker.toolchain_os), - "mac_toolchain() must specify a \"toolchain_os\"") + # When invoking this toolchain not as the default one, these args will be + # passed to the build. They are ignored when this is the default toolchain. + assert(defined(invoker.toolchain_args), + "Toolchains must declare toolchain_args") + toolchain_args = { + # Populate toolchain args from the invoker. + forward_variables_from(invoker.toolchain_args, "*") - if (use_goma) { - assert(cc_wrapper == "", "Goma and cc_wrapper can't be used together.") - _compiler_prefix = "$goma_dir/gomacc " - } else if (cc_wrapper != "") { - _compiler_prefix = cc_wrapper + " " + # The host toolchain value computed by the default toolchain's setup + # needs to be passed through unchanged to all secondary toolchains to + # ensure that it's always the same, regardless of the values that may be + # set on those toolchains. + host_toolchain = host_toolchain + } + + # When the invoker has explicitly overridden use_goma or cc_wrapper in the + # toolchain args, use those values, otherwise default to the global one. + # This works because the only reasonable override that toolchains might + # supply for these values are to force-disable them. + if (defined(toolchain_args.use_goma)) { + toolchain_uses_goma = toolchain_args.use_goma } else { - _compiler_prefix = "" + toolchain_uses_goma = use_goma + } + if (defined(toolchain_args.cc_wrapper)) { + toolchain_cc_wrapper = toolchain_args.cc_wrapper + } else { + toolchain_cc_wrapper = cc_wrapper } - if (invoker.toolchain_os != "ios" || !use_xcode_clang) { - _compiler_prefix += rebase_path("$clang_base_path/bin/", root_build_dir) + # Compute the compiler prefix. + if (toolchain_uses_goma) { + assert(toolchain_cc_wrapper == "", + "Goma and cc_wrapper can't be used together.") + compiler_prefix = "$goma_dir/gomacc " + } else if (toolchain_cc_wrapper != "") { + compiler_prefix = toolchain_cc_wrapper + " " + } else { + compiler_prefix = "" } - cc = "${_compiler_prefix}clang" - cxx = "${_compiler_prefix}clang++" + if (toolchain_args.current_os != "ios" || !use_xcode_clang) { + compiler_prefix += rebase_path("$clang_base_path/bin/", root_build_dir) + } + + cc = "${compiler_prefix}clang" + cxx = "${compiler_prefix}clang++" ld = cxx linker_driver = @@ -94,7 +121,7 @@ # On iOS, the final applications are assembled using lipo (to support fat # builds). The correct flags are passed to the linker_driver.py script # directly during the lipo call. - if (invoker.toolchain_os != "ios") { + if (toolchain_args.current_os != "ios") { _enable_dsyms = enable_dsyms _save_unstripped_output = save_unstripped_output } else { @@ -384,48 +411,49 @@ description = "COMPILE_XCASSETS {{output}}" pool = ":bundle_pool($default_toolchain)" } - - toolchain_args() { - current_cpu = invoker.toolchain_cpu - current_os = invoker.toolchain_os - - # These values need to be passed through unchanged. - host_toolchain = host_toolchain - target_os = target_os - target_cpu = target_cpu - is_clang = true - } } } mac_toolchain("clang_arm") { - toolchain_cpu = "arm" - toolchain_os = "mac" + toolchain_args = { + current_cpu = "arm" + current_os = "mac" + } } mac_toolchain("clang_x64") { - toolchain_cpu = "x64" - toolchain_os = "mac" + toolchain_args = { + current_cpu = "x64" + current_os = "mac" + } } if (is_ios) { mac_toolchain("ios_clang_arm") { - toolchain_cpu = "arm" - toolchain_os = "ios" + toolchain_args = { + current_cpu = "arm" + current_os = "ios" + } } mac_toolchain("ios_clang_arm64") { - toolchain_cpu = "arm64" - toolchain_os = "ios" + toolchain_args = { + current_cpu = "arm64" + current_os = "ios" + } } mac_toolchain("ios_clang_x86") { - toolchain_cpu = "x86" - toolchain_os = "ios" + toolchain_args = { + current_cpu = "x86" + current_os = "ios" + } } mac_toolchain("ios_clang_x64") { - toolchain_cpu = "x64" - toolchain_os = "ios" + toolchain_args = { + current_cpu = "x64" + current_os = "ios" + } } }
diff --git a/build/toolchain/mac/compile_xcassets.py b/build/toolchain/mac/compile_xcassets.py index b788544..2e8c00e 100644 --- a/build/toolchain/mac/compile_xcassets.py +++ b/build/toolchain/mac/compile_xcassets.py
@@ -4,9 +4,55 @@ import argparse import os +import subprocess import sys +def CompileXCAssets(output, platform, min_deployment_target, inputs): + command = [ + 'xcrun', 'actool', '--output-format=human-readable-text', + '--compress-pngs', '--notices', '--warnings', '--errors', + '--platform', platform, '--minimum-deployment-target', + min_deployment_target, + ] + + if platform == 'macosx': + command.extend(['--target-device', 'mac']) + else: + command.extend(['--target-device', 'iphone', '--target-device', 'ipad']) + + # actool crashes if paths are relative, so convert input and output paths + # to absolute paths. + command.extend(['--compile', os.path.dirname(os.path.abspath(output))]) + command.extend(map(os.path.abspath, inputs)) + + # Run actool and redirect stdout and stderr to the same pipe (as actool + # is confused about what should go to stderr/stdout). + process = subprocess.Popen( + command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + stdout, _ = process.communicate() + + if process.returncode: + sys.stderr.write(stdout) + sys.exit(process.returncode) + + # In case of success, the output looks like the following: + # /* com.apple.actool.compilation-results */ + # /Full/Path/To/Bundle.app/Assets.car + # + # Ignore any lines in the output matching those (last line is an empty line) + # and consider that the build failed if the output contains any other lines. + for line in stdout.splitlines(): + if not line: + continue + if line == '/* com.apple.actool.compilation-results */': + continue + if line == os.path.abspath(output): + continue + sys.stderr.write(stdout) + sys.exit(1) + + def Main(): parser = argparse.ArgumentParser( description='compile assets catalog for a bundle') @@ -29,26 +75,14 @@ sys.stderr.write( 'output should be path to compiled asset catalog, not ' 'to the containing bundle: %s\n' % (args.output,)) + sys.exit(1) - command = [ - 'xcrun', 'actool', '--output-format', 'human-readable-text', - '--compress-pngs', '--notices', '--warnings', '--errors', - '--platform', args.platform, '--minimum-deployment-target', + CompileXCAssets( + args.output, + args.platform, args.minimum_deployment_target, - ] + args.inputs) - if args.platform == 'macosx': - command.extend(['--target-device', 'mac']) - else: - command.extend(['--target-device', 'iphone', '--target-device', 'ipad']) - - # actool crashes if paths are relative, so use os.path.abspath to get absolute - # path for input and outputs. - command.extend(['--compile', os.path.abspath(os.path.dirname(args.output))]) - command.extend(map(os.path.abspath, args.inputs)) - - os.execvp('xcrun', command) - sys.exit(1) if __name__ == '__main__': sys.exit(Main())
diff --git a/build/toolchain/nacl/BUILD.gn b/build/toolchain/nacl/BUILD.gn index 085f8a6..f317108d 100644 --- a/build/toolchain/nacl/BUILD.gn +++ b/build/toolchain/nacl/BUILD.gn
@@ -63,12 +63,10 @@ nacl_toolchain(target_name) { toolchain_package = "pnacl_newlib" toolchain_revision = pnacl_newlib_rev - toolchain_cpu = "pnacl" toolprefix = rebase_path("${nacl_toolchain_dir}/${toolchain_package}/bin/pnacl-", root_build_dir) - is_clang = true cc = compiler_scriptprefix + toolprefix + "clang" + scriptsuffix cxx = compiler_scriptprefix + toolprefix + "clang++" + scriptsuffix ar = scriptprefix + toolprefix + "ar" + scriptsuffix @@ -83,6 +81,11 @@ ld = scriptprefix + toolprefix + "clang++" + scriptsuffix executable_extension = invoker.executable_extension + + toolchain_args = { + is_clang = true + current_cpu = "pnacl" + } } } @@ -128,9 +131,6 @@ } nacl_toolchain("glibc_" + toolchain_cpu) { - is_clang = false - is_nacl_glibc = true - cc = toolprefix + "gcc" + toolsuffix cxx = toolprefix + "g++" + toolsuffix ar = toolprefix + "ar" + toolsuffix @@ -138,6 +138,12 @@ readelf = toolprefix + "readelf" + toolsuffix nm = toolprefix + "nm" + toolsuffix strip = toolprefix + "strip" + toolsuffix + + toolchain_args = { + current_cpu = toolchain_cpu + is_clang = false + is_nacl_glibc = true + } } } @@ -187,7 +193,6 @@ } nacl_toolchain("clang_newlib_" + toolchain_cpu) { - is_clang = true cc = toolprefix + "clang" + toolsuffix cxx = toolprefix + "clang++" + toolsuffix ar = toolprefix + "ar" + toolsuffix @@ -195,6 +200,11 @@ readelf = toolprefix + "readelf" + toolsuffix nm = toolprefix + "nm" + toolsuffix strip = toolprefix + "strip" + toolsuffix + + toolchain_args = { + current_cpu = toolchain_cpu + is_clang = true + } } } @@ -229,7 +239,6 @@ tls_edit = "${host_toolchain_out_dir}/tls_edit" nacl_toolchain("irt_" + toolchain_cpu) { - is_clang = true cc = toolprefix + "clang" + toolsuffix cxx = toolprefix + "clang++" + toolsuffix ar = toolprefix + "ar" + toolsuffix @@ -237,14 +246,19 @@ nm = toolprefix + "nm" + toolsuffix strip = toolprefix + "strip" + toolsuffix - # Always build the IRT with full debugging symbols, regardless of - # how Chromium itself is being built (or other NaCl executables). - symbol_level = 2 - # Some IRT implementations (notably, Chromium's) contain C++ code, # so we need to link w/ the C++ linker. ld = "${python_path} ${link_irt} --tls-edit=${tls_edit} --link-cmd=${cxx} --readelf-cmd=${readelf}" + toolchain_args = { + current_cpu = toolchain_cpu + is_clang = true + + # Always build the IRT with full debugging symbols, regardless of + # how Chromium itself is being built (or other NaCl executables). + symbol_level = 2 + } + # TODO(ncbray): depend on link script deps = [ tls_edit_label,
diff --git a/build/toolchain/nacl_toolchain.gni b/build/toolchain/nacl_toolchain.gni index ea4c5ec69..eb6ffcc 100644 --- a/build/toolchain/nacl_toolchain.gni +++ b/build/toolchain/nacl_toolchain.gni
@@ -12,25 +12,19 @@ # - cxx # - ar # - ld -# and the following which is used in the toolchain_args -# - toolchain_cpu (What "current_cpu" should be set to when invoking a -# build using this toolchain.) template("nacl_toolchain") { assert(defined(invoker.cc), "nacl_toolchain() must specify a \"cc\" value") assert(defined(invoker.cxx), "nacl_toolchain() must specify a \"cxx\" value") assert(defined(invoker.ar), "nacl_toolchain() must specify a \"ar\" value") assert(defined(invoker.ld), "nacl_toolchain() must specify a \"ld\" value") - assert(defined(invoker.toolchain_cpu), - "nacl_toolchain() must specify a \"toolchain_cpu\"") gcc_toolchain(target_name) { - toolchain_os = "nacl" - if (defined(invoker.executable_extension)) { executable_extension = invoker.executable_extension } else { executable_extension = ".nexe" } + rebuild_define = "NACL_TC_REV=" + invoker.toolchain_revision forward_variables_from(invoker, [ @@ -43,25 +37,19 @@ "nm", "readelf", "strip", - "toolchain_cpu", ]) - if (defined(invoker.is_clang)) { - is_clang = invoker.is_clang - } - if (defined(invoker.is_nacl_glibc)) { - is_nacl_glibc = invoker.is_nacl_glibc - } - if (defined(invoker.symbol_level)) { - symbol_level = invoker.symbol_level - } + toolchain_args = { + # Use all values set on the invoker's toolchain_args. + forward_variables_from(invoker.toolchain_args, "*") - # We do not support component builds with the NaCl toolchains. - is_component_build = false + current_os = "nacl" - # We do not support tcmalloc in the NaCl toolchains. - use_allocator = "none" + # We do not support component builds with the NaCl toolchains. + is_component_build = false - rebuild_define = "NACL_TC_REV=" + invoker.toolchain_revision + # We do not support tcmalloc in the NaCl toolchains. + use_allocator = "none" + } } }
diff --git a/build/toolchain/win/BUILD.gn b/build/toolchain/win/BUILD.gn index d726504..f46b90ff 100644 --- a/build/toolchain/win/BUILD.gn +++ b/build/toolchain/win/BUILD.gn
@@ -44,54 +44,27 @@ } # Parameters: -# toolchain_cpu: current_cpu to pass as a build arg -# toolchain_os: current_os to pass as a build arg -# environment: File name of environment file. +# environment: File name of environment file. +# +# You would also define a toolchain_args variable with at least these set: +# current_cpu: current_cpu to pass as a build arg +# current_os: current_os to pass as a build arg template("msvc_toolchain") { - env = invoker.environment - - if (invoker.is_clang && host_os != "win") { - # This toolchain definition uses response files for compilations. GN uses - # the quoting rules of the host OS, while clang-cl always defaults to - # cmd.exe quoting rules for parsing response files. Tell clang-cl to use - # POSIX quoting rules, so it can understand what GN generates. - cl = "${invoker.cl} --rsp-quoting=posix" - } else { - cl = invoker.cl - } - - if (use_lld) { - if (host_os == "win") { - lld_link = "lld-link.exe" - } else { - lld_link = "lld-link" - } - prefix = rebase_path("$clang_base_path/bin", root_build_dir) - - # lld-link includes a replacement for lib.exe that can produce thin - # archives and understands bitcode (for lto builds). - lib = "$prefix/$lld_link /lib /llvmlibthin" - link = "$prefix/$lld_link" - } else { - lib = "lib.exe" - link = "link.exe" - } - - # If possible, pass system includes as flags to the compiler. When that's - # not possible, load a full environment file (containing %INCLUDE% and - # %PATH%) -- e.g. 32-bit MSVS builds require %PATH% to be set and just passing - # in a list of include directories isn't enough. - if (defined(invoker.sys_include_flags)) { - env_wrapper = "" - sys_include_flags = "${invoker.sys_include_flags} " # Note trailing space. - } else { - # clang-cl doesn't need this env hoop, so omit it there. - assert(!invoker.is_clang) - env_wrapper = "ninja -t msvc -e $env -- " # Note trailing space. - sys_include_flags = "" - } - toolchain(target_name) { + # When invoking this toolchain not as the default one, these args will be + # passed to the build. They are ignored when this is the default toolchain. + assert(defined(invoker.toolchain_args)) + toolchain_args = { + if (defined(invoker.toolchain_args)) { + forward_variables_from(invoker.toolchain_args, "*") + } + + # This value needs to be passed through unchanged. + host_toolchain = host_toolchain + + current_os = "win" + } + # Make these apply to all tools below. lib_switch = "" lib_dir_switch = "/LIBPATH:" @@ -99,6 +72,59 @@ # Object files go in this directory. object_subdir = "{{target_out_dir}}/{{label_name}}" + env = invoker.environment + + # When the invoker has explicitly overridden use_goma or cc_wrapper in the + # toolchain args, use those values, otherwise default to the global one. + # This works because the only reasonable override that toolchains might + # supply for these values are to force-disable them. + if (defined(toolchain_args.is_clang)) { + toolchain_uses_clang = toolchain_args.is_clang + } else { + toolchain_uses_clang = is_clang + } + + if (toolchain_uses_clang && host_os != "win") { + # This toolchain definition uses response files for compilations. GN uses + # the quoting rules of the host OS, while clang-cl always defaults to + # cmd.exe quoting rules for parsing response files. Tell clang-cl to use + # POSIX quoting rules, so it can understand what GN generates. + cl = "${invoker.cl} --rsp-quoting=posix" + } else { + cl = invoker.cl + } + + if (use_lld) { + if (host_os == "win") { + lld_link = "lld-link.exe" + } else { + lld_link = "lld-link" + } + prefix = rebase_path("$clang_base_path/bin", root_build_dir) + + # lld-link includes a replacement for lib.exe that can produce thin + # archives and understands bitcode (for lto builds). + lib = "$prefix/$lld_link /lib /llvmlibthin" + link = "$prefix/$lld_link" + } else { + lib = "lib.exe" + link = "link.exe" + } + + # If possible, pass system includes as flags to the compiler. When that's + # not possible, load a full environment file (containing %INCLUDE% and + # %PATH%) -- e.g. 32-bit MSVS builds require %PATH% to be set and just + # passing in a list of include directories isn't enough. + if (defined(invoker.sys_include_flags)) { + env_wrapper = "" + sys_include_flags = "${invoker.sys_include_flags} " # Note trailing space. + } else { + # clang-cl doesn't need this env hoop, so omit it there. + assert(!toolchain_uses_clang) + env_wrapper = "ninja -t msvc -e $env -- " # Note trailing space. + sys_include_flags = "" + } + tool("cc") { rspfile = "{{output}}.rsp" precompiled_header_type = "msvc" @@ -142,7 +168,7 @@ } tool("asm") { - if (invoker.toolchain_cpu == "x64") { + if (toolchain_args.current_cpu == "x64") { ml = "ml64.exe" } else { ml = "ml.exe" @@ -264,28 +290,6 @@ command = copy_command description = copy_description } - - # When invoking this toolchain not as the default one, these args will be - # passed to the build. They are ignored when this is the default toolchain. - toolchain_args() { - current_cpu = invoker.toolchain_cpu - if (defined(invoker.toolchain_os)) { - current_os = invoker.toolchain_os - } - - # These share a name with global variables that are already defined, and - # forward_variables_from won't clobber the existing value, so we need to - # set it explicitly. - if (defined(invoker.is_clang)) { - is_clang = invoker.is_clang - } - if (defined(invoker.is_component_build)) { - is_component_build = invoker.is_component_build - } - - # This value needs to be passed through unchanged. - host_toolchain = host_toolchain - } } } @@ -319,19 +323,23 @@ msvc_toolchain("x86") { environment = "environment.x86" - toolchain_cpu = "x86" cl = "${goma_prefix}\"${x86_toolchain_data.vc_bin_dir}/cl.exe\"" - is_clang = false + toolchain_args = { + current_cpu = "x86" + is_clang = false + } } msvc_toolchain("clang_x86") { environment = "environment.x86" - toolchain_cpu = "x86" prefix = rebase_path("$clang_base_path/bin", root_build_dir) cl = "${goma_prefix}$prefix/${clang_cl}" - toolchain_os = "win" - is_clang = true sys_include_flags = "${x86_toolchain_data.include_flags}" + + toolchain_args = { + current_cpu = "x86" + is_clang = true + } } } @@ -356,30 +364,29 @@ msvc_toolchain(target_name) { environment = "environment.x64" - toolchain_cpu = "x64" cl = "${goma_prefix}\"${x64_toolchain_data.vc_bin_dir}/cl.exe\"" - is_clang = false - # This shares a name with a global and forward_variables_from won't clobber - # the existing value, so we need to set it explicitly. - if (defined(invoker.is_component_build)) { - is_component_build = invoker.is_component_build + toolchain_args = { + if (defined(invoker.toolchain_args)) { + forward_variables_from(invoker.toolchain_args, "*") + } + is_clang = false + current_cpu = "x64" } } msvc_toolchain("clang_" + target_name) { environment = "environment.x64" - toolchain_cpu = "x64" prefix = rebase_path("$clang_base_path/bin", root_build_dir) cl = "${goma_prefix}$prefix/${clang_cl}" - toolchain_os = "win" - is_clang = true sys_include_flags = "${x64_toolchain_data.include_flags}" - # This shares a name with a global and forward_variables_from won't clobber - # the existing value, so we need to set it explicitly. - if (defined(invoker.is_component_build)) { - is_component_build = invoker.is_component_build + toolchain_args = { + if (defined(invoker.toolchain_args)) { + forward_variables_from(invoker.toolchain_args, "*") + } + is_clang = true + current_cpu = "x64" } } } @@ -397,13 +404,15 @@ # is_component_build to false in the toolchain_args() block, because # building nacl64.exe in component style does not work. win_x64_toolchains("nacl_win64") { - is_component_build = false - # TODO(mcgrathr): These assignments are only required because of # crbug.com/395883. Drop them if that ever gets fixed in GN. goma_prefix = goma_prefix x64_toolchain_data = x64_toolchain_data clang_cl = clang_cl + + toolchain_args = { + is_component_build = false + } } # WinRT toolchains. Only define these when targeting them. @@ -416,18 +425,20 @@ msvc_toolchain("winrt_x86") { environment = "environment.winrt_x86" cl = "${goma_prefix}\"${vc_bin_dir}/cl.exe\"" - is_clang = false - toolchain_cpu = "x86" - toolchain_os = current_os + toolchain_args = { + is_clang = false + current_cpu = "x86" + } } msvc_toolchain("winrt_x64") { environment = "environment.winrt_x64" cl = "${goma_prefix}\"${vc_bin_dir}/cl.exe\"" - is_clang = false - toolchain_cpu = "x64" - toolchain_os = current_os + toolchain_args = { + is_clang = false + current_cpu = "x64" + } } }
diff --git a/cc/blink/web_display_item_list_impl.cc b/cc/blink/web_display_item_list_impl.cc index c524008..7a4be016 100644 --- a/cc/blink/web_display_item_list_impl.cc +++ b/cc/blink/web_display_item_list_impl.cc
@@ -51,7 +51,7 @@ const blink::WebRect& visual_rect, sk_sp<const SkPicture> picture) { if (display_item_list_->RetainsIndividualDisplayItems()) { - display_item_list_->CreateAndAppendItem<cc::DrawingDisplayItem>( + display_item_list_->CreateAndAppendDrawingItem<cc::DrawingDisplayItem>( visual_rect, std::move(picture)); } else { cc::DrawingDisplayItem item(std::move(picture)); @@ -60,7 +60,6 @@ } void WebDisplayItemListImpl::appendClipItem( - const blink::WebRect& visual_rect, const blink::WebRect& clip_rect, const blink::WebVector<SkRRect>& rounded_clip_rects) { std::vector<SkRRect> rounded_rects; @@ -69,97 +68,88 @@ } bool antialias = true; if (display_item_list_->RetainsIndividualDisplayItems()) { - display_item_list_->CreateAndAppendItem<cc::ClipDisplayItem>( - visual_rect, clip_rect, rounded_rects, antialias); + display_item_list_->CreateAndAppendPairedBeginItem<cc::ClipDisplayItem>( + clip_rect, rounded_rects, antialias); } else { cc::ClipDisplayItem item(clip_rect, rounded_rects, antialias); display_item_list_->RasterIntoCanvas(item); } } -void WebDisplayItemListImpl::appendEndClipItem( - const blink::WebRect& visual_rect) { +void WebDisplayItemListImpl::appendEndClipItem() { if (display_item_list_->RetainsIndividualDisplayItems()) { - display_item_list_->CreateAndAppendItem<cc::EndClipDisplayItem>( - visual_rect); + display_item_list_->CreateAndAppendPairedEndItem<cc::EndClipDisplayItem>(); } else { display_item_list_->RasterIntoCanvas(cc::EndClipDisplayItem()); } } void WebDisplayItemListImpl::appendClipPathItem( - const blink::WebRect& visual_rect, const SkPath& clip_path, SkRegion::Op clip_op, bool antialias) { if (display_item_list_->RetainsIndividualDisplayItems()) { - display_item_list_->CreateAndAppendItem<cc::ClipPathDisplayItem>( - visual_rect, clip_path, clip_op, antialias); + display_item_list_->CreateAndAppendPairedBeginItem<cc::ClipPathDisplayItem>( + clip_path, clip_op, antialias); } else { cc::ClipPathDisplayItem item(clip_path, clip_op, antialias); display_item_list_->RasterIntoCanvas(item); } } -void WebDisplayItemListImpl::appendEndClipPathItem( - const blink::WebRect& visual_rect) { +void WebDisplayItemListImpl::appendEndClipPathItem() { if (display_item_list_->RetainsIndividualDisplayItems()) { - display_item_list_->CreateAndAppendItem<cc::EndClipPathDisplayItem>( - visual_rect); + display_item_list_ + ->CreateAndAppendPairedEndItem<cc::EndClipPathDisplayItem>(); } else { display_item_list_->RasterIntoCanvas(cc::EndClipPathDisplayItem()); } } void WebDisplayItemListImpl::appendFloatClipItem( - const blink::WebRect& visual_rect, const blink::WebFloatRect& clip_rect) { if (display_item_list_->RetainsIndividualDisplayItems()) { - display_item_list_->CreateAndAppendItem<cc::FloatClipDisplayItem>( - visual_rect, clip_rect); + display_item_list_ + ->CreateAndAppendPairedBeginItem<cc::FloatClipDisplayItem>(clip_rect); } else { cc::FloatClipDisplayItem item(clip_rect); display_item_list_->RasterIntoCanvas(item); } } -void WebDisplayItemListImpl::appendEndFloatClipItem( - const blink::WebRect& visual_rect) { +void WebDisplayItemListImpl::appendEndFloatClipItem() { if (display_item_list_->RetainsIndividualDisplayItems()) { - display_item_list_->CreateAndAppendItem<cc::EndFloatClipDisplayItem>( - visual_rect); + display_item_list_ + ->CreateAndAppendPairedEndItem<cc::EndFloatClipDisplayItem>(); } else { display_item_list_->RasterIntoCanvas(cc::EndFloatClipDisplayItem()); } } void WebDisplayItemListImpl::appendTransformItem( - const blink::WebRect& visual_rect, const SkMatrix44& matrix) { gfx::Transform transform(gfx::Transform::kSkipInitialization); transform.matrix() = matrix; if (display_item_list_->RetainsIndividualDisplayItems()) { - display_item_list_->CreateAndAppendItem<cc::TransformDisplayItem>( - visual_rect, transform); + display_item_list_ + ->CreateAndAppendPairedBeginItem<cc::TransformDisplayItem>(transform); } else { cc::TransformDisplayItem item(transform); display_item_list_->RasterIntoCanvas(item); } } -void WebDisplayItemListImpl::appendEndTransformItem( - const blink::WebRect& visual_rect) { +void WebDisplayItemListImpl::appendEndTransformItem() { if (display_item_list_->RetainsIndividualDisplayItems()) { - display_item_list_->CreateAndAppendItem<cc::EndTransformDisplayItem>( - visual_rect); + display_item_list_ + ->CreateAndAppendPairedEndItem<cc::EndTransformDisplayItem>(); } else { display_item_list_->RasterIntoCanvas(cc::EndTransformDisplayItem()); } } void WebDisplayItemListImpl::appendCompositingItem( - const blink::WebRect& visual_rect, float opacity, SkXfermode::Mode xfermode, SkRect* bounds, @@ -171,9 +161,10 @@ const bool kLcdTextRequiresOpaqueLayer = true; if (display_item_list_->RetainsIndividualDisplayItems()) { - display_item_list_->CreateAndAppendItem<cc::CompositingDisplayItem>( - visual_rect, static_cast<uint8_t>(gfx::ToFlooredInt(255 * opacity)), - xfermode, bounds, sk_ref_sp(color_filter), kLcdTextRequiresOpaqueLayer); + display_item_list_ + ->CreateAndAppendPairedBeginItem<cc::CompositingDisplayItem>( + static_cast<uint8_t>(gfx::ToFlooredInt(255 * opacity)), xfermode, + bounds, sk_ref_sp(color_filter), kLcdTextRequiresOpaqueLayer); } else { cc::CompositingDisplayItem item( static_cast<uint8_t>(gfx::ToFlooredInt(255 * opacity)), xfermode, @@ -182,52 +173,47 @@ } } -void WebDisplayItemListImpl::appendEndCompositingItem( - const blink::WebRect& visual_rect) { +void WebDisplayItemListImpl::appendEndCompositingItem() { if (display_item_list_->RetainsIndividualDisplayItems()) { - display_item_list_->CreateAndAppendItem<cc::EndCompositingDisplayItem>( - visual_rect); + display_item_list_ + ->CreateAndAppendPairedEndItem<cc::EndCompositingDisplayItem>(); } else { display_item_list_->RasterIntoCanvas(cc::EndCompositingDisplayItem()); } } void WebDisplayItemListImpl::appendFilterItem( - const blink::WebRect& visual_rect, const cc::FilterOperations& filters, const blink::WebFloatRect& bounds) { if (display_item_list_->RetainsIndividualDisplayItems()) { - display_item_list_->CreateAndAppendItem<cc::FilterDisplayItem>( - visual_rect, filters, bounds); + display_item_list_->CreateAndAppendPairedBeginItem<cc::FilterDisplayItem>( + filters, bounds); } else { cc::FilterDisplayItem item(filters, bounds); display_item_list_->RasterIntoCanvas(item); } } -void WebDisplayItemListImpl::appendEndFilterItem( - const blink::WebRect& visual_rect) { +void WebDisplayItemListImpl::appendEndFilterItem() { if (display_item_list_->RetainsIndividualDisplayItems()) { - display_item_list_->CreateAndAppendItem<cc::EndFilterDisplayItem>( - visual_rect); + display_item_list_ + ->CreateAndAppendPairedEndItem<cc::EndFilterDisplayItem>(); } else { display_item_list_->RasterIntoCanvas(cc::EndFilterDisplayItem()); } } void WebDisplayItemListImpl::appendScrollItem( - const blink::WebRect& visual_rect, const blink::WebSize& scroll_offset, ScrollContainerId) { SkMatrix44 matrix(SkMatrix44::kUninitialized_Constructor); matrix.setTranslate(-scroll_offset.width, -scroll_offset.height, 0); // TODO(wkorman): Should we translate the visual rect as well? - appendTransformItem(visual_rect, matrix); + appendTransformItem(matrix); } -void WebDisplayItemListImpl::appendEndScrollItem( - const blink::WebRect& visual_rect) { - appendEndTransformItem(visual_rect); +void WebDisplayItemListImpl::appendEndScrollItem() { + appendEndTransformItem(); } void WebDisplayItemListImpl::setIsSuitableForGpuRasterization(bool isSuitable) {
diff --git a/cc/blink/web_display_item_list_impl.h b/cc/blink/web_display_item_list_impl.h index 3e0ca83..9b61e5b1 100644 --- a/cc/blink/web_display_item_list_impl.h +++ b/cc/blink/web_display_item_list_impl.h
@@ -42,38 +42,31 @@ ~WebDisplayItemListImpl() override; // blink::WebDisplayItemList implementation. - void appendDrawingItem(const blink::WebRect&, - sk_sp<const SkPicture>) override; + void appendDrawingItem(const blink::WebRect& visual_rect, + sk_sp<const SkPicture> picture) override; void appendClipItem( - const blink::WebRect& visual_rect, const blink::WebRect& clip_rect, const blink::WebVector<SkRRect>& rounded_clip_rects) override; - void appendEndClipItem(const blink::WebRect& visual_rect) override; - void appendClipPathItem(const blink::WebRect& visual_rect, - const SkPath& clip_path, + void appendEndClipItem() override; + void appendClipPathItem(const SkPath& clip_path, SkRegion::Op clip_op, bool antialias) override; - void appendEndClipPathItem(const blink::WebRect& visual_rect) override; - void appendFloatClipItem(const blink::WebRect& visual_rect, - const blink::WebFloatRect& clip_rect) override; - void appendEndFloatClipItem(const blink::WebRect& visual_rect) override; - void appendTransformItem(const blink::WebRect& visual_rect, - const SkMatrix44& matrix) override; - void appendEndTransformItem(const blink::WebRect& visual_rect) override; - void appendCompositingItem(const blink::WebRect& visual_rect, - float opacity, + void appendEndClipPathItem() override; + void appendFloatClipItem(const blink::WebFloatRect& clip_rect) override; + void appendEndFloatClipItem() override; + void appendTransformItem(const SkMatrix44& matrix) override; + void appendEndTransformItem() override; + void appendCompositingItem(float opacity, SkXfermode::Mode, SkRect* bounds, SkColorFilter*) override; - void appendEndCompositingItem(const blink::WebRect& visual_rect) override; - void appendFilterItem(const blink::WebRect& visual_rect, - const cc::FilterOperations& filters, + void appendEndCompositingItem() override; + void appendFilterItem(const cc::FilterOperations& filters, const blink::WebFloatRect& bounds) override; - void appendEndFilterItem(const blink::WebRect& visual_rect) override; - void appendScrollItem(const blink::WebRect& visual_rect, - const blink::WebSize& scrollOffset, + void appendEndFilterItem() override; + void appendScrollItem(const blink::WebSize& scrollOffset, ScrollContainerId) override; - void appendEndScrollItem(const blink::WebRect& visual_rect) override; + void appendEndScrollItem() override; void setIsSuitableForGpuRasterization(bool isSuitable) override;
diff --git a/cc/debug/invalidation_benchmark.cc b/cc/debug/invalidation_benchmark.cc index 681e29e..36547c1d 100644 --- a/cc/debug/invalidation_benchmark.cc +++ b/cc/debug/invalidation_benchmark.cc
@@ -69,12 +69,14 @@ } void InvalidationBenchmark::RunOnLayer(PictureLayer* layer) { - PropertyTrees* property_trees = layer->layer_tree_host()->property_trees(); - LayerList update_list; - update_list.push_back(layer); - draw_property_utils::ComputeVisibleRectsForTesting( - property_trees, property_trees->non_root_surfaces_enabled, &update_list); - gfx::Rect visible_layer_rect = layer->visible_layer_rect_for_testing(); + gfx::Rect visible_layer_rect = gfx::Rect(layer->bounds()); + gfx::Transform from_screen; + bool invertible = layer->screen_space_transform().GetInverse(&from_screen); + if (!invertible) + from_screen = gfx::Transform(); + gfx::Rect viewport_rect = MathUtil::ProjectEnclosingClippedRect( + from_screen, gfx::Rect(layer->layer_tree_host()->device_viewport_size())); + visible_layer_rect.Intersect(viewport_rect); switch (mode_) { case FIXED_SIZE: { // Invalidation with a random position and fixed size. @@ -105,7 +107,7 @@ } case VIEWPORT: { // Invalidate entire viewport. - layer->SetNeedsDisplayRect(layer->visible_layer_rect_for_testing()); + layer->SetNeedsDisplayRect(visible_layer_rect); break; } }
diff --git a/cc/debug/unittest_only_benchmark.h b/cc/debug/unittest_only_benchmark.h index 5a00c15..4f46a55 100644 --- a/cc/debug/unittest_only_benchmark.h +++ b/cc/debug/unittest_only_benchmark.h
@@ -8,10 +8,6 @@ #include "base/memory/weak_ptr.h" #include "cc/debug/micro_benchmark.h" -namespace base { -class SingleThreadIdleTaskRunner; -} - namespace cc { class CC_EXPORT UnittestOnlyBenchmark : public MicroBenchmark {
diff --git a/cc/ipc/cc_serialization_perftest.cc b/cc/ipc/cc_serialization_perftest.cc index 30d7835..e7a4a52 100644 --- a/cc/ipc/cc_serialization_perftest.cc +++ b/cc/ipc/cc_serialization_perftest.cc
@@ -56,19 +56,22 @@ base::TimeTicks start = base::TimeTicks::Now(); base::TimeTicks end = start + base::TimeDelta::FromMilliseconds(kTimeLimitMillis); + base::TimeTicks now = start; base::TimeDelta min_time; size_t count = 0; while (start < end) { for (int i = 0; i < kTimeCheckInterval; ++i) { - ++count; CompositorFrame compositor_frame; ReadMessage(&msg, &compositor_frame); + now = base::TimeTicks::Now(); + // We don't count iterations after the end time. + if (now < end) + ++count; } - base::TimeTicks now = base::TimeTicks::Now(); if (now - start < min_time || min_time.is_zero()) min_time = now - start; - start = base::TimeTicks::Now(); + start = now; } perf_test::PrintResult( @@ -89,19 +92,22 @@ base::TimeTicks start = base::TimeTicks::Now(); base::TimeTicks end = start + base::TimeDelta::FromMilliseconds(kTimeLimitMillis); + base::TimeTicks now = start; base::TimeDelta min_time; size_t count = 0; while (start < end) { for (int i = 0; i < kTimeCheckInterval; ++i) { IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL); IPC::ParamTraits<CompositorFrame>::Write(&msg, frame); - ++count; + now = base::TimeTicks::Now(); + // We don't count iterations after the end time. + if (now < end) + ++count; } - base::TimeTicks now = base::TimeTicks::Now(); if (now - start < min_time || min_time.is_zero()) min_time = now - start; - start = base::TimeTicks::Now(); + start = now; } perf_test::PrintResult( @@ -124,19 +130,22 @@ base::TimeTicks start = base::TimeTicks::Now(); base::TimeTicks end = start + base::TimeDelta::FromMilliseconds(kTimeLimitMillis); + base::TimeTicks now = start; base::TimeDelta min_time; size_t count = 0; while (start < end) { for (int i = 0; i < kTimeCheckInterval; ++i) { CompositorFrame compositor_frame; mojom::CompositorFrame::Deserialize(data, &compositor_frame); - ++count; + now = base::TimeTicks::Now(); + // We don't count iterations after the end time. + if (now < end) + ++count; } - base::TimeTicks now = base::TimeTicks::Now(); if (now - start < min_time || min_time.is_zero()) min_time = now - start; - start = base::TimeTicks::Now(); + start = now; } perf_test::PrintResult( @@ -158,19 +167,22 @@ base::TimeTicks start = base::TimeTicks::Now(); base::TimeTicks end = start + base::TimeDelta::FromMilliseconds(kTimeLimitMillis); + base::TimeTicks now = start; base::TimeDelta min_time; size_t count = 0; while (start < end) { for (int i = 0; i < kTimeCheckInterval; ++i) { mojo::Array<uint8_t> data = mojom::CompositorFrame::Serialize(&frame); DCHECK_GT(data.size(), 0u); - ++count; + now = base::TimeTicks::Now(); + // We don't count iterations after the end time. + if (now < end) + ++count; } - base::TimeTicks now = base::TimeTicks::Now(); if (now - start < min_time || min_time.is_zero()) min_time = now - start; - start = base::TimeTicks::Now(); + start = now; } perf_test::PrintResult(
diff --git a/cc/ipc/quads.mojom b/cc/ipc/quads.mojom index 77252589..5de6917 100644 --- a/cc/ipc/quads.mojom +++ b/cc/ipc/quads.mojom
@@ -46,6 +46,12 @@ bool force_anti_aliasing_off; }; +struct StreamVideoQuadState { + uint32 resource_id; + gfx.mojom.Size resource_size_in_pixels; + gfx.mojom.Transform matrix; +}; + struct SurfaceQuadState { cc.mojom.SurfaceId surface; }; @@ -70,12 +76,6 @@ bool nearest_neighbor; }; -struct StreamVideoQuadState { - uint32 resource_id; - gfx.mojom.Size resource_size_in_pixels; - gfx.mojom.Transform matrix; -}; - enum YUVColorSpace { REC_601, // SDTV standard with restricted "studio swing" color range. REC_709, // HDTV standard with restricted "studio swing" color range. @@ -97,22 +97,18 @@ uint32 bits_per_channel; }; -enum Material { - INVALID, - DEBUG_BORDER, - PICTURE_CONTENT, - RENDER_PASS, - SOLID_COLOR, - STREAM_VIDEO_CONTENT, - SURFACE_CONTENT, - TEXTURE_CONTENT, - TILED_CONTENT, - YUV_VIDEO_CONTENT, +union DrawQuadState { + DebugBorderQuadState debug_border_quad_state; + RenderPassQuadState render_pass_quad_state; + SolidColorQuadState solid_color_quad_state; + StreamVideoQuadState stream_video_quad_state; + SurfaceQuadState surface_quad_state; + TextureQuadState texture_quad_state; + TileQuadState tile_quad_state; + YUVVideoQuadState yuv_video_quad_state; }; struct DrawQuad { - Material material; - // This rect, after applying the quad_transform(), gives the geometry that // this quad should draw to. This rect lives in content space. gfx.mojom.Rect rect; @@ -133,13 +129,5 @@ // quads. SharedQuadState? sqs; - // Only one of the following will be set, depending on the material. - DebugBorderQuadState? debug_border_quad_state; - RenderPassQuadState? render_pass_quad_state; - SolidColorQuadState? solid_color_quad_state; - SurfaceQuadState? surface_quad_state; - TextureQuadState? texture_quad_state; - TileQuadState? tile_quad_state; - StreamVideoQuadState? stream_video_quad_state; - YUVVideoQuadState? yuv_video_quad_state; + DrawQuadState draw_quad_state; };
diff --git a/cc/ipc/quads_struct_traits.cc b/cc/ipc/quads_struct_traits.cc index 98edf87..536b3b9 100644 --- a/cc/ipc/quads_struct_traits.cc +++ b/cc/ipc/quads_struct_traits.cc
@@ -7,45 +7,40 @@ namespace mojo { -cc::DrawQuad* AllocateAndConstruct(cc::mojom::Material material, - cc::QuadList* list) { +cc::DrawQuad* AllocateAndConstruct( + cc::mojom::DrawQuadState::DataView::Tag material, + cc::QuadList* list) { cc::DrawQuad* quad = nullptr; switch (material) { - case cc::mojom::Material::INVALID: - return nullptr; - case cc::mojom::Material::DEBUG_BORDER: + case cc::mojom::DrawQuadState::DataView::Tag::DEBUG_BORDER_QUAD_STATE: quad = list->AllocateAndConstruct<cc::DebugBorderDrawQuad>(); quad->material = cc::DrawQuad::DEBUG_BORDER; return quad; - case cc::mojom::Material::PICTURE_CONTENT: - quad = list->AllocateAndConstruct<cc::PictureDrawQuad>(); - quad->material = cc::DrawQuad::PICTURE_CONTENT; - return quad; - case cc::mojom::Material::RENDER_PASS: + case cc::mojom::DrawQuadState::DataView::Tag::RENDER_PASS_QUAD_STATE: quad = list->AllocateAndConstruct<cc::RenderPassDrawQuad>(); quad->material = cc::DrawQuad::RENDER_PASS; return quad; - case cc::mojom::Material::SOLID_COLOR: + case cc::mojom::DrawQuadState::DataView::Tag::SOLID_COLOR_QUAD_STATE: quad = list->AllocateAndConstruct<cc::SolidColorDrawQuad>(); quad->material = cc::DrawQuad::SOLID_COLOR; return quad; - case cc::mojom::Material::STREAM_VIDEO_CONTENT: + case cc::mojom::DrawQuadState::DataView::Tag::STREAM_VIDEO_QUAD_STATE: quad = list->AllocateAndConstruct<cc::StreamVideoDrawQuad>(); quad->material = cc::DrawQuad::STREAM_VIDEO_CONTENT; return quad; - case cc::mojom::Material::SURFACE_CONTENT: + case cc::mojom::DrawQuadState::DataView::Tag::SURFACE_QUAD_STATE: quad = list->AllocateAndConstruct<cc::SurfaceDrawQuad>(); quad->material = cc::DrawQuad::SURFACE_CONTENT; return quad; - case cc::mojom::Material::TEXTURE_CONTENT: + case cc::mojom::DrawQuadState::DataView::Tag::TEXTURE_QUAD_STATE: quad = list->AllocateAndConstruct<cc::TextureDrawQuad>(); quad->material = cc::DrawQuad::TEXTURE_CONTENT; return quad; - case cc::mojom::Material::TILED_CONTENT: + case cc::mojom::DrawQuadState::DataView::Tag::TILE_QUAD_STATE: quad = list->AllocateAndConstruct<cc::TileDrawQuad>(); quad->material = cc::DrawQuad::TILED_CONTENT; return quad; - case cc::mojom::Material::YUV_VIDEO_CONTENT: + case cc::mojom::DrawQuadState::DataView::Tag::YUV_VIDEO_QUAD_STATE: quad = list->AllocateAndConstruct<cc::YUVVideoDrawQuad>(); quad->material = cc::DrawQuad::YUV_VIDEO_CONTENT; return quad; @@ -53,90 +48,6 @@ NOTREACHED(); return nullptr; } -namespace { - -bool ReadDrawQuad(cc::mojom::DrawQuadDataView data, cc::DrawQuad* quad) { - cc::DrawQuad::Material material; - if (!data.ReadMaterial(&material) || material != quad->material) { - return false; - } - if (!data.ReadRect(&quad->rect) || !data.ReadOpaqueRect(&quad->opaque_rect) || - !data.ReadVisibleRect(&quad->visible_rect)) { - return false; - } - quad->needs_blending = data.needs_blending(); - return true; -} - -} // namespace - -// static -cc::mojom::Material -EnumTraits<cc::mojom::Material, cc::DrawQuad::Material>::ToMojom( - cc::DrawQuad::Material material) { - switch (material) { - case cc::DrawQuad::INVALID: - return cc::mojom::Material::INVALID; - case cc::DrawQuad::DEBUG_BORDER: - return cc::mojom::Material::DEBUG_BORDER; - case cc::DrawQuad::PICTURE_CONTENT: - return cc::mojom::Material::PICTURE_CONTENT; - case cc::DrawQuad::RENDER_PASS: - return cc::mojom::Material::RENDER_PASS; - case cc::DrawQuad::SOLID_COLOR: - return cc::mojom::Material::SOLID_COLOR; - case cc::DrawQuad::STREAM_VIDEO_CONTENT: - return cc::mojom::Material::STREAM_VIDEO_CONTENT; - case cc::DrawQuad::SURFACE_CONTENT: - return cc::mojom::Material::SURFACE_CONTENT; - case cc::DrawQuad::TEXTURE_CONTENT: - return cc::mojom::Material::TEXTURE_CONTENT; - case cc::DrawQuad::TILED_CONTENT: - return cc::mojom::Material::TILED_CONTENT; - case cc::DrawQuad::YUV_VIDEO_CONTENT: - return cc::mojom::Material::YUV_VIDEO_CONTENT; - } - return cc::mojom::Material::INVALID; -} - -// static -bool EnumTraits<cc::mojom::Material, cc::DrawQuad::Material>::FromMojom( - cc::mojom::Material input, - cc::DrawQuad::Material* out) { - switch (input) { - case cc::mojom::Material::INVALID: - *out = cc::DrawQuad::INVALID; - return true; - case cc::mojom::Material::DEBUG_BORDER: - *out = cc::DrawQuad::DEBUG_BORDER; - return true; - case cc::mojom::Material::PICTURE_CONTENT: - *out = cc::DrawQuad::PICTURE_CONTENT; - return true; - case cc::mojom::Material::RENDER_PASS: - *out = cc::DrawQuad::RENDER_PASS; - return true; - case cc::mojom::Material::SOLID_COLOR: - *out = cc::DrawQuad::SOLID_COLOR; - return true; - case cc::mojom::Material::STREAM_VIDEO_CONTENT: - *out = cc::DrawQuad::STREAM_VIDEO_CONTENT; - return true; - case cc::mojom::Material::SURFACE_CONTENT: - *out = cc::DrawQuad::SURFACE_CONTENT; - return true; - case cc::mojom::Material::TEXTURE_CONTENT: - *out = cc::DrawQuad::TEXTURE_CONTENT; - return true; - case cc::mojom::Material::TILED_CONTENT: - *out = cc::DrawQuad::TILED_CONTENT; - return true; - case cc::mojom::Material::YUV_VIDEO_CONTENT: - *out = cc::DrawQuad::YUV_VIDEO_CONTENT; - return true; - } - return false; -} // static bool StructTraits<cc::mojom::DebugBorderQuadState, cc::DrawQuad>::Read( @@ -310,34 +221,12 @@ bool StructTraits<cc::mojom::DrawQuad, cc::DrawQuad>::Read( cc::mojom::DrawQuadDataView data, cc::DrawQuad* out) { - if (!ReadDrawQuad(data, out)) + if (!data.ReadRect(&out->rect) || !data.ReadOpaqueRect(&out->opaque_rect) || + !data.ReadVisibleRect(&out->visible_rect)) { return false; - switch (data.material()) { - case cc::mojom::Material::INVALID: - break; - case cc::mojom::Material::DEBUG_BORDER: - return data.ReadDebugBorderQuadState(out); - case cc::mojom::Material::PICTURE_CONTENT: - // TODO(fsamuel): Implement PictureDrawQuad - // serialization/deserialization. - break; - case cc::mojom::Material::RENDER_PASS: - return data.ReadRenderPassQuadState(out); - case cc::mojom::Material::SOLID_COLOR: - return data.ReadSolidColorQuadState(out); - case cc::mojom::Material::STREAM_VIDEO_CONTENT: - return data.ReadStreamVideoQuadState(out); - case cc::mojom::Material::SURFACE_CONTENT: - return data.ReadSurfaceQuadState(out); - case cc::mojom::Material::TEXTURE_CONTENT: - return data.ReadTextureQuadState(out); - case cc::mojom::Material::TILED_CONTENT: - return data.ReadTileQuadState(out); - case cc::mojom::Material::YUV_VIDEO_CONTENT: - return data.ReadYuvVideoQuadState(out); } - NOTREACHED(); - return false; + out->needs_blending = data.needs_blending(); + return data.ReadDrawQuadState(out); } } // namespace mojo
diff --git a/cc/ipc/quads_struct_traits.h b/cc/ipc/quads_struct_traits.h index 6643b43..489049c 100644 --- a/cc/ipc/quads_struct_traits.h +++ b/cc/ipc/quads_struct_traits.h
@@ -24,26 +24,98 @@ namespace mojo { -cc::DrawQuad* AllocateAndConstruct(cc::mojom::Material material, - cc::QuadList* list); +cc::DrawQuad* AllocateAndConstruct( + cc::mojom::DrawQuadState::DataView::Tag material, + cc::QuadList* list); + template <> -struct EnumTraits<cc::mojom::Material, cc::DrawQuad::Material> { - static cc::mojom::Material ToMojom(cc::DrawQuad::Material material); - static bool FromMojom(cc::mojom::Material input, cc::DrawQuad::Material* out); +struct UnionTraits<cc::mojom::DrawQuadState, cc::DrawQuad> { + static cc::mojom::DrawQuadState::DataView::Tag GetTag( + const cc::DrawQuad& quad) { + switch (quad.material) { + case cc::DrawQuad::INVALID: + break; + case cc::DrawQuad::DEBUG_BORDER: + return cc::mojom::DrawQuadState::DataView::Tag::DEBUG_BORDER_QUAD_STATE; + case cc::DrawQuad::PICTURE_CONTENT: + break; + case cc::DrawQuad::RENDER_PASS: + return cc::mojom::DrawQuadState::DataView::Tag::RENDER_PASS_QUAD_STATE; + case cc::DrawQuad::SOLID_COLOR: + return cc::mojom::DrawQuadState::DataView::Tag::SOLID_COLOR_QUAD_STATE; + case cc::DrawQuad::STREAM_VIDEO_CONTENT: + return cc::mojom::DrawQuadState::DataView::Tag::STREAM_VIDEO_QUAD_STATE; + case cc::DrawQuad::SURFACE_CONTENT: + return cc::mojom::DrawQuadState::DataView::Tag::SURFACE_QUAD_STATE; + case cc::DrawQuad::TEXTURE_CONTENT: + return cc::mojom::DrawQuadState::DataView::Tag::TEXTURE_QUAD_STATE; + case cc::DrawQuad::TILED_CONTENT: + return cc::mojom::DrawQuadState::DataView::Tag::TILE_QUAD_STATE; + case cc::DrawQuad::YUV_VIDEO_CONTENT: + return cc::mojom::DrawQuadState::DataView::Tag::YUV_VIDEO_QUAD_STATE; + } + NOTREACHED(); + return cc::mojom::DrawQuadState::DataView::Tag::DEBUG_BORDER_QUAD_STATE; + } + + static const cc::DrawQuad& debug_border_quad_state(const cc::DrawQuad& quad) { + return quad; + } + + static const cc::DrawQuad& render_pass_quad_state(const cc::DrawQuad& quad) { + return quad; + } + + static const cc::DrawQuad& solid_color_quad_state(const cc::DrawQuad& quad) { + return quad; + } + + static const cc::DrawQuad& surface_quad_state(const cc::DrawQuad& quad) { + return quad; + } + + static const cc::DrawQuad& texture_quad_state(const cc::DrawQuad& quad) { + return quad; + } + + static const cc::DrawQuad& tile_quad_state(const cc::DrawQuad& quad) { + return quad; + } + + static const cc::DrawQuad& stream_video_quad_state(const cc::DrawQuad& quad) { + return quad; + } + + static const cc::DrawQuad& yuv_video_quad_state(const cc::DrawQuad& quad) { + return quad; + } + + static bool Read(cc::mojom::DrawQuadState::DataView data, cc::DrawQuad* out) { + switch (data.tag()) { + case cc::mojom::DrawQuadState::DataView::Tag::DEBUG_BORDER_QUAD_STATE: + return data.ReadDebugBorderQuadState(out); + case cc::mojom::DrawQuadState::DataView::Tag::RENDER_PASS_QUAD_STATE: + return data.ReadRenderPassQuadState(out); + case cc::mojom::DrawQuadState::DataView::Tag::SOLID_COLOR_QUAD_STATE: + return data.ReadSolidColorQuadState(out); + case cc::mojom::DrawQuadState::DataView::Tag::SURFACE_QUAD_STATE: + return data.ReadSurfaceQuadState(out); + case cc::mojom::DrawQuadState::DataView::Tag::TEXTURE_QUAD_STATE: + return data.ReadTextureQuadState(out); + case cc::mojom::DrawQuadState::DataView::Tag::TILE_QUAD_STATE: + return data.ReadTileQuadState(out); + case cc::mojom::DrawQuadState::DataView::Tag::STREAM_VIDEO_QUAD_STATE: + return data.ReadStreamVideoQuadState(out); + case cc::mojom::DrawQuadState::DataView::Tag::YUV_VIDEO_QUAD_STATE: + return data.ReadYuvVideoQuadState(out); + } + NOTREACHED(); + return false; + } }; template <> struct StructTraits<cc::mojom::DebugBorderQuadState, cc::DrawQuad> { - static bool IsNull(const cc::DrawQuad& input) { - return input.material != cc::DrawQuad::DEBUG_BORDER; - } - - static void SetToNull(cc::DrawQuad* output) { - // There is nothing to deserialize here if the DrawQuad is not a - // DebugBorderDrawQuad. If it is, then this should not be called. - DCHECK_NE(cc::DrawQuad::DEBUG_BORDER, output->material); - } - static uint32_t color(const cc::DrawQuad& input) { const cc::DebugBorderDrawQuad* quad = cc::DebugBorderDrawQuad::MaterialCast(&input); @@ -62,16 +134,6 @@ template <> struct StructTraits<cc::mojom::RenderPassQuadState, cc::DrawQuad> { - static bool IsNull(const cc::DrawQuad& quad) { - return quad.material != cc::DrawQuad::RENDER_PASS; - } - - static void SetToNull(cc::DrawQuad* output) { - // There is nothing to deserialize here if the DrawQuad is not a - // RenderPassDrawQuad. If it is, then this should not be called. - DCHECK_NE(cc::DrawQuad::RENDER_PASS, output->material); - } - static const cc::RenderPassId& render_pass_id(const cc::DrawQuad& input) { const cc::RenderPassDrawQuad* quad = cc::RenderPassDrawQuad::MaterialCast(&input); @@ -121,16 +183,6 @@ template <> struct StructTraits<cc::mojom::SolidColorQuadState, cc::DrawQuad> { - static bool IsNull(const cc::DrawQuad& input) { - return input.material != cc::DrawQuad::SOLID_COLOR; - } - - static void SetToNull(cc::DrawQuad* output) { - // There is nothing to deserialize here if the DrawQuad is not a - // SolidColorDrawQuad. If it is, then this should not be called. - DCHECK_NE(cc::DrawQuad::SOLID_COLOR, output->material); - } - static uint32_t color(const cc::DrawQuad& input) { const cc::SolidColorDrawQuad* quad = cc::SolidColorDrawQuad::MaterialCast(&input); @@ -149,16 +201,6 @@ template <> struct StructTraits<cc::mojom::StreamVideoQuadState, cc::DrawQuad> { - static bool IsNull(const cc::DrawQuad& input) { - return input.material != cc::DrawQuad::STREAM_VIDEO_CONTENT; - } - - static void SetToNull(cc::DrawQuad* output) { - // There is nothing to deserialize here if the DrawQuad is not a - // StreamVideoDrawQuad. If it is, then this should not be called. - DCHECK_NE(cc::DrawQuad::STREAM_VIDEO_CONTENT, output->material); - } - static uint32_t resource_id(const cc::DrawQuad& input) { const cc::StreamVideoDrawQuad* quad = cc::StreamVideoDrawQuad::MaterialCast(&input); @@ -184,16 +226,6 @@ template <> struct StructTraits<cc::mojom::SurfaceQuadState, cc::DrawQuad> { - static bool IsNull(const cc::DrawQuad& input) { - return input.material != cc::DrawQuad::SURFACE_CONTENT; - } - - static void SetToNull(cc::DrawQuad* output) { - // There is nothing to deserialize here if the DrawQuad is not a - // SurfaceDrawQuad. If it is, then this should not be called. - DCHECK_NE(cc::DrawQuad::SURFACE_CONTENT, output->material); - } - static const cc::SurfaceId& surface(const cc::DrawQuad& input) { const cc::SurfaceDrawQuad* quad = cc::SurfaceDrawQuad::MaterialCast(&input); return quad->surface_id; @@ -204,16 +236,6 @@ template <> struct StructTraits<cc::mojom::TextureQuadState, cc::DrawQuad> { - static bool IsNull(const cc::DrawQuad& input) { - return input.material != cc::DrawQuad::TEXTURE_CONTENT; - } - - static void SetToNull(cc::DrawQuad* output) { - // There is nothing to deserialize here if the DrawQuad is not a - // TextureContentDrawQuad. If it is, then this should not be called. - DCHECK_NE(cc::DrawQuad::TEXTURE_CONTENT, output->material); - } - static uint32_t resource_id(const cc::DrawQuad& input) { const cc::TextureDrawQuad* quad = cc::TextureDrawQuad::MaterialCast(&input); return quad->resource_id(); @@ -264,16 +286,6 @@ template <> struct StructTraits<cc::mojom::TileQuadState, cc::DrawQuad> { - static bool IsNull(const cc::DrawQuad& input) { - return input.material != cc::DrawQuad::TILED_CONTENT; - } - - static void SetToNull(cc::DrawQuad* output) { - // There is nothing to deserialize here if the DrawQuad is not a - // TileDrawQuad. If it is, then this should not be called. - DCHECK_NE(cc::DrawQuad::TILED_CONTENT, output->material); - } - static const gfx::RectF& tex_coord_rect(const cc::DrawQuad& input) { const cc::TileDrawQuad* quad = cc::TileDrawQuad::MaterialCast(&input); return quad->tex_coord_rect; @@ -312,16 +324,6 @@ template <> struct StructTraits<cc::mojom::YUVVideoQuadState, cc::DrawQuad> { - static bool IsNull(const cc::DrawQuad& input) { - return input.material != cc::DrawQuad::YUV_VIDEO_CONTENT; - } - - static void SetToNull(cc::DrawQuad* output) { - // There is nothing to deserialize here if the DrawQuad is not a - // YUVVideoDrawQuad. If it is, then this should not be called. - DCHECK_NE(cc::DrawQuad::YUV_VIDEO_CONTENT, output->material); - } - static const gfx::RectF& ya_tex_coord_rect(const cc::DrawQuad& input) { const cc::YUVVideoDrawQuad* quad = cc::YUVVideoDrawQuad::MaterialCast(&input); @@ -406,11 +408,6 @@ template <> struct StructTraits<cc::mojom::DrawQuad, DrawQuadWithSharedQuadState> { - static cc::DrawQuad::Material material( - const DrawQuadWithSharedQuadState& input) { - return input.quad->material; - } - static const gfx::Rect& rect(const DrawQuadWithSharedQuadState& input) { return input.quad->rect; } @@ -429,49 +426,14 @@ return input.quad->needs_blending; } - static const cc::DrawQuad& debug_border_quad_state( - const DrawQuadWithSharedQuadState& input) { - return *input.quad; - } - - static const cc::DrawQuad& render_pass_quad_state( - const DrawQuadWithSharedQuadState& input) { - return *input.quad; - } - - static const cc::DrawQuad& solid_color_quad_state( - const DrawQuadWithSharedQuadState& input) { - return *input.quad; - } - - static const cc::DrawQuad& surface_quad_state( - const DrawQuadWithSharedQuadState& input) { - return *input.quad; - } - - static const cc::DrawQuad& texture_quad_state( - const DrawQuadWithSharedQuadState& input) { - return *input.quad; - } - - static const cc::DrawQuad& tile_quad_state( - const DrawQuadWithSharedQuadState& input) { - return *input.quad; - } - - static const cc::DrawQuad& stream_video_quad_state( - const DrawQuadWithSharedQuadState& input) { - return *input.quad; - } - - static const cc::DrawQuad& yuv_video_quad_state( - const DrawQuadWithSharedQuadState& input) { - return *input.quad; - } - static OptSharedQuadState sqs(const DrawQuadWithSharedQuadState& input) { return {input.shared_quad_state}; } + + static const cc::DrawQuad& draw_quad_state( + const DrawQuadWithSharedQuadState& input) { + return *input.quad; + } }; // This StructTraits is only used for deserialization within RenderPasses.
diff --git a/cc/ipc/render_pass_struct_traits.cc b/cc/ipc/render_pass_struct_traits.cc index 61ed5b9..d8396a4 100644 --- a/cc/ipc/render_pass_struct_traits.cc +++ b/cc/ipc/render_pass_struct_traits.cc
@@ -27,8 +27,11 @@ for (size_t i = 0; i < quads.size(); ++i) { cc::mojom::DrawQuadDataView quad_data_view; quads.GetDataView(i, &quad_data_view); + cc::mojom::DrawQuadStateDataView quad_state_data_view; + quad_data_view.GetDrawQuadStateDataView(&quad_state_data_view); + cc::DrawQuad* quad = - AllocateAndConstruct(quad_data_view.material(), &(*out)->quad_list); + AllocateAndConstruct(quad_state_data_view.tag(), &(*out)->quad_list); if (!quad) return false; if (!quads.Read(i, quad))
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc index 6f9239a..8881b00a 100644 --- a/cc/layers/layer.cc +++ b/cc/layers/layer.cc
@@ -985,15 +985,6 @@ return effect_tree_index_; } -int Layer::render_target_effect_tree_index() const { - EffectNode* effect_node = - layer_tree_host_->property_trees()->effect_tree.Node(effect_tree_index_); - if (effect_node->has_render_surface) - return effect_node->id; - else - return effect_node->target_id; -} - void Layer::SetScrollTreeIndex(int index) { DCHECK(IsPropertyChangeAllowed()); if (scroll_tree_index_ == index)
diff --git a/cc/layers/layer.h b/cc/layers/layer.h index 560e3e77..eaba892b 100644 --- a/cc/layers/layer.h +++ b/cc/layers/layer.h
@@ -430,10 +430,6 @@ void SetEffectTreeIndex(int index); int effect_tree_index() const; - // TODO(sunxd): Remove this when we do not compute target space transforms on - // main thread in tests. - int render_target_effect_tree_index() const; - void SetScrollTreeIndex(int index); int scroll_tree_index() const;
diff --git a/cc/layers/nine_patch_layer_impl_unittest.cc b/cc/layers/nine_patch_layer_impl_unittest.cc index c31094cd..19c301a 100644 --- a/cc/layers/nine_patch_layer_impl_unittest.cc +++ b/cc/layers/nine_patch_layer_impl_unittest.cc
@@ -151,7 +151,8 @@ FakeImplTaskRunnerProvider task_runner_provider; TestSharedBitmapManager shared_bitmap_manager; TestTaskGraphRunner task_graph_runner; - std::unique_ptr<OutputSurface> output_surface = FakeOutputSurface::Create3d(); + std::unique_ptr<OutputSurface> output_surface = + FakeOutputSurface::CreateDelegating3d(); FakeUIResourceLayerTreeHostImpl host_impl( &task_runner_provider, &shared_bitmap_manager, &task_graph_runner); host_impl.SetVisible(true);
diff --git a/cc/layers/picture_image_layer.cc b/cc/layers/picture_image_layer.cc index 4971e48..8ce991e5 100644 --- a/cc/layers/picture_image_layer.cc +++ b/cc/layers/picture_image_layer.cc
@@ -83,7 +83,7 @@ // transparent images blend correctly. canvas->drawImage(image_.get(), 0, 0); - display_list->CreateAndAppendItem<DrawingDisplayItem>( + display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>( PaintableRegion(), recorder.finishRecordingAsPicture()); display_list->Finalize();
diff --git a/cc/layers/picture_layer.cc b/cc/layers/picture_layer.cc index a7939de..91768eb9 100644 --- a/cc/layers/picture_layer.cc +++ b/cc/layers/picture_layer.cc
@@ -266,7 +266,8 @@ } recording_source_->FromProtobuf(picture.recording_source(), - picture_layer_inputs_.display_list); + picture_layer_inputs_.display_list, + picture_layer_inputs_.recorded_viewport); // Inform picture cache about which SkPictures are now in use. for (uint32_t engine_picture_id : used_engine_picture_ids)
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc index 12fe4e6..b3bf1e6 100644 --- a/cc/layers/picture_layer_impl.cc +++ b/cc/layers/picture_layer_impl.cc
@@ -12,6 +12,7 @@ #include <limits> #include <set> +#include "base/metrics/histogram_macros.h" #include "base/time/time.h" #include "base/trace_event/trace_event_argument.h" #include "cc/base/math_util.h" @@ -1229,6 +1230,8 @@ ideal_contents_scale_ = std::max(GetIdealContentsScale(), min_contents_scale); ideal_source_scale_ = ideal_contents_scale_ / ideal_page_scale_ / ideal_device_scale_; + UMA_HISTOGRAM_CUSTOM_COUNTS("Renderer4.IdealContentsScale", + ideal_contents_scale_, 0, 10000, 50); } void PictureLayerImpl::GetDebugBorderProperties(
diff --git a/cc/layers/picture_layer_unittest.cc b/cc/layers/picture_layer_unittest.cc index ae655b3..4a2de8a 100644 --- a/cc/layers/picture_layer_unittest.cc +++ b/cc/layers/picture_layer_unittest.cc
@@ -254,8 +254,7 @@ TestSharedBitmapManager shared_bitmap_manager; std::unique_ptr<FakeOutputSurface> output_surface = - FakeOutputSurface::CreateSoftware( - base::WrapUnique(new SoftwareOutputDevice)); + FakeOutputSurface::CreateDelegatingSoftware(); FakeLayerTreeHostImpl host_impl(LayerTreeSettings(), &impl_task_runner_provider, &shared_bitmap_manager, &task_graph_runner);
diff --git a/cc/layers/scrollbar_layer_unittest.cc b/cc/layers/scrollbar_layer_unittest.cc index bc5f50ea..d44865c 100644 --- a/cc/layers/scrollbar_layer_unittest.cc +++ b/cc/layers/scrollbar_layer_unittest.cc
@@ -738,9 +738,9 @@ vertical_scrollbar_layer_->ComputeThumbQuadRect()); } -class ScrollbarLayerTestMaxTextureSize : public LayerTreeTest { +class ScrollbarLayerTestWithFixedScrollbarBounds : public LayerTreeTest { public: - ScrollbarLayerTestMaxTextureSize() {} + ScrollbarLayerTestWithFixedScrollbarBounds() {} void SetScrollbarBounds(const gfx::Size& bounds) { bounds_ = bounds; } @@ -783,22 +783,13 @@ gfx::Size bounds_; }; -TEST_F(ScrollbarLayerTestMaxTextureSize, DirectRenderer) { +TEST_F(ScrollbarLayerTestWithFixedScrollbarBounds, MaxTextureSize) { std::unique_ptr<TestWebGraphicsContext3D> context = TestWebGraphicsContext3D::Create(); int max_size = 0; context->getIntegerv(GL_MAX_TEXTURE_SIZE, &max_size); SetScrollbarBounds(gfx::Size(max_size + 100, max_size + 100)); - RunTest(CompositorMode::THREADED, false); -} - -TEST_F(ScrollbarLayerTestMaxTextureSize, DelegatingRenderer) { - std::unique_ptr<TestWebGraphicsContext3D> context = - TestWebGraphicsContext3D::Create(); - int max_size = 0; - context->getIntegerv(GL_MAX_TEXTURE_SIZE, &max_size); - SetScrollbarBounds(gfx::Size(max_size + 100, max_size + 100)); - RunTest(CompositorMode::THREADED, true); + RunTest(CompositorMode::THREADED); } class ScrollbarLayerTestResourceCreationAndRelease : public ScrollbarLayerTest {
diff --git a/cc/layers/texture_layer_unittest.cc b/cc/layers/texture_layer_unittest.cc index 39cad04..eaf59bb 100644 --- a/cc/layers/texture_layer_unittest.cc +++ b/cc/layers/texture_layer_unittest.cc
@@ -757,9 +757,7 @@ scoped_refptr<TextureLayer> layer_; }; -SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F( - TextureLayerImplWithMailboxThreadedCallback); - +SINGLE_AND_MULTI_THREAD_TEST_F(TextureLayerImplWithMailboxThreadedCallback); class TextureLayerMailboxIsActivatedDuringCommit : public LayerTreeTest { protected: @@ -844,8 +842,7 @@ scoped_refptr<TextureLayer> layer_; }; -SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F( - TextureLayerMailboxIsActivatedDuringCommit); +SINGLE_AND_MULTI_THREAD_TEST_F(TextureLayerMailboxIsActivatedDuringCommit); class TextureLayerImplWithMailboxTest : public TextureLayerTest { protected: @@ -1383,8 +1380,7 @@ scoped_refptr<TextureLayer> layer_; }; -SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F( - TextureLayerWithMailboxMainThreadDeleted); +SINGLE_AND_MULTI_THREAD_TEST_F(TextureLayerWithMailboxMainThreadDeleted); class TextureLayerWithMailboxImplThreadDeleted : public LayerTreeTest { public: @@ -1457,8 +1453,7 @@ scoped_refptr<TextureLayer> layer_; }; -SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F( - TextureLayerWithMailboxImplThreadDeleted); +SINGLE_AND_MULTI_THREAD_TEST_F(TextureLayerWithMailboxImplThreadDeleted); } // namespace } // namespace cc
diff --git a/cc/output/ca_layer_overlay.cc b/cc/output/ca_layer_overlay.cc index 1336e63..8c06814e 100644 --- a/cc/output/ca_layer_overlay.cc +++ b/cc/output/ca_layer_overlay.cc
@@ -17,8 +17,6 @@ namespace { -bool g_allow_rpdq_quad_conversion = false; - // This enum is used for histogram states and should only have new values added // to the end before COUNT. enum CALayerResult { @@ -44,6 +42,7 @@ CA_LAYER_FAILED_RENDER_PASS_BACKGROUND_FILTERS, CA_LAYER_FAILED_RENDER_PASS_MASK, CA_LAYER_FAILED_RENDER_PASS_FILTER_OPERATION, + CA_LAYER_FAILED_RENDER_PASS_SORTING_CONTEXT_ID, CA_LAYER_FAILED_COUNT, }; @@ -70,8 +69,9 @@ CALayerOverlay* ca_layer_overlay) { if (quad->background_filters.size() != 0) return CA_LAYER_FAILED_RENDER_PASS_BACKGROUND_FILTERS; - if (quad->mask_resource_id() != 0) - return CA_LAYER_FAILED_RENDER_PASS_MASK; + + if (quad->shared_quad_state->sorting_context_id != 0) + return CA_LAYER_FAILED_RENDER_PASS_SORTING_CONTEXT_ID; for (const FilterOperation& operation : quad->filters.operations()) { bool success = FilterOperationSupported(operation); @@ -79,22 +79,10 @@ return CA_LAYER_FAILED_RENDER_PASS_FILTER_OPERATION; } - if (quad->filters_scale != gfx::Vector2dF(1, 1)) { - for (const FilterOperation& operation : quad->filters.operations()) { - if (operation.type() == FilterOperation::BLUR || - operation.type() == FilterOperation::DROP_SHADOW) { - return CA_LAYER_FAILED_RENDER_PASS_FILTER_SCALE; - } - } - } - + ca_layer_overlay->rpdq = quad; ca_layer_overlay->contents_rect = gfx::RectF(0, 0, 1, 1); - // TODO(erikchen): Enable this when RenderPassDrawQuad promotion to CALayer - // is fully functional. https://crbug.com/581526. - if (g_allow_rpdq_quad_conversion) - return CA_LAYER_SUCCESS; - return CA_LAYER_FAILED_RENDER_PASS; + return CA_LAYER_SUCCESS; } CALayerResult FromStreamVideoQuad(ResourceProvider* resource_provider, @@ -310,8 +298,4 @@ return true; } -void EnableRenderPassDrawQuadForTesting() { - g_allow_rpdq_quad_conversion = true; -} - } // namespace cc
diff --git a/cc/output/ca_layer_overlay.h b/cc/output/ca_layer_overlay.h index 0b3f79d..34eb054e 100644 --- a/cc/output/ca_layer_overlay.h +++ b/cc/output/ca_layer_overlay.h
@@ -15,6 +15,7 @@ namespace cc { class DrawQuad; +class RenderPassDrawQuad; class ResourceProvider; // Holds information that is frequently shared between consecutive @@ -23,7 +24,6 @@ : public base::RefCounted<CALayerOverlaySharedState> { public: CALayerOverlaySharedState() {} - // Layers in a non-zero sorting context exist in the same 3D space and should // intersect. unsigned sorting_context_id = 0; @@ -63,6 +63,9 @@ unsigned edge_aa_mask = 0; // The minification and magnification filters for the CALayer. unsigned filter; + // If |rpdq| is present, then the renderer must draw the filter effects and + // copy the result into an IOSurface. + const RenderPassDrawQuad* rpdq = nullptr; }; typedef std::vector<CALayerOverlay> CALayerOverlayList; @@ -74,9 +77,6 @@ const QuadList& quad_list, CALayerOverlayList* ca_layer_overlays); -// Allows RenderPassDrawQuads to be converted to CALayerOverlays. -void CC_EXPORT EnableRenderPassDrawQuadForTesting(); - } // namespace cc #endif // CC_OUTPUT_CA_LAYER_OVERLAY_H_
diff --git a/cc/output/delegating_renderer.cc b/cc/output/delegating_renderer.cc index 9438fb8..cae2de7b 100644 --- a/cc/output/delegating_renderer.cc +++ b/cc/output/delegating_renderer.cc
@@ -20,15 +20,6 @@ namespace cc { -std::unique_ptr<DelegatingRenderer> DelegatingRenderer::Create( - RendererClient* client, - const RendererSettings* settings, - OutputSurface* output_surface, - ResourceProvider* resource_provider) { - return base::WrapUnique(new DelegatingRenderer( - client, settings, output_surface, resource_provider)); -} - DelegatingRenderer::DelegatingRenderer(RendererClient* client, const RendererSettings* settings, OutputSurface* output_surface,
diff --git a/cc/output/delegating_renderer.h b/cc/output/delegating_renderer.h index 9e48349..79ed3c1 100644 --- a/cc/output/delegating_renderer.h +++ b/cc/output/delegating_renderer.h
@@ -19,11 +19,10 @@ class CC_EXPORT DelegatingRenderer : public Renderer { public: - static std::unique_ptr<DelegatingRenderer> Create( - RendererClient* client, - const RendererSettings* settings, - OutputSurface* output_surface, - ResourceProvider* resource_provider); + DelegatingRenderer(RendererClient* client, + const RendererSettings* settings, + OutputSurface* output_surface, + ResourceProvider* resource_provider); ~DelegatingRenderer() override; const RendererCapabilitiesImpl& Capabilities() const override; @@ -40,11 +39,6 @@ void ReclaimResources(const ReturnedResourceArray&) override; private: - DelegatingRenderer(RendererClient* client, - const RendererSettings* settings, - OutputSurface* output_surface, - ResourceProvider* resource_provider); - void DidChangeVisibility() override; OutputSurface* output_surface_;
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc index e760ac0..11db994 100644 --- a/cc/output/gl_renderer.cc +++ b/cc/output/gl_renderer.cc
@@ -160,11 +160,11 @@ const Resource* contents_texture = nullptr; const gfx::QuadF* clip_region = nullptr; bool flip_texture = false; - gfx::Transform window_matrix; gfx::Transform projection_matrix; + gfx::Transform quad_to_target_transform; - // |frame| is needed for background effects. + // |frame| is only used for background effects. DirectRenderer::DrawingFrame* frame = nullptr; // Whether the texture to be sampled from needs to be flipped. @@ -215,6 +215,7 @@ bool use_color_matrix = false; gfx::QuadF surface_quad; + gfx::Transform contents_device_transform; }; @@ -363,18 +364,6 @@ DISALLOW_COPY_AND_ASSIGN(SyncQuery); }; -std::unique_ptr<GLRenderer> GLRenderer::Create( - RendererClient* client, - const RendererSettings* settings, - OutputSurface* output_surface, - ResourceProvider* resource_provider, - TextureMailboxDeleter* texture_mailbox_deleter, - int highp_threshold_min) { - return base::WrapUnique( - new GLRenderer(client, settings, output_surface, resource_provider, - texture_mailbox_deleter, highp_threshold_min)); -} - GLRenderer::GLRenderer(RendererClient* client, const RendererSettings* settings, OutputSurface* output_surface, @@ -1068,6 +1057,8 @@ void GLRenderer::DrawRenderPassQuadInternal( DrawRenderPassDrawQuadParams* params) { + params->quad_to_target_transform = + params->quad->shared_quad_state->quad_to_target_transform; if (!InitializeRPDQParameters(params)) return; UpdateRPDQShadersForBlending(params); @@ -1093,8 +1084,7 @@ static_cast<float>(dst_rect.width()), static_cast<float>(dst_rect.height())); gfx::Transform quad_rect_matrix; - QuadRectTransform(&quad_rect_matrix, - quad->shared_quad_state->quad_to_target_transform, + QuadRectTransform(&quad_rect_matrix, params->quad_to_target_transform, params->dst_rect); params->contents_device_transform = params->window_matrix * params->projection_matrix * quad_rect_matrix; @@ -1217,8 +1207,7 @@ if (clip_rect.IsEmpty()) { clip_rect = current_draw_rect_; } - gfx::Transform transform = - quad->shared_quad_state->quad_to_target_transform; + gfx::Transform transform = params->quad_to_target_transform; gfx::QuadF clip_quad = gfx::QuadF(gfx::RectF(clip_rect)); gfx::QuadF local_clip = MapQuadToLocalSpace(transform, clip_quad); params->dst_rect.Intersect(local_clip.BoundingBox()); @@ -1499,8 +1488,7 @@ } void GLRenderer::DrawRPDQ(const DrawRenderPassDrawQuadParams& params) { - DrawQuadGeometry(params.projection_matrix, - params.quad->shared_quad_state->quad_to_target_transform, + DrawQuadGeometry(params.projection_matrix, params.quad_to_target_transform, params.dst_rect, params.locations.matrix); // Flush the compositor context before the filter bitmap goes out of @@ -2728,6 +2716,8 @@ } bool GLRenderer::FlippedFramebuffer(const DrawingFrame* frame) const { + if (force_drawing_frame_framebuffer_unflipped_) + return false; if (frame->current_render_pass != frame->root_render_pass) return true; return FlippedRootFramebuffer(); @@ -3777,10 +3767,11 @@ scoped_refptr<CALayerOverlaySharedState> shared_state; size_t copied_render_pass_count = 0; for (const CALayerOverlay& ca_layer_overlay : frame->ca_layer_overlay_list) { - if (!overlay_resource_pool_) { - overlay_resource_pool_ = ResourcePool::CreateForGpuMemoryBufferResources( - resource_provider_, base::ThreadTaskRunnerHandle::Get().get(), - gfx::BufferUsage::SCANOUT); + if (ca_layer_overlay.rpdq) { + ScheduleRenderPassDrawQuad(&ca_layer_overlay, frame); + shared_state = nullptr; + ++copied_render_pass_count; + continue; } ResourceId contents_resource_id = ca_layer_overlay.contents_resource_id; @@ -3854,4 +3845,184 @@ } } +// This function draws the RenderPassDrawQuad into a temporary +// texture/framebuffer, and then copies the result into an IOSurface. The +// inefficient (but simple) way to do this would be to: +// 1. Allocate a framebuffer the size of the screen. +// 2. Draw using all the normal RPDQ draw logic. +// +// Instead, this method does the following: +// 1. Configure parameters as if drawing to a framebuffer the size of the +// screen. This reuses most of the RPDQ draw logic. +// 2. Update parameters to draw into a framebuffer only as large as needed. +// 3. Fix shader uniforms that were broken by (2). +// +// Then: +// 4. Allocate an IOSurface as the drawing destination. +// 5. Draw the RPDQ. +void GLRenderer::CopyRenderPassDrawQuadToOverlayResource( + const CALayerOverlay* ca_layer_overlay, + Resource** resource, + DrawingFrame* external_frame, + gfx::RectF* new_bounds) { + ScopedResource* contents_texture = + render_pass_textures_[ca_layer_overlay->rpdq->render_pass_id].get(); + DCHECK(contents_texture); + + // Configure parameters as if drawing to a framebuffer the size of the + // screen. + DrawRenderPassDrawQuadParams params; + params.quad = ca_layer_overlay->rpdq; + params.flip_texture = true; + params.contents_texture = contents_texture; + params.quad_to_target_transform = + params.quad->shared_quad_state->quad_to_target_transform; + + // Calculate projection and window matrices using InitializeViewport(). This + // requires creating a dummy DrawingFrame. + { + DrawingFrame frame; + gfx::Rect frame_rect = external_frame->device_viewport_rect; + force_drawing_frame_framebuffer_unflipped_ = true; + InitializeViewport(&frame, frame_rect, frame_rect, frame_rect.size()); + force_drawing_frame_framebuffer_unflipped_ = false; + params.projection_matrix = frame.projection_matrix; + params.window_matrix = frame.window_matrix; + } + + // Perform basic initialization with the screen-sized viewport. + if (!InitializeRPDQParameters(¶ms)) + return; + + if (!UpdateRPDQWithSkiaFilters(¶ms)) + return; + + // |params.dst_rect| now contain values that reflect a potentially increased + // size quad. + gfx::RectF updated_dst_rect = params.dst_rect; + *new_bounds = updated_dst_rect; + + // Calculate new projection and window matrices for a minimally sized viewport + // using InitializeViewport(). This requires creating a dummy DrawingFrame. + { + DrawingFrame frame; + force_drawing_frame_framebuffer_unflipped_ = true; + gfx::Rect frame_rect = + gfx::Rect(0, 0, updated_dst_rect.width(), updated_dst_rect.height()); + InitializeViewport(&frame, frame_rect, frame_rect, frame_rect.size()); + force_drawing_frame_framebuffer_unflipped_ = false; + params.projection_matrix = frame.projection_matrix; + params.window_matrix = frame.window_matrix; + } + + // Calculate a new quad_to_target_transform. + params.quad_to_target_transform = gfx::Transform(); + params.quad_to_target_transform.Translate(-updated_dst_rect.x(), + -updated_dst_rect.y()); + + // Antialiasing works by fading out content that is close to the edge of the + // viewport. All of these values need to be recalculated. + if (params.use_aa) { + current_window_space_viewport_ = + gfx::Rect(0, 0, updated_dst_rect.width(), updated_dst_rect.height()); + gfx::Transform quad_rect_matrix; + QuadRectTransform(&quad_rect_matrix, params.quad_to_target_transform, + updated_dst_rect); + params.contents_device_transform = + params.window_matrix * params.projection_matrix * quad_rect_matrix; + bool clipped = false; + params.contents_device_transform.FlattenTo2d(); + gfx::QuadF device_layer_quad = MathUtil::MapQuad( + params.contents_device_transform, SharedGeometryQuad(), &clipped); + LayerQuad device_layer_edges(device_layer_quad); + InflateAntiAliasingDistances(device_layer_quad, &device_layer_edges, + params.edge); + } + + // Establish destination texture. + *resource = overlay_resource_pool_->AcquireResource( + gfx::Size(updated_dst_rect.width(), updated_dst_rect.height()), + ResourceFormat::RGBA_8888); + ResourceProvider::ScopedWriteLockGL destination(resource_provider_, + (*resource)->id(), false); + GLuint temp_fbo; + + gl_->GenFramebuffers(1, &temp_fbo); + gl_->BindFramebuffer(GL_FRAMEBUFFER, temp_fbo); + gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + destination.target(), destination.texture_id(), 0); + DCHECK(gl_->CheckFramebufferStatus(GL_FRAMEBUFFER) == + GL_FRAMEBUFFER_COMPLETE); + + // Clear to 0 to ensure the background is transparent. + gl_->ClearColor(0, 0, 0, 0); + gl_->Clear(GL_COLOR_BUFFER_BIT); + + UpdateRPDQTexturesForSampling(¶ms); + UpdateRPDQBlendMode(¶ms); + ChooseRPDQProgram(¶ms); + UpdateRPDQUniforms(¶ms); + + // Prior to drawing, set up the destination framebuffer and viewport. + gl_->BindFramebuffer(GL_FRAMEBUFFER, temp_fbo); + gl_->Viewport(0, 0, updated_dst_rect.width(), updated_dst_rect.height()); + + DrawRPDQ(params); + gl_->DeleteFramebuffers(1, &temp_fbo); +} + +void GLRenderer::ScheduleRenderPassDrawQuad( + const CALayerOverlay* ca_layer_overlay, + DrawingFrame* external_frame) { + DCHECK(ca_layer_overlay->rpdq); + + if (!overlay_resource_pool_) { + overlay_resource_pool_ = ResourcePool::CreateForGpuMemoryBufferResources( + resource_provider_, base::ThreadTaskRunnerHandle::Get().get(), + gfx::BufferUsage::SCANOUT); + } + + Resource* resource = nullptr; + gfx::RectF new_bounds; + CopyRenderPassDrawQuadToOverlayResource(ca_layer_overlay, &resource, + external_frame, &new_bounds); + if (!resource || !resource->id()) + return; + + pending_overlay_resources_.push_back( + base::WrapUnique(new ResourceProvider::ScopedReadLockGL( + resource_provider_, resource->id()))); + unsigned texture_id = pending_overlay_resources_.back()->texture_id(); + + // Once a resource is released, it is marked as "busy". It will be + // available for reuse after the ScopedReadLockGL is destroyed. + overlay_resource_pool_->ReleaseResource(resource); + + GLfloat contents_rect[4] = { + ca_layer_overlay->contents_rect.x(), ca_layer_overlay->contents_rect.y(), + ca_layer_overlay->contents_rect.width(), + ca_layer_overlay->contents_rect.height(), + }; + GLfloat bounds_rect[4] = { + new_bounds.x(), new_bounds.y(), new_bounds.width(), new_bounds.height(), + }; + GLboolean is_clipped = ca_layer_overlay->shared_state->is_clipped; + GLfloat clip_rect[4] = {ca_layer_overlay->shared_state->clip_rect.x(), + ca_layer_overlay->shared_state->clip_rect.y(), + ca_layer_overlay->shared_state->clip_rect.width(), + ca_layer_overlay->shared_state->clip_rect.height()}; + GLint sorting_context_id = ca_layer_overlay->shared_state->sorting_context_id; + SkMatrix44 transform = ca_layer_overlay->shared_state->transform; + GLfloat gl_transform[16]; + transform.asColMajorf(gl_transform); + unsigned filter = ca_layer_overlay->filter; + + gl_->ScheduleCALayerSharedStateCHROMIUM( + ca_layer_overlay->shared_state->opacity, is_clipped, clip_rect, + sorting_context_id, gl_transform); + gl_->ScheduleCALayerCHROMIUM( + texture_id, contents_rect, ca_layer_overlay->background_color, + ca_layer_overlay->edge_aa_mask, bounds_rect, filter); +} + } // namespace cc
diff --git a/cc/output/gl_renderer.h b/cc/output/gl_renderer.h index 4e5c59c..0eb8426d 100644 --- a/cc/output/gl_renderer.h +++ b/cc/output/gl_renderer.h
@@ -50,14 +50,12 @@ public: class ScopedUseGrContext; - static std::unique_ptr<GLRenderer> Create( - RendererClient* client, - const RendererSettings* settings, - OutputSurface* output_surface, - ResourceProvider* resource_provider, - TextureMailboxDeleter* texture_mailbox_deleter, - int highp_threshold_min); - + GLRenderer(RendererClient* client, + const RendererSettings* settings, + OutputSurface* output_surface, + ResourceProvider* resource_provider, + TextureMailboxDeleter* texture_mailbox_deleter, + int highp_threshold_min); ~GLRenderer() override; const RendererCapabilitiesImpl& Capabilities() const override; @@ -74,13 +72,6 @@ virtual bool IsContextLost(); protected: - GLRenderer(RendererClient* client, - const RendererSettings* settings, - OutputSurface* output_surface, - ResourceProvider* resource_provider, - TextureMailboxDeleter* texture_mailbox_deleter, - int highp_threshold_min); - void DidChangeVisibility() override; bool IsBackbufferDiscarded() const { return is_backbuffer_discarded_; } @@ -270,6 +261,22 @@ void ScheduleCALayers(DrawingFrame* frame); void ScheduleOverlays(DrawingFrame* frame); + // Copies the contents of the render pass draw quad, including filter effects, + // to an overlay resource, returned in |resource|. The resource is allocated + // from |overlay_resource_pool_|. + // The resulting Resource may be larger than the original quad. The new size + // and position is placed in |new_bounds|. + void CopyRenderPassDrawQuadToOverlayResource( + const CALayerOverlay* ca_layer_overlay, + Resource** resource, + DrawingFrame* frame, + gfx::RectF* new_bounds); + + // Schedules the |ca_layer_overlay|, which is guaranteed to have a non-null + // |rpdq| parameter. + void ScheduleRenderPassDrawQuad(const CALayerOverlay* ca_layer_overlay, + DrawingFrame* external_frame); + using OverlayResourceLock = std::unique_ptr<ResourceProvider::ScopedReadLockGL>; using OverlayResourceLockList = std::vector<OverlayResourceLock>; @@ -534,6 +541,14 @@ // If true, draw a green border after compositing a texture quad using GL. bool gl_composited_texture_quad_border_; + + // The method FlippedFramebuffer determines whether the framebuffer associated + // with a DrawingFrame is flipped. It makes the assumption that the + // DrawingFrame is being used as part of a render pass. If a DrawingFrame is + // not being used as part of a render pass, setting it here forces + // FlippedFramebuffer to return |true|. + bool force_drawing_frame_framebuffer_unflipped_ = false; + BoundGeometry bound_geometry_; DISALLOW_COPY_AND_ASSIGN(GLRenderer); };
diff --git a/cc/output/overlay_processor.cc b/cc/output/overlay_processor.cc index bad6f3e..7996ce67 100644 --- a/cc/output/overlay_processor.cc +++ b/cc/output/overlay_processor.cc
@@ -52,7 +52,6 @@ // layers then clear the list and remove the backbuffer from the overcandidate // list. overlay_candidates->clear(); - render_pass->quad_list.clear(); overlay_damage_rect_ = render_pass->output_rect; *damage_rect = gfx::Rect(); return true;
diff --git a/cc/output/overlay_unittest.cc b/cc/output/overlay_unittest.cc index 1b7c3a2..da22606 100644 --- a/cc/output/overlay_unittest.cc +++ b/cc/output/overlay_unittest.cc
@@ -1141,7 +1141,7 @@ overlay_processor_->ProcessForOverlays(resource_provider_.get(), pass.get(), &overlay_list, &ca_layer_list, &damage_rect); - EXPECT_EQ(0U, pass->quad_list.size()); + EXPECT_EQ(gfx::Rect(), damage_rect); EXPECT_EQ(0U, overlay_list.size()); EXPECT_EQ(1U, ca_layer_list.size()); EXPECT_EQ(0U, output_surface_->bind_framebuffer_count()); @@ -1184,7 +1184,7 @@ overlay_processor_->ProcessForOverlays(resource_provider_.get(), pass.get(), &overlay_list, &ca_layer_list, &damage_rect); - EXPECT_EQ(0U, pass->quad_list.size()); + EXPECT_EQ(gfx::Rect(), damage_rect); EXPECT_EQ(0U, overlay_list.size()); EXPECT_EQ(1U, ca_layer_list.size()); EXPECT_EQ(0U, output_surface_->bind_framebuffer_count()); @@ -1204,7 +1204,7 @@ overlay_processor_->ProcessForOverlays(resource_provider_.get(), pass.get(), &overlay_list, &ca_layer_list, &damage_rect); - EXPECT_EQ(0U, pass->quad_list.size()); + EXPECT_EQ(gfx::Rect(), damage_rect); EXPECT_EQ(0U, overlay_list.size()); EXPECT_EQ(1U, ca_layer_list.size()); EXPECT_TRUE(ca_layer_list.back().shared_state->is_clipped); @@ -1226,7 +1226,7 @@ overlay_processor_->ProcessForOverlays(resource_provider_.get(), pass.get(), &overlay_list, &ca_layer_list, &damage_rect); - EXPECT_EQ(0U, pass->quad_list.size()); + EXPECT_EQ(gfx::Rect(), damage_rect); EXPECT_EQ(0U, overlay_list.size()); EXPECT_EQ(0U, ca_layer_list.size()); EXPECT_EQ(0U, output_surface_->bind_framebuffer_count()); @@ -1756,7 +1756,6 @@ protected: void SetUp() override { CALayerOverlayTest::SetUp(); - EnableRenderPassDrawQuadForTesting(); pass_ = CreateRenderPass(); quad_ = pass_->CreateAndAppendDrawQuad<RenderPassDrawQuad>(); render_pass_id_.layer_id = 3; @@ -1823,7 +1822,7 @@ kOverlayRect, render_pass_id_, 0, gfx::Vector2dF(), gfx::Size(), filters_, gfx::Vector2dF(1, 2), background_filters_); ProcessForOverlays(); - EXPECT_EQ(0U, ca_layer_list_.size()); + EXPECT_EQ(1U, ca_layer_list_.size()); } TEST_F(CALayerOverlayRPDQTest, RenderPassDrawQuadDropShadowFilterScale) { @@ -1833,7 +1832,7 @@ kOverlayRect, render_pass_id_, 0, gfx::Vector2dF(), gfx::Size(), filters_, gfx::Vector2dF(1, 2), background_filters_); ProcessForOverlays(); - EXPECT_EQ(0U, ca_layer_list_.size()); + EXPECT_EQ(1U, ca_layer_list_.size()); } TEST_F(CALayerOverlayRPDQTest, RenderPassDrawQuadBackgroundFilter) { @@ -1850,7 +1849,7 @@ kOverlayRect, render_pass_id_, 2, gfx::Vector2dF(), gfx::Size(), filters_, gfx::Vector2dF(1, 1), background_filters_); ProcessForOverlays(); - EXPECT_EQ(0U, ca_layer_list_.size()); + EXPECT_EQ(1U, ca_layer_list_.size()); } TEST_F(CALayerOverlayRPDQTest, RenderPassDrawQuadUnsupportedFilter) {
diff --git a/cc/output/renderer_unittest.cc b/cc/output/renderer_unittest.cc index e02110d..0a71c73 100644 --- a/cc/output/renderer_unittest.cc +++ b/cc/output/renderer_unittest.cc
@@ -63,8 +63,8 @@ const RendererSettings* settings, OutputSurface* output_surface, ResourceProvider* resource_provider) { - return DelegatingRenderer::Create( - client, settings, output_surface, resource_provider); + return base::MakeUnique<DelegatingRenderer>(client, settings, output_surface, + resource_provider); } template <> @@ -73,8 +73,8 @@ const RendererSettings* settings, OutputSurface* output_surface, ResourceProvider* resource_provider) { - return GLRenderer::Create( - client, settings, output_surface, resource_provider, NULL, 0); + return base::MakeUnique<GLRenderer>(client, settings, output_surface, + resource_provider, nullptr, 0); } template <typename T>
diff --git a/cc/output/software_renderer.cc b/cc/output/software_renderer.cc index ddc5e4c..2aeaead 100644 --- a/cc/output/software_renderer.cc +++ b/cc/output/software_renderer.cc
@@ -51,15 +51,6 @@ } // anonymous namespace -std::unique_ptr<SoftwareRenderer> SoftwareRenderer::Create( - RendererClient* client, - const RendererSettings* settings, - OutputSurface* output_surface, - ResourceProvider* resource_provider) { - return base::WrapUnique(new SoftwareRenderer(client, settings, output_surface, - resource_provider)); -} - SoftwareRenderer::SoftwareRenderer(RendererClient* client, const RendererSettings* settings, OutputSurface* output_surface,
diff --git a/cc/output/software_renderer.h b/cc/output/software_renderer.h index c7e0f809..0261bbb 100644 --- a/cc/output/software_renderer.h +++ b/cc/output/software_renderer.h
@@ -26,13 +26,13 @@ class CC_EXPORT SoftwareRenderer : public DirectRenderer { public: - static std::unique_ptr<SoftwareRenderer> Create( - RendererClient* client, - const RendererSettings* settings, - OutputSurface* output_surface, - ResourceProvider* resource_provider); + SoftwareRenderer(RendererClient* client, + const RendererSettings* settings, + OutputSurface* output_surface, + ResourceProvider* resource_provider); ~SoftwareRenderer() override; + const RendererCapabilitiesImpl& Capabilities() const override; void Finish() override; void SwapBuffers(CompositorFrameMetadata metadata) override; @@ -51,7 +51,6 @@ void PrepareSurfaceForPass(DrawingFrame* frame, SurfaceInitializationMode initialization_mode, const gfx::Rect& render_pass_scissor) override; - void DoDrawQuad(DrawingFrame* frame, const DrawQuad* quad, const gfx::QuadF* draw_region) override; @@ -63,12 +62,6 @@ void CopyCurrentRenderPassToBitmap( DrawingFrame* frame, std::unique_ptr<CopyOutputRequest> request) override; - - SoftwareRenderer(RendererClient* client, - const RendererSettings* settings, - OutputSurface* output_surface, - ResourceProvider* resource_provider); - void DidChangeVisibility() override; private:
diff --git a/cc/output/software_renderer_unittest.cc b/cc/output/software_renderer_unittest.cc index db86db3..bf40c86 100644 --- a/cc/output/software_renderer_unittest.cc +++ b/cc/output/software_renderer_unittest.cc
@@ -42,7 +42,7 @@ shared_bitmap_manager_.reset(new TestSharedBitmapManager()); resource_provider_ = FakeResourceProvider::Create( output_surface_.get(), shared_bitmap_manager_.get()); - renderer_ = SoftwareRenderer::Create( + renderer_ = base::MakeUnique<SoftwareRenderer>( this, &settings_, output_surface_.get(), resource_provider()); }
diff --git a/cc/output/vulkan_renderer.cc b/cc/output/vulkan_renderer.cc index 6fc94637..688491e 100644 --- a/cc/output/vulkan_renderer.cc +++ b/cc/output/vulkan_renderer.cc
@@ -6,18 +6,6 @@ namespace cc { -std::unique_ptr<VulkanRenderer> VulkanRenderer::Create( - RendererClient* client, - const RendererSettings* settings, - OutputSurface* output_surface, - ResourceProvider* resource_provider, - TextureMailboxDeleter* texture_mailbox_deleter, - int highp_threshold_min) { - return std::unique_ptr<VulkanRenderer>( - new VulkanRenderer(client, settings, output_surface, resource_provider, - texture_mailbox_deleter, highp_threshold_min)); -} - VulkanRenderer::~VulkanRenderer() {} const RendererCapabilitiesImpl& VulkanRenderer::Capabilities() const {
diff --git a/cc/output/vulkan_renderer.h b/cc/output/vulkan_renderer.h index 076a7c87..2d78aa15 100644 --- a/cc/output/vulkan_renderer.h +++ b/cc/output/vulkan_renderer.h
@@ -15,14 +15,12 @@ class CC_EXPORT VulkanRenderer : public DirectRenderer { public: - static std::unique_ptr<VulkanRenderer> Create( - RendererClient* client, - const RendererSettings* settings, - OutputSurface* output_surface, - ResourceProvider* resource_provider, - TextureMailboxDeleter* texture_mailbox_deleter, - int highp_threshold_min); - + VulkanRenderer(RendererClient* client, + const RendererSettings* settings, + OutputSurface* output_surface, + ResourceProvider* resource_provider, + TextureMailboxDeleter* texture_mailbox_deleter, + int highp_threshold_min); ~VulkanRenderer() override; // Implementation of public Renderer functions. @@ -32,13 +30,6 @@ void ReceiveSwapBuffersAck(const CompositorFrameAck& ack) override; protected: - VulkanRenderer(RendererClient* client, - const RendererSettings* settings, - OutputSurface* output_surface, - ResourceProvider* resource_provider, - TextureMailboxDeleter* texture_mailbox_deleter, - int highp_threshold_min); - // Implementations of protected Renderer functions. void DidChangeVisibility() override;
diff --git a/cc/playback/discardable_image_map.cc b/cc/playback/discardable_image_map.cc index 840de37..822d49b 100644 --- a/cc/playback/discardable_image_map.cc +++ b/cc/playback/discardable_image_map.cc
@@ -24,6 +24,33 @@ return dst; } +// Returns a rect clamped to |max_size|. Note that |paint_rect| should intersect +// or be contained by a rect defined by (0, 0) and |max_size|. +gfx::Rect SafeClampPaintRectToSize(const SkRect& paint_rect, + const gfx::Size& max_size) { + // bounds_rect.x() + bounds_rect.width() (aka bounds_rect.right()) might + // overflow integer bounds, so do custom intersect, since gfx::Rect::Intersect + // uses bounds_rect.right(). + gfx::RectF bounds_rect = gfx::SkRectToRectF(paint_rect); + float x_offset_if_negative = bounds_rect.x() < 0.f ? bounds_rect.x() : 0.f; + float y_offset_if_negative = bounds_rect.y() < 0.f ? bounds_rect.y() : 0.f; + bounds_rect.set_x(std::max(0.f, bounds_rect.x())); + bounds_rect.set_y(std::max(0.f, bounds_rect.y())); + + // Verify that the rects intersect or that bound_rect is contained by + // max_size. + DCHECK_GE(bounds_rect.width(), -x_offset_if_negative); + DCHECK_GE(bounds_rect.height(), -y_offset_if_negative); + DCHECK_GE(max_size.width(), bounds_rect.x()); + DCHECK_GE(max_size.height(), bounds_rect.y()); + + bounds_rect.set_width(std::min(bounds_rect.width() + x_offset_if_negative, + max_size.width() - bounds_rect.x())); + bounds_rect.set_height(std::min(bounds_rect.height() + y_offset_if_negative, + max_size.height() - bounds_rect.y())); + return gfx::ToEnclosingRect(bounds_rect); +} + namespace { // We're using an NWay canvas with no added canvases, so in effect @@ -36,7 +63,8 @@ std::vector<std::pair<DrawImage, gfx::Rect>>* image_set) : SkNWayCanvas(width, height), image_set_(image_set), - canvas_bounds_(SkRect::MakeIWH(width, height)) {} + canvas_bounds_(SkRect::MakeIWH(width, height)), + canvas_size_(width, height) {} protected: // we need to "undo" the behavior of SkNWayCanvas, which will try to forward @@ -146,11 +174,12 @@ src_rect.roundOut(&src_irect); image_set_->push_back(std::make_pair( DrawImage(std::move(image), src_irect, filter_quality, matrix), - gfx::ToEnclosingRect(gfx::SkRectToRectF(paint_rect)))); + SafeClampPaintRectToSize(paint_rect, canvas_size_))); } std::vector<std::pair<DrawImage, gfx::Rect>>* image_set_; const SkRect canvas_bounds_; + const gfx::Size canvas_size_; std::vector<SkPaint> saved_paints_; };
diff --git a/cc/playback/discardable_image_map_unittest.cc b/cc/playback/discardable_image_map_unittest.cc index 6510939f..05585b0 100644 --- a/cc/playback/discardable_image_map_unittest.cc +++ b/cc/playback/discardable_image_map_unittest.cc
@@ -308,7 +308,7 @@ GetDiscardableImagesInRect(image_map, gfx::Rect(0, 0, 1, 1)); EXPECT_EQ(1u, images.size()); EXPECT_TRUE(images[0].image == discardable_image); - EXPECT_EQ(gfx::Rect(0, 0, 1 << 25, 1 << 25), images[0].image_rect); + EXPECT_EQ(gfx::Rect(0, 0, 2048, 2048), images[0].image_rect); } TEST_F(DiscardableImageMapTest, PaintDestroyedWhileImageIsDrawn) { @@ -337,4 +337,125 @@ EXPECT_TRUE(images[0].image == discardable_image); } +TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectMaxImage) { + gfx::Rect visible_rect(2048, 2048); + FakeContentLayerClient content_layer_client; + content_layer_client.set_bounds(visible_rect.size()); + + int dimension = std::numeric_limits<int>::max(); + sk_sp<SkImage> discardable_image = + CreateDiscardableImage(gfx::Size(dimension, dimension)); + SkPaint paint; + content_layer_client.add_draw_image(discardable_image, gfx::Point(42, 42), + paint); + + scoped_refptr<DisplayItemList> display_list = + content_layer_client.PaintContentsToDisplayList( + ContentLayerClient::PAINTING_BEHAVIOR_NORMAL); + + DiscardableImageMap image_map; + { + DiscardableImageMap::ScopedMetadataGenerator generator(&image_map, + visible_rect.size()); + display_list->Raster(generator.canvas(), nullptr, visible_rect, 1.f); + } + std::vector<PositionDrawImage> images = + GetDiscardableImagesInRect(image_map, gfx::Rect(42, 42, 1, 1)); + EXPECT_EQ(1u, images.size()); + EXPECT_TRUE(images[0].image == discardable_image); + EXPECT_EQ(gfx::Rect(42, 42, 2006, 2006), images[0].image_rect); +} + +TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectMaxImageMaxLayer) { + // At large values of integer x, x != static_cast<int>(static_cast<float>(x)). + // So, make sure the dimension can be converted back and forth for the + // purposes of the unittest. Also, at near max int values, Skia seems to skip + // some draw calls, so we subtract 64 since we only care about "really large" + // values, not necessarily max int values. + int dimension = static_cast<int>( + static_cast<float>(std::numeric_limits<int>::max() - 64)); + gfx::Rect visible_rect(dimension, dimension); + FakeContentLayerClient content_layer_client; + content_layer_client.set_bounds(visible_rect.size()); + + sk_sp<SkImage> discardable_image = + CreateDiscardableImage(gfx::Size(dimension, dimension)); + SkPaint paint; + content_layer_client.add_draw_image(discardable_image, gfx::Point(0, 0), + paint); + content_layer_client.add_draw_image(discardable_image, gfx::Point(10000, 0), + paint); + content_layer_client.add_draw_image(discardable_image, + gfx::Point(-10000, 500), paint); + + scoped_refptr<DisplayItemList> display_list = + content_layer_client.PaintContentsToDisplayList( + ContentLayerClient::PAINTING_BEHAVIOR_NORMAL); + + DiscardableImageMap image_map; + { + DiscardableImageMap::ScopedMetadataGenerator generator(&image_map, + visible_rect.size()); + display_list->Raster(generator.canvas(), nullptr, visible_rect, 1.f); + } + std::vector<PositionDrawImage> images = + GetDiscardableImagesInRect(image_map, gfx::Rect(0, 0, 1, 1)); + EXPECT_EQ(1u, images.size()); + EXPECT_EQ(gfx::Rect(0, 0, dimension, dimension), images[0].image_rect); + + images = GetDiscardableImagesInRect(image_map, gfx::Rect(10000, 0, 1, 1)); + EXPECT_EQ(2u, images.size()); + int expected10k = static_cast<int>(static_cast<float>(dimension - 10000)); + int expected500 = static_cast<int>(static_cast<float>(dimension - 500)); + EXPECT_EQ(gfx::Rect(10000, 0, expected10k, dimension), images[1].image_rect); + EXPECT_EQ(gfx::Rect(0, 0, dimension, dimension), images[0].image_rect); + + images = GetDiscardableImagesInRect(image_map, gfx::Rect(0, 500, 1, 1)); + EXPECT_EQ(2u, images.size()); + EXPECT_EQ(gfx::Rect(0, 500, expected10k, expected500), images[1].image_rect); + EXPECT_EQ(gfx::Rect(0, 0, dimension, dimension), images[0].image_rect); +} + +TEST_F(DiscardableImageMapTest, GetDiscardableImagesRectInBounds) { + gfx::Rect visible_rect(1000, 1000); + FakeContentLayerClient content_layer_client; + content_layer_client.set_bounds(visible_rect.size()); + + sk_sp<SkImage> discardable_image = + CreateDiscardableImage(gfx::Size(100, 100)); + sk_sp<SkImage> long_discardable_image = + CreateDiscardableImage(gfx::Size(10000, 100)); + + SkPaint paint; + content_layer_client.add_draw_image(discardable_image, gfx::Point(-10, -11), + paint); + content_layer_client.add_draw_image(discardable_image, gfx::Point(950, 951), + paint); + content_layer_client.add_draw_image(long_discardable_image, + gfx::Point(-100, 500), paint); + + scoped_refptr<DisplayItemList> display_list = + content_layer_client.PaintContentsToDisplayList( + ContentLayerClient::PAINTING_BEHAVIOR_NORMAL); + + DiscardableImageMap image_map; + { + DiscardableImageMap::ScopedMetadataGenerator generator(&image_map, + visible_rect.size()); + display_list->Raster(generator.canvas(), nullptr, visible_rect, 1.f); + } + std::vector<PositionDrawImage> images = + GetDiscardableImagesInRect(image_map, gfx::Rect(0, 0, 1, 1)); + EXPECT_EQ(1u, images.size()); + EXPECT_EQ(gfx::Rect(0, 0, 90, 89), images[0].image_rect); + + images = GetDiscardableImagesInRect(image_map, gfx::Rect(999, 999, 1, 1)); + EXPECT_EQ(1u, images.size()); + EXPECT_EQ(gfx::Rect(950, 951, 50, 49), images[0].image_rect); + + images = GetDiscardableImagesInRect(image_map, gfx::Rect(0, 500, 1, 1)); + EXPECT_EQ(1u, images.size()); + EXPECT_EQ(gfx::Rect(0, 500, 1000, 100), images[0].image_rect); +} + } // namespace cc
diff --git a/cc/playback/display_item_list.cc b/cc/playback/display_item_list.cc index 24736f4..1f2c6be 100644 --- a/cc/playback/display_item_list.cc +++ b/cc/playback/display_item_list.cc
@@ -164,6 +164,12 @@ } } +void DisplayItemList::GrowCurrentBeginItemVisualRect( + const gfx::Rect& visual_rect) { + if (!inputs_.begin_item_indices.empty()) + inputs_.visual_rects[inputs_.begin_item_indices.back()].Union(visual_rect); +} + void DisplayItemList::ProcessAppendedItem(const DisplayItem* item) { if (inputs_.settings.use_cached_picture) { DCHECK(recorder_);
diff --git a/cc/playback/display_item_list.h b/cc/playback/display_item_list.h index 402e73f..2f19bb77 100644 --- a/cc/playback/display_item_list.h +++ b/cc/playback/display_item_list.h
@@ -70,18 +70,63 @@ // approximate_op_count_. void RasterIntoCanvas(const DisplayItem& display_item); - // Because processing happens in this function, all the set up for - // this item should be done via the args, which is why the return - // type needs to be const, to prevent set-after-processing mistakes. + // Because processing happens in these CreateAndAppend functions, all the set + // up for the item should be done via the args, which is why the return type + // needs to be const, to prevent set-after-processing mistakes. template <typename DisplayItemType, typename... Args> - const DisplayItemType& CreateAndAppendItem(const gfx::Rect& visual_rect, - Args&&... args) { + const DisplayItemType& CreateAndAppendPairedBeginItem(Args&&... args) { + size_t item_index = inputs_.visual_rects.size(); + inputs_.visual_rects.push_back(gfx::Rect()); + inputs_.begin_item_indices.push_back(item_index); + + return AllocateAndConstruct<DisplayItemType>(std::forward<Args>(args)...); + } + + template <typename DisplayItemType, typename... Args> + const DisplayItemType& CreateAndAppendPairedEndItem(Args&&... args) { + DCHECK(!inputs_.begin_item_indices.empty()); + size_t last_begin_index = inputs_.begin_item_indices.back(); + inputs_.begin_item_indices.pop_back(); + + // Note that we are doing two separate things below: + // + // 1. Appending a new rect to the |visual_rects| list associated with + // the newly-being-added paired end item, with that visual rect + // having same bounds as its paired begin item, referenced via + // |last_begin_index|. The paired begin item may or may not be the + // current last visual rect in |visual_rects|, and its bounds has + // potentially been grown via calls to CreateAndAppendDrawingItem(). + // + // 2. If there is still a containing paired begin item after closing the + // pair ended in this method call, growing that item's visual rect to + // incorporate the bounds of the now-finished pair. + // + // Thus we're carefully pushing and growing by the visual rect of the + // paired begin item we're closing in this method call, which is not + // necessarily the same as |visual_rects.back()|, and given that the + // |visual_rects| list is mutated in step 1 before step 2, we also can't + // shorten the reference via a |const auto| reference. We could make a + // copy of the rect before list mutation, but that would incur copy + // overhead. + + // Ending bounds match the starting bounds. + inputs_.visual_rects.push_back(inputs_.visual_rects[last_begin_index]); + + // The block that ended needs to be included in the bounds of the enclosing + // block. + GrowCurrentBeginItemVisualRect(inputs_.visual_rects[last_begin_index]); + + return AllocateAndConstruct<DisplayItemType>(std::forward<Args>(args)...); + } + + template <typename DisplayItemType, typename... Args> + const DisplayItemType& CreateAndAppendDrawingItem( + const gfx::Rect& visual_rect, + Args&&... args) { inputs_.visual_rects.push_back(visual_rect); - auto* item = &inputs_.items.AllocateAndConstruct<DisplayItemType>( - std::forward<Args>(args)...); - approximate_op_count_ += item->ApproximateOpCount(); - ProcessAppendedItem(item); - return *item; + GrowCurrentBeginItemVisualRect(visual_rect); + + return AllocateAndConstruct<DisplayItemType>(std::forward<Args>(args)...); } // Called after all items are appended, to process the items and, if @@ -108,6 +153,8 @@ float raster_scale, std::vector<DrawImage>* images); + size_t size() const { return inputs_.items.size(); } + gfx::Rect VisualRectForTesting(int index) { return inputs_.visual_rects[index]; } @@ -126,8 +173,20 @@ bool retain_individual_display_items); ~DisplayItemList(); + // If we're currently within a paired display item block, unions the + // given visual rect with the begin display item's visual rect. + void GrowCurrentBeginItemVisualRect(const gfx::Rect& visual_rect); void ProcessAppendedItem(const DisplayItem* item); + template <typename DisplayItemType, typename... Args> + const DisplayItemType& AllocateAndConstruct(Args&&... args) { + auto* item = &inputs_.items.AllocateAndConstruct<DisplayItemType>( + std::forward<Args>(args)...); + approximate_op_count_ += item->ApproximateOpCount(); + ProcessAppendedItem(item); + return *item; + } + sk_sp<SkPicture> picture_; std::unique_ptr<SkPictureRecorder> recorder_; @@ -151,7 +210,7 @@ // |items| . These rects are intentionally kept separate // because they are not needed while walking the |items| for raster. std::vector<gfx::Rect> visual_rects; - + std::vector<size_t> begin_item_indices; const DisplayItemListSettings settings; gfx::Rect layer_rect; bool is_suitable_for_gpu_rasterization;
diff --git a/cc/playback/display_item_list_unittest.cc b/cc/playback/display_item_list_unittest.cc index 1bb6d3d..67d96b4a 100644 --- a/cc/playback/display_item_list_unittest.cc +++ b/cc/playback/display_item_list_unittest.cc
@@ -23,6 +23,7 @@ #include "cc/test/fake_client_picture_cache.h" #include "cc/test/fake_engine_picture_cache.h" #include "cc/test/fake_image_serialization_processor.h" +#include "cc/test/geometry_test_utils.h" #include "cc/test/skia_common.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -45,6 +46,21 @@ const gfx::Rect kVisualRect(0, 0, 42, 42); +scoped_refptr<DisplayItemList> CreateDefaultList() { + return DisplayItemList::Create(gfx::Rect(), DisplayItemListSettings()); +} + +sk_sp<const SkPicture> CreateRectPicture(const gfx::Rect& bounds) { + SkPictureRecorder recorder; + sk_sp<SkCanvas> canvas; + + canvas = sk_ref_sp(recorder.beginRecording(bounds.width(), bounds.height())); + canvas->drawRect( + SkRect::MakeXYWH(bounds.x(), bounds.y(), bounds.width(), bounds.height()), + SkPaint()); + return recorder.finishRecordingAsPicture(); +} + void AppendFirstSerializationTestPicture(scoped_refptr<DisplayItemList> list, const gfx::Size& layer_size) { gfx::PointF offset(2.f, 3.f); @@ -58,7 +74,7 @@ offset.x(), offset.y(), layer_size.width(), layer_size.height()))); canvas->translate(offset.x(), offset.y()); canvas->drawRectCoords(0.f, 0.f, 4.f, 4.f, red_paint); - list->CreateAndAppendItem<DrawingDisplayItem>( + list->CreateAndAppendDrawingItem<DrawingDisplayItem>( kVisualRect, recorder.finishRecordingAsPicture()); } @@ -75,7 +91,7 @@ offset.x(), offset.y(), layer_size.width(), layer_size.height()))); canvas->translate(offset.x(), offset.y()); canvas->drawRectCoords(3.f, 3.f, 7.f, 7.f, blue_paint); - list->CreateAndAppendItem<DrawingDisplayItem>( + list->CreateAndAppendDrawingItem<DrawingDisplayItem>( kVisualRect, recorder.finishRecordingAsPicture()); } @@ -160,14 +176,14 @@ gfx::Rect clip_rect(6, 6, 1, 1); std::vector<SkRRect> rrects; rrects.push_back(SkRRect::MakeOval(SkRect::MakeXYWH(5.f, 5.f, 4.f, 4.f))); - list->CreateAndAppendItem<ClipDisplayItem>(kVisualRect, clip_rect, rrects, - true); + list->CreateAndAppendPairedBeginItem<ClipDisplayItem>(clip_rect, rrects, + true); // Build the second DrawingDisplayItem. AppendSecondSerializationTestPicture(list, layer_size); // Build the EndClipDisplayItem. - list->CreateAndAppendItem<EndClipDisplayItem>(kVisualRect); + list->CreateAndAppendPairedEndItem<EndClipDisplayItem>(); ValidateDisplayItemListSerialization(layer_size, list); } @@ -185,14 +201,14 @@ // Build the ClipPathDisplayItem. SkPath path; path.addCircle(5.f, 5.f, 2.f, SkPath::Direction::kCW_Direction); - list->CreateAndAppendItem<ClipPathDisplayItem>( - kVisualRect, path, SkRegion::Op::kReplace_Op, false); + list->CreateAndAppendPairedBeginItem<ClipPathDisplayItem>( + path, SkRegion::Op::kReplace_Op, false); // Build the second DrawingDisplayItem. AppendSecondSerializationTestPicture(list, layer_size); // Build the EndClipPathDisplayItem. - list->CreateAndAppendItem<EndClipPathDisplayItem>(kVisualRect); + list->CreateAndAppendPairedEndItem<EndClipPathDisplayItem>(); ValidateDisplayItemListSerialization(layer_size, list); } @@ -208,8 +224,8 @@ AppendFirstSerializationTestPicture(list, layer_size); // Build the CompositingDisplayItem. - list->CreateAndAppendItem<CompositingDisplayItem>( - kVisualRect, 150, SkXfermode::Mode::kDst_Mode, nullptr, + list->CreateAndAppendPairedBeginItem<CompositingDisplayItem>( + 150, SkXfermode::Mode::kDst_Mode, nullptr, SkColorMatrixFilter::MakeLightingFilter(SK_ColorRED, SK_ColorGREEN), false); @@ -217,7 +233,7 @@ AppendSecondSerializationTestPicture(list, layer_size); // Build the EndCompositingDisplayItem. - list->CreateAndAppendItem<EndCompositingDisplayItem>(kVisualRect); + list->CreateAndAppendPairedEndItem<EndCompositingDisplayItem>(); ValidateDisplayItemListSerialization(layer_size, list); } @@ -234,13 +250,13 @@ // Build the FloatClipDisplayItem. gfx::RectF clip_rect(6.f, 6.f, 1.f, 1.f); - list->CreateAndAppendItem<FloatClipDisplayItem>(kVisualRect, clip_rect); + list->CreateAndAppendPairedBeginItem<FloatClipDisplayItem>(clip_rect); // Build the second DrawingDisplayItem. AppendSecondSerializationTestPicture(list, layer_size); // Build the EndFloatClipDisplayItem. - list->CreateAndAppendItem<EndFloatClipDisplayItem>(kVisualRect); + list->CreateAndAppendPairedEndItem<EndFloatClipDisplayItem>(); ValidateDisplayItemListSerialization(layer_size, list); } @@ -259,13 +275,13 @@ gfx::Transform transform; transform.Scale(1.25f, 1.25f); transform.Translate(-1.f, -1.f); - list->CreateAndAppendItem<TransformDisplayItem>(kVisualRect, transform); + list->CreateAndAppendPairedBeginItem<TransformDisplayItem>(transform); // Build the second DrawingDisplayItem. AppendSecondSerializationTestPicture(list, layer_size); // Build the EndTransformDisplayItem. - list->CreateAndAppendItem<EndTransformDisplayItem>(kVisualRect); + list->CreateAndAppendPairedEndItem<EndTransformDisplayItem>(); ValidateDisplayItemListSerialization(layer_size, list); } @@ -290,7 +306,7 @@ canvas->translate(offset.x(), offset.y()); canvas->drawRectCoords(0.f, 0.f, 60.f, 60.f, red_paint); canvas->drawRectCoords(50.f, 50.f, 75.f, 75.f, blue_paint); - list->CreateAndAppendItem<DrawingDisplayItem>( + list->CreateAndAppendDrawingItem<DrawingDisplayItem>( kVisualRect, recorder.finishRecordingAsPicture()); list->Finalize(); DrawDisplayList(pixels, layer_rect, list); @@ -332,12 +348,12 @@ recorder.beginRecording(gfx::RectFToSkRect(first_recording_rect))); canvas->translate(first_offset.x(), first_offset.y()); canvas->drawRectCoords(0.f, 0.f, 60.f, 60.f, red_paint); - list->CreateAndAppendItem<DrawingDisplayItem>( + list->CreateAndAppendDrawingItem<DrawingDisplayItem>( kVisualRect, recorder.finishRecordingAsPicture()); gfx::Rect clip_rect(60, 60, 10, 10); - list->CreateAndAppendItem<ClipDisplayItem>(kVisualRect, clip_rect, - std::vector<SkRRect>(), true); + list->CreateAndAppendPairedBeginItem<ClipDisplayItem>( + clip_rect, std::vector<SkRRect>(), true); gfx::PointF second_offset(2.f, 3.f); gfx::RectF second_recording_rect(second_offset, @@ -346,10 +362,10 @@ recorder.beginRecording(gfx::RectFToSkRect(second_recording_rect))); canvas->translate(second_offset.x(), second_offset.y()); canvas->drawRectCoords(50.f, 50.f, 75.f, 75.f, blue_paint); - list->CreateAndAppendItem<DrawingDisplayItem>( + list->CreateAndAppendDrawingItem<DrawingDisplayItem>( kVisualRect, recorder.finishRecordingAsPicture()); - list->CreateAndAppendItem<EndClipDisplayItem>(kVisualRect); + list->CreateAndAppendPairedEndItem<EndClipDisplayItem>(); list->Finalize(); DrawDisplayList(pixels, layer_rect, list); @@ -392,12 +408,12 @@ recorder.beginRecording(gfx::RectFToSkRect(first_recording_rect))); canvas->translate(first_offset.x(), first_offset.y()); canvas->drawRectCoords(0.f, 0.f, 60.f, 60.f, red_paint); - list->CreateAndAppendItem<DrawingDisplayItem>( + list->CreateAndAppendDrawingItem<DrawingDisplayItem>( kVisualRect, recorder.finishRecordingAsPicture()); gfx::Transform transform; transform.Rotate(45.0); - list->CreateAndAppendItem<TransformDisplayItem>(kVisualRect, transform); + list->CreateAndAppendPairedBeginItem<TransformDisplayItem>(transform); gfx::PointF second_offset(2.f, 3.f); gfx::RectF second_recording_rect(second_offset, @@ -406,10 +422,10 @@ recorder.beginRecording(gfx::RectFToSkRect(second_recording_rect))); canvas->translate(second_offset.x(), second_offset.y()); canvas->drawRectCoords(50.f, 50.f, 75.f, 75.f, blue_paint); - list->CreateAndAppendItem<DrawingDisplayItem>( + list->CreateAndAppendDrawingItem<DrawingDisplayItem>( kVisualRect, recorder.finishRecordingAsPicture()); - list->CreateAndAppendItem<EndTransformDisplayItem>(kVisualRect); + list->CreateAndAppendPairedEndItem<EndTransformDisplayItem>(); list->Finalize(); DrawDisplayList(pixels, layer_rect, list); @@ -461,9 +477,9 @@ filters.Append(FilterOperation::CreateReferenceFilter(image_filter)); filters.Append(FilterOperation::CreateBrightnessFilter(0.5f)); gfx::RectF filter_bounds(10.f, 10.f, 50.f, 50.f); - list->CreateAndAppendItem<FilterDisplayItem>(kVisualRect, filters, - filter_bounds); - list->CreateAndAppendItem<EndFilterDisplayItem>(kVisualRect); + list->CreateAndAppendPairedBeginItem<FilterDisplayItem>(filters, + filter_bounds); + list->CreateAndAppendPairedEndItem<EndFilterDisplayItem>(); list->Finalize(); DrawDisplayList(pixels, layer_rect, list); @@ -505,8 +521,8 @@ canvas->drawRectCoords(0.f, 0.f, 60.f, 60.f, red_paint); canvas->drawRectCoords(50.f, 50.f, 75.f, 75.f, blue_paint); sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture(); - list_without_caching->CreateAndAppendItem<DrawingDisplayItem>(kVisualRect, - picture); + list_without_caching->CreateAndAppendDrawingItem<DrawingDisplayItem>( + kVisualRect, picture); list_without_caching->Finalize(); DrawDisplayList(pixels, layer_rect, list_without_caching); @@ -515,8 +531,8 @@ caching_settings.use_cached_picture = true; scoped_refptr<DisplayItemList> list_with_caching = DisplayItemList::Create(layer_rect, caching_settings); - list_with_caching->CreateAndAppendItem<DrawingDisplayItem>(kVisualRect, - picture); + list_with_caching->CreateAndAppendDrawingItem<DrawingDisplayItem>(kVisualRect, + picture); list_with_caching->Finalize(); DrawDisplayList(expected_pixels, layer_rect, list_with_caching); @@ -544,7 +560,7 @@ DisplayItemListSettings caching_settings; caching_settings.use_cached_picture = true; list = DisplayItemList::Create(layer_rect, caching_settings); - list->CreateAndAppendItem<DrawingDisplayItem>(kVisualRect, picture); + list->CreateAndAppendDrawingItem<DrawingDisplayItem>(kVisualRect, picture); list->Finalize(); memory_usage = list->ApproximateMemoryUsage(); EXPECT_GE(memory_usage, picture_size); @@ -554,7 +570,7 @@ DisplayItemListSettings no_caching_settings; no_caching_settings.use_cached_picture = false; list = DisplayItemList::Create(layer_rect, no_caching_settings); - list->CreateAndAppendItem<DrawingDisplayItem>(kVisualRect, picture); + list->CreateAndAppendDrawingItem<DrawingDisplayItem>(kVisualRect, picture); list->Finalize(); memory_usage = list->ApproximateMemoryUsage(); EXPECT_GE(memory_usage, picture_size); @@ -564,7 +580,7 @@ // picture and items are retained (currently this only happens due to certain // categories being traced). list = new DisplayItemList(layer_rect, caching_settings, true); - list->CreateAndAppendItem<DrawingDisplayItem>(kVisualRect, picture); + list->CreateAndAppendDrawingItem<DrawingDisplayItem>(kVisualRect, picture); list->Finalize(); memory_usage = list->ApproximateMemoryUsage(); EXPECT_EQ(static_cast<size_t>(0), memory_usage); @@ -592,9 +608,9 @@ DisplayItemList::Create(layer_rect, DisplayItemListSettings()); gfx::Transform transform; transform.Translate(6.f, 7.f); - list->CreateAndAppendItem<TransformDisplayItem>(kVisualRect, transform); + list->CreateAndAppendPairedBeginItem<TransformDisplayItem>(transform); AppendFirstSerializationTestPicture(list, layer_rect.size()); - list->CreateAndAppendItem<EndTransformDisplayItem>(kVisualRect); + list->CreateAndAppendPairedEndItem<EndTransformDisplayItem>(); list->Finalize(); std::string value = list->AsValue(true)->ToString(); @@ -611,8 +627,7 @@ } TEST(DisplayItemListTest, AsValueWithEmptyRectAndNoItems) { - scoped_refptr<DisplayItemList> list = - DisplayItemList::Create(gfx::Rect(), DisplayItemListSettings()); + scoped_refptr<DisplayItemList> list = CreateDefaultList(); list->Finalize(); std::string value = list->AsValue(true)->ToString(); @@ -627,13 +642,12 @@ } TEST(DisplayItemListTest, AsValueWithEmptyRectAndItems) { - scoped_refptr<DisplayItemList> list = - DisplayItemList::Create(gfx::Rect(), DisplayItemListSettings()); + scoped_refptr<DisplayItemList> list = CreateDefaultList(); gfx::Transform transform; transform.Translate(6.f, 7.f); - list->CreateAndAppendItem<TransformDisplayItem>(kVisualRect, transform); + list->CreateAndAppendPairedBeginItem<TransformDisplayItem>(transform); AppendFirstSerializationTestPicture(list, gfx::Size()); - list->CreateAndAppendItem<EndTransformDisplayItem>(kVisualRect); + list->CreateAndAppendPairedEndItem<EndTransformDisplayItem>(); list->Finalize(); std::string value = list->AsValue(true)->ToString(); @@ -651,4 +665,282 @@ EXPECT_EQ(value.find("\"skp64\":"), std::string::npos); } +TEST(DisplayItemListTest, SizeEmpty) { + scoped_refptr<DisplayItemList> list = CreateDefaultList(); + EXPECT_EQ(0u, list->size()); +} + +TEST(DisplayItemListTest, SizeOne) { + scoped_refptr<DisplayItemList> list = CreateDefaultList(); + gfx::Rect drawing_bounds(5, 6, 1, 1); + list->CreateAndAppendDrawingItem<DrawingDisplayItem>( + drawing_bounds, CreateRectPicture(drawing_bounds)); + EXPECT_EQ(1u, list->size()); +} + +TEST(DisplayItemListTest, SizeMultiple) { + scoped_refptr<DisplayItemList> list = CreateDefaultList(); + gfx::Rect clip_bounds(5, 6, 7, 8); + list->CreateAndAppendPairedBeginItem<ClipDisplayItem>( + clip_bounds, std::vector<SkRRect>(), true); + list->CreateAndAppendPairedEndItem<EndClipDisplayItem>(); + EXPECT_EQ(2u, list->size()); +} + +TEST(DisplayItemListTest, AppendVisualRectSimple) { + scoped_refptr<DisplayItemList> list = CreateDefaultList(); + + // One drawing: D. + + gfx::Rect drawing_bounds(5, 6, 7, 8); + list->CreateAndAppendDrawingItem<DrawingDisplayItem>( + drawing_bounds, CreateRectPicture(drawing_bounds)); + + EXPECT_EQ(1u, list->size()); + EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(0)); +} + +TEST(DisplayItemListTest, AppendVisualRectEmptyBlock) { + scoped_refptr<DisplayItemList> list = CreateDefaultList(); + + // One block: B1, E1. + + gfx::Rect clip_bounds(5, 6, 7, 8); + list->CreateAndAppendPairedBeginItem<ClipDisplayItem>( + clip_bounds, std::vector<SkRRect>(), true); + + list->CreateAndAppendPairedEndItem<EndClipDisplayItem>(); + + EXPECT_EQ(2u, list->size()); + EXPECT_RECT_EQ(gfx::Rect(), list->VisualRectForTesting(0)); + EXPECT_RECT_EQ(gfx::Rect(), list->VisualRectForTesting(1)); +} + +TEST(DisplayItemListTest, AppendVisualRectEmptyBlockContainingEmptyBlock) { + scoped_refptr<DisplayItemList> list = CreateDefaultList(); + + // Two nested blocks: B1, B2, E2, E1. + + gfx::Rect clip_bounds(5, 6, 7, 8); + list->CreateAndAppendPairedBeginItem<ClipDisplayItem>( + clip_bounds, std::vector<SkRRect>(), true); + list->CreateAndAppendPairedBeginItem<TransformDisplayItem>(gfx::Transform()); + list->CreateAndAppendPairedEndItem<EndTransformDisplayItem>(); + list->CreateAndAppendPairedEndItem<EndClipDisplayItem>(); + + EXPECT_EQ(4u, list->size()); + EXPECT_RECT_EQ(gfx::Rect(), list->VisualRectForTesting(0)); + EXPECT_RECT_EQ(gfx::Rect(), list->VisualRectForTesting(1)); + EXPECT_RECT_EQ(gfx::Rect(), list->VisualRectForTesting(2)); + EXPECT_RECT_EQ(gfx::Rect(), list->VisualRectForTesting(3)); +} + +TEST(DisplayItemListTest, AppendVisualRectBlockContainingDrawing) { + scoped_refptr<DisplayItemList> list = CreateDefaultList(); + + // One block with one drawing: B1, Da, E1. + + gfx::Rect clip_bounds(5, 6, 7, 8); + list->CreateAndAppendPairedBeginItem<ClipDisplayItem>( + clip_bounds, std::vector<SkRRect>(), true); + + gfx::Rect drawing_bounds(5, 6, 1, 1); + list->CreateAndAppendDrawingItem<DrawingDisplayItem>( + drawing_bounds, CreateRectPicture(drawing_bounds)); + + list->CreateAndAppendPairedEndItem<EndClipDisplayItem>(); + + EXPECT_EQ(3u, list->size()); + EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(0)); + EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(1)); + EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(2)); +} + +TEST(DisplayItemListTest, AppendVisualRectBlockContainingEscapedDrawing) { + scoped_refptr<DisplayItemList> list = CreateDefaultList(); + + // One block with one drawing: B1, Da (escapes), E1. + + gfx::Rect clip_bounds(5, 6, 7, 8); + list->CreateAndAppendPairedBeginItem<ClipDisplayItem>( + clip_bounds, std::vector<SkRRect>(), true); + + gfx::Rect drawing_bounds(1, 2, 3, 4); + list->CreateAndAppendDrawingItem<DrawingDisplayItem>( + drawing_bounds, CreateRectPicture(drawing_bounds)); + + list->CreateAndAppendPairedEndItem<EndClipDisplayItem>(); + + EXPECT_EQ(3u, list->size()); + EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(0)); + EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(1)); + EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(2)); +} + +TEST(DisplayItemListTest, + AppendVisualRectDrawingFollowedByBlockContainingEscapedDrawing) { + scoped_refptr<DisplayItemList> list = CreateDefaultList(); + + // One drawing followed by one block with one drawing: Da, B1, Db (escapes), + // E1. + + gfx::Rect drawing_a_bounds(1, 2, 3, 4); + list->CreateAndAppendDrawingItem<DrawingDisplayItem>( + drawing_a_bounds, CreateRectPicture(drawing_a_bounds)); + + gfx::Rect clip_bounds(5, 6, 7, 8); + list->CreateAndAppendPairedBeginItem<ClipDisplayItem>( + clip_bounds, std::vector<SkRRect>(), true); + + gfx::Rect drawing_b_bounds(13, 14, 1, 1); + list->CreateAndAppendDrawingItem<DrawingDisplayItem>( + drawing_b_bounds, CreateRectPicture(drawing_b_bounds)); + + list->CreateAndAppendPairedEndItem<EndClipDisplayItem>(); + + EXPECT_EQ(4u, list->size()); + EXPECT_RECT_EQ(drawing_a_bounds, list->VisualRectForTesting(0)); + EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(1)); + EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(2)); + EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(3)); +} + +TEST(DisplayItemListTest, AppendVisualRectTwoBlocksTwoDrawings) { + scoped_refptr<DisplayItemList> list = CreateDefaultList(); + + // Multiple nested blocks with drawings amidst: B1, Da, B2, Db, E2, E1. + + gfx::Rect clip_bounds(5, 6, 7, 8); + list->CreateAndAppendPairedBeginItem<ClipDisplayItem>( + clip_bounds, std::vector<SkRRect>(), true); + + gfx::Rect drawing_a_bounds(5, 6, 1, 1); + list->CreateAndAppendDrawingItem<DrawingDisplayItem>( + drawing_a_bounds, CreateRectPicture(drawing_a_bounds)); + + list->CreateAndAppendPairedBeginItem<TransformDisplayItem>(gfx::Transform()); + + gfx::Rect drawing_b_bounds(7, 8, 1, 1); + list->CreateAndAppendDrawingItem<DrawingDisplayItem>( + drawing_b_bounds, CreateRectPicture(drawing_b_bounds)); + + list->CreateAndAppendPairedEndItem<EndTransformDisplayItem>(); + list->CreateAndAppendPairedEndItem<EndClipDisplayItem>(); + + EXPECT_EQ(6u, list->size()); + gfx::Rect merged_drawing_bounds = gfx::Rect(drawing_a_bounds); + merged_drawing_bounds.Union(drawing_b_bounds); + EXPECT_RECT_EQ(merged_drawing_bounds, list->VisualRectForTesting(0)); + EXPECT_RECT_EQ(drawing_a_bounds, list->VisualRectForTesting(1)); + EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(2)); + EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(3)); + EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(4)); + EXPECT_RECT_EQ(merged_drawing_bounds, list->VisualRectForTesting(5)); +} + +TEST(DisplayItemListTest, + AppendVisualRectTwoBlocksTwoDrawingsInnerDrawingEscaped) { + scoped_refptr<DisplayItemList> list = CreateDefaultList(); + + // Multiple nested blocks with drawings amidst: B1, Da, B2, Db (escapes), E2, + // E1. + + gfx::Rect clip_bounds(5, 6, 7, 8); + list->CreateAndAppendPairedBeginItem<ClipDisplayItem>( + clip_bounds, std::vector<SkRRect>(), true); + + gfx::Rect drawing_a_bounds(5, 6, 1, 1); + list->CreateAndAppendDrawingItem<DrawingDisplayItem>( + drawing_a_bounds, CreateRectPicture(drawing_a_bounds)); + + list->CreateAndAppendPairedBeginItem<TransformDisplayItem>(gfx::Transform()); + + gfx::Rect drawing_b_bounds(1, 2, 3, 4); + list->CreateAndAppendDrawingItem<DrawingDisplayItem>( + drawing_b_bounds, CreateRectPicture(drawing_b_bounds)); + + list->CreateAndAppendPairedEndItem<EndTransformDisplayItem>(); + list->CreateAndAppendPairedEndItem<EndClipDisplayItem>(); + + EXPECT_EQ(6u, list->size()); + gfx::Rect merged_drawing_bounds = gfx::Rect(drawing_a_bounds); + merged_drawing_bounds.Union(drawing_b_bounds); + EXPECT_RECT_EQ(merged_drawing_bounds, list->VisualRectForTesting(0)); + EXPECT_RECT_EQ(drawing_a_bounds, list->VisualRectForTesting(1)); + EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(2)); + EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(3)); + EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(4)); + EXPECT_RECT_EQ(merged_drawing_bounds, list->VisualRectForTesting(5)); +} + +TEST(DisplayItemListTest, + AppendVisualRectTwoBlocksTwoDrawingsOuterDrawingEscaped) { + scoped_refptr<DisplayItemList> list = CreateDefaultList(); + + // Multiple nested blocks with drawings amidst: B1, Da (escapes), B2, Db, E2, + // E1. + + gfx::Rect clip_bounds(5, 6, 7, 8); + list->CreateAndAppendPairedBeginItem<ClipDisplayItem>( + clip_bounds, std::vector<SkRRect>(), true); + + gfx::Rect drawing_a_bounds(1, 2, 3, 4); + list->CreateAndAppendDrawingItem<DrawingDisplayItem>( + drawing_a_bounds, CreateRectPicture(drawing_a_bounds)); + + list->CreateAndAppendPairedBeginItem<TransformDisplayItem>(gfx::Transform()); + + gfx::Rect drawing_b_bounds(7, 8, 1, 1); + list->CreateAndAppendDrawingItem<DrawingDisplayItem>( + drawing_b_bounds, CreateRectPicture(drawing_b_bounds)); + + list->CreateAndAppendPairedEndItem<EndTransformDisplayItem>(); + list->CreateAndAppendPairedEndItem<EndClipDisplayItem>(); + + EXPECT_EQ(6u, list->size()); + gfx::Rect merged_drawing_bounds = gfx::Rect(drawing_a_bounds); + merged_drawing_bounds.Union(drawing_b_bounds); + EXPECT_RECT_EQ(merged_drawing_bounds, list->VisualRectForTesting(0)); + EXPECT_RECT_EQ(drawing_a_bounds, list->VisualRectForTesting(1)); + EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(2)); + EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(3)); + EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(4)); + EXPECT_RECT_EQ(merged_drawing_bounds, list->VisualRectForTesting(5)); +} + +TEST(DisplayItemListTest, + AppendVisualRectTwoBlocksTwoDrawingsBothDrawingsEscaped) { + scoped_refptr<DisplayItemList> list = CreateDefaultList(); + + // Multiple nested blocks with drawings amidst: + // B1, Da (escapes to the right), B2, Db (escapes to the left), E2, E1. + + gfx::Rect clip_bounds(5, 6, 7, 8); + list->CreateAndAppendPairedBeginItem<ClipDisplayItem>( + clip_bounds, std::vector<SkRRect>(), true); + + gfx::Rect drawing_a_bounds(13, 14, 1, 1); + list->CreateAndAppendDrawingItem<DrawingDisplayItem>( + drawing_a_bounds, CreateRectPicture(drawing_a_bounds)); + + list->CreateAndAppendPairedBeginItem<TransformDisplayItem>(gfx::Transform()); + + gfx::Rect drawing_b_bounds(1, 2, 3, 4); + list->CreateAndAppendDrawingItem<DrawingDisplayItem>( + drawing_b_bounds, CreateRectPicture(drawing_b_bounds)); + + list->CreateAndAppendPairedEndItem<EndTransformDisplayItem>(); + list->CreateAndAppendPairedEndItem<EndClipDisplayItem>(); + + EXPECT_EQ(6u, list->size()); + gfx::Rect merged_drawing_bounds = gfx::Rect(drawing_a_bounds); + merged_drawing_bounds.Union(drawing_b_bounds); + EXPECT_RECT_EQ(merged_drawing_bounds, list->VisualRectForTesting(0)); + EXPECT_RECT_EQ(drawing_a_bounds, list->VisualRectForTesting(1)); + EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(2)); + EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(3)); + EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(4)); + EXPECT_RECT_EQ(merged_drawing_bounds, list->VisualRectForTesting(5)); +} + } // namespace cc
diff --git a/cc/playback/display_item_proto_factory.cc b/cc/playback/display_item_proto_factory.cc index 75de323..8677acc 100644 --- a/cc/playback/display_item_proto_factory.cc +++ b/cc/playback/display_item_proto_factory.cc
@@ -26,44 +26,44 @@ std::vector<uint32_t>* used_engine_picture_ids) { switch (proto.type()) { case proto::DisplayItem::Type_Clip: - list->CreateAndAppendItem<ClipDisplayItem>(visual_rect, proto); + list->CreateAndAppendPairedBeginItem<ClipDisplayItem>(proto); return; case proto::DisplayItem::Type_EndClip: - list->CreateAndAppendItem<EndClipDisplayItem>(visual_rect, proto); + list->CreateAndAppendPairedEndItem<EndClipDisplayItem>(proto); return; case proto::DisplayItem::Type_ClipPath: - list->CreateAndAppendItem<ClipPathDisplayItem>(visual_rect, proto); + list->CreateAndAppendPairedBeginItem<ClipPathDisplayItem>(proto); return; case proto::DisplayItem::Type_EndClipPath: - list->CreateAndAppendItem<EndClipPathDisplayItem>(visual_rect, proto); + list->CreateAndAppendPairedEndItem<EndClipPathDisplayItem>(proto); return; case proto::DisplayItem::Type_Compositing: - list->CreateAndAppendItem<CompositingDisplayItem>(visual_rect, proto); + list->CreateAndAppendPairedBeginItem<CompositingDisplayItem>(proto); return; case proto::DisplayItem::Type_EndCompositing: - list->CreateAndAppendItem<EndCompositingDisplayItem>(visual_rect, proto); + list->CreateAndAppendPairedEndItem<EndCompositingDisplayItem>(proto); return; case proto::DisplayItem::Type_Drawing: - list->CreateAndAppendItem<DrawingDisplayItem>( + list->CreateAndAppendDrawingItem<DrawingDisplayItem>( visual_rect, proto, client_picture_cache, used_engine_picture_ids); return; case proto::DisplayItem::Type_Filter: - list->CreateAndAppendItem<FilterDisplayItem>(visual_rect, proto); + list->CreateAndAppendPairedBeginItem<FilterDisplayItem>(proto); return; case proto::DisplayItem::Type_EndFilter: - list->CreateAndAppendItem<EndFilterDisplayItem>(visual_rect, proto); + list->CreateAndAppendPairedEndItem<EndFilterDisplayItem>(proto); return; case proto::DisplayItem::Type_FloatClip: - list->CreateAndAppendItem<FloatClipDisplayItem>(visual_rect, proto); + list->CreateAndAppendPairedBeginItem<FloatClipDisplayItem>(proto); return; case proto::DisplayItem::Type_EndFloatClip: - list->CreateAndAppendItem<EndFloatClipDisplayItem>(visual_rect, proto); + list->CreateAndAppendPairedEndItem<EndFloatClipDisplayItem>(proto); return; case proto::DisplayItem::Type_Transform: - list->CreateAndAppendItem<TransformDisplayItem>(visual_rect, proto); + list->CreateAndAppendPairedBeginItem<TransformDisplayItem>(proto); return; case proto::DisplayItem::Type_EndTransform: - list->CreateAndAppendItem<EndTransformDisplayItem>(visual_rect, proto); + list->CreateAndAppendPairedEndItem<EndTransformDisplayItem>(proto); return; }
diff --git a/cc/playback/recording_source.cc b/cc/playback/recording_source.cc index 198fb266..ae4933c 100644 --- a/cc/playback/recording_source.cc +++ b/cc/playback/recording_source.cc
@@ -55,7 +55,8 @@ void RecordingSource::FromProtobuf( const proto::RecordingSource& proto, - const scoped_refptr<DisplayItemList>& display_list) { + const scoped_refptr<DisplayItemList>& display_list, + const gfx::Rect& recorded_viewport) { size_ = ProtoToSize(proto.size()); slow_down_raster_scale_factor_for_debug_ = proto.slow_down_raster_scale_factor_for_debug(); @@ -68,6 +69,7 @@ background_color_ = static_cast<SkColor>(proto.background_color()); display_list_ = display_list; + recorded_viewport_ = recorded_viewport; if (display_list_) FinishDisplayItemListUpdate(); }
diff --git a/cc/playback/recording_source.h b/cc/playback/recording_source.h index 88a1e26..67bc93e 100644 --- a/cc/playback/recording_source.h +++ b/cc/playback/recording_source.h
@@ -48,7 +48,8 @@ void ToProtobuf(proto::RecordingSource* proto) const; void FromProtobuf(const proto::RecordingSource& proto, - const scoped_refptr<DisplayItemList>& display_list); + const scoped_refptr<DisplayItemList>& display_list, + const gfx::Rect& recorded_viewport); bool UpdateAndExpandInvalidation(Region* invalidation, const gfx::Size& layer_size,
diff --git a/cc/playback/recording_source_unittest.cc b/cc/playback/recording_source_unittest.cc index be8c755a..26594ffe70 100644 --- a/cc/playback/recording_source_unittest.cc +++ b/cc/playback/recording_source_unittest.cc
@@ -41,7 +41,7 @@ source->ToProtobuf(&proto); FakeRecordingSource new_source; - new_source.FromProtobuf(proto, nullptr); + new_source.FromProtobuf(proto, nullptr, gfx::Rect()); EXPECT_TRUE(source->EqualsTo(new_source)); }
diff --git a/cc/quads/render_pass_draw_quad.cc b/cc/quads/render_pass_draw_quad.cc index 3832a02..1f55c85 100644 --- a/cc/quads/render_pass_draw_quad.cc +++ b/cc/quads/render_pass_draw_quad.cc
@@ -9,6 +9,7 @@ #include "cc/base/math_util.h" #include "cc/debug/traced_value.h" #include "third_party/skia/include/core/SkImageFilter.h" +#include "ui/gfx/geometry/rect_f.h" namespace cc {
diff --git a/cc/quads/render_pass_draw_quad.h b/cc/quads/render_pass_draw_quad.h index 97dd4f2..a8cc9ee 100644 --- a/cc/quads/render_pass_draw_quad.h +++ b/cc/quads/render_pass_draw_quad.h
@@ -13,7 +13,6 @@ #include "cc/output/filter_operations.h" #include "cc/quads/draw_quad.h" #include "cc/quads/render_pass_id.h" -#include "cc/resources/resource_provider.h" namespace cc {
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc index 6ab6846..ce9b233 100644 --- a/cc/resources/resource_provider.cc +++ b/cc/resources/resource_provider.cc
@@ -668,6 +668,7 @@ base::Owned(release_callback_impl.release())); resource->read_lock_fences_enabled = read_lock_fences_enabled; resource->is_overlay_candidate = mailbox.is_overlay_candidate(); + resource->color_space = mailbox.color_space(); return id; } @@ -1031,6 +1032,7 @@ texture_id_ = resource->gl_id; target_ = resource->target; size_ = resource->size; + color_space_ = resource->color_space; } ResourceProvider::ScopedReadLockGL::~ScopedReadLockGL() {
diff --git a/cc/resources/resource_provider.h b/cc/resources/resource_provider.h index ff7970b..0207d87d 100644 --- a/cc/resources/resource_provider.h +++ b/cc/resources/resource_provider.h
@@ -224,6 +224,7 @@ unsigned texture_id() const { return texture_id_; } GLenum target() const { return target_; } const gfx::Size& size() const { return size_; } + const gfx::ColorSpace& color_space() const { return color_space_; } private: ResourceProvider* resource_provider_; @@ -231,6 +232,7 @@ unsigned texture_id_; GLenum target_; gfx::Size size_; + gfx::ColorSpace color_space_; DISALLOW_COPY_AND_ASSIGN(ScopedReadLockGL); }; @@ -248,6 +250,9 @@ unsigned texture_id() const { return resource_lock_.texture_id(); } GLenum target() const { return target_; } + const gfx::ColorSpace& color_space() const { + return resource_lock_.color_space(); + } private: ScopedReadLockGL resource_lock_;
diff --git a/cc/resources/resource_provider_unittest.cc b/cc/resources/resource_provider_unittest.cc index f726c17..74d35267 100644 --- a/cc/resources/resource_provider_unittest.cc +++ b/cc/resources/resource_provider_unittest.cc
@@ -654,9 +654,13 @@ child_context_->genSyncToken(child_context_->insertFenceSync(), external_sync_token.GetData()); EXPECT_TRUE(external_sync_token.HasData()); + + gfx::ColorSpace id4_color_space = gfx::ColorSpace::CreateSRGB(); + TextureMailbox id4_mailbox(external_mailbox, external_sync_token, + GL_TEXTURE_EXTERNAL_OES); + id4_mailbox.set_color_space(id4_color_space); ResourceId id4 = child_resource_provider_->CreateResourceFromTextureMailbox( - TextureMailbox(external_mailbox, external_sync_token, - GL_TEXTURE_EXTERNAL_OES), + id4_mailbox, SingleReleaseCallbackImpl::Create(base::Bind(&EmptyReleaseCallback))); ReturnedResourceArray returned_to_child; @@ -742,6 +746,18 @@ resource_provider_.get(), context(), mapped_id2, size, format, result); EXPECT_EQ(0, memcmp(data2, result, pixel_size)); + EXPECT_FALSE(resource_provider_->IsOverlayCandidate(mapped_id1)); + EXPECT_FALSE(resource_provider_->IsOverlayCandidate(mapped_id2)); + EXPECT_TRUE(resource_provider_->IsOverlayCandidate(mapped_id3)); + EXPECT_FALSE(resource_provider_->IsOverlayCandidate(mapped_id4)); + + { + resource_provider_->WaitSyncTokenIfNeeded(mapped_id4); + ResourceProvider::ScopedReadLockGL lock(resource_provider_.get(), + mapped_id4); + EXPECT_TRUE(lock.color_space() == id4_color_space); + } + { // Check that transfering again the same resource from the child to the // parent works.
diff --git a/cc/surfaces/display.cc b/cc/surfaces/display.cc index 9ded1a21..9a5c7e5 100644 --- a/cc/surfaces/display.cc +++ b/cc/surfaces/display.cc
@@ -88,6 +88,7 @@ // The context given to the Display's OutputSurface should already be // initialized, so Bind can not fail. DCHECK(ok); + InitializeRenderer(); } void Display::SetSurfaceId(const SurfaceId& id, float device_scale_factor) { @@ -151,10 +152,7 @@ } void Display::InitializeRenderer() { - if (resource_provider_) - return; - - std::unique_ptr<ResourceProvider> resource_provider(new ResourceProvider( + resource_provider_.reset(new ResourceProvider( output_surface_->context_provider(), bitmap_manager_, gpu_memory_buffer_manager_, nullptr, settings_.highp_threshold_min, settings_.texture_id_allocation_chunk_size, @@ -164,36 +162,27 @@ if (output_surface_->context_provider()) { DCHECK(texture_mailbox_deleter_); - std::unique_ptr<GLRenderer> renderer = GLRenderer::Create( - this, &settings_, output_surface_.get(), resource_provider.get(), + renderer_ = base::MakeUnique<GLRenderer>( + this, &settings_, output_surface_.get(), resource_provider_.get(), texture_mailbox_deleter_.get(), settings_.highp_threshold_min); - if (!renderer) - return; - renderer_ = std::move(renderer); } else if (output_surface_->vulkan_context_provider()) { #if defined(ENABLE_VULKAN) DCHECK(texture_mailbox_deleter_); - std::unique_ptr<VulkanRenderer> renderer = VulkanRenderer::Create( - this, &settings_, output_surface_.get(), resource_provider.get(), + renderer_ = base::MakeUnique<VulkanRenderer>( + this, &settings_, output_surface_.get(), resource_provider_.get(), texture_mailbox_deleter_.get(), settings_.highp_threshold_min); - if (!renderer) - return; - renderer_ = std::move(renderer); #else NOTREACHED(); #endif } else { - std::unique_ptr<SoftwareRenderer> renderer = SoftwareRenderer::Create( - this, &settings_, output_surface_.get(), resource_provider.get()); - if (!renderer) - return; + auto renderer = base::MakeUnique<SoftwareRenderer>( + this, &settings_, output_surface_.get(), resource_provider_.get()); software_renderer_ = renderer.get(); renderer_ = std::move(renderer); } renderer_->SetEnlargePassTextureAmount(enlarge_texture_amount_); - resource_provider_ = std::move(resource_provider); // TODO(jbauman): Outputting an incomplete quad list doesn't work when using // overlays. bool output_partial_list = renderer_->Capabilities().using_partial_swap && @@ -227,7 +216,6 @@ return false; } - InitializeRenderer(); if (!output_surface_) { TRACE_EVENT_INSTANT0("cc", "No output surface", TRACE_EVENT_SCOPE_THREAD); return false;
diff --git a/cc/surfaces/surface_aggregator.cc b/cc/surfaces/surface_aggregator.cc index b6b9fa6..c7a3b8e0 100644 --- a/cc/surfaces/surface_aggregator.cc +++ b/cc/surfaces/surface_aggregator.cc
@@ -24,6 +24,7 @@ #include "cc/quads/solid_color_draw_quad.h" #include "cc/quads/surface_draw_quad.h" #include "cc/quads/texture_draw_quad.h" +#include "cc/resources/resource_provider.h" #include "cc/surfaces/surface.h" #include "cc/surfaces/surface_factory.h" #include "cc/surfaces/surface_manager.h"
diff --git a/cc/test/fake_content_layer_client.cc b/cc/test/fake_content_layer_client.cc index d1b1537a..597eb02 100644 --- a/cc/test/fake_content_layer_client.cc +++ b/cc/test/fake_content_layer_client.cc
@@ -65,25 +65,24 @@ const SkPaint& paint = it->second; canvas = sk_ref_sp(recorder.beginRecording(gfx::RectFToSkRect(draw_rect))); canvas->drawRect(gfx::RectFToSkRect(draw_rect), paint); - display_list->CreateAndAppendItem<DrawingDisplayItem>( + display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>( ToEnclosingRect(draw_rect), recorder.finishRecordingAsPicture()); } for (ImageVector::const_iterator it = draw_images_.begin(); it != draw_images_.end(); ++it) { if (!it->transform.IsIdentity()) { - display_list->CreateAndAppendItem<TransformDisplayItem>(PaintableRegion(), - it->transform); + display_list->CreateAndAppendPairedBeginItem<TransformDisplayItem>( + it->transform); } canvas = sk_ref_sp( recorder.beginRecording(it->image->width(), it->image->height())); canvas->drawImage(it->image.get(), it->point.x(), it->point.y(), &it->paint); - display_list->CreateAndAppendItem<DrawingDisplayItem>( + display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>( PaintableRegion(), recorder.finishRecordingAsPicture()); if (!it->transform.IsIdentity()) { - display_list->CreateAndAppendItem<EndTransformDisplayItem>( - PaintableRegion()); + display_list->CreateAndAppendPairedEndItem<EndTransformDisplayItem>(); } } @@ -95,7 +94,7 @@ paint.setColor(red ? SK_ColorRED : SK_ColorBLUE); canvas = sk_ref_sp(recorder.beginRecording(gfx::RectToSkRect(draw_rect))); canvas->drawIRect(gfx::RectToSkIRect(draw_rect), paint); - display_list->CreateAndAppendItem<DrawingDisplayItem>( + display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>( draw_rect, recorder.finishRecordingAsPicture()); draw_rect.Inset(1, 1); }
diff --git a/cc/test/fake_impl_task_runner_provider.h b/cc/test/fake_impl_task_runner_provider.h index 2a6b8d6..b8968dc5 100644 --- a/cc/test/fake_impl_task_runner_provider.h +++ b/cc/test/fake_impl_task_runner_provider.h
@@ -9,10 +9,6 @@ #include "cc/trees/single_thread_proxy.h" #include "cc/trees/task_runner_provider.h" -namespace base { -class SingleThreadIdleTaskRunner; -} - namespace cc { class FakeImplTaskRunnerProvider : public TaskRunnerProvider {
diff --git a/cc/test/geometry_test_utils.h b/cc/test/geometry_test_utils.h index eee215c..6e015131 100644 --- a/cc/test/geometry_test_utils.h +++ b/cc/test/geometry_test_utils.h
@@ -21,6 +21,15 @@ EXPECT_FLOAT_EQ((expected).height(), (actual).height()); \ } while (false) +#define EXPECT_RECT_EQ(expected, actual) \ + do { \ + const gfx::Rect& actualRect = actual; \ + EXPECT_EQ(expected.x(), actualRect.x()); \ + EXPECT_EQ(expected.y(), actualRect.y()); \ + EXPECT_EQ(expected.width(), actualRect.width()); \ + EXPECT_EQ(expected.height(), actualRect.height()); \ + } while (false) + #define EXPECT_RECT_NEAR(expected, actual, abs_error) \ do { \ EXPECT_NEAR((expected).x(), (actual).x(), (abs_error)); \
diff --git a/cc/test/layer_tree_pixel_test.cc b/cc/test/layer_tree_pixel_test.cc index ae31dba..9ac63625 100644 --- a/cc/test/layer_tree_pixel_test.cc +++ b/cc/test/layer_tree_pixel_test.cc
@@ -189,7 +189,7 @@ content_root_ = content_root; readback_target_ = NULL; ref_file_ = file_name; - RunTest(CompositorMode::THREADED, false); + RunTest(CompositorMode::THREADED); } void LayerTreePixelTest::RunSingleThreadedPixelTest( @@ -200,7 +200,7 @@ content_root_ = content_root; readback_target_ = NULL; ref_file_ = file_name; - RunTest(CompositorMode::SINGLE_THREADED, false); + RunTest(CompositorMode::SINGLE_THREADED); } void LayerTreePixelTest::RunPixelTestWithReadbackTarget( @@ -212,7 +212,7 @@ content_root_ = content_root; readback_target_ = target; ref_file_ = file_name; - RunTest(CompositorMode::THREADED, false); + RunTest(CompositorMode::THREADED); } void LayerTreePixelTest::SetupTree() {
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc index 8947789..86bb2e0 100644 --- a/cc/test/layer_tree_test.cc +++ b/cc/test/layer_tree_test.cc
@@ -787,7 +787,7 @@ layer_tree_host_->SetNextCommitWaitsForActivation(); } -void LayerTreeTest::RunTest(CompositorMode mode, bool delegating_renderer) { +void LayerTreeTest::RunTest(CompositorMode mode) { mode_ = mode; if (mode_ == CompositorMode::THREADED || mode_ == CompositorMode::REMOTE) { impl_thread_.reset(new base::Thread("Compositor")); @@ -798,8 +798,6 @@ gpu_memory_buffer_manager_.reset(new TestGpuMemoryBufferManager); task_graph_runner_.reset(new TestTaskGraphRunner); - delegating_renderer_ = delegating_renderer; - // Spend less time waiting for BeginFrame because the output is // mocked out. settings_.renderer_settings.refresh_rate = 200.0;
diff --git a/cc/test/layer_tree_test.h b/cc/test/layer_tree_test.h index d682495..cba971d 100644 --- a/cc/test/layer_tree_test.h +++ b/cc/test/layer_tree_test.h
@@ -124,7 +124,7 @@ virtual void BeginTest() = 0; virtual void SetupTree(); - virtual void RunTest(CompositorMode mode, bool delegating_renderer); + virtual void RunTest(CompositorMode mode); bool HasImplThread() const { return !!impl_thread_; } base::SingleThreadTaskRunner* ImplThreadTaskRunner() { @@ -145,7 +145,6 @@ LayerTreeHost* layer_tree_host(); LayerTreeHost* remote_client_layer_tree_host(); - bool delegating_renderer() const { return delegating_renderer_; } SharedBitmapManager* shared_bitmap_manager() const { return shared_bitmap_manager_.get(); } @@ -201,7 +200,6 @@ bool scheduled_ = false; bool started_ = false; bool ended_ = false; - bool delegating_renderer_ = false; int timeout_seconds_ = false; @@ -221,34 +219,18 @@ } // namespace cc -#define SINGLE_THREAD_DIRECT_RENDERER_TEST_F(TEST_FIXTURE_NAME) \ - TEST_F(TEST_FIXTURE_NAME, RunSingleThread_DirectRenderer) { \ - RunTest(CompositorMode::SINGLE_THREADED, false); \ - } \ - class SingleThreadDirectImplNeedsSemicolon##TEST_FIXTURE_NAME {} - #define SINGLE_THREAD_TEST_F(TEST_FIXTURE_NAME) \ TEST_F(TEST_FIXTURE_NAME, RunSingleThread_DelegatingRenderer) { \ - RunTest(CompositorMode::SINGLE_THREADED, true); \ + RunTest(CompositorMode::SINGLE_THREADED); \ } \ class SingleThreadDelegatingImplNeedsSemicolon##TEST_FIXTURE_NAME {} -#define MULTI_THREAD_DIRECT_RENDERER_TEST_F(TEST_FIXTURE_NAME) \ - TEST_F(TEST_FIXTURE_NAME, RunMultiThread_DirectRenderer) { \ - RunTest(CompositorMode::THREADED, false); \ - } \ - class MultiThreadDirectImplNeedsSemicolon##TEST_FIXTURE_NAME {} - #define MULTI_THREAD_TEST_F(TEST_FIXTURE_NAME) \ TEST_F(TEST_FIXTURE_NAME, RunMultiThread_DelegatingRenderer) { \ - RunTest(CompositorMode::THREADED, true); \ + RunTest(CompositorMode::THREADED); \ } \ class MultiThreadDelegatingImplNeedsSemicolon##TEST_FIXTURE_NAME {} -#define SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(TEST_FIXTURE_NAME) \ - SINGLE_THREAD_DIRECT_RENDERER_TEST_F(TEST_FIXTURE_NAME); \ - MULTI_THREAD_DIRECT_RENDERER_TEST_F(TEST_FIXTURE_NAME) - #define SINGLE_AND_MULTI_THREAD_TEST_F(TEST_FIXTURE_NAME) \ SINGLE_THREAD_TEST_F(TEST_FIXTURE_NAME); \ MULTI_THREAD_TEST_F(TEST_FIXTURE_NAME)
diff --git a/cc/test/pixel_test.cc b/cc/test/pixel_test.cc index bbfbf6ca..ad08fc8de 100644 --- a/cc/test/pixel_test.cc +++ b/cc/test/pixel_test.cc
@@ -147,7 +147,7 @@ texture_mailbox_deleter_ = base::WrapUnique( new TextureMailboxDeleter(base::ThreadTaskRunnerHandle::Get())); - renderer_ = GLRenderer::Create( + renderer_ = base::MakeUnique<GLRenderer>( this, &settings_.renderer_settings, output_surface_.get(), resource_provider_.get(), texture_mailbox_deleter_.get(), 0); } @@ -187,9 +187,9 @@ main_thread_task_runner_.get(), 0, 1, delegated_sync_points_required, settings_.renderer_settings.use_gpu_memory_buffer_resources, settings_.renderer_settings.buffer_to_texture_target_map); - std::unique_ptr<SoftwareRenderer> renderer = - SoftwareRenderer::Create(this, &settings_.renderer_settings, - output_surface_.get(), resource_provider_.get()); + auto renderer = base::MakeUnique<SoftwareRenderer>( + this, &settings_.renderer_settings, output_surface_.get(), + resource_provider_.get()); software_renderer_ = renderer.get(); renderer_ = std::move(renderer); }
diff --git a/cc/test/pixel_test.h b/cc/test/pixel_test.h index 4f9eb6e..be32c60 100644 --- a/cc/test/pixel_test.h +++ b/cc/test/pixel_test.h
@@ -25,7 +25,7 @@ class TestGpuMemoryBufferManager; class TestSharedBitmapManager; -class PixelTest : public testing::Test, RendererClient { +class PixelTest : public testing::Test, public RendererClient { protected: PixelTest(); ~PixelTest() override;
diff --git a/cc/test/solid_color_content_layer_client.cc b/cc/test/solid_color_content_layer_client.cc index efa63552..f3a8ccd 100644 --- a/cc/test/solid_color_content_layer_client.cc +++ b/cc/test/solid_color_content_layer_client.cc
@@ -54,7 +54,7 @@ scoped_refptr<DisplayItemList> display_list = DisplayItemList::Create(clip, settings); - display_list->CreateAndAppendItem<DrawingDisplayItem>( + display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>( clip, recorder.finishRecordingAsPicture()); display_list->Finalize();
diff --git a/cc/test/test_web_graphics_context_3d.cc b/cc/test/test_web_graphics_context_3d.cc index 4f0e3e61..8f690b73 100644 --- a/cc/test/test_web_graphics_context_3d.cc +++ b/cc/test/test_web_graphics_context_3d.cc
@@ -609,7 +609,7 @@ GLsizei width, GLsizei height, GLenum internalformat) { - DCHECK_EQ(GL_RGBA, static_cast<int>(internalformat)); + DCHECK(internalformat == GL_RGB || internalformat == GL_RGBA); GLuint image_id = NextImageId(); base::AutoLock lock(namespace_->lock); std::unordered_set<unsigned>& images = namespace_->images; @@ -632,7 +632,7 @@ GLsizei height, GLenum internalformat, GLenum usage) { - DCHECK_EQ(GL_RGBA, static_cast<int>(internalformat)); + DCHECK(internalformat == GL_RGB || internalformat == GL_RGBA); GLuint image_id = NextImageId(); base::AutoLock lock(namespace_->lock); std::unordered_set<unsigned>& images = namespace_->images;
diff --git a/cc/test/test_web_graphics_context_3d.h b/cc/test/test_web_graphics_context_3d.h index 1f51040..c3012335 100644 --- a/cc/test/test_web_graphics_context_3d.h +++ b/cc/test/test_web_graphics_context_3d.h
@@ -300,7 +300,7 @@ size_t NumUsedTextures() const { return used_textures_.size(); } bool UsedTexture(int texture) const { - return ContainsKey(used_textures_, texture); + return base::ContainsKey(used_textures_, texture); } void ResetUsedTextures() { used_textures_.clear(); }
diff --git a/cc/tiles/software_image_decode_controller.cc b/cc/tiles/software_image_decode_controller.cc index 4d0ca7e..9dbda12b 100644 --- a/cc/tiles/software_image_decode_controller.cc +++ b/cc/tiles/software_image_decode_controller.cc
@@ -369,7 +369,7 @@ switch (key.filter_quality()) { case kNone_SkFilterQuality: case kLow_SkFilterQuality: - return GetOriginalImageDecode(key, std::move(image)); + return GetOriginalImageDecode(std::move(image)); case kMedium_SkFilterQuality: case kHigh_SkFilterQuality: return GetScaledImageDecode(key, std::move(image)); @@ -490,7 +490,6 @@ std::unique_ptr<SoftwareImageDecodeController::DecodedImage> SoftwareImageDecodeController::GetOriginalImageDecode( - const ImageKey& key, sk_sp<const SkImage> image) { SkImageInfo decoded_info = CreateImageInfo(image->width(), image->height(), format_);
diff --git a/cc/tiles/software_image_decode_controller.h b/cc/tiles/software_image_decode_controller.h index 62a825fd..baf9594 100644 --- a/cc/tiles/software_image_decode_controller.h +++ b/cc/tiles/software_image_decode_controller.h
@@ -230,7 +230,6 @@ // does not scale the image. Like DecodeImageInternal, it should be called // with no lock acquired and it returns nullptr if the decoding failed. std::unique_ptr<DecodedImage> GetOriginalImageDecode( - const ImageKey& key, sk_sp<const SkImage> image); // GetScaledImageDecode is called by DecodeImageInternal when the quality
diff --git a/cc/tiles/tile_manager_unittest.cc b/cc/tiles/tile_manager_unittest.cc index 7c90a6f..3d657d7b 100644 --- a/cc/tiles/tile_manager_unittest.cc +++ b/cc/tiles/tile_manager_unittest.cc
@@ -24,6 +24,7 @@ #include "cc/test/fake_recording_source.h" #include "cc/test/fake_tile_manager.h" #include "cc/test/fake_tile_task_manager.h" +#include "cc/test/layer_tree_settings_for_testing.h" #include "cc/test/test_gpu_memory_buffer_manager.h" #include "cc/test/test_layer_tree_host_base.h" #include "cc/test/test_shared_bitmap_manager.h" @@ -46,10 +47,8 @@ class TileManagerTilePriorityQueueTest : public TestLayerTreeHostBase { public: LayerTreeSettings CreateSettings() override { - LayerTreeSettings settings; + LayerTreeSettingsForTesting settings; settings.create_low_res_tiling = true; - settings.verify_clip_tree_calculations = true; - settings.verify_transform_tree_calculations = true; settings.renderer_settings.buffer_to_texture_target_map = DefaultBufferToTextureTargetMapForTesting(); return settings; @@ -1502,10 +1501,9 @@ task_graph_runner, gpu_memory_buffer_manager)); } - // By default use SoftwareOutputSurface. + // By default use software compositing (no context provider). std::unique_ptr<OutputSurface> CreateOutputSurface() override { - return FakeOutputSurface::CreateSoftware( - base::WrapUnique(new SoftwareOutputDevice)); + return FakeOutputSurface::CreateDelegatingSoftware(); } MockLayerTreeHostImpl& MockHostImpl() {
diff --git a/cc/trees/draw_property_utils.cc b/cc/trees/draw_property_utils.cc index f41e2eff..44b5fa4b 100644 --- a/cc/trees/draw_property_utils.cc +++ b/cc/trees/draw_property_utils.cc
@@ -85,8 +85,7 @@ : effect_tree.Node(effect_node->target_id); } -template <typename LayerType> -bool ComputeClipRectInTargetSpace(const LayerType* layer, +bool ComputeClipRectInTargetSpace(const LayerImpl* layer, const ClipNode* clip_node, const PropertyTrees* property_trees, int target_node_id, @@ -352,16 +351,6 @@ } } -bool GetLayerClipRect(const scoped_refptr<Layer> layer, - const ClipNode* clip_node, - const PropertyTrees* property_trees, - int target_node_id, - gfx::RectF* clip_rect_in_target_space) { - return ComputeClipRectInTargetSpace(layer.get(), clip_node, property_trees, - target_node_id, - clip_rect_in_target_space); -} - bool GetLayerClipRect(const LayerImpl* layer, const ClipNode* clip_node, const PropertyTrees* property_trees, @@ -373,11 +362,9 @@ ->ancestors_are_invertible; } -template <typename LayerType> -void CalculateVisibleRects( - const typename LayerType::LayerListType& visible_layer_list, - const PropertyTrees* property_trees, - bool non_root_surfaces_enabled) { +void CalculateVisibleRects(const LayerImplList& visible_layer_list, + const PropertyTrees* property_trees, + bool non_root_surfaces_enabled) { const EffectTree& effect_tree = property_trees->effect_tree; const TransformTree& transform_tree = property_trees->transform_tree; const ClipTree& clip_tree = property_trees->clip_tree; @@ -565,6 +552,22 @@ return layer->id() == node->owner_id ? tree.parent(node)->id : node->id; } +static bool IsTargetSpaceTransformBackFaceVisible(Layer* layer, + int transform_tree_index, + const TransformTree& tree) { + // We do not skip back face invisible layers on main thread as target space + // transform will not be available here. + return false; +} + +static bool IsTargetSpaceTransformBackFaceVisible(LayerImpl* layer, + int transform_tree_index, + const TransformTree& tree) { + return tree + .ToTarget(transform_tree_index, layer->render_target_effect_tree_index()) + .IsBackFaceVisible(); +} + template <typename LayerType> static bool IsLayerBackFaceVisible(LayerType* layer, int transform_tree_index, @@ -572,9 +575,8 @@ const TransformNode* node = tree.Node(transform_tree_index); return layer->use_local_transform_for_backface_visibility() ? node->local.IsBackFaceVisible() - : tree.ToTarget(transform_tree_index, - layer->render_target_effect_tree_index()) - .IsBackFaceVisible(); + : IsTargetSpaceTransformBackFaceVisible( + layer, transform_tree_index, tree); } static inline bool TransformToScreenIsKnown(Layer* layer, @@ -1101,8 +1103,8 @@ property_trees->effect_tree, visible_layer_list); CalculateClipRects<LayerImpl>(*visible_layer_list, property_trees, can_render_to_separate_surface); - CalculateVisibleRects<LayerImpl>(*visible_layer_list, property_trees, - can_render_to_separate_surface); + CalculateVisibleRects(*visible_layer_list, property_trees, + can_render_to_separate_surface); } void UpdatePropertyTrees(PropertyTrees* property_trees, @@ -1123,13 +1125,6 @@ ComputeClips(property_trees, can_render_to_separate_surface); } -void ComputeVisibleRectsForTesting(PropertyTrees* property_trees, - bool can_render_to_separate_surface, - LayerList* update_layer_list) { - CalculateVisibleRects<Layer>(*update_layer_list, property_trees, - can_render_to_separate_surface); -} - void BuildPropertyTreesAndComputeVisibleRects( LayerImpl* root_layer, const LayerImpl* page_scale_layer,
diff --git a/cc/trees/layer_tree_host_common_perftest.cc b/cc/trees/layer_tree_host_common_perftest.cc index 25a27ad..e53f6e0d 100644 --- a/cc/trees/layer_tree_host_common_perftest.cc +++ b/cc/trees/layer_tree_host_common_perftest.cc
@@ -80,7 +80,7 @@ class CalcDrawPropsTest : public LayerTreeHostCommonPerfTest { public: - void RunCalcDrawProps() { RunTest(CompositorMode::SINGLE_THREADED, false); } + void RunCalcDrawProps() { RunTest(CompositorMode::SINGLE_THREADED); } void BeginTest() override { PostSetNeedsCommitToMainThread(); } @@ -128,7 +128,7 @@ class BspTreePerfTest : public CalcDrawPropsTest { public: BspTreePerfTest() : num_duplicates_(1) {} - void RunSortLayers() { RunTest(CompositorMode::SINGLE_THREADED, false); } + void RunSortLayers() { RunTest(CompositorMode::SINGLE_THREADED); } void SetNumberOfDuplicates(int num_duplicates) { num_duplicates_ = num_duplicates;
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc index 09e196ee..654622b 100644 --- a/cc/trees/layer_tree_host_common_unittest.cc +++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -169,6 +169,8 @@ page_scale_application_layer); } + const LayerList* GetUpdateLayerList() { return &update_layer_list_; } + void ExecuteCalculateDrawPropertiesWithPropertyTrees(Layer* root_layer) { DCHECK(root_layer->layer_tree_host()); PropertyTreeBuilder::PreCalculateMetaInformation(root_layer); @@ -203,8 +205,6 @@ draw_property_utils::FindLayersThatNeedUpdates( root_layer->layer_tree_host(), property_trees->transform_tree, property_trees->effect_tree, &update_layer_list_); - draw_property_utils::ComputeVisibleRectsForTesting( - property_trees, can_render_to_separate_surface, &update_layer_list_); } void ExecuteCalculateDrawPropertiesWithPropertyTrees(LayerImpl* root_layer) { @@ -280,6 +280,12 @@ } const LayerList& update_layer_list() const { return update_layer_list_; } + bool VerifyLayerInList(scoped_refptr<Layer> layer, + const LayerList* layer_list) { + return std::find(layer_list->begin(), layer_list->end(), layer) != + layer_list->end(); + } + private: std::unique_ptr<std::vector<LayerImpl*>> render_surface_layer_list_impl_; LayerList update_layer_list_; @@ -6896,6 +6902,41 @@ scroll_child_impl->ScreenSpaceTransform()); } +TEST_F(LayerTreeHostCommonTest, NonFlatContainerForFixedPosLayer) { + scoped_refptr<Layer> root = Layer::Create(); + scoped_refptr<Layer> container = Layer::Create(); + scoped_refptr<Layer> scroller = Layer::Create(); + scoped_refptr<Layer> fixed_pos = Layer::Create(); + + scroller->SetIsContainerForFixedPositionLayers(true); + root->AddChild(container); + container->AddChild(scroller); + scroller->AddChild(fixed_pos); + host()->SetRootLayer(root); + + LayerPositionConstraint fixed_position; + fixed_position.set_is_fixed_position(true); + scroller->SetScrollClipLayerId(container->id()); + fixed_pos->SetPositionConstraint(fixed_position); + + root->SetBounds(gfx::Size(50, 50)); + container->SetBounds(gfx::Size(50, 50)); + scroller->SetBounds(gfx::Size(50, 50)); + fixed_pos->SetBounds(gfx::Size(50, 50)); + + gfx::Transform rotate; + rotate.RotateAboutXAxis(20); + container->SetTransform(rotate); + + ExecuteCalculateDrawProperties(root.get()); + TransformTree& tree = + root->layer_tree_host()->property_trees()->transform_tree; + gfx::Transform transform; + tree.ComputeTranslation(fixed_pos->transform_tree_index(), + container->transform_tree_index(), &transform); + EXPECT_TRUE(transform.IsIdentity()); +} + TEST_F(LayerTreeHostCommonTest, ScrollSnappingWithFixedPosChild) { // This test verifies that a fixed pos child of a scrolling layer doesn't get // snapped to integer coordinates. @@ -7849,45 +7890,47 @@ } TEST_F(LayerTreeHostCommonTest, VisibleContentRectForAnimatedLayer) { - scoped_refptr<Layer> root = Layer::Create(); - scoped_refptr<LayerWithForcedDrawsContent> animated = - make_scoped_refptr(new LayerWithForcedDrawsContent()); + host_impl()->CreatePendingTree(); + std::unique_ptr<LayerImpl> pending_root = + LayerImpl::Create(host_impl()->pending_tree(), 1); + LayerImpl* root = pending_root.get(); + host_impl()->pending_tree()->SetRootLayerForTesting(std::move(pending_root)); + std::unique_ptr<LayerImpl> animated_ptr = + LayerImpl::Create(host_impl()->pending_tree(), 2); + LayerImpl* animated = animated_ptr.get(); + root->test_properties()->AddChild(std::move(animated_ptr)); - root->AddChild(animated); - host()->SetRootLayer(root); - host()->SetElementIdsForTesting(); + animated->SetDrawsContent(true); + host_impl()->pending_tree()->SetElementIdsForTesting(); root->SetBounds(gfx::Size(100, 100)); root->SetMasksToBounds(true); - root->SetForceRenderSurfaceForTesting(true); - animated->SetOpacity(0.f); + root->test_properties()->force_render_surface = true; + animated->test_properties()->opacity = 0.f; animated->SetBounds(gfx::Size(20, 20)); - AddOpacityTransitionToElementWithPlayer(animated->element_id(), timeline(), - 10.0, 0.f, 1.f, false); - ExecuteCalculateDrawPropertiesWithPropertyTrees(root.get()); + AddOpacityTransitionToElementWithPlayer( + animated->element_id(), timeline_impl(), 10.0, 0.f, 1.f, false); + animated->test_properties()->opacity_can_animate = true; + root->layer_tree_impl()->property_trees()->needs_rebuild = true; + ExecuteCalculateDrawPropertiesWithPropertyTrees(root); - EXPECT_FALSE(animated->visible_layer_rect_for_testing().IsEmpty()); + EXPECT_FALSE(animated->visible_layer_rect().IsEmpty()); } TEST_F(LayerTreeHostCommonTest, VisibleContentRectForAnimatedLayerWithSingularTransform) { - scoped_refptr<Layer> root = Layer::Create(); - scoped_refptr<Layer> clip = Layer::Create(); - scoped_refptr<LayerWithForcedDrawsContent> animated = - make_scoped_refptr(new LayerWithForcedDrawsContent()); - scoped_refptr<LayerWithForcedDrawsContent> surface = - make_scoped_refptr(new LayerWithForcedDrawsContent()); - scoped_refptr<LayerWithForcedDrawsContent> descendant_of_animation = - make_scoped_refptr(new LayerWithForcedDrawsContent()); + LayerImpl* root = root_layer_for_testing(); + LayerImpl* clip = AddChild<LayerImpl>(root); + LayerImpl* animated = AddChild<LayerImpl>(clip); + LayerImpl* surface = AddChild<LayerImpl>(animated); + LayerImpl* descendant_of_animation = AddChild<LayerImpl>(surface); - root->AddChild(clip); - clip->AddChild(animated); - animated->AddChild(surface); - surface->AddChild(descendant_of_animation); + SetElementIdsForTesting(); - host()->SetRootLayer(root); - host()->SetElementIdsForTesting(); + animated->SetDrawsContent(true); + surface->SetDrawsContent(true); + descendant_of_animation->SetDrawsContent(true); gfx::Transform uninvertible_matrix; uninvertible_matrix.Scale3d(6.f, 6.f, 0.f); @@ -7898,44 +7941,41 @@ animated->SetTransform(uninvertible_matrix); animated->SetBounds(gfx::Size(120, 120)); surface->SetBounds(gfx::Size(100, 100)); - surface->SetForceRenderSurfaceForTesting(true); + surface->test_properties()->force_render_surface = true; descendant_of_animation->SetBounds(gfx::Size(200, 200)); TransformOperations start_transform_operations; start_transform_operations.AppendMatrix(uninvertible_matrix); TransformOperations end_transform_operations; - SetElementIdsForTesting(); - AddAnimatedTransformToElementWithPlayer(animated->element_id(), timeline(), - 10.0, start_transform_operations, - end_transform_operations); - ExecuteCalculateDrawPropertiesWithPropertyTrees(root.get()); + AddAnimatedTransformToElementWithPlayer( + animated->element_id(), timeline_impl(), 10.0, start_transform_operations, + end_transform_operations); + ExecuteCalculateDrawPropertiesWithPropertyTrees(root); // The animated layer has a singular transform and maps to a non-empty rect in // clipped target space, so is treated as fully visible. - EXPECT_EQ(gfx::Rect(120, 120), animated->visible_layer_rect_for_testing()); + EXPECT_EQ(gfx::Rect(120, 120), animated->visible_layer_rect()); // The singular transform on |animated| is flattened when inherited by // |surface|, and this happens to make it invertible. - EXPECT_EQ(gfx::Rect(2, 2), surface->visible_layer_rect_for_testing()); - EXPECT_EQ(gfx::Rect(2, 2), - descendant_of_animation->visible_layer_rect_for_testing()); + EXPECT_EQ(gfx::Rect(2, 2), surface->visible_layer_rect()); + EXPECT_EQ(gfx::Rect(2, 2), descendant_of_animation->visible_layer_rect()); gfx::Transform zero_matrix; zero_matrix.Scale3d(0.f, 0.f, 0.f); - animated->SetTransform(zero_matrix); - ExecuteCalculateDrawPropertiesWithPropertyTrees(root.get()); + animated->OnTransformAnimated(zero_matrix); + ExecuteCalculateDrawPropertiesWithPropertyTrees(root); // The animated layer maps to the empty rect in clipped target space, so is // treated as having an empty visible rect. - EXPECT_EQ(gfx::Rect(), animated->visible_layer_rect_for_testing()); + EXPECT_EQ(gfx::Rect(), animated->visible_layer_rect()); // This time, flattening does not make |animated|'s transform invertible. This // means the clip cannot be projected into |surface|'s space, so we treat // |surface| and layers that draw into it as having empty visible rect. - EXPECT_EQ(gfx::Rect(), surface->visible_layer_rect_for_testing()); - EXPECT_EQ(gfx::Rect(), - descendant_of_animation->visible_layer_rect_for_testing()); + EXPECT_EQ(gfx::Rect(), surface->visible_layer_rect()); + EXPECT_EQ(gfx::Rect(), descendant_of_animation->visible_layer_rect()); } // Verify that having animated opacity but current opacity 1 still creates @@ -8287,24 +8327,26 @@ // Check the non-skipped case. ExecuteCalculateDrawPropertiesWithPropertyTrees(root.get()); - EXPECT_EQ(gfx::Rect(10, 10), grandchild->visible_layer_rect_for_testing()); + const LayerList* update_list = GetUpdateLayerList(); + EXPECT_TRUE(VerifyLayerInList(grandchild, update_list)); // Now we will reset the visible rect from property trees for the grandchild, // and we will configure |child| in several ways that should force the subtree // to be skipped. The visible content rect for |grandchild| should, therefore, // remain empty. - grandchild->set_visible_layer_rect(gfx::Rect()); gfx::Transform singular; singular.matrix().set(0, 0, 0); child->SetTransform(singular); ExecuteCalculateDrawPropertiesWithPropertyTrees(root.get()); - EXPECT_EQ(gfx::Rect(0, 0), grandchild->visible_layer_rect_for_testing()); + update_list = GetUpdateLayerList(); + EXPECT_FALSE(VerifyLayerInList(grandchild, update_list)); child->SetTransform(gfx::Transform()); child->SetHideLayerAndSubtree(true); ExecuteCalculateDrawPropertiesWithPropertyTrees(root.get()); - EXPECT_EQ(gfx::Rect(0, 0), grandchild->visible_layer_rect_for_testing()); + update_list = GetUpdateLayerList(); + EXPECT_FALSE(VerifyLayerInList(grandchild, update_list)); child->SetHideLayerAndSubtree(false); gfx::Transform zero_z_scale; @@ -8322,15 +8364,16 @@ AddAnimationToElementWithPlayer(child->element_id(), timeline(), std::move(animation)); ExecuteCalculateDrawPropertiesWithPropertyTrees(root.get()); - EXPECT_EQ(gfx::Rect(10, 10), grandchild->visible_layer_rect_for_testing()); - grandchild->set_visible_layer_rect(gfx::Rect()); + update_list = GetUpdateLayerList(); + EXPECT_TRUE(VerifyLayerInList(grandchild, update_list)); RemoveAnimationFromElementWithExistingPlayer(child->element_id(), timeline(), animation_id); child->SetTransform(gfx::Transform()); child->SetOpacity(0.f); ExecuteCalculateDrawPropertiesWithPropertyTrees(root.get()); - EXPECT_EQ(gfx::Rect(0, 0), grandchild->visible_layer_rect_for_testing()); + update_list = GetUpdateLayerList(); + EXPECT_FALSE(VerifyLayerInList(grandchild, update_list)); // Now, even though child has zero opacity, we will configure |grandchild| and // |greatgrandchild| in several ways that should force the subtree to be @@ -8338,8 +8381,8 @@ grandchild->RequestCopyOfOutput( CopyOutputRequest::CreateBitmapRequest(base::Bind(&CopyOutputCallback))); ExecuteCalculateDrawPropertiesWithPropertyTrees(root.get()); - EXPECT_EQ(gfx::Rect(10, 10), grandchild->visible_layer_rect_for_testing()); - greatgrandchild->set_visible_layer_rect(gfx::Rect()); + update_list = GetUpdateLayerList(); + EXPECT_TRUE(VerifyLayerInList(grandchild, update_list)); // Add an opacity animation with a start delay. animation_id = 1; @@ -8351,7 +8394,8 @@ AddAnimationToElementWithExistingPlayer(child->element_id(), timeline(), std::move(animation)); ExecuteCalculateDrawPropertiesWithPropertyTrees(root.get()); - EXPECT_EQ(gfx::Rect(10, 10), grandchild->visible_layer_rect_for_testing()); + update_list = GetUpdateLayerList(); + EXPECT_TRUE(VerifyLayerInList(grandchild, update_list)); } TEST_F(LayerTreeHostCommonTest, SkippingLayerImpl) {
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 149b7e2..1cd732a 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -53,8 +53,6 @@ #include "cc/output/compositor_frame_metadata.h" #include "cc/output/copy_output_request.h" #include "cc/output/delegating_renderer.h" -#include "cc/output/gl_renderer.h" -#include "cc/output/software_renderer.h" #include "cc/output/texture_mailbox_deleter.h" #include "cc/quads/render_pass_draw_quad.h" #include "cc/quads/shared_quad_state.h" @@ -2108,22 +2106,10 @@ DCHECK(output_surface_); DCHECK(resource_provider_); - if (output_surface_->capabilities().delegated_rendering) { - renderer_ = - DelegatingRenderer::Create(this, &settings_.renderer_settings, - output_surface_, resource_provider_.get()); - } else if (output_surface_->context_provider()) { - renderer_ = GLRenderer::Create( - this, &settings_.renderer_settings, output_surface_, - resource_provider_.get(), texture_mailbox_deleter_.get(), - settings_.renderer_settings.highp_threshold_min); - } else if (output_surface_->software_device()) { - renderer_ = - SoftwareRenderer::Create(this, &settings_.renderer_settings, - output_surface_, resource_provider_.get()); - } - DCHECK(renderer_); - + DCHECK(output_surface_->capabilities().delegated_rendering); + renderer_ = base::MakeUnique<DelegatingRenderer>( + this, &settings_.renderer_settings, output_surface_, + resource_provider_.get()); renderer_->SetVisible(visible_); SetFullRootLayerDamage();
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index 2244c9a3..7ecd6475f 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -10706,22 +10706,12 @@ // A mock output surface which lets us detect calls to ForceReclaimResources. class MockReclaimResourcesOutputSurface : public FakeOutputSurface { public: - static std::unique_ptr<MockReclaimResourcesOutputSurface> Create3d() { - return base::WrapUnique(new MockReclaimResourcesOutputSurface( - TestContextProvider::Create(), TestContextProvider::CreateWorker(), - false)); - } + MockReclaimResourcesOutputSurface() + : FakeOutputSurface(TestContextProvider::Create(), + TestContextProvider::CreateWorker(), + true) {} MOCK_METHOD0(ForceReclaimResources, void()); - - protected: - MockReclaimResourcesOutputSurface( - scoped_refptr<ContextProvider> context_provider, - scoped_refptr<ContextProvider> worker_context_provider, - bool delegated_rendering) - : FakeOutputSurface(context_provider, - worker_context_provider, - delegated_rendering) {} }; // Display::Draw (and the planned Display Scheduler) currently rely on resources @@ -10729,8 +10719,7 @@ // ensures that BeginCommit triggers ForceReclaimResources. See // crbug.com/489515. TEST_F(LayerTreeHostImplTest, BeginCommitReclaimsResources) { - std::unique_ptr<MockReclaimResourcesOutputSurface> output_surface( - MockReclaimResourcesOutputSurface::Create3d()); + auto output_surface = base::MakeUnique<MockReclaimResourcesOutputSurface>(); // Hold an unowned pointer to the output surface to use for mock expectations. MockReclaimResourcesOutputSurface* mock_output_surface = output_surface.get();
diff --git a/cc/trees/layer_tree_host_perftest.cc b/cc/trees/layer_tree_host_perftest.cc index e288f52..7b7a86aa 100644 --- a/cc/trees/layer_tree_host_perftest.cc +++ b/cc/trees/layer_tree_host_perftest.cc
@@ -151,13 +151,13 @@ TEST_F(LayerTreeHostPerfTestJsonReader, TenTenSingleThread) { SetTestName("10_10_single_thread"); ReadTestFile("10_10_layer_tree"); - RunTest(CompositorMode::SINGLE_THREADED, false); + RunTest(CompositorMode::SINGLE_THREADED); } TEST_F(LayerTreeHostPerfTestJsonReader, TenTenThreaded) { SetTestName("10_10_threaded_impl_side"); ReadTestFile("10_10_layer_tree"); - RunTest(CompositorMode::THREADED, false); + RunTest(CompositorMode::THREADED); } // Simulates a tab switcher scene with two stacks of 10 tabs each. @@ -166,14 +166,14 @@ full_damage_each_frame_ = true; SetTestName("10_10_single_thread_full_damage_each_frame"); ReadTestFile("10_10_layer_tree"); - RunTest(CompositorMode::SINGLE_THREADED, false); + RunTest(CompositorMode::SINGLE_THREADED); } TEST_F(LayerTreeHostPerfTestJsonReader, TenTenThreaded_FullDamageEachFrame) { full_damage_each_frame_ = true; SetTestName("10_10_threaded_impl_side_full_damage_each_frame"); ReadTestFile("10_10_layer_tree"); - RunTest(CompositorMode::THREADED, false); + RunTest(CompositorMode::THREADED); } // Invalidates a leaf layer in the tree on the main thread after every commit. @@ -207,13 +207,13 @@ TEST_F(LayerTreeHostPerfTestLeafInvalidates, TenTenSingleThread) { SetTestName("10_10_single_thread_leaf_invalidates"); ReadTestFile("10_10_layer_tree"); - RunTest(CompositorMode::SINGLE_THREADED, false); + RunTest(CompositorMode::SINGLE_THREADED); } TEST_F(LayerTreeHostPerfTestLeafInvalidates, TenTenThreaded) { SetTestName("10_10_threaded_impl_side_leaf_invalidates"); ReadTestFile("10_10_layer_tree"); - RunTest(CompositorMode::THREADED, false); + RunTest(CompositorMode::THREADED); } // Simulates main-thread scrolling on each frame. @@ -244,13 +244,13 @@ TEST_F(ScrollingLayerTreePerfTest, LongScrollablePageSingleThread) { SetTestName("long_scrollable_page"); ReadTestFile("long_scrollable_page"); - RunTest(CompositorMode::SINGLE_THREADED, false); + RunTest(CompositorMode::SINGLE_THREADED); } TEST_F(ScrollingLayerTreePerfTest, LongScrollablePageThreaded) { SetTestName("long_scrollable_page_threaded_impl_side"); ReadTestFile("long_scrollable_page"); - RunTest(CompositorMode::THREADED, false); + RunTest(CompositorMode::THREADED); } // Simulates main-thread scrolling on each frame. @@ -337,7 +337,7 @@ measure_commit_cost_ = true; SetTestName("dense_layer_tree"); ReadTestFile("dense_layer_tree"); - RunTest(CompositorMode::THREADED, false); + RunTest(CompositorMode::THREADED); } // Simulates a page with several large, transformed and animated layers. @@ -346,7 +346,7 @@ measure_commit_cost_ = true; SetTestName("heavy_page"); ReadTestFile("heavy_layer_tree"); - RunTest(CompositorMode::THREADED, false); + RunTest(CompositorMode::THREADED); } } // namespace
diff --git a/cc/trees/layer_tree_host_pixeltest_masks.cc b/cc/trees/layer_tree_host_pixeltest_masks.cc index d991b644..3d63cda3 100644 --- a/cc/trees/layer_tree_host_pixeltest_masks.cc +++ b/cc/trees/layer_tree_host_pixeltest_masks.cc
@@ -61,7 +61,7 @@ scoped_refptr<DisplayItemList> display_list = DisplayItemList::Create(PaintableRegion(), DisplayItemListSettings()); - display_list->CreateAndAppendItem<DrawingDisplayItem>( + display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>( PaintableRegion(), recorder.finishRecordingAsPicture()); display_list->Finalize(); @@ -361,7 +361,7 @@ scoped_refptr<DisplayItemList> display_list = DisplayItemList::Create(PaintableRegion(), DisplayItemListSettings()); - display_list->CreateAndAppendItem<DrawingDisplayItem>( + display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>( PaintableRegion(), recorder.finishRecordingAsPicture()); display_list->Finalize(); @@ -399,7 +399,7 @@ scoped_refptr<DisplayItemList> display_list = DisplayItemList::Create(PaintableRegion(), DisplayItemListSettings()); - display_list->CreateAndAppendItem<DrawingDisplayItem>( + display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>( PaintableRegion(), recorder.finishRecordingAsPicture()); display_list->Finalize();
diff --git a/cc/trees/layer_tree_host_pixeltest_tiles.cc b/cc/trees/layer_tree_host_pixeltest_tiles.cc index a7833dd..b6b1bb4 100644 --- a/cc/trees/layer_tree_host_pixeltest_tiles.cc +++ b/cc/trees/layer_tree_host_pixeltest_tiles.cc
@@ -132,7 +132,7 @@ paint.setColor(SK_ColorYELLOW); canvas->drawRect(gfx::RectToSkRect(yellow_rect), paint); - display_list->CreateAndAppendItem<DrawingDisplayItem>( + display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>( PaintableRegion(), recorder.finishRecordingAsPicture()); display_list->Finalize(); return display_list;
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc index b0e4cfe..1ea85c3 100644 --- a/cc/trees/layer_tree_host_unittest.cc +++ b/cc/trees/layer_tree_host_unittest.cc
@@ -80,9 +80,9 @@ public: LayerTreeHostTestHasImplThreadTest() : threaded_(false) {} - void RunTest(CompositorMode mode, bool delegating_renderer) override { + void RunTest(CompositorMode mode) override { threaded_ = mode == CompositorMode::THREADED; - LayerTreeHostTest::RunTest(mode, delegating_renderer); + LayerTreeHostTest::RunTest(mode); } void BeginTest() override { @@ -5662,12 +5662,12 @@ TEST_F(LayerTreeHostTestSynchronousCompositeSwapPromise, NoReclaim) { reclaim_resources_ = false; - RunTest(CompositorMode::SINGLE_THREADED, true); + RunTest(CompositorMode::SINGLE_THREADED); } TEST_F(LayerTreeHostTestSynchronousCompositeSwapPromise, Reclaim) { reclaim_resources_ = true; - RunTest(CompositorMode::SINGLE_THREADED, true); + RunTest(CompositorMode::SINGLE_THREADED); } // Make sure page scale and top control deltas are applied to the client even
diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc index 23d344fd..feebe2e 100644 --- a/cc/trees/layer_tree_host_unittest_context.cc +++ b/cc/trees/layer_tree_host_unittest_context.cc
@@ -783,27 +783,27 @@ }; TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures, - LoseAfterEvict_SingleThread_DelegatingRenderer) { + LoseAfterEvict_SingleThread) { lose_after_evict_ = true; - RunTest(CompositorMode::SINGLE_THREADED, true); + RunTest(CompositorMode::SINGLE_THREADED); } TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures, - LoseAfterEvict_MultiThread_DelegatingRenderer) { + LoseAfterEvict_MultiThread) { lose_after_evict_ = true; - RunTest(CompositorMode::THREADED, true); + RunTest(CompositorMode::THREADED); } TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures, - LoseBeforeEvict_SingleThread_DelegatingRenderer) { + LoseBeforeEvict_SingleThread) { lose_after_evict_ = false; - RunTest(CompositorMode::SINGLE_THREADED, true); + RunTest(CompositorMode::SINGLE_THREADED); } TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures, - LoseBeforeEvict_MultiThread_DelegatingRenderer) { + LoseBeforeEvict_MultiThread) { lose_after_evict_ = false; - RunTest(CompositorMode::THREADED, true); + RunTest(CompositorMode::THREADED); } class LayerTreeHostContextTestLayersNotified : public LayerTreeHostContextTest {
diff --git a/cc/trees/layer_tree_host_unittest_copyrequest.cc b/cc/trees/layer_tree_host_unittest_copyrequest.cc index 7177580c..f18fa63 100644 --- a/cc/trees/layer_tree_host_unittest_copyrequest.cc +++ b/cc/trees/layer_tree_host_unittest_copyrequest.cc
@@ -153,43 +153,42 @@ scoped_refptr<FakePictureLayer> grand_child; }; -// Readback can't be done with a delegating renderer. TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, GLRenderer_RunSingleThread) { use_gl_renderer_ = true; - RunTest(CompositorMode::SINGLE_THREADED, false); + RunTest(CompositorMode::SINGLE_THREADED); } TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, GLRenderer_RunMultiThread) { use_gl_renderer_ = true; - RunTest(CompositorMode::THREADED, false); + RunTest(CompositorMode::THREADED); } TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, GLRenderer_RunSingleThread_OutOfOrderCallbacks) { use_gl_renderer_ = true; out_of_order_callbacks_ = true; - RunTest(CompositorMode::SINGLE_THREADED, false); + RunTest(CompositorMode::SINGLE_THREADED); } TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, GLRenderer_RunMultiThread_OutOfOrderCallbacks) { use_gl_renderer_ = true; out_of_order_callbacks_ = true; - RunTest(CompositorMode::THREADED, false); + RunTest(CompositorMode::THREADED); } TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, SoftwareRenderer_RunSingleThread) { use_gl_renderer_ = false; - RunTest(CompositorMode::SINGLE_THREADED, false); + RunTest(CompositorMode::SINGLE_THREADED); } TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, SoftwareRenderer_RunMultiThread) { use_gl_renderer_ = false; - RunTest(CompositorMode::THREADED, false); + RunTest(CompositorMode::THREADED); } // TODO(crbug.com/564832): Remove this test when the workaround it tests is no @@ -243,8 +242,7 @@ scoped_refptr<FakePictureLayer> layer_; }; -SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F( - LayerTreeHostCopyRequestCompletionCausesCommit); +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestCompletionCausesCommit); class LayerTreeHostCopyRequestTestLayerDestroyed : public LayerTreeHostCopyRequestTest { @@ -436,8 +434,7 @@ scoped_refptr<FakePictureLayer> copy_layer_; }; -SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F( - LayerTreeHostCopyRequestTestInHiddenSubtree); +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestTestInHiddenSubtree); class LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest : public LayerTreeHostCopyRequestTest { @@ -545,8 +542,7 @@ scoped_refptr<FakePictureLayer> copy_layer_; }; -// No output to copy for delegated renderers. -SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F( +SINGLE_AND_MULTI_THREAD_TEST_F( LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest); class LayerTreeHostCopyRequestTestClippedOut @@ -595,8 +591,7 @@ scoped_refptr<FakePictureLayer> copy_layer_; }; -SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F( - LayerTreeHostCopyRequestTestClippedOut); +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestTestClippedOut); class LayerTreeHostCopyRequestTestScaledLayer : public LayerTreeHostCopyRequestTest { @@ -648,8 +643,7 @@ scoped_refptr<FakePictureLayer> child_layer_; }; -SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F( - LayerTreeHostCopyRequestTestScaledLayer); +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestTestScaledLayer); class LayerTreeHostTestAsyncTwoReadbacksWithoutDraw : public LayerTreeHostCopyRequestTest { @@ -732,8 +726,7 @@ scoped_refptr<FakePictureLayer> copy_layer_; }; -SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F( - LayerTreeHostTestAsyncTwoReadbacksWithoutDraw); +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestAsyncTwoReadbacksWithoutDraw); class LayerTreeHostCopyRequestTestDeleteTexture : public LayerTreeHostCopyRequestTest { @@ -844,8 +837,7 @@ std::unique_ptr<CopyOutputResult> result_; }; -SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F( - LayerTreeHostCopyRequestTestDeleteTexture); +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestTestDeleteTexture); class LayerTreeHostCopyRequestTestCountTextures : public LayerTreeHostCopyRequestTest { @@ -976,8 +968,7 @@ std::unique_ptr<SingleReleaseCallback> release_; }; -SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F( - LayerTreeHostCopyRequestTestCreatesTexture); +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestTestCreatesTexture); class LayerTreeHostCopyRequestTestProvideTexture : public LayerTreeHostCopyRequestTestCountTextures { @@ -1033,8 +1024,7 @@ gpu::SyncToken sync_token_; }; -SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F( - LayerTreeHostCopyRequestTestProvideTexture); +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestTestProvideTexture); class LayerTreeHostCopyRequestTestDestroyBeforeCopy : public LayerTreeHostCopyRequestTest { @@ -1111,8 +1101,7 @@ scoped_refptr<FakePictureLayer> copy_layer_; }; -SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F( - LayerTreeHostCopyRequestTestDestroyBeforeCopy); +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestTestDestroyBeforeCopy); class LayerTreeHostCopyRequestTestShutdownBeforeCopy : public LayerTreeHostCopyRequestTest { @@ -1183,8 +1172,7 @@ scoped_refptr<FakePictureLayer> copy_layer_; }; -SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F( - LayerTreeHostCopyRequestTestShutdownBeforeCopy); +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestTestShutdownBeforeCopy); class LayerTreeHostCopyRequestTestMultipleDrawsHiddenCopyRequest : public LayerTreeHostCopyRequestTest { @@ -1299,7 +1287,7 @@ bool draw_happened_; }; -SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F( +SINGLE_AND_MULTI_THREAD_TEST_F( LayerTreeHostCopyRequestTestMultipleDrawsHiddenCopyRequest); } // namespace
diff --git a/cc/trees/layer_tree_host_unittest_scroll.cc b/cc/trees/layer_tree_host_unittest_scroll.cc index 340c0f2..3c2f289c 100644 --- a/cc/trees/layer_tree_host_unittest_scroll.cc +++ b/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -772,88 +772,43 @@ scoped_refptr<Layer> expected_no_scroll_layer_; }; -TEST_F(LayerTreeHostScrollTestCaseWithChild, - DeviceScaleFactor1_ScrollChild_DirectRenderer) { +TEST_F(LayerTreeHostScrollTestCaseWithChild, DeviceScaleFactor1_ScrollChild) { device_scale_factor_ = 1.f; scroll_child_layer_ = true; - RunTest(CompositorMode::THREADED, false); + RunTest(CompositorMode::THREADED); } -TEST_F(LayerTreeHostScrollTestCaseWithChild, - DeviceScaleFactor1_ScrollChild_DelegatingRenderer) { - device_scale_factor_ = 1.f; - scroll_child_layer_ = true; - RunTest(CompositorMode::THREADED, true); -} - -TEST_F(LayerTreeHostScrollTestCaseWithChild, - DeviceScaleFactor15_ScrollChild_DirectRenderer) { +TEST_F(LayerTreeHostScrollTestCaseWithChild, DeviceScaleFactor15_ScrollChild) { device_scale_factor_ = 1.5f; scroll_child_layer_ = true; - RunTest(CompositorMode::THREADED, false); + RunTest(CompositorMode::THREADED); } -TEST_F(LayerTreeHostScrollTestCaseWithChild, - DeviceScaleFactor15_ScrollChild_DelegatingRenderer) { - device_scale_factor_ = 1.5f; - scroll_child_layer_ = true; - RunTest(CompositorMode::THREADED, true); -} - -TEST_F(LayerTreeHostScrollTestCaseWithChild, - DeviceScaleFactor2_ScrollChild_DirectRenderer) { +TEST_F(LayerTreeHostScrollTestCaseWithChild, DeviceScaleFactor2_ScrollChild) { device_scale_factor_ = 2.f; scroll_child_layer_ = true; - RunTest(CompositorMode::THREADED, false); + RunTest(CompositorMode::THREADED); } TEST_F(LayerTreeHostScrollTestCaseWithChild, - DeviceScaleFactor2_ScrollChild_DelegatingRenderer) { - device_scale_factor_ = 2.f; - scroll_child_layer_ = true; - RunTest(CompositorMode::THREADED, true); -} - -TEST_F(LayerTreeHostScrollTestCaseWithChild, - DeviceScaleFactor1_ScrollRootScrollLayer_DirectRenderer) { + DeviceScaleFactor1_ScrollRootScrollLayer) { device_scale_factor_ = 1.f; scroll_child_layer_ = false; - RunTest(CompositorMode::THREADED, false); + RunTest(CompositorMode::THREADED); } TEST_F(LayerTreeHostScrollTestCaseWithChild, - DeviceScaleFactor1_ScrollRootScrollLayer_DelegatingRenderer) { - device_scale_factor_ = 1.f; - scroll_child_layer_ = false; - RunTest(CompositorMode::THREADED, true); -} - -TEST_F(LayerTreeHostScrollTestCaseWithChild, - DeviceScaleFactor15_ScrollRootScrollLayer_DirectRenderer) { + DeviceScaleFactor15_ScrollRootScrollLayer) { device_scale_factor_ = 1.5f; scroll_child_layer_ = false; - RunTest(CompositorMode::THREADED, false); + RunTest(CompositorMode::THREADED); } TEST_F(LayerTreeHostScrollTestCaseWithChild, - DeviceScaleFactor15_ScrollRootScrollLayer_DelegatingRenderer) { - device_scale_factor_ = 1.5f; - scroll_child_layer_ = false; - RunTest(CompositorMode::THREADED, true); -} - -TEST_F(LayerTreeHostScrollTestCaseWithChild, - DeviceScaleFactor2_ScrollRootScrollLayer_DirectRenderer) { + DeviceScaleFactor2_ScrollRootScrollLayer) { device_scale_factor_ = 2.f; scroll_child_layer_ = false; - RunTest(CompositorMode::THREADED, false); -} - -TEST_F(LayerTreeHostScrollTestCaseWithChild, - DeviceScaleFactor2_ScrollRootScrollLayer_DelegatingRenderer) { - device_scale_factor_ = 2.f; - scroll_child_layer_ = false; - RunTest(CompositorMode::THREADED, true); + RunTest(CompositorMode::THREADED); } class LayerTreeHostScrollTestSimple : public LayerTreeHostScrollTest { @@ -1497,12 +1452,12 @@ }; TEST_F(LayerTreeHostScrollTestLayerStructureChange, ScrollDestroyLayer) { - RunTest(CompositorMode::THREADED, false); + RunTest(CompositorMode::THREADED); } TEST_F(LayerTreeHostScrollTestLayerStructureChange, ScrollDestroyWholeTree) { scroll_destroy_whole_tree_ = true; - RunTest(CompositorMode::THREADED, false); + RunTest(CompositorMode::THREADED); } class LayerTreeHostScrollTestScrollMFBA : public LayerTreeHostScrollTest {
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc index b2af225d..0d1adb0 100644 --- a/cc/trees/property_tree.cc +++ b/cc/trees/property_tree.cc
@@ -161,10 +161,44 @@ bool TransformTree::ComputeTranslation(int source_id, int dest_id, gfx::Transform* transform) const { - bool success = ComputeTransform(source_id, dest_id, transform); + transform->MakeIdentity(); + if (source_id == dest_id) + return true; + + const TransformNode* dest = Node(dest_id); + if (!dest->ancestors_are_invertible) + return false; + if (source_id != kInvalidNodeId) + transform->ConcatTransform(ToScreen(source_id)); + if (dest_id != kInvalidNodeId) { + if (dest->local.IsFlat() && (dest->node_and_ancestors_are_flat || + dest->flattens_inherited_transform)) { + // In this case, flattenning will not affect the result, so we can use the + // FromScreen transform of the dest node. + transform->ConcatTransform(FromScreen(dest_id)); + } else { + // In this case, some node between source and destination flattens + // inherited transform. Consider the tree R->A->B->C->D, where D is the + // source, A is the destination and C flattens inherited transform. The + // expected result is D * C * flattened(B). D's ToScreen will be D * C * + // flattened(B * A * R), but as the source to destination transform is + // at most translation, C and B cannot be non-flat and so flattened(B * A + // * R) = B * flattened(A * R). So, to get the expected result we have to + // multiply D's ToScreen transform with flattened(A * R)^{-1}, which is + // the inverse of flattened ToScreen of destination. + gfx::Transform to_screen = ToScreen(dest_id); + to_screen.FlattenTo2d(); + gfx::Transform from_screen; + bool success = to_screen.GetInverse(&from_screen); + if (!success) + return false; + transform->ConcatTransform(from_screen); + } + } + DCHECK( transform->IsApproximatelyIdentityOrTranslation(SkDoubleToMScalar(1e-4))); - return success; + return true; } bool TransformTree::NeedsSourceToParentUpdate(TransformNode* node) {
diff --git a/cc/trees/property_tree.h b/cc/trees/property_tree.h index 9bf1ed44..cace597 100644 --- a/cc/trees/property_tree.h +++ b/cc/trees/property_tree.h
@@ -157,7 +157,9 @@ // Computes the change of basis transform from node |source_id| to |dest_id|. // This is used by scroll children to compute transform from their scroll // parent space (source) to their parent space (destination) and it can atmost - // be a translation. + // be a translation. This function assumes that the path from source to + // destination has only translations. So, it should not be called when there + // can be intermediate 3d transforms but the end result is a translation. bool ComputeTranslation(int source_id, int dest_id, gfx::Transform* transform) const;
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn index b56bbb8..e894e2a 100644 --- a/chrome/BUILD.gn +++ b/chrome/BUILD.gn
@@ -314,7 +314,7 @@ "//build/config/sanitizers:deps", "//chrome/app:command_ids", "//chrome/common:features", - "//third_party/cld_2", + "//third_party/cld", ] if (is_win) { output_name = "chrome" @@ -970,7 +970,7 @@ "//components/crash/content/app", "//components/policy", "//content/public/app:both", - "//third_party/cld_2", + "//third_party/cld", ] if (is_component_build) { @@ -1409,6 +1409,10 @@ "//ui/resources", ] + if (is_android) { + sources += [ "$root_gen_dir/android_webview/aw_resources.pak" ] + deps += [ "//android_webview:generate_aw_resources" ] + } if (!is_ios && !is_android) { # New paks should be added here by default. sources += [
diff --git a/chrome/VERSION b/chrome/VERSION index 9980cb68..fa8b377 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=54 MINOR=0 -BUILD=2825 +BUILD=2826 PATCH=0
diff --git a/chrome/android/java/proguard.flags b/chrome/android/java/proguard.flags index cf546d1..c6c45d17 100644 --- a/chrome/android/java/proguard.flags +++ b/chrome/android/java/proguard.flags
@@ -25,7 +25,7 @@ } # Keep all Parcelables as they might be marshalled outside Chrome. --keepnames class * implements android.os.Parcelable { +-keepclassmembernames class * implements android.os.Parcelable { public static final ** CREATOR; }
diff --git a/chrome/android/java/res/drawable-hdpi/infobar_screen_share.png b/chrome/android/java/res/drawable-hdpi/infobar_screen_share.png new file mode 100644 index 0000000..353bd69 --- /dev/null +++ b/chrome/android/java/res/drawable-hdpi/infobar_screen_share.png Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/infobar_screen_share.png b/chrome/android/java/res/drawable-mdpi/infobar_screen_share.png new file mode 100644 index 0000000..6854b81 --- /dev/null +++ b/chrome/android/java/res/drawable-mdpi/infobar_screen_share.png Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/shortcut_newtab.png b/chrome/android/java/res/drawable-mdpi/shortcut_newtab.png index b918691..773ffb3 100644 --- a/chrome/android/java/res/drawable-mdpi/shortcut_newtab.png +++ b/chrome/android/java/res/drawable-mdpi/shortcut_newtab.png Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/infobar_screen_share.png b/chrome/android/java/res/drawable-xhdpi/infobar_screen_share.png new file mode 100644 index 0000000..532394f --- /dev/null +++ b/chrome/android/java/res/drawable-xhdpi/infobar_screen_share.png Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/infobar_screen_share.png b/chrome/android/java/res/drawable-xxhdpi/infobar_screen_share.png new file mode 100644 index 0000000..aa88c7f92a --- /dev/null +++ b/chrome/android/java/res/drawable-xxhdpi/infobar_screen_share.png Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/infobar_screen_share.png b/chrome/android/java/res/drawable-xxxhdpi/infobar_screen_share.png new file mode 100644 index 0000000..c8959196 --- /dev/null +++ b/chrome/android/java/res/drawable-xxxhdpi/infobar_screen_share.png Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/shortcut_newtab.png b/chrome/android/java/res/drawable-xxxhdpi/shortcut_newtab.png index e4890fb..e9b181eb 100644 --- a/chrome/android/java/res/drawable-xxxhdpi/shortcut_newtab.png +++ b/chrome/android/java/res/drawable-xxxhdpi/shortcut_newtab.png Binary files differ
diff --git a/chrome/android/java/res/layout/new_tab_page_action_card.xml b/chrome/android/java/res/layout/new_tab_page_action_card.xml new file mode 100644 index 0000000..8c2d1b41 --- /dev/null +++ b/chrome/android/java/res/layout/new_tab_page_action_card.xml
@@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. --> + +<!-- The Layout takes the regular NTP Card attributes (padding, background + drawable) and adds the selectable ripple effects as foreground. The + foreground property requires to use a FrameLayout. --> +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:chrome="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:foreground="?attr/selectableItemBackgroundBorderless" + android:clickable="true" + android:padding="@dimen/snippets_padding_and_peeking_card_height" + android:background="@drawable/ntp_card"> + + <!-- We don't use a button here since the effect and the click handler will + be done at the parent level, directly on the layout. We transferred + select styling properties from ButtonCompatBorderless and made it + unfocusable.--> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:clickable="false" + android:focusable="false" + android:gravity="center_vertical|center_horizontal" + android:minHeight="36dp" + android:paddingStart="8dp" + android:text="@string/more" + android:textAllCaps="true" + android:textColor="@color/light_active_color" + android:textSize="15sp" + android:textStyle="bold" /> + +</FrameLayout>
diff --git a/chrome/android/java/res/layout/new_tab_page_snippets_header.xml b/chrome/android/java/res/layout/new_tab_page_snippets_header.xml index f13a91d9..34d7d15 100644 --- a/chrome/android/java/res/layout/new_tab_page_snippets_header.xml +++ b/chrome/android/java/res/layout/new_tab_page_snippets_header.xml
@@ -5,10 +5,9 @@ <TextView xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/snippets_list_header" + android:id="@+id/suggestions_section_header" android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="@string/snippets_header" android:textColor="@color/snippets_list_header_text_color" android:textSize="12sp" android:paddingStart="@dimen/snippets_padding_and_peeking_card_height"
diff --git a/chrome/android/java/res/layout/password_entry_editor.xml b/chrome/android/java/res/layout/password_entry_editor.xml index 0957ea22..544b8bb 100644 --- a/chrome/android/java/res/layout/password_entry_editor.xml +++ b/chrome/android/java/res/layout/password_entry_editor.xml
@@ -55,6 +55,15 @@ android:dividerPadding="0dp" android:orientation="horizontal" android:showDividers="middle"> + + <Button + android:id="@+id/password_entry_editor_cancel" + style="?android:attr/buttonBarButtonStyle" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_weight="1" + android:focusable="true" + android:text="@string/cancel" /> <Button android:id="@+id/password_entry_editor_delete" @@ -64,15 +73,6 @@ android:layout_weight="1" android:focusable="true" android:text="@string/delete" /> - - <Button - android:id="@+id/password_entry_editor_cancel" - style="?android:attr/buttonBarButtonStyle" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_weight="1" - android:focusable="true" - android:text="@string/cancel" /> </LinearLayout> </LinearLayout>
diff --git a/chrome/android/java/res/layout/password_entry_editor_interactive.xml b/chrome/android/java/res/layout/password_entry_editor_interactive.xml index 3e43d50..7a999b1 100644 --- a/chrome/android/java/res/layout/password_entry_editor_interactive.xml +++ b/chrome/android/java/res/layout/password_entry_editor_interactive.xml
@@ -78,8 +78,7 @@ android:layout_height="wrap_content" android:layout_marginTop="10dp" android:layout_marginStart="15dp" - android:textAppearance="?android:attr/textAppearanceMedium" - android:contentDescription="@string/password_entry_editor_copy_stored_username" /> + android:textAppearance="?android:attr/textAppearanceMedium" /> <View android:layout_width="0dp" @@ -93,7 +92,8 @@ android:layout_gravity="end" android:layout_marginTop="10dp" android:layout_marginEnd="15dp" - android:src="@drawable/ic_content_copy" /> + android:src="@drawable/ic_content_copy" + android:contentDescription="@string/password_entry_editor_copy_stored_username" /> </LinearLayout>
diff --git a/chrome/android/java/res/values/values.xml b/chrome/android/java/res/values/values.xml index 93f447a..eabd0645 100644 --- a/chrome/android/java/res/values/values.xml +++ b/chrome/android/java/res/values/values.xml
@@ -3,7 +3,10 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<resources xmlns:android="http://schemas.android.com/apk/res/android"> +<resources + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + tools:ignore="MissingTranslation"> <!-- Font to use when a spec asks for "Roboto Medium". Bolding the text makes it look almost, but not quite, entirely unlike Roboto Medium,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/BluetoothChooserDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/BluetoothChooserDialog.java index 0076fe3..c3bece9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/BluetoothChooserDialog.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/BluetoothChooserDialog.java
@@ -337,8 +337,8 @@ @VisibleForTesting @CalledByNative - void addDevice(String deviceId, String deviceName) { - mItemChooserDialog.addItemToList( + void addOrUpdateDevice(String deviceId, String deviceName) { + mItemChooserDialog.addOrUpdateItem( new ItemChooserDialog.ItemChooserRow(deviceId, deviceName)); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java index e640dec..d7f294f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
@@ -92,7 +92,6 @@ import org.chromium.chrome.browser.tabmodel.document.StorageDelegate; import org.chromium.chrome.browser.tabmodel.document.TabDelegate; import org.chromium.chrome.browser.util.FeatureUtilities; -import org.chromium.chrome.browser.webapps.WebApkInstaller; import org.chromium.components.sync.signin.AccountManagerDelegate; import org.chromium.components.sync.signin.AccountManagerHelper; import org.chromium.components.sync.signin.SystemAccountManagerDelegate; @@ -366,13 +365,6 @@ } /** - * Returns factory for installing WebAPKs. - */ - public WebApkInstaller createWebApkInstaller() { - return null; - } - - /** * Return a {@link AuthenticatorNavigationInterceptor} for the given {@link Tab}. * This can be null if there are no applicable interceptor to be built. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java index d424738..518007b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java
@@ -86,9 +86,6 @@ */ public static final String MARKET_URL_FOR_TESTING = "market-url-for-testing"; - /** Enables the download manager UI. */ - public static final String ENABLE_DOWNLOAD_MANAGER_UI = "enable-download-manager-ui"; - /////////////////////////////////////////////////////////////////////////////////////////////// // Native Switches ///////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java index 19f5186b..dfa55625 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser; +import android.annotation.TargetApi; import android.app.Activity; import android.app.ActivityManager; import android.content.Context; @@ -58,7 +59,7 @@ import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider; import org.chromium.chrome.browser.device.DeviceClassManager; import org.chromium.chrome.browser.document.ChromeLauncherActivity; -import org.chromium.chrome.browser.download.DownloadActivity; +import org.chromium.chrome.browser.download.DownloadUtils; import org.chromium.chrome.browser.firstrun.FirstRunActivity; import org.chromium.chrome.browser.firstrun.FirstRunFlowSequencer; import org.chromium.chrome.browser.firstrun.FirstRunSignInProcessor; @@ -1098,11 +1099,7 @@ getToolbarManager().setUrlBarFocus(true); } } else if (id == R.id.downloads_menu_id) { - if (isTablet()) { - currentTab.loadUrl(new LoadUrlParams(UrlConstants.DOWNLOADS_URL)); - } else { - DownloadActivity.launch(this); - } + DownloadUtils.showDownloadManager(this, currentTab); } else if (id == R.id.open_recently_closed_tab) { TabModel currentModel = mTabModelSelectorImpl.getCurrentModel(); if (!currentModel.isIncognito()) currentModel.openMostRecentlyClosedTab(); @@ -1509,6 +1506,7 @@ * Merges tabs from a second ChromeTabbedActivity instance if necesssary and calls * finishAndRemoveTask() on the other activity. */ + @TargetApi(Build.VERSION_CODES.M) @VisibleForTesting public void maybeMergeTabs() { if (!FeatureUtilities.isTabModelMergingEnabled()) return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ItemChooserDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/ItemChooserDialog.java index 934bb24..1596fb5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ItemChooserDialog.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ItemChooserDialog.java
@@ -64,7 +64,7 @@ */ public static class ItemChooserRow { private final String mKey; - private final String mDescription; + private String mDescription; public ItemChooserRow(String key, String description) { mKey = key; @@ -148,6 +148,9 @@ // Item descriptions are counted in a map. private Map<String, Integer> mItemDescriptionMap = new HashMap<>(); + // Map of keys to items so that we can access the items in O(1). + private Map<String, ItemChooserRow> mKeyToItemMap = new HashMap<>(); + public ItemAdapter(Context context, int resource) { super(context, resource); @@ -159,17 +162,25 @@ R.color.default_text_color); } - @Override - public void add(ItemChooserRow item) { + public void addOrUpdate(ItemChooserRow item) { + if (mKeyToItemMap.containsKey(item.mKey)) { + // TODO(ortuno): Update description. + // https://crbug.com/634366 + return; + } + ItemChooserRow result = mKeyToItemMap.put(item.mKey, item); + assert result == null; + String description = item.mDescription; int count = mItemDescriptionMap.containsKey(description) ? mItemDescriptionMap.get(description) : 0; mItemDescriptionMap.put(description, count + 1); - super.add(item); + add(item); } @Override public void remove(ItemChooserRow item) { + mKeyToItemMap.remove(item.mKey); String description = item.mDescription; if (mItemDescriptionMap.containsKey(description)) { int count = mItemDescriptionMap.get(description); @@ -185,6 +196,7 @@ @Override public void clear() { mSelectedItem = ListView.INVALID_POSITION; + mKeyToItemMap.clear(); mDisabledEntries.clear(); mItemDescriptionMap.clear(); mConfirmButton.setEnabled(false); @@ -414,13 +426,14 @@ } /** - * Add an item to the end of the list to show in the dialog. + * Add an item to the end of the list to show in the dialog if the item + * was not in the chooser. Otherwise update the items description. * - * @param item The item to be added to the end of the chooser. + * @param item The item to be added to the end of the chooser or updated. */ - public void addItemToList(ItemChooserRow item) { + public void addOrUpdateItem(ItemChooserRow item) { mProgressBar.setVisibility(View.GONE); - mItemAdapter.add(item); + mItemAdapter.addOrUpdate(item); setState(State.PROGRESS_UPDATE_AVAILABLE); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/UsbChooserDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/UsbChooserDialog.java index 9aafe06..08b7dc1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/UsbChooserDialog.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/UsbChooserDialog.java
@@ -125,7 +125,7 @@ @VisibleForTesting @CalledByNative void addDevice(String deviceId, String deviceName) { - mItemChooserDialog.addItemToList( + mItemChooserDialog.addOrUpdateItem( new ItemChooserDialog.ItemChooserRow(deviceId, deviceName)); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java index 0516138..6eee512 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java
@@ -8,10 +8,9 @@ import android.view.Menu; import android.view.MenuItem; -import org.chromium.base.CommandLine; import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeActivity; -import org.chromium.chrome.browser.ChromeSwitches; +import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.ShortcutHelper; import org.chromium.chrome.browser.UrlConstants; import org.chromium.chrome.browser.bookmarks.BookmarkBridge; @@ -107,8 +106,8 @@ updateBookmarkMenuItem(bookmarkMenuItem, currentTab); } - menu.findItem(R.id.downloads_menu_id).setVisible( - CommandLine.getInstance().hasSwitch(ChromeSwitches.ENABLE_DOWNLOAD_MANAGER_UI)); + menu.findItem(R.id.downloads_menu_id) + .setVisible(ChromeFeatureList.isEnabled("DownloadsUi")); menu.findItem(R.id.update_menu_id).setVisible( UpdateMenuItemHelper.getInstance().shouldShowMenuItem(mActivity));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/banners/AppBannerManager.java b/chrome/android/java/src/org/chromium/chrome/browser/banners/AppBannerManager.java index b3e0dea..bfee3ab 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/banners/AppBannerManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/banners/AppBannerManager.java
@@ -152,10 +152,10 @@ nativeSetEngagementWeights(directEngagement, indirectEngagement); } - /** Returns whether an AppBannerDataFetcher is actively retrieving data. */ + /** Returns whether the native AppBannerManager is working. */ @VisibleForTesting - public boolean isFetcherActiveForTesting() { - return nativeIsFetcherActive(mNativePointer); + public boolean isActiveForTesting() { + return nativeIsActiveForTesting(mNativePointer); } /** Returns the AppBannerManager object. This is owned by the C++ banner manager. */ @@ -173,5 +173,5 @@ private static native void nativeDisableSecureSchemeCheckForTesting(); private static native void nativeSetEngagementWeights(double directEngagement, double indirectEngagement); - private native boolean nativeIsFetcherActive(long nativeAppBannerManagerAndroid); + private native boolean nativeIsActiveForTesting(long nativeAppBannerManagerAndroid); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkRow.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkRow.java index 933eab7..b47afcc 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkRow.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkRow.java
@@ -56,7 +56,7 @@ mMoreIcon.setVisibility(bookmarkItem.isEditable() ? VISIBLE : GONE); setChecked(mDelegate.getSelectionDelegate().isItemSelected(bookmarkId)); } - super.setId(bookmarkId); + super.setItem(bookmarkId); return bookmarkItem; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java index 5cbab7e..283c814 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
@@ -433,8 +433,8 @@ mTranslateController.cacheNativeTranslateData(); } else { boolean shouldPrefetch = mPolicy.shouldPrefetchSearchResult(); - mSearchRequest = createContextualSearchRequest(mSelectionController.getSelectedText(), - null, shouldPrefetch); + mSearchRequest = createContextualSearchRequest( + mSelectionController.getSelectedText(), null, null, shouldPrefetch); mTranslateController.forceAutoDetectTranslateUnlessDisabled(mSearchRequest); mDidStartLoadingResolvedSearchRequest = false; mSearchPanel.setSearchTerm(mSelectionController.getSelectedText()); @@ -531,9 +531,9 @@ * @param altTerm An alternate search term. * @param isLowPriorityEnabled Whether the request can be made at low priority. */ - protected ContextualSearchRequest createContextualSearchRequest(String term, String altTerm, - boolean isLowPriorityEnabled) { - return new ContextualSearchRequest(term, altTerm, isLowPriorityEnabled); + protected ContextualSearchRequest createContextualSearchRequest( + String term, String altTerm, String mid, boolean isLowPriorityEnabled) { + return new ContextualSearchRequest(term, altTerm, mid, isLowPriorityEnabled); } /** @@ -646,6 +646,8 @@ * @param searchTerm The term to use in our subsequent search. * @param displayText The text to display in our UX. * @param alternateTerm The alternate term to display on the results page. + * @param mid the MID for an entity to use to trigger a Knowledge Panel, or an empty string. + * A MID is a unique identifier for an entity in the Search Knowledge Graph. * @param selectionStartAdjust A positive number of characters that the start of the existing * selection should be expanded by. * @param selectionEndAdjust A positive number of characters that the end of the existing @@ -655,18 +657,18 @@ @CalledByNative public void onSearchTermResolutionResponse(boolean isNetworkUnavailable, int responseCode, final String searchTerm, final String displayText, final String alternateTerm, - boolean doPreventPreload, int selectionStartAdjust, int selectionEndAdjust, - final String contextLanguage) { + final String mid, boolean doPreventPreload, int selectionStartAdjust, + int selectionEndAdjust, final String contextLanguage) { mNetworkCommunicator.handleSearchTermResolutionResponse(isNetworkUnavailable, responseCode, - searchTerm, displayText, alternateTerm, doPreventPreload, selectionStartAdjust, + searchTerm, displayText, alternateTerm, mid, doPreventPreload, selectionStartAdjust, selectionEndAdjust, contextLanguage); } @Override public void handleSearchTermResolutionResponse(boolean isNetworkUnavailable, int responseCode, - String searchTerm, String displayText, String alternateTerm, boolean doPreventPreload, - int selectionStartAdjust, int selectionEndAdjust, String contextLanguage) { - + String searchTerm, String displayText, String alternateTerm, String mid, + boolean doPreventPreload, int selectionStartAdjust, int selectionEndAdjust, + String contextLanguage) { // Show an appropriate message for what to search for. String message; boolean doLiteralSearch = false; @@ -697,8 +699,8 @@ // TODO(donnd): Instead of preloading, we should prefetch (ie the URL should not // appear in the user's history until the user views it). See crbug.com/406446. boolean shouldPreload = !doPreventPreload && mPolicy.shouldPrefetchSearchResult(); - mSearchRequest = createContextualSearchRequest(searchTerm, alternateTerm, - shouldPreload); + mSearchRequest = + createContextualSearchRequest(searchTerm, alternateTerm, mid, shouldPreload); // Trigger translation, if enabled. mTranslateController.forceTranslateIfNeeded(mSearchRequest, contextLanguage); mDidStartLoadingResolvedSearchRequest = false; @@ -915,7 +917,7 @@ // is in progress or we should do a verbatim search now. if (mSearchRequest == null && mPolicy.shouldCreateVerbatimRequest()) { mSearchRequest = createContextualSearchRequest( - mSelectionController.getSelectedText(), null, false); + mSelectionController.getSelectedText(), null, null, false); mDidStartLoadingResolvedSearchRequest = false; } if (mSearchRequest != null && (!mDidStartLoadingResolvedSearchRequest @@ -1161,7 +1163,7 @@ @Override public void onSelectionChanged(String selection) { - if (!mActivity.getFullscreenManager().isOverlayVideoMode()) { + if (!isOverlayVideoMode()) { mSelectionController.handleSelectionChanged(selection); mSearchPanel.updateTopControlsState(TopControlsState.BOTH, true); } @@ -1169,7 +1171,7 @@ @Override public void onSelectionEvent(int eventType, float posXPix, float posYPix) { - if (!mActivity.getFullscreenManager().isOverlayVideoMode()) { + if (!isOverlayVideoMode()) { mSelectionController.handleSelectionEvent(eventType, posXPix, posYPix); } } @@ -1177,11 +1179,16 @@ @Override public void showUnhandledTapUIIfNeeded(final int x, final int y) { mDidBasePageLoadJustStart = false; - if (!mActivity.getFullscreenManager().isOverlayVideoMode()) { + if (!isOverlayVideoMode()) { mSelectionController.handleShowUnhandledTapUIIfNeeded(x, y); } } + private boolean isOverlayVideoMode() { + return mActivity.getFullscreenManager() != null + && mActivity.getFullscreenManager().isOverlayVideoMode(); + } + // ============================================================================================ // Selection // ============================================================================================
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchNetworkCommunicator.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchNetworkCommunicator.java index 2ccbc6b..dd26d71 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchNetworkCommunicator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchNetworkCommunicator.java
@@ -28,6 +28,8 @@ * @param searchTerm the term to search for. * @param displayText the text to display that describes the search term. * @param alternateTerm the alternate search term. + * @param mid the MID for an entity to use to trigger a Knowledge Panel, or an empty string. + * A MID is a unique identifier for an entity in the Search Knowledge Graph. * @param doPreventPreload whether to prevent preloading the search result. * @param selectionStartAdjust The start offset adjustment of the selection to use to highlight * the search term. @@ -36,8 +38,9 @@ * @param contextLanguage The language of the context, or the empty string if unknown. */ void handleSearchTermResolutionResponse(boolean isNetworkUnavailable, int responseCode, - String searchTerm, String displayText, String alternateTerm, boolean doPreventPreload, - int selectionStartAdjust, int selectionEndAdjust, String contextLanguage); + String searchTerm, String displayText, String alternateTerm, String mid, + boolean doPreventPreload, int selectionStartAdjust, int selectionEndAdjust, + String contextLanguage); // -------------------------------------------------------------------------------------------- // These are non-network actions that need to be stubbed out for testing.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequest.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequest.java index 4ec980ef..64d1eea 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequest.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequest.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser.contextualsearch; import android.net.Uri; +import android.text.TextUtils; import org.chromium.base.VisibleForTesting; import org.chromium.chrome.browser.search_engines.TemplateUrlService; @@ -42,6 +43,7 @@ @VisibleForTesting static final String TLITE_SOURCE_LANGUAGE_PARAM = "tlitesl"; private static final String TLITE_TARGET_LANGUAGE_PARAM = "tlitetl"; private static final String TLITE_QUERY_PARAM = "tlitetxt"; + private static final String KP_TRIGGERING_MID_PARAM = "kgmid"; /** * Creates a search request for the given search term without any alternate term and @@ -49,7 +51,7 @@ * @param searchTerm The resolved search term. */ ContextualSearchRequest(String searchTerm) { - this(searchTerm, null, false); + this(searchTerm, null, null, false); } /** @@ -57,15 +59,17 @@ * low-priority loading capability. * @param searchTerm The resolved search term. * @param alternateTerm The alternate search term. + * @param mid The MID for an entity to use to trigger a Knowledge Panel, or an empty string. + * A MID is a unique identifier for an entity in the Search Knowledge Graph. * @param isLowPriorityEnabled Whether the request can be made at a low priority. */ - ContextualSearchRequest(String searchTerm, @Nullable String alternateTerm, + ContextualSearchRequest(String searchTerm, @Nullable String alternateTerm, @Nullable String mid, boolean isLowPriorityEnabled) { mWasPrefetch = isLowPriorityEnabled; - mNormalPriorityUri = getUriTemplate(searchTerm, alternateTerm, false); + mNormalPriorityUri = getUriTemplate(searchTerm, alternateTerm, mid, false); if (isLowPriorityEnabled) { // TODO(donnd): Call TemplateURL once we have an API for 3rd-party providers. - Uri baseLowPriorityUri = getUriTemplate(searchTerm, alternateTerm, true); + Uri baseLowPriorityUri = getUriTemplate(searchTerm, alternateTerm, mid, true); mLowPriorityUri = makeLowPriorityUri(baseLowPriorityUri); mIsLowPriority = true; } else { @@ -186,15 +190,21 @@ * {@link String} for {@code query} with the contextual search version param set. * @param query The search term to use as the main query in the returned search url. * @param alternateTerm The alternate search term to use as an alternate suggestion. + * @param mid The MID for an entity to use to trigger a Knowledge Panel, or an empty string. + * A MID is a unique identifier for an entity in the Search Knowledge Graph. * @param shouldPrefetch Whether the returned url should include a prefetch parameter. * @return A {@link Uri} that contains the url of the default search engine with * {@code query} and {@code alternateTerm} inserted as parameters and contextual * search and prefetch parameters conditionally set. */ - protected Uri getUriTemplate(String query, @Nullable String alternateTerm, + protected Uri getUriTemplate(String query, @Nullable String alternateTerm, @Nullable String mid, boolean shouldPrefetch) { - return Uri.parse(TemplateUrlService.getInstance().getUrlForContextualSearchQuery( + Uri uri = Uri.parse(TemplateUrlService.getInstance().getUrlForContextualSearchQuery( query, alternateTerm, shouldPrefetch, CTXS_TWO_REQUEST_PROTOCOL)); + if (!TextUtils.isEmpty(mid)) { + uri = makeKPTriggeringUri(uri, mid); + } + return uri; } /** @@ -229,4 +239,17 @@ builder.appendQueryParameter(TLITE_QUERY_PARAM, baseUri.getQueryParameter(GWS_QUERY_PARAM)); return builder.build(); } + + /** + * Converts a URI to a URI that will trigger a Knowledge Panel for the given entity. + * @param baseUri The base URI to convert. + * @param mid The un-encoded MID (unique identifier) for an entity to use to trigger a Knowledge + * Panel. + * @return The converted URI. + */ + private Uri makeKPTriggeringUri(Uri baseUri, String mid) { + // Need to add a param like &kgmid=/m/0cqt90 + // Note that the mid must not be escaped - appendQueryParameter will take care of that. + return baseUri.buildUpon().appendQueryParameter(KP_TRIGGERING_MID_PARAM, mid).build(); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionController.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionController.java index 9f56db3a..6234318 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionController.java
@@ -44,12 +44,12 @@ private static final String CONTAINS_WORD_PATTERN = "(\\w|\\p{L}|\\p{N})+"; // A URL is: - // 0-1: schema:// + // 1: scheme:// // 1+: any word char, _ or - // 1+: . followed by 1+ of any word char, _ or - // 0-1: 0+ of any word char or .,@?^=%&:/~#- followed by any word char or @?^-%&/~+#- - // TODO(twellington): expand accepted schemas? Require a schema? - private static final Pattern URL_PATTERN = Pattern.compile("((http|https|file)://)?" + // TODO(twellington): expand accepted schemes? + private static final Pattern URL_PATTERN = Pattern.compile("((http|https|file|ftp|ssh)://)" + "([\\w_-]+(?:(?:\\.[\\w_-]+)+))([\\w.,@?^=%&:/~+#-]*[\\w@?^=%&/~+#-])?"); // Max selection length must be limited or the entire request URL can go past the 2K limit.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java index 0ab18c1..690cc6c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java
@@ -54,7 +54,7 @@ @Override public boolean startActivityIfNeeded(Intent intent) { - boolean isExternalProtocol = !UrlUtilities.isAcceptedScheme(intent.getDataString()); + boolean isExternalProtocol = !UrlUtilities.isAcceptedScheme(intent.toUri(0)); boolean hasDefaultHandler = hasDefaultHandler(intent); try { // For a URL chrome can handle and there is no default set, handle it ourselves.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadItem.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadItem.java index 1589743..0ed4980 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadItem.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadItem.java
@@ -4,13 +4,11 @@ package org.chromium.chrome.browser.download; -import org.chromium.chrome.browser.widget.DateDividedAdapter.TimedItem; - /** * A generic class representing a download item. The item can be either downloaded through the * Android DownloadManager, or through Chrome's network stack */ -public class DownloadItem implements TimedItem { +public class DownloadItem { static final long INVALID_DOWNLOAD_ID = -1L; private boolean mUseAndroidDownloadManager; private DownloadInfo mDownloadInfo; @@ -85,7 +83,6 @@ * * @return Download start time from System.currentTimeMillis(). */ - @Override public long getStartTime() { return mStartTime; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java index d74fe17..6335d3f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
@@ -1143,6 +1143,15 @@ } /** + * Removes a download from the list. + * @param downloadGuid GUID of the download. + * @param isOffTheRecord Whether the download is off the record. + */ + public void removeDownload(String downloadGuid, boolean isOffTheRecord) { + nativeRemoveDownload(getNativeDownloadManagerService(), downloadGuid, isOffTheRecord); + } + + /** * Helper method to create and retrieve the native DownloadManagerService when needed. * @return pointer to native DownloadManagerService. */ @@ -1501,7 +1510,14 @@ DownloadItem item = createDownloadItem( guid, displayName, filepath, url, mimeType, startTimestamp, totalBytes); for (DownloadHistoryAdapter adapter : mHistoryAdapters) { - adapter.updateDownloadItem(item); + adapter.onDownloadItemUpdated(item); + } + } + + @CalledByNative + private void onDownloadItemRemoved(String guid) { + for (DownloadHistoryAdapter adapter : mHistoryAdapters) { + adapter.onDownloadItemRemoved(guid); } } @@ -1592,6 +1608,8 @@ boolean isNotificationDismissed); private native void nativePauseDownload(long nativeDownloadManagerService, String downloadGuid, boolean isOffTheRecord); + private native void nativeRemoveDownload(long nativeDownloadManagerService, String downloadGuid, + boolean isOffTheRecord); private native void nativeGetAllDownloads(long nativeDownloadManagerService); private native void nativeGetDownloadInfoFor( long nativeDownloadManagerService, String downloadGuid, boolean isOffTheRecord);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java index c9629f94..94375a0d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
@@ -219,8 +219,9 @@ } } int notificationId = getNotificationId(downloadGuid); - addOrReplaceSharedPreferenceEntry(new DownloadSharedPreferenceEntry( - notificationId, isOffTheRecord, canDownloadWhileMetered, downloadGuid, fileName)); + addOrReplaceSharedPreferenceEntry(new DownloadSharedPreferenceEntry(notificationId, + isOffTheRecord, canDownloadWhileMetered, downloadGuid, fileName, + DownloadSharedPreferenceEntry.ITEM_TYPE_DOWNLOAD)); if (startTime > 0) builder.setWhen(startTime); Intent cancelIntent = buildActionIntent( ACTION_DOWNLOAD_CANCEL, notificationId, downloadGuid, fileName); @@ -423,8 +424,8 @@ boolean metered = DownloadManagerService.isActiveNetworkMetered(mContext); boolean isOffTheRecord = IntentUtils.safeGetBooleanExtra( intent, EXTRA_DOWNLOAD_IS_OFF_THE_RECORD, false); - return new DownloadSharedPreferenceEntry( - notificationId, isOffTheRecord, metered, guid, fileName); + return new DownloadSharedPreferenceEntry(notificationId, isOffTheRecord, metered, guid, + fileName, DownloadSharedPreferenceEntry.ITEM_TYPE_DOWNLOAD); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSharedPreferenceEntry.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSharedPreferenceEntry.java index e323b4a..703f35fc 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSharedPreferenceEntry.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSharedPreferenceEntry.java
@@ -17,22 +17,32 @@ */ public class DownloadSharedPreferenceEntry { private static final String TAG = "DownloadEntry"; + // Current version of the DownloadSharedPreferenceEntry. When changing the SharedPreference, // we need to change the version number too. - @VisibleForTesting static final int VERSION = 2; + @VisibleForTesting + static final int VERSION = 3; + public static final int ITEM_TYPE_DOWNLOAD = 1; + public static final int ITEM_TYPE_OFFLINE_PAGE = 2; + public final int notificationId; public final boolean isOffTheRecord; // Whether the download is public (non incognito). public boolean canDownloadWhileMetered; public final String fileName; public final String downloadGuid; + public final int itemType; + + static final DownloadSharedPreferenceEntry INVALID_ENTRY = + new DownloadSharedPreferenceEntry(-1, false, false, null, "", ITEM_TYPE_DOWNLOAD); DownloadSharedPreferenceEntry(int notificationId, boolean isOffTheRecord, - boolean canDownloadWhileMetered, String guid, String fileName) { + boolean canDownloadWhileMetered, String guid, String fileName, int itemType) { this.notificationId = notificationId; this.isOffTheRecord = isOffTheRecord; this.canDownloadWhileMetered = canDownloadWhileMetered; this.downloadGuid = guid; this.fileName = fileName; + this.itemType = itemType; } /** @@ -43,28 +53,51 @@ * @return a DownloadSharedPreferenceEntry object. */ static DownloadSharedPreferenceEntry parseFromString(String sharedPrefString) { - String[] values = sharedPrefString.split(",", 6); - if (values.length == 6) { - try { - int version = Integer.parseInt(values[0]); - // Ignore all SharedPreference entries that has an invalid version for now. - if (version < 1) { - return new DownloadSharedPreferenceEntry(-1, false, false, null, ""); - } - int id = Integer.parseInt(values[1]); - boolean isOffTheRecord = - (version >= 2) ? "1".equals(values[2]) : "0".equals(values[2]); - boolean canDownloadWhileMetered = "1".equals(values[3]); - if (!isValidGUID(values[4])) { - return new DownloadSharedPreferenceEntry(-1, false, false, null, ""); - } - return new DownloadSharedPreferenceEntry( - id, isOffTheRecord, canDownloadWhileMetered, values[4], values[5]); - } catch (NumberFormatException nfe) { - Log.w(TAG, "Exception while parsing pending download:" + sharedPrefString); - } + String versionString = sharedPrefString.substring(0, sharedPrefString.indexOf(",")); + // Ignore all SharedPreference entries that has an invalid version for now. + int version = 0; + try { + version = Integer.parseInt(versionString); + } catch (NumberFormatException nfe) { + Log.w(TAG, "Exception while parsing pending download:" + sharedPrefString); } - return new DownloadSharedPreferenceEntry(-1, false, false, null, ""); + if (version <= 0 || version > 3) return INVALID_ENTRY; + + // Expected number of items for version 1 and 2 is 6, version 3 is 7. + int expectedItemsNumber = (version == 3 ? 7 : 6); + String[] values = sharedPrefString.split(",", expectedItemsNumber); + if (values.length != expectedItemsNumber) return INVALID_ENTRY; + + // Index == 0 is used for version, therefor we start from 1. + int currentIndex = 1; + int id = 0; + int itemType = ITEM_TYPE_DOWNLOAD; + try { + id = Integer.parseInt(values[currentIndex++]); + if (version > 2) { + itemType = Integer.parseInt(values[currentIndex++]); + } + } catch (NumberFormatException nfe) { + Log.w(TAG, "Exception while parsing pending download:" + sharedPrefString); + return INVALID_ENTRY; + } + if (itemType != ITEM_TYPE_DOWNLOAD && itemType != ITEM_TYPE_OFFLINE_PAGE) { + return INVALID_ENTRY; + } + + boolean isOffTheRecord = (version >= 2) ? "1".equals(values[currentIndex]) + : "0".equals(values[currentIndex]); + ++currentIndex; + + boolean canDownloadWhileMetered = "1".equals(values[currentIndex++]); + + String guid = values[currentIndex++]; + if (!isValidGUID(guid)) return INVALID_ENTRY; + + String fileName = values[currentIndex++]; + + return new DownloadSharedPreferenceEntry( + id, isOffTheRecord, canDownloadWhileMetered, guid, fileName, itemType); } /** @@ -72,8 +105,8 @@ * SharedPrefs. */ String getSharedPreferenceString() { - return VERSION + "," + notificationId + "," + (isOffTheRecord ? "1" : "0") + "," - + (canDownloadWhileMetered ? "1" : "0") + "," + downloadGuid + "," + fileName; + return VERSION + "," + notificationId + "," + itemType + "," + (isOffTheRecord ? "1" : "0") + + "," + (canDownloadWhileMetered ? "1" : "0") + "," + downloadGuid + "," + fileName; } /** @@ -116,6 +149,7 @@ return TextUtils.equals(downloadGuid, other.downloadGuid) && TextUtils.equals(fileName, other.fileName) && notificationId == other.notificationId + && itemType == other.itemType && isOffTheRecord == other.isOffTheRecord && canDownloadWhileMetered == other.canDownloadWhileMetered; } @@ -126,6 +160,7 @@ hash = 37 * hash + (isOffTheRecord ? 1 : 0); hash = 37 * hash + (canDownloadWhileMetered ? 1 : 0); hash = 37 * hash + notificationId; + hash = 37 * hash + itemType; hash = 37 * hash + downloadGuid.hashCode(); hash = 37 * hash + fileName.hashCode(); return hash;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java new file mode 100644 index 0000000..09f820d --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
@@ -0,0 +1,29 @@ +// 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. + +package org.chromium.chrome.browser.download; + +import android.app.Activity; + +import org.chromium.chrome.browser.UrlConstants; +import org.chromium.chrome.browser.tab.Tab; +import org.chromium.content_public.browser.LoadUrlParams; +import org.chromium.ui.base.DeviceFormFactor; + +/** + * A class containing some utility static methods. + */ +public class DownloadUtils { + + /** + * Displays the download manager UI. Note the UI is different on tablets and on phones. + */ + public static void showDownloadManager(Activity activity, Tab tab) { + if (DeviceFormFactor.isTablet(activity)) { + tab.loadUrl(new LoadUrlParams(UrlConstants.DOWNLOADS_URL)); + } else { + DownloadActivity.launch(activity); + } + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java index 99d5765..ddfd9162 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java
@@ -15,15 +15,21 @@ import android.widget.ImageView; import android.widget.TextView; +import org.chromium.base.ContextUtils; import org.chromium.chrome.R; import org.chromium.chrome.browser.download.DownloadItem; +import org.chromium.chrome.browser.download.DownloadManagerService; +import org.chromium.chrome.browser.download.ui.DownloadHistoryItemWrapper.DownloadItemWrapper; +import org.chromium.chrome.browser.download.ui.DownloadHistoryItemWrapper.OfflinePageItemWrapper; import org.chromium.chrome.browser.download.ui.DownloadManagerUi.DownloadUiObserver; +import org.chromium.chrome.browser.offlinepages.downloads.OfflinePageDownloadBridge; +import org.chromium.chrome.browser.offlinepages.downloads.OfflinePageDownloadItem; +import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.util.UrlUtilities; import org.chromium.chrome.browser.widget.DateDividedAdapter; import java.util.ArrayList; import java.util.List; -import java.util.Locale; /** Bridges the user's download history and the UI used to display it. */ public class DownloadHistoryAdapter extends DateDividedAdapter implements DownloadUiObserver { @@ -49,35 +55,56 @@ } } - private static final String MIMETYPE_VIDEO = "video"; - private static final String MIMETYPE_AUDIO = "audio"; - private static final String MIMETYPE_IMAGE = "image"; - private static final String MIMETYPE_DOCUMENT = "text"; + /** See {@link #findItemIndex}. */ + private static final int INVALID_INDEX = -1; - private final List<DownloadItem> mAllItems = new ArrayList<>(); - private final List<DownloadItem> mFilteredItems = new ArrayList<>(); + private final List<DownloadItemWrapper> mDownloadItems = new ArrayList<>(); + private final List<OfflinePageItemWrapper> mOfflinePageItems = new ArrayList<>(); + private final List<DownloadHistoryItemWrapper> mFilteredItems = new ArrayList<>(); private int mFilter = DownloadFilter.FILTER_ALL; private DownloadManagerUi mManager; + private OfflinePageDownloadBridge mOfflinePageBridge; @Override public void initialize(DownloadManagerUi manager) { manager.addObserver(this); mManager = manager; + + getDownloadManagerService().addDownloadHistoryAdapter(this); + getDownloadManagerService().getAllDownloads(); + + initializeOfflinePageBridge(); } - /** Called when the user's download history has been gathered into a List of DownloadItems. */ - public void onAllDownloadsRetrieved(List<DownloadItem> list) { - mAllItems.clear(); - mAllItems.addAll(list); + /** Called when the user's download history has been gathered. */ + public void onAllDownloadsRetrieved(List<DownloadItem> result) { + mDownloadItems.clear(); + for (DownloadItem item : result) { + mDownloadItems.add(new DownloadItemWrapper(item)); + } + filter(DownloadFilter.FILTER_ALL); + } + + /** Called when the user's offline page history has been gathered. */ + private void onAllOfflinePagesRetrieved(List<OfflinePageDownloadItem> result) { + mOfflinePageItems.clear(); + for (OfflinePageDownloadItem item : result) { + mOfflinePageItems.add(new OfflinePageItemWrapper(item)); + } + + // TODO(ianwen): Implement a loading screen to prevent filter-changing wonkiness. filter(DownloadFilter.FILTER_ALL); } /** Returns the total size of all the downloaded items. */ public long getTotalDownloadSize() { long totalSize = 0; - for (int i = 0; i < mAllItems.size(); i++) { - totalSize += mAllItems.get(i).getDownloadInfo().getContentLength(); + for (DownloadHistoryItemWrapper wrapper : mDownloadItems) { + totalSize += wrapper.getFileSize(); + } + for (DownloadHistoryItemWrapper wrapper : mOfflinePageItems) { + totalSize += wrapper.getFileSize(); } return totalSize; } @@ -97,19 +124,19 @@ @Override public void bindViewHolderForTimedItem(ViewHolder current, TimedItem timedItem) { - final DownloadItem item = (DownloadItem) timedItem; + final DownloadHistoryItemWrapper item = (DownloadHistoryItemWrapper) timedItem; ItemViewHolder holder = (ItemViewHolder) current; Context context = holder.mFilesizeView.getContext(); - holder.mFilenameView.setText(item.getDownloadInfo().getFileName()); + holder.mFilenameView.setText(item.getDisplayFileName()); holder.mHostnameView.setText( - UrlUtilities.formatUrlForSecurityDisplay(item.getDownloadInfo().getUrl(), false)); + UrlUtilities.formatUrlForSecurityDisplay(item.getUrl(), false)); holder.mFilesizeView.setText( - Formatter.formatFileSize(context, item.getDownloadInfo().getContentLength())); - holder.mItemView.initialize(mManager, item); + Formatter.formatFileSize(context, item.getFileSize())); + holder.mItemView.initialize(item); // Pick what icon to display for the item. - int fileType = convertMimeTypeToFilterType(item.getDownloadInfo().getMimeType()); + int fileType = item.getFilterType(); int iconResource = R.drawable.ic_drive_file_white_24dp; switch (fileType) { case DownloadFilter.FILTER_PAGE: @@ -136,30 +163,48 @@ /** * Updates the list when new information about a download comes in. */ - public void updateDownloadItem(DownloadItem item) { - boolean isFound = false; - - // Search for an existing entry representing the DownloadItem. - for (int i = 0; i < mAllItems.size() && !isFound; i++) { - if (TextUtils.equals(mAllItems.get(i).getId(), item.getId())) { - mAllItems.set(i, item); - isFound = true; - } + public void onDownloadItemUpdated(DownloadItem item) { + int index = findItemIndex(mDownloadItems, item.getId()); + if (index == INVALID_INDEX) { + // Add a new entry. + mDownloadItems.add(new DownloadItemWrapper(item)); + } else { + // Update the old one. + mDownloadItems.set(index, new DownloadItemWrapper(item)); } - // Add a new entry if one doesn't already exist. - if (!isFound) mAllItems.add(item); filter(mFilter); } + /** + * Removes the DownloadItem with the given ID. + * @param guid ID of the DownloadItem that has been removed. + */ + public void onDownloadItemRemoved(String guid) { + int index = findItemIndex(mDownloadItems, guid); + if (index != INVALID_INDEX) { + DownloadItemWrapper wrapper = mDownloadItems.remove(index); + if (mManager.getSelectionDelegate().isItemSelected(wrapper)) { + mManager.getSelectionDelegate().toggleSelectionForItem(wrapper); + } + filter(mFilter); + } + } + @Override public void onFilterChanged(int filter) { filter(filter); } @Override - public void onDestroy(DownloadManagerUi manager) { - manager.removeObserver(this); + public void onManagerDestroyed(DownloadManagerUi manager) { + getDownloadManagerService().removeDownloadHistoryAdapter(this); + + if (mOfflinePageBridge != null) { + mOfflinePageBridge.destroy(); + mOfflinePageBridge = null; + } + mManager = null; } @@ -168,35 +213,81 @@ mFilter = filterType; mFilteredItems.clear(); if (filterType == DownloadFilter.FILTER_ALL) { - mFilteredItems.addAll(mAllItems); + mFilteredItems.addAll(mDownloadItems); + mFilteredItems.addAll(mOfflinePageItems); } else { - for (int i = 0; i < mAllItems.size(); i++) { - int currentFiletype = convertMimeTypeToFilterType( - mAllItems.get(i).getDownloadInfo().getMimeType()); - if (currentFiletype == filterType) mFilteredItems.add(mAllItems.get(i)); + for (DownloadHistoryItemWrapper item : mDownloadItems) { + if (item.getFilterType() == filterType) mFilteredItems.add(item); + } + + if (filterType == DownloadFilter.FILTER_PAGE) { + for (DownloadHistoryItemWrapper item : mOfflinePageItems) mFilteredItems.add(item); } } loadItems(mFilteredItems); } - /** Identifies the type of file represented by the given MIME type string. */ - private static int convertMimeTypeToFilterType(String mimeType) { - if (TextUtils.isEmpty(mimeType)) return DownloadFilter.FILTER_OTHER; + private void initializeOfflinePageBridge() { + mOfflinePageBridge = new OfflinePageDownloadBridge( + Profile.getLastUsedProfile().getOriginalProfile()); - String[] pieces = mimeType.toLowerCase(Locale.getDefault()).split("/"); - if (pieces.length != 2) return DownloadFilter.FILTER_OTHER; + mOfflinePageBridge.addObserver(new OfflinePageDownloadBridge.Observer() { + @Override + public void onItemsLoaded() { + onAllOfflinePagesRetrieved(mOfflinePageBridge.getAllItems()); + } - if (MIMETYPE_VIDEO.equals(pieces[0])) { - return DownloadFilter.FILTER_VIDEO; - } else if (MIMETYPE_AUDIO.equals(pieces[0])) { - return DownloadFilter.FILTER_AUDIO; - } else if (MIMETYPE_IMAGE.equals(pieces[0])) { - return DownloadFilter.FILTER_IMAGE; - } else if (MIMETYPE_DOCUMENT.equals(pieces[0])) { - return DownloadFilter.FILTER_DOCUMENT; - } else { - return DownloadFilter.FILTER_OTHER; - } + @Override + public void onItemAdded(OfflinePageDownloadItem item) { + mOfflinePageItems.add(new OfflinePageItemWrapper(item)); + updateFilter(); + } + + @Override + public void onItemDeleted(String guid) { + int index = findItemIndex(mOfflinePageItems, guid); + if (index != INVALID_INDEX) { + DownloadHistoryItemWrapper wrapper = mOfflinePageItems.remove(index); + if (mManager.getSelectionDelegate().isItemSelected(wrapper)) { + mManager.getSelectionDelegate().toggleSelectionForItem(wrapper); + } + updateFilter(); + } + } + + @Override + public void onItemUpdated(OfflinePageDownloadItem item) { + int index = findItemIndex(mOfflinePageItems, item.getGuid()); + if (index != INVALID_INDEX) { + mOfflinePageItems.set(index, new OfflinePageItemWrapper(item)); + updateFilter(); + } + } + + /** Re-filter the items if needed. */ + private void updateFilter() { + if (mFilter == DownloadFilter.FILTER_PAGE) filter(mFilter); + } + }); } + + /** + * Search for an existing entry for the {@link DownloadHistoryItemWrapper} with the given ID. + * @param list List to search through. + * @param guid GUID of the entry. + * @return The index of the item, or INVALID_INDEX if it couldn't be found. + */ + private <T extends DownloadHistoryItemWrapper> int findItemIndex(List<T> list, String guid) { + for (int i = 0; i < list.size(); i++) { + if (TextUtils.equals(list.get(i).getId(), guid)) return i; + } + return INVALID_INDEX; + } + + private static DownloadManagerService getDownloadManagerService() { + return DownloadManagerService.getDownloadManagerService( + ContextUtils.getApplicationContext()); + } + }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryItemWrapper.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryItemWrapper.java new file mode 100644 index 0000000..4f857bb --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryItemWrapper.java
@@ -0,0 +1,270 @@ +// 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. + +package org.chromium.chrome.browser.download.ui; + +import android.content.ActivityNotFoundException; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.net.Uri; +import android.os.AsyncTask; +import android.text.TextUtils; + +import org.chromium.base.ContextUtils; +import org.chromium.base.Log; +import org.chromium.chrome.R; +import org.chromium.chrome.browser.download.DownloadItem; +import org.chromium.chrome.browser.download.DownloadManagerService; +import org.chromium.chrome.browser.offlinepages.downloads.OfflinePageDownloadItem; +import org.chromium.chrome.browser.widget.DateDividedAdapter.TimedItem; +import org.chromium.ui.widget.Toast; + +import java.io.File; +import java.util.List; +import java.util.Locale; + +/** Wraps different classes that contain information about downloads. */ +abstract class DownloadHistoryItemWrapper implements TimedItem { + private static final String TAG = "download_ui"; + + /** @return Item that is being wrapped. */ + abstract Object getItem(); + + /** @return ID representing the download. */ + abstract String getId(); + + /** @return String showing where the download resides. */ + abstract String getFilePath(); + + /** @return A URI to where the file resides. */ + abstract Uri getUri(); + + /** @return String to display for the file. */ + abstract String getDisplayFileName(); + + /** @return Size of the file. */ + abstract long getFileSize(); + + /** @return URL the file was downloaded from. */ + abstract String getUrl(); + + /** @return {@link DownloadFilter} that represents the file type. */ + abstract int getFilterType(); + + /** @return The mime type or null if the item doesn't have one. */ + abstract String getMimeType(); + + /** Called when the user wants to open the file. */ + abstract void open(); + + /** Called when the user wants to delete the file. */ + abstract void delete(); + + /** Wraps a {@link DownloadItem}. */ + static class DownloadItemWrapper extends DownloadHistoryItemWrapper { + private static final String MIMETYPE_VIDEO = "video"; + private static final String MIMETYPE_AUDIO = "audio"; + private static final String MIMETYPE_IMAGE = "image"; + private static final String MIMETYPE_DOCUMENT = "text"; + + private final DownloadItem mItem; + + DownloadItemWrapper(DownloadItem item) { + mItem = item; + } + + @Override + public DownloadItem getItem() { + return mItem; + } + + @Override + public String getId() { + return mItem.getId(); + } + + @Override + public long getStartTime() { + return mItem.getStartTime(); + } + + @Override + public String getFilePath() { + return mItem.getDownloadInfo().getFilePath(); + } + + @Override + public Uri getUri() { + return Uri.fromFile(new File(getFilePath())); + } + + @Override + public String getDisplayFileName() { + return mItem.getDownloadInfo().getFileName(); + } + + @Override + public long getFileSize() { + return mItem.getDownloadInfo().getContentLength(); + } + + @Override + public String getUrl() { + return mItem.getDownloadInfo().getUrl(); + } + + @Override + public int getFilterType() { + return convertMimeTypeToFilterType(getMimeType()); + } + + @Override + public String getMimeType() { + return mItem.getDownloadInfo().getMimeType(); + } + + @Override + public void open() { + Context context = ContextUtils.getApplicationContext(); + boolean success = false; + + String mimeType = mItem.getDownloadInfo().getMimeType(); + Uri fileUri = Uri.fromFile(new File(getFilePath())); + + // Check if any apps can open the file. + Intent fileIntent = new Intent(); + fileIntent.setAction(Intent.ACTION_VIEW); + fileIntent.setDataAndType(fileUri, mimeType); + fileIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + List<ResolveInfo> handlers = context.getPackageManager() + .queryIntentActivities(fileIntent, PackageManager.MATCH_DEFAULT_ONLY); + if (handlers.size() > 0) { + Intent chooserIntent = Intent.createChooser(fileIntent, null); + chooserIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + context.startActivity(chooserIntent); + success = true; + } catch (ActivityNotFoundException e) { + // Can't launch the Intent. + } + } + + if (!success) { + Toast.makeText(context, context.getString(R.string.download_cant_open_file), + Toast.LENGTH_SHORT).show(); + } + } + + @Override + public void delete() { + // Tell the DownloadManager to remove the file from history. + DownloadManagerService service = DownloadManagerService.getDownloadManagerService( + ContextUtils.getApplicationContext()); + service.removeDownload(getId(), false); + + // Delete the file from storage. + new AsyncTask<Void, Void, Void>() { + @Override + public Void doInBackground(Void... params) { + File file = new File(getFilePath()); + if (file.exists() && !file.delete()) { + Log.e(TAG, "Failed to delete: " + getFilePath()); + } + return null; + } + }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + + /** Identifies the type of file represented by the given MIME type string. */ + private static int convertMimeTypeToFilterType(String mimeType) { + if (TextUtils.isEmpty(mimeType)) return DownloadFilter.FILTER_OTHER; + + String[] pieces = mimeType.toLowerCase(Locale.getDefault()).split("/"); + if (pieces.length != 2) return DownloadFilter.FILTER_OTHER; + + if (MIMETYPE_VIDEO.equals(pieces[0])) { + return DownloadFilter.FILTER_VIDEO; + } else if (MIMETYPE_AUDIO.equals(pieces[0])) { + return DownloadFilter.FILTER_AUDIO; + } else if (MIMETYPE_IMAGE.equals(pieces[0])) { + return DownloadFilter.FILTER_IMAGE; + } else if (MIMETYPE_DOCUMENT.equals(pieces[0])) { + return DownloadFilter.FILTER_DOCUMENT; + } else { + return DownloadFilter.FILTER_OTHER; + } + } + } + + /** Wraps a {@link OfflinePageDownloadItem}. */ + static class OfflinePageItemWrapper extends DownloadHistoryItemWrapper { + private final OfflinePageDownloadItem mItem; + + OfflinePageItemWrapper(OfflinePageDownloadItem item) { + mItem = item; + } + + @Override + public OfflinePageDownloadItem getItem() { + return mItem; + } + + @Override + public String getId() { + return mItem.getGuid(); + } + + @Override + public long getStartTime() { + return mItem.getStartTimeMs(); + } + + @Override + public String getFilePath() { + return mItem.getTargetPath(); + } + + @Override + public Uri getUri() { + return Uri.fromFile(new File(getFilePath())); + } + + @Override + public String getDisplayFileName() { + File path = new File(getFilePath()); + return path.getName(); + } + + @Override + public long getFileSize() { + return mItem.getTotalBytes(); + } + + @Override + public String getUrl() { + return mItem.getUrl(); + } + + @Override + public int getFilterType() { + return DownloadFilter.FILTER_PAGE; + } + + @Override + public String getMimeType() { + return null; + } + + public void open() { + // TODO(dfalcantara): Figure out what to do here. + } + + @Override + public void delete() { + // TODO(dfalcantara): Figure out what to do here. + } + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java index 303d202..fadb5ac2 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java
@@ -7,15 +7,13 @@ import android.content.Context; import android.util.AttributeSet; -import org.chromium.chrome.browser.download.DownloadItem; import org.chromium.chrome.browser.widget.selection.SelectableItemView; /** * The view for a downloaded item displayed in the Downloads list. */ -public class DownloadItemView extends SelectableItemView<String> { - DownloadManagerUi mManager; - DownloadItem mItem; +public class DownloadItemView extends SelectableItemView<DownloadHistoryItemWrapper> { + DownloadHistoryItemWrapper mItem; /** * Constructor for inflating from XML. @@ -27,17 +25,15 @@ /** * Initialize the DownloadItemView. Must be called before the item can respond to click events. * - * @param manager The DownloadManagerUi responsible for opening DownloadItems. - * @param item The DownloadItem represented by this DownloadItemView. + * @param item The item represented by this DownloadItemView. */ - public void initialize(DownloadManagerUi manager, DownloadItem item) { - mManager = manager; + public void initialize(DownloadHistoryItemWrapper item) { mItem = item; - setId(item.getId()); + setItem(item); } @Override public void onClick() { - mManager.onDownloadItemClicked(mItem); + if (mItem != null) mItem.open(); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerToolbar.java index 7fc67ca5..b1e16019 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerToolbar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerToolbar.java
@@ -15,7 +15,8 @@ /** * Handles toolbar functionality for the {@link DownloadManagerUi}. */ -public class DownloadManagerToolbar extends SelectionToolbar<String> implements DownloadUiObserver { +public class DownloadManagerToolbar extends SelectionToolbar<DownloadHistoryItemWrapper> + implements DownloadUiObserver { public DownloadManagerToolbar(Context context, AttributeSet attrs) { super(context, attrs); inflateMenu(R.menu.download_manager_menu); @@ -38,7 +39,6 @@ } @Override - public void onDestroy(DownloadManagerUi manager) { - manager.removeObserver(this); + public void onManagerDestroyed(DownloadManagerUi manager) { } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerUi.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerUi.java index df1a9e5..5ea54ce 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerUi.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerUi.java
@@ -5,15 +5,13 @@ package org.chromium.chrome.browser.download.ui; import android.app.Activity; -import android.content.ActivityNotFoundException; import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; import android.net.Uri; import android.support.v4.widget.DrawerLayout; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar.OnMenuItemClickListener; +import android.text.TextUtils; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MenuItem; @@ -22,19 +20,15 @@ import android.widget.ListView; import org.chromium.base.ApiCompatibilityUtils; -import org.chromium.base.ContextUtils; import org.chromium.base.ObserverList; import org.chromium.chrome.R; import org.chromium.chrome.browser.BasicNativePage; -import org.chromium.chrome.browser.download.DownloadItem; -import org.chromium.chrome.browser.download.DownloadManagerService; import org.chromium.chrome.browser.widget.FadingShadow; import org.chromium.chrome.browser.widget.FadingShadowView; import org.chromium.chrome.browser.widget.selection.SelectionDelegate; import org.chromium.ui.base.DeviceFormFactor; -import org.chromium.ui.widget.Toast; -import java.io.File; +import java.util.ArrayList; import java.util.List; /** @@ -61,10 +55,12 @@ /** * Called when the download manager is not shown anymore. */ - public void onDestroy(DownloadManagerUi manager); + public void onManagerDestroyed(DownloadManagerUi manager); } private static final String TAG = "download_ui"; + private static final String DEFAULT_MIME_TYPE = "*/*"; + private static final String MIME_TYPE_DELIMITER = "/"; private final DownloadHistoryAdapter mHistoryAdapter; private final FilterAdapter mFilterAdapter; @@ -79,17 +75,21 @@ private BasicNativePage mNativePage; - private SelectionDelegate<String> mSelectionDelegate; + private SelectionDelegate<DownloadHistoryItemWrapper> mSelectionDelegate; public DownloadManagerUi(Activity activity) { mActivity = activity; mMainView = (ViewGroup) LayoutInflater.from(activity).inflate(R.layout.download_main, null); - mSelectionDelegate = new SelectionDelegate<String>(); + mSelectionDelegate = new SelectionDelegate<DownloadHistoryItemWrapper>(); mHistoryAdapter = new DownloadHistoryAdapter(); mHistoryAdapter.initialize(this); + mSpaceDisplay = new SpaceDisplay(mMainView, mHistoryAdapter); + mHistoryAdapter.registerAdapterDataObserver(mSpaceDisplay); + mSpaceDisplay.onChanged(); + mFilterAdapter = new FilterAdapter(); mFilterAdapter.initialize(this); @@ -103,7 +103,6 @@ mToolbar.initialize(mSelectionDelegate, R.string.menu_downloads, drawerLayout, R.id.normal_menu_group, R.id.selection_mode_menu_group); - mSpaceDisplay = new SpaceDisplay(mMainView, mHistoryAdapter); mFilterView = (ListView) mMainView.findViewById(R.id.section_list); mFilterView.setAdapter(mFilterAdapter); mFilterView.setOnItemClickListener(mFilterAdapter); @@ -120,14 +119,9 @@ R.color.toolbar_shadow_color), FadingShadow.POSITION_TOP); } - mSpaceDisplay.onChanged(); mToolbar.setTitle(R.string.menu_downloads); - getDownloadManagerService().addDownloadHistoryAdapter(mHistoryAdapter); - mHistoryAdapter.registerAdapterDataObserver(mSpaceDisplay); - // TODO(ianwen): add support for loading state. - getDownloadManagerService().getAllDownloads(); } /** @@ -141,7 +135,11 @@ * Called when the activity/native page is destroyed. */ public void onDestroyed() { - getDownloadManagerService().removeDownloadHistoryAdapter(mHistoryAdapter); + for (DownloadUiObserver observer : mObservers) { + observer.onManagerDestroyed(this); + removeObserver(observer); + } + mHistoryAdapter.unregisterAdapterDataObserver(mSpaceDisplay); } @@ -175,7 +173,7 @@ /** * @return The SelectionDelegate responsible for tracking selected download items. */ - public SelectionDelegate<String> getSelectionDelegate() { + public SelectionDelegate<DownloadHistoryItemWrapper> getSelectionDelegate() { return mSelectionDelegate; } @@ -192,8 +190,13 @@ if (item.getItemId() == R.id.close_menu_id && !DeviceFormFactor.isTablet(mActivity)) { mActivity.finish(); return true; + } else if (item.getItemId() == R.id.selection_mode_delete_menu_id) { + deleteSelectedItems(); + return true; + } else if (item.getItemId() == R.id.selection_mode_share_menu_id) { + shareSelectedItems(); + return true; } - // TODO(twellington): Hook up delete and share icons. return false; } @@ -213,38 +216,6 @@ return mActivity; } - /** Called when a particular download item has been clicked. */ - void onDownloadItemClicked(DownloadItem item) { - boolean success = false; - - String mimeType = item.getDownloadInfo().getMimeType(); - String filePath = item.getDownloadInfo().getFilePath(); - Uri fileUri = Uri.fromFile(new File(filePath)); - - // Check if any apps can open the file. - Intent fileIntent = new Intent(); - fileIntent.setAction(Intent.ACTION_VIEW); - fileIntent.setDataAndType(fileUri, mimeType); - fileIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - List<ResolveInfo> handlers = ContextUtils.getApplicationContext().getPackageManager() - .queryIntentActivities(fileIntent, PackageManager.MATCH_DEFAULT_ONLY); - if (handlers.size() > 0) { - Intent chooserIntent = Intent.createChooser(fileIntent, null); - chooserIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - try { - mActivity.startActivity(chooserIntent); - success = true; - } catch (ActivityNotFoundException e) { - // Can't launch the Intent. - } - } - - if (!success) { - Toast.makeText(mActivity, mActivity.getString(R.string.download_cant_open_file), - Toast.LENGTH_SHORT).show(); - } - } - /** Called when the filter has been changed by the user. */ void onFilterChanged(int filter) { for (DownloadUiObserver observer : mObservers) { @@ -270,9 +241,71 @@ mObservers.removeObserver(observer); } - private static DownloadManagerService getDownloadManagerService() { - return DownloadManagerService.getDownloadManagerService( - ContextUtils.getApplicationContext()); + private void shareSelectedItems() { + // TODO(twellington): disable the share button when offline pages are selected. + + List<DownloadHistoryItemWrapper> selectedItems = mSelectionDelegate.getSelectedItems(); + assert selectedItems.size() > 0; + + Intent shareIntent = new Intent(); + String intentMimeType = Intent.normalizeMimeType(selectedItems.get(0).getMimeType()); + String intentAction; + + if (selectedItems.size() == 1) { + // Set up intent for 1 item. + intentAction = Intent.ACTION_SEND; + shareIntent.putExtra(Intent.EXTRA_STREAM, selectedItems.get(0).getUri()); + } else { + // Set up intent for multiple items. + intentAction = Intent.ACTION_SEND_MULTIPLE; + ArrayList<Uri> itemUris = new ArrayList<Uri>(); + + String[] intentMimeParts = {"", ""}; + if (intentMimeType != null) intentMimeParts = intentMimeType.split(MIME_TYPE_DELIMITER); + + for (DownloadHistoryItemWrapper itemWrapper : mSelectionDelegate.getSelectedItems()) { + itemUris.add(itemWrapper.getUri()); + + String mimeType = Intent.normalizeMimeType(itemWrapper.getMimeType()); + + // If a mime type was not retrieved from the backend or could not be normalized, + // set the mime type to the default. + if (mimeType == null) { + intentMimeType = DEFAULT_MIME_TYPE; + continue; + } + + // Either the mime type is already the default or it matches the current intent + // mime type. In either case, intentMimeType is already the correct value. + if (TextUtils.equals(intentMimeType, DEFAULT_MIME_TYPE) + || TextUtils.equals(intentMimeType, mimeType)) { + continue; + } + + String[] mimeParts = mimeType.split(MIME_TYPE_DELIMITER); + if (!TextUtils.equals(intentMimeParts[0], mimeParts[0])) { + // The top-level types don't match; fallback to the default mime type. + intentMimeType = DEFAULT_MIME_TYPE; + } else { + // The mime type should be {top-level type}/* + intentMimeType = intentMimeParts[0] + MIME_TYPE_DELIMITER + "*"; + } + } + + shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, itemUris); + } + + shareIntent.setAction(intentAction); + shareIntent.setType(intentMimeType); + shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mActivity.startActivity(Intent.createChooser(shareIntent, + mActivity.getString(R.string.share_link_chooser_title))); } + private void deleteSelectedItems() { + for (DownloadHistoryItemWrapper wrappedItem : mSelectionDelegate.getSelectedItems()) { + wrappedItem.delete(); + } + mSelectionDelegate.clearSelection(); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/FilterAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/FilterAdapter.java index db7c8f3..e2bfaff1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/FilterAdapter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/FilterAdapter.java
@@ -99,8 +99,7 @@ } @Override - public void onDestroy(DownloadManagerUi manager) { - mManagerUi.removeObserver(this); + public void onManagerDestroyed(DownloadManagerUi manager) { mManagerUi = null; } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java index d717db18..c509fd0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
@@ -445,6 +445,18 @@ // to launch the WebAPK without showing the intent picker. String targetWebApkPackageName = mDelegate.findWebApkPackageName(resolvingInfos); + + // We can't rely on this falling through to startActivityIfNeeded and behaving + // correctly for WebAPKs. This is because the target of the intent is the + // WebApk's main activity but that's just a bouncer which will redirect to + // WebApkActivity in chrome. To avoid bouncing indefinitely, don't override the + // navigation if we are currently showing the WebApk + // |params.webApkPackageName()| that we will redirect to. + if (targetWebApkPackageName != null + && targetWebApkPackageName.equals(params.webApkPackageName())) { + return OverrideUrlLoadingResult.NO_OVERRIDE; + } + if (targetWebApkPackageName != null && mDelegate.countSpecializedHandlers(resolvingInfos) == 1) { intent.setPackage(targetWebApkPackageName);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java index ec5384ff..2bc3b022 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser.init; import android.annotation.SuppressLint; +import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; import android.content.Intent; @@ -71,6 +72,8 @@ } @Override + // TODO(estevenson): Replace with Build.VERSION_CODES.N when available. + @TargetApi(24) protected void attachBaseContext(Context newBase) { super.attachBaseContext(newBase);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/MediaRouteChooserDialogFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/MediaRouteChooserDialogFactory.java index 1f6786c..ba1e146 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/MediaRouteChooserDialogFactory.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/MediaRouteChooserDialogFactory.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser.media.remote; +import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.content.DialogInterface; @@ -89,6 +90,7 @@ mPlayer = null; } + @SuppressLint("ValidFragment") Fragment(MediaRouteController controller, MediaStateListener player) { mController = controller; mPlayer = player;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtils.java index 86735622..6f1bbfc 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtils.java
@@ -242,6 +242,7 @@ * @return True if the Activity still has a task in Android recents, regardless of whether * the Activity has been destroyed. */ + @TargetApi(Build.VERSION_CODES.M) private boolean isActivityTaskInRecents(String className, Context context) { ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/IncognitoNewTabPage.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/IncognitoNewTabPage.java index 2734802..af955af8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/IncognitoNewTabPage.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/IncognitoNewTabPage.java
@@ -83,7 +83,7 @@ @Override public void destroy() { - assert getView().getParent() == null : "Destroy called before removed from window"; + assert !getView().isAttachedToWindow() : "Destroy called before removed from window"; } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java index ae135048..9805257 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
@@ -764,7 +764,7 @@ @Override public void destroy() { assert !mIsDestroyed; - assert getView().getParent() == null : "Destroy called before removed from window"; + assert !getView().isAttachedToWindow() : "Destroy called before removed from window"; if (mIsLoaded && !mTab.isHidden()) recordNTPInteractionTime(); if (mFaviconHelper != null) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ActionListItem.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ActionListItem.java new file mode 100644 index 0000000..9d93dab --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ActionListItem.java
@@ -0,0 +1,35 @@ +// 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. + +package org.chromium.chrome.browser.ntp.cards; + +import android.view.View; + +import org.chromium.chrome.R; +import org.chromium.chrome.browser.ntp.NewTabPageView.NewTabPageManager; +import org.chromium.chrome.browser.ntp.UiConfig; + +/** + * Item that allows the user to perform an action on the NTP. + */ +class ActionListItem implements NewTabPageListItem { + @Override + public int getType() { + return NewTabPageListItem.VIEW_TYPE_ACTION; + } + + public static class ViewHolder extends CardViewHolder { + public ViewHolder(NewTabPageRecyclerView recyclerView, final NewTabPageManager manager, + UiConfig uiConfig) { + super(R.layout.new_tab_page_action_card, recyclerView, uiConfig); + itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // TODO(dgn): Implement other behaviours. + manager.navigateToBookmarks(); + } + }); + } + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java index 61285b3c..b9673f24 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
@@ -19,15 +19,12 @@ import org.chromium.chrome.browser.ntp.UiConfig; import org.chromium.chrome.browser.ntp.snippets.CategoryStatus; import org.chromium.chrome.browser.ntp.snippets.CategoryStatus.CategoryStatusEnum; -import org.chromium.chrome.browser.ntp.snippets.KnownCategories; -import org.chromium.chrome.browser.ntp.snippets.KnownCategories.KnownCategoriesEnum; import org.chromium.chrome.browser.ntp.snippets.SnippetArticleListItem; import org.chromium.chrome.browser.ntp.snippets.SnippetArticleViewHolder; import org.chromium.chrome.browser.ntp.snippets.SnippetHeaderListItem; import org.chromium.chrome.browser.ntp.snippets.SnippetHeaderViewHolder; import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge; -import org.chromium.chrome.browser.ntp.snippets.SnippetsSource; -import org.chromium.chrome.browser.ntp.snippets.SnippetsSource.SnippetsObserver; +import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource; import java.util.ArrayList; import java.util.Collections; @@ -41,12 +38,13 @@ * the above-the-fold view (containing the logo, search box, and most visited tiles) and subsequent * elements will be the cards shown to the user */ -public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder> implements SnippetsObserver { +public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder> + implements SuggestionsSource.Observer { private static final String TAG = "Ntp"; private final NewTabPageManager mNewTabPageManager; private final NewTabPageLayout mNewTabPageLayout; - private SnippetsSource mSnippetsSource; + private SuggestionsSource mSuggestionsSource; private final UiConfig mUiConfig; private final ItemTouchCallbacks mItemTouchCallbacks = new ItemTouchCallbacks(); private NewTabPageRecyclerView mRecyclerView; @@ -116,22 +114,22 @@ * @param manager the NewTabPageManager to use to interact with the rest of the system. * @param newTabPageLayout the layout encapsulating all the above-the-fold elements * (logo, search box, most visited tiles) - * @param snippetsSource the bridge to interact with the snippets service. + * @param suggestionsSource the bridge to interact with the content suggestions service. * @param uiConfig the NTP UI configuration, to be passed to created views. */ public NewTabPageAdapter(NewTabPageManager manager, NewTabPageLayout newTabPageLayout, - SnippetsSource snippetsSource, UiConfig uiConfig) { + SuggestionsSource suggestionsSource, UiConfig uiConfig) { mNewTabPageManager = manager; mNewTabPageLayout = newTabPageLayout; - mSnippetsSource = snippetsSource; + mSuggestionsSource = suggestionsSource; mUiConfig = uiConfig; - // TODO(mvanouwerkerk): Do not hard code ARTICLES. Maybe do not initialize an empty - // section in the constructor. - setSuggestions(KnownCategories.ARTICLES, - Collections.<SnippetArticleListItem>emptyList(), - snippetsSource.getCategoryStatus(KnownCategories.ARTICLES)); - snippetsSource.setObserver(this); + for (int category : mSuggestionsSource.getCategories()) { + setSuggestions(category, suggestionsSource.getSuggestionsForCategory(category), + suggestionsSource.getCategoryStatus(category)); + } + suggestionsSource.setObserver(this); + updateGroups(); } /** Returns callbacks to configure the interactions with the RecyclerView's items. */ @@ -140,31 +138,33 @@ } @Override - public void onSuggestionsReceived( - @KnownCategoriesEnum int category, List<SnippetArticleListItem> suggestions) { + public void onNewSuggestions(int category) { // We never want to refresh the suggestions if we already have some content. if (mSections.containsKey(category) && mSections.get(category).hasSuggestions()) return; // The status may have changed while the suggestions were loading, perhaps they should not // be displayed any more. if (!SnippetsBridge.isCategoryStatusInitOrAvailable( - mSnippetsSource.getCategoryStatus(category))) { + mSuggestionsSource.getCategoryStatus(category))) { return; } + List<SnippetArticleListItem> suggestions = + mSuggestionsSource.getSuggestionsForCategory(category); + Log.d(TAG, "Received %d new suggestions for category %d.", suggestions.size(), category); // At first, there might be no suggestions available, we wait until they have been fetched. if (suggestions.isEmpty()) return; - setSuggestions(category, suggestions, mSnippetsSource.getCategoryStatus(category)); + setSuggestions(category, suggestions, mSuggestionsSource.getCategoryStatus(category)); + updateGroups(); NewTabPageUma.recordSnippetAction(NewTabPageUma.SNIPPETS_ACTION_SHOWN); } @Override - public void onCategoryStatusChanged( - @KnownCategoriesEnum int category, @CategoryStatusEnum int status) { + public void onCategoryStatusChanged(int category, @CategoryStatusEnum int status) { // Observers should not be registered for this state. assert status != CategoryStatus.ALL_SUGGESTIONS_EXPLICITLY_DISABLED; @@ -178,6 +178,7 @@ if (SnippetsBridge.isCategoryStatusAvailable(status) && section.hasSuggestions()) return; setSuggestions(category, Collections.<SnippetArticleListItem>emptyList(), status); + updateGroups(); } @Override @@ -200,7 +201,7 @@ if (viewType == NewTabPageListItem.VIEW_TYPE_SNIPPET) { return new SnippetArticleViewHolder( - mRecyclerView, mNewTabPageManager, mSnippetsSource, mUiConfig); + mRecyclerView, mNewTabPageManager, mSuggestionsSource, mUiConfig); } if (viewType == NewTabPageListItem.VIEW_TYPE_SPACING) { @@ -215,6 +216,10 @@ return new ProgressViewHolder(mRecyclerView); } + if (viewType == NewTabPageListItem.VIEW_TYPE_ACTION) { + return new ActionListItem.ViewHolder(mRecyclerView, mNewTabPageManager, mUiConfig); + } + return null; } @@ -241,11 +246,17 @@ } public int getFirstCardPosition() { - return getFirstHeaderPosition() + 1; + // TODO(mvanouwerkerk): Don't rely on getFirstHeaderPosition() here. + int firstHeaderPosition = getFirstHeaderPosition(); + if (firstHeaderPosition == RecyclerView.NO_POSITION) return RecyclerView.NO_POSITION; + return firstHeaderPosition + 1; } public int getLastContentItemPosition() { - return getBottomSpacerPosition() - 1; + // TODO(mvanouwerkerk): Don't rely on getBottomSpacerPosition() here. + int bottomSpacerPosition = getBottomSpacerPosition(); + if (bottomSpacerPosition == RecyclerView.NO_POSITION) return RecyclerView.NO_POSITION; + return bottomSpacerPosition - 1; } public int getBottomSpacerPosition() { @@ -257,21 +268,23 @@ SnippetsBridge.fetchSnippets(/*forceRequest=*/true); } - private void setSuggestions(@KnownCategoriesEnum int category, - List<SnippetArticleListItem> suggestions, @CategoryStatusEnum int status) { - mGroups.clear(); - mGroups.add(mAboveTheFold); - + private void setSuggestions(int category, List<SnippetArticleListItem> suggestions, + @CategoryStatusEnum int status) { if (!mSections.containsKey(category)) { - mSections.put(category, - new SuggestionsSection(suggestions, status, this)); + SuggestionsCategoryInfo info = mSuggestionsSource.getCategoryInfo(category); + mSections.put(category, new SuggestionsSection(suggestions, status, info, this)); } else { mSections.get(category).setSuggestions(suggestions, status, this); } + } + private void updateGroups() { + mGroups.clear(); + mGroups.add(mAboveTheFold); mGroups.addAll(mSections.values()); - - mGroups.add(mBottomSpacer); + if (!mSections.isEmpty()) { + mGroups.add(mBottomSpacer); + } // TODO(bauerb): Notify about a smaller range. notifyDataSetChanged(); @@ -297,7 +310,7 @@ int position = itemViewHolder.getAdapterPosition(); SnippetArticleListItem suggestion = (SnippetArticleListItem) getItems().get(position); - mSnippetsSource.getSnippedVisited(suggestion, new Callback<Boolean>() { + mSuggestionsSource.getSuggestionVisited(suggestion, new Callback<Boolean>() { @Override public void onResult(Boolean result) { NewTabPageUma.recordSnippetAction(result @@ -306,7 +319,7 @@ } }); - mSnippetsSource.discardSnippet(suggestion); + mSuggestionsSource.dismissSuggestion(suggestion); SuggestionsSection section = (SuggestionsSection) getGroup(position); section.dismissSuggestion(suggestion);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageListItem.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageListItem.java index 9a73f13..ce96a5b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageListItem.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageListItem.java
@@ -18,7 +18,7 @@ * @see NewTabPageListItem#getType() */ @IntDef({VIEW_TYPE_ABOVE_THE_FOLD, VIEW_TYPE_HEADER, VIEW_TYPE_SNIPPET, VIEW_TYPE_SPACING, - VIEW_TYPE_STATUS, VIEW_TYPE_PROGRESS}) + VIEW_TYPE_STATUS, VIEW_TYPE_PROGRESS, VIEW_TYPE_ACTION}) @Retention(RetentionPolicy.SOURCE) public @interface ViewType {} @@ -59,6 +59,12 @@ public static final int VIEW_TYPE_PROGRESS = 6; /** + * View type for a {@link ActionListItem}, an action button. + * @see Adapter#getItemViewType(int) + */ + public static final int VIEW_TYPE_ACTION = 7; + + /** * Returns the type ({@link ViewType}) of this list item. This is so we can * distinguish between different elements that are held in a single RecyclerView holder. *
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java index 951e988..b158127 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java
@@ -6,6 +6,7 @@ import android.content.Context; import android.content.res.Resources; +import android.graphics.Region; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; @@ -19,6 +20,7 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.ntp.NewTabPageLayout; import org.chromium.chrome.browser.ntp.snippets.SnippetHeaderViewHolder; +import org.chromium.chrome.browser.util.ViewUtils; /** * Simple wrapper on top of a RecyclerView that will acquire focus when tapped. Ensures the @@ -144,10 +146,15 @@ * below the fold to push the header up to to the top of the screen. */ int calculateBottomSpacing() { + int firstHeaderPos = getNewTabPageAdapter().getFirstHeaderPosition(); int firstVisiblePos = mLayoutManager.findFirstVisibleItemPosition(); + if (firstHeaderPos == RecyclerView.NO_POSITION + || firstVisiblePos == RecyclerView.NO_POSITION) { + return mMinBottomSpacing; + } // We have enough items to fill the view, since the snap point item is not even visible. - if (firstVisiblePos > getNewTabPageAdapter().getFirstHeaderPosition()) { + if (firstVisiblePos > firstHeaderPos) { return mMinBottomSpacing; } @@ -361,4 +368,10 @@ start + snapScrollHeight); } } + + @Override + public boolean gatherTransparentRegion(Region region) { + ViewUtils.gatherTransparentRegionsForOpaqueView(this, region); + return true; + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsCategoryInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsCategoryInfo.java new file mode 100644 index 0000000..b91a0d3 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsCategoryInfo.java
@@ -0,0 +1,38 @@ +// 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. + +package org.chromium.chrome.browser.ntp.cards; + +import org.chromium.chrome.browser.ntp.snippets.ContentSuggestionsCardLayout.ContentSuggestionsCardLayoutEnum; + +/** + * Contains static meta information about a Category. Equivalent of the CategoryInfo class in + * components/ntp_snippets/category_info.h. + */ +public class SuggestionsCategoryInfo { + /** + * Localized title of the category. + */ + private final String mTitle; + + /** + * Layout of the cards to be used to display suggestions in this category. + */ + @ContentSuggestionsCardLayoutEnum + private final int mCardLayout; + + public SuggestionsCategoryInfo(String title, @ContentSuggestionsCardLayoutEnum int cardLayout) { + this.mTitle = title; + this.mCardLayout = cardLayout; + } + + public String getTitle() { + return this.mTitle; + } + + @ContentSuggestionsCardLayoutEnum + public int getCardLayout() { + return this.mCardLayout; + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java index f3d98d2..0129065e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
@@ -18,13 +18,18 @@ */ public class SuggestionsSection implements ItemGroup { private final List<SnippetArticleListItem> mSuggestions = new ArrayList<>(); - private final SnippetHeaderListItem mHeader = new SnippetHeaderListItem(); + private final SuggestionsCategoryInfo mInfo; + private final SnippetHeaderListItem mHeader; private StatusListItem mStatus; private final ProgressListItem mProgressIndicator = new ProgressListItem(); + private final ActionListItem mMoreButton; public SuggestionsSection(List<SnippetArticleListItem> suggestions, - @CategoryStatusEnum int status, NewTabPageAdapter adapter) { - // TODO(mvanouwerkerk): Pass in the header text. + @CategoryStatusEnum int status, SuggestionsCategoryInfo info, + NewTabPageAdapter adapter) { + mInfo = info; + mHeader = new SnippetHeaderListItem(mInfo.getTitle()); + mMoreButton = null; // TODO(pke): Read from info => ? new ActionListItem() : null; setSuggestions(suggestions, status, adapter); } @@ -36,6 +41,8 @@ if (mSuggestions.isEmpty()) { items.add(mStatus); items.add(mProgressIndicator); + } else if (mMoreButton != null) { + items.add(mMoreButton); } return Collections.unmodifiableList(items); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java index 300ec766..02acf3e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java
@@ -68,7 +68,7 @@ private static final int ID_REMOVE = 4; private final NewTabPageManager mNewTabPageManager; - private final SnippetsSource mSnippetsSource; + private final SuggestionsSource mSuggestionsSource; private final TextView mHeadlineTextView; private final TextView mPublisherTextView; private final TextView mArticleSnippetTextView; @@ -86,15 +86,15 @@ * * @param parent The ViewGroup that is going to contain the newly created view. * @param manager The NTPManager object used to open an article - * @param snippetsSource The SnippetsBridge used to retrieve the snippet thumbnails. + * @param suggestionsSource The source used to retrieve the thumbnails. * @param uiConfig The NTP UI configuration object used to adjust the article UI. */ public SnippetArticleViewHolder(NewTabPageRecyclerView parent, NewTabPageManager manager, - SnippetsSource snippetsSource, UiConfig uiConfig) { + SuggestionsSource suggestionsSource, UiConfig uiConfig) { super(R.layout.new_tab_page_snippets_card, parent, uiConfig); mNewTabPageManager = manager; - mSnippetsSource = snippetsSource; + mSuggestionsSource = suggestionsSource; mThumbnailView = (ImageView) itemView.findViewById(R.id.article_thumbnail); mHeadlineTextView = (TextView) itemView.findViewById(R.id.article_headline); mPublisherTextView = (TextView) itemView.findViewById(R.id.article_publisher); @@ -254,7 +254,7 @@ } else { mThumbnailView.setImageResource(R.drawable.ic_snippet_thumbnail_placeholder); mImageCallback = new FetchImageCallback(this, mArticle); - mSnippetsSource.fetchSnippetImage(mArticle, mImageCallback); + mSuggestionsSource.fetchSuggestionImage(mArticle, mImageCallback); } // Set the favicon of the publisher.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetHeaderListItem.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetHeaderListItem.java index 242199c..e2a2f7a4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetHeaderListItem.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetHeaderListItem.java
@@ -18,6 +18,13 @@ /** Whether the header should be shown. */ private boolean mVisible = false; + /** The header text to be shown. */ + private final String mHeaderText; + + public SnippetHeaderListItem(String headerText) { + this.mHeaderText = headerText; + } + /** * Creates the View object for displaying the header for a group of snippets * @@ -41,4 +48,8 @@ public void setVisible(boolean visible) { mVisible = visible; } + + public String getHeaderText() { + return mHeaderText; + } } \ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetHeaderViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetHeaderViewHolder.java index 647487e..1437558 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetHeaderViewHolder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetHeaderViewHolder.java
@@ -6,6 +6,7 @@ import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; +import android.widget.TextView; import org.chromium.chrome.R; import org.chromium.chrome.browser.ntp.UiConfig; @@ -23,9 +24,10 @@ private final int mMaxSnippetHeaderHeight; private final int mMaxPeekPadding; + private final TextView mHeaderTextView; private final NewTabPageRecyclerView mRecyclerView; - private SnippetHeaderListItem mHeader; + private SnippetHeaderListItem mHeaderListItem; /** Can the header transition. */ private boolean mCanTransition = false; @@ -39,13 +41,14 @@ mMaxPeekPadding = itemView.getResources().getDimensionPixelSize( R.dimen.snippets_padding_and_peeking_card_height); + mHeaderTextView = (TextView) itemView.findViewById(R.id.suggestions_section_header); mRecyclerView = recyclerView; MarginResizer.createWithViewAdapter(itemView, config); } @Override public void onBindViewHolder(NewTabPageListItem header) { - mHeader = (SnippetHeaderListItem) header; + mHeaderListItem = (SnippetHeaderListItem) header; updateDisplay(); } @@ -60,7 +63,7 @@ * @return The header height we want to set. */ private int getHeaderHeight() { - if (!mHeader.isVisible()) return 0; + if (!mHeaderListItem.isVisible()) return 0; // If the header cannot transition but is visible - set the height to the maximum so // it always displays @@ -78,6 +81,7 @@ * Update the view for the fade in/out and heading height. */ public void updateDisplay() { + mHeaderTextView.setText(mHeaderListItem.getHeaderText()); RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) itemView.getLayoutParams(); int headerHeight = getHeaderHeight();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java index 98a8415..3893bfc8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java
@@ -8,21 +8,21 @@ import org.chromium.base.Callback; import org.chromium.base.annotations.CalledByNative; +import org.chromium.chrome.browser.ntp.cards.SuggestionsCategoryInfo; import org.chromium.chrome.browser.ntp.snippets.CategoryStatus.CategoryStatusEnum; -import org.chromium.chrome.browser.ntp.snippets.KnownCategories.KnownCategoriesEnum; import org.chromium.chrome.browser.profiles.Profile; import java.util.ArrayList; import java.util.List; /** - * Provides access to the snippets to display on the NTP using the C++ NTP Snippets Service + * Provides access to the snippets to display on the NTP using the C++ ContentSuggestionsService. */ -public class SnippetsBridge implements SnippetsSource { +public class SnippetsBridge implements SuggestionsSource { private static final String TAG = "SnippetsBridge"; private long mNativeSnippetsBridge; - private SnippetsObserver mObserver; + private SuggestionsSource.Observer mObserver; public static boolean isCategoryStatusAvailable(@CategoryStatusEnum int status) { // Note: This code is duplicated in content_suggestions_category_status.cc. @@ -73,33 +73,47 @@ nativeRescheduleFetching(); } - /** - * Tells the native service to discard a snippet. It will be removed from the native side - * storage and will also be discarded from subsequent fetch results. - * - * @param snippet Snippet to discard. - */ @Override - public void discardSnippet(SnippetArticleListItem snippet) { + public int[] getCategories() { assert mNativeSnippetsBridge != 0; - nativeDiscardSnippet(mNativeSnippetsBridge, snippet.mId); + return nativeGetCategories(mNativeSnippetsBridge); } - /** - * Fetches the thumbnail image for a snippet. - */ @Override - public void fetchSnippetImage(SnippetArticleListItem snippet, Callback<Bitmap> callback) { - nativeFetchImage(mNativeSnippetsBridge, snippet.mId, callback); + @CategoryStatusEnum + public int getCategoryStatus(int category) { + assert mNativeSnippetsBridge != 0; + return nativeGetCategoryStatus(mNativeSnippetsBridge, category); } - /** - * Checks whether a snippet has been visited by querying the history for the snippet's URL. - */ @Override - public void getSnippedVisited(SnippetArticleListItem snippet, Callback<Boolean> callback) { + public SuggestionsCategoryInfo getCategoryInfo(int category) { assert mNativeSnippetsBridge != 0; - nativeSnippetVisited(mNativeSnippetsBridge, callback, snippet.mUrl); + return nativeGetCategoryInfo(mNativeSnippetsBridge, category); + } + + @Override + public List<SnippetArticleListItem> getSuggestionsForCategory(int category) { + assert mNativeSnippetsBridge != 0; + return nativeGetSuggestionsForCategory(mNativeSnippetsBridge, category); + } + + @Override + public void fetchSuggestionImage(SnippetArticleListItem suggestion, Callback<Bitmap> callback) { + nativeFetchSuggestionImage(mNativeSnippetsBridge, suggestion.mId, callback); + } + + @Override + public void dismissSuggestion(SnippetArticleListItem suggestion) { + assert mNativeSnippetsBridge != 0; + nativeDismissSuggestion(mNativeSnippetsBridge, suggestion.mId); + } + + @Override + public void getSuggestionVisited( + SnippetArticleListItem suggestion, Callback<Boolean> callback) { + assert mNativeSnippetsBridge != 0; + nativeGetURLVisited(mNativeSnippetsBridge, callback, suggestion.mUrl); } /** @@ -112,20 +126,13 @@ * stop observing. */ @Override - public void setObserver(SnippetsObserver observer) { + public void setObserver(SuggestionsSource.Observer observer) { assert mObserver == null || mObserver == observer; mObserver = observer; nativeSetObserver(mNativeSnippetsBridge, observer == null ? null : this); } - @Override - @CategoryStatusEnum - public int getCategoryStatus(@KnownCategoriesEnum int category) { - assert mNativeSnippetsBridge != 0; - return nativeGetCategoryStatus(mNativeSnippetsBridge, category); - } - @CalledByNative private static List<SnippetArticleListItem> createSuggestionList() { return new ArrayList<>(); @@ -141,17 +148,20 @@ } @CalledByNative - private void onSuggestionsAvailable(/* @KnownCategoriesEnum */ int category, - List<SnippetArticleListItem> suggestions) { - assert mNativeSnippetsBridge != 0; - assert mObserver != null; - - mObserver.onSuggestionsReceived(category, suggestions); + private static SuggestionsCategoryInfo createSuggestionsCategoryInfo( + String title, int cardLayout) { + return new SuggestionsCategoryInfo(title, cardLayout); } @CalledByNative - private void onCategoryStatusChanged(/* @KnownCategoriesEnum */ int category, - /* @CategoryStatusEnum */ int newStatus) { + private void onNewSuggestions(int category) { + assert mNativeSnippetsBridge != 0; + assert mObserver != null; + mObserver.onNewSuggestions(category); + } + + @CalledByNative + private void onCategoryStatusChanged(int category, /* @CategoryStatusEnum */ int newStatus) { if (mObserver != null) mObserver.onCategoryStatusChanged(category, newStatus); } @@ -159,11 +169,16 @@ private native void nativeDestroy(long nativeNTPSnippetsBridge); private static native void nativeFetchSnippets(boolean forceRequest); private static native void nativeRescheduleFetching(); - private native void nativeDiscardSnippet(long nativeNTPSnippetsBridge, String snippetId); - private native void nativeSetObserver(long nativeNTPSnippetsBridge, SnippetsBridge bridge); - private static native void nativeSnippetVisited(long nativeNTPSnippetsBridge, - Callback<Boolean> callback, String url); - private native void nativeFetchImage( - long nativeNTPSnippetsBridge, String snippetId, Callback<Bitmap> callback); + private native int[] nativeGetCategories(long nativeNTPSnippetsBridge); private native int nativeGetCategoryStatus(long nativeNTPSnippetsBridge, int category); + private native SuggestionsCategoryInfo nativeGetCategoryInfo( + long nativeNTPSnippetsBridge, int category); + private native List<SnippetArticleListItem> nativeGetSuggestionsForCategory( + long nativeNTPSnippetsBridge, int category); + private native void nativeFetchSuggestionImage( + long nativeNTPSnippetsBridge, String suggestionId, Callback<Bitmap> callback); + private native void nativeDismissSuggestion(long nativeNTPSnippetsBridge, String suggestionId); + private static native void nativeGetURLVisited( + long nativeNTPSnippetsBridge, Callback<Boolean> callback, String url); + private native void nativeSetObserver(long nativeNTPSnippetsBridge, SnippetsBridge bridge); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsSource.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsSource.java deleted file mode 100644 index baab92e4..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsSource.java +++ /dev/null
@@ -1,55 +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. - -package org.chromium.chrome.browser.ntp.snippets; - -import android.graphics.Bitmap; - -import org.chromium.base.Callback; -import org.chromium.chrome.browser.ntp.snippets.CategoryStatus.CategoryStatusEnum; -import org.chromium.chrome.browser.ntp.snippets.KnownCategories.KnownCategoriesEnum; - -import java.util.List; - -/** - * An interface for classes that provide snippets. - */ -public interface SnippetsSource { - /** - * An observer for events in the snippets service. - */ - public interface SnippetsObserver { - void onSuggestionsReceived(@KnownCategoriesEnum int category, - List<SnippetArticleListItem> snippets); - - /** Called when a category changed its status. */ - void onCategoryStatusChanged(@KnownCategoriesEnum int category, - @CategoryStatusEnum int newStatus); - } - - /** - * Tells the source to discard the snippet. - */ - public void discardSnippet(SnippetArticleListItem snippet); - - /** - * Fetches the thumbnail image for a snippet. - */ - public void fetchSnippetImage(SnippetArticleListItem snippet, Callback<Bitmap> callback); - - /** - * Checks whether a snippet has been visited. - */ - public void getSnippedVisited(SnippetArticleListItem snippet, Callback<Boolean> callback); - - /** - * Sets the recipient for the fetched snippets. - */ - public void setObserver(SnippetsObserver observer); - - /** - * Gives the reason snippets are disabled. - */ - public int getCategoryStatus(@KnownCategoriesEnum int category); -} \ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SuggestionsSource.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SuggestionsSource.java new file mode 100644 index 0000000..2d69120 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SuggestionsSource.java
@@ -0,0 +1,74 @@ +// 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. + +package org.chromium.chrome.browser.ntp.snippets; + +import android.graphics.Bitmap; + +import org.chromium.base.Callback; +import org.chromium.chrome.browser.ntp.cards.SuggestionsCategoryInfo; +import org.chromium.chrome.browser.ntp.snippets.CategoryStatus.CategoryStatusEnum; + +import java.util.List; + +/** + * An interface for classes that provide content suggestions. + */ +public interface SuggestionsSource { + /** + * An observer for events in the content suggestions service. + */ + interface Observer { + /** Called when a category has a new list of content suggestions. */ + void onNewSuggestions(int category); + + /** Called when a category changed its status. */ + void onCategoryStatusChanged(int category, @CategoryStatusEnum int newStatus); + } + + /** + * Gets the categories in the order in which they should be displayed. + * @return The categories. + */ + int[] getCategories(); + + /** + * Gets the status of a category, possibly indicating the reason why it is disabled. + */ + @CategoryStatusEnum + int getCategoryStatus(int category); + + /** + * Gets the meta information of a category. + */ + SuggestionsCategoryInfo getCategoryInfo(int category); + + /** + * Gets the current content suggestions for a category, in the order in which they should be + * displayed. + */ + List<SnippetArticleListItem> getSuggestionsForCategory(int category); + + /** + * Fetches the thumbnail image for a content suggestion. A null Bitmap is returned if no image + * is available. The callback is never called synchronously. + */ + void fetchSuggestionImage(SnippetArticleListItem suggestion, Callback<Bitmap> callback); + + /** + * Tells the source to dismiss the content suggestion. + */ + void dismissSuggestion(SnippetArticleListItem suggestion); + + /** + * Checks whether a content suggestion has been visited. The callback is never called + * synchronously. + */ + void getSuggestionVisited(SnippetArticleListItem suggestion, Callback<Boolean> callback); + + /** + * Sets the recipient for update events from the source. + */ + void setObserver(Observer observer); +} \ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java index 653f20b9..9c411e3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
@@ -97,6 +97,7 @@ } private static final String TAG = "cr_PaymentRequest"; + private static final String ANDROID_PAY_METHOD_NAME = "https://android.com/pay"; private static final int SUGGESTIONS_LIMIT = 4; private static final Comparator<Completable> COMPLETENESS_COMPARATOR = new Comparator<Completable>() { @@ -1032,11 +1033,22 @@ } } - // If the payment method was an Autofill credit card with an identifier, record its use. - if (mPaymentMethodsSection.getSelectedItem() instanceof AutofillPaymentInstrument - && !mPaymentMethodsSection.getSelectedItem().getIdentifier().isEmpty()) { - PersonalDataManager.getInstance().recordAndLogCreditCardUse( - mPaymentMethodsSection.getSelectedItem().getIdentifier()); + // Record the payment method used to complete the transaction. If the payment method was an + // Autofill credit card with an identifier, record its use. + PaymentOption selectedPaymentMethod = mPaymentMethodsSection.getSelectedItem(); + if (selectedPaymentMethod instanceof AutofillPaymentInstrument) { + if (!selectedPaymentMethod.getIdentifier().isEmpty()) { + PersonalDataManager.getInstance().recordAndLogCreditCardUse( + selectedPaymentMethod.getIdentifier()); + } + PaymentRequestMetrics.recordSelectedPaymentMethodHistogram( + PaymentRequestMetrics.SELECTED_METHOD_CREDIT_CARD); + } else if (methodName.equals(ANDROID_PAY_METHOD_NAME)) { + PaymentRequestMetrics.recordSelectedPaymentMethodHistogram( + PaymentRequestMetrics.SELECTED_METHOD_ANDROID_PAY); + } else { + PaymentRequestMetrics.recordSelectedPaymentMethodHistogram( + PaymentRequestMetrics.SELECTED_METHOD_OTHER_PAYMENT_APP); } mUI.showProcessingMessage();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestMetrics.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestMetrics.java index 6aa7e3f8..de2ece2 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestMetrics.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestMetrics.java
@@ -46,6 +46,16 @@ @VisibleForTesting public static final int ABORT_REASON_MAX = 9; + // PaymentRequestPaymentMethods defined in tools/metrics/histograms/histograms.xml. + @VisibleForTesting + public static final int SELECTED_METHOD_CREDIT_CARD = 0; + @VisibleForTesting + public static final int SELECTED_METHOD_ANDROID_PAY = 1; + @VisibleForTesting + public static final int SELECTED_METHOD_OTHER_PAYMENT_APP = 2; + @VisibleForTesting + public static final int SELECTED_METHOD_MAX = 3; + // There should be no instance of PaymentRequestMetrics created. private PaymentRequestMetrics() {} @@ -66,4 +76,16 @@ RecordHistogram.recordEnumeratedHistogram("PaymentRequest.RequestedInformation", requestInformation, REQUESTED_INFORMATION_MAX); } + + /* + * Records the metric that keeps track of what payment method was used to complete a Payment + * Request transaction. + * + * @param paymentMethod The payment method that was used to complete the current transaction. + */ + public static void recordSelectedPaymentMethodHistogram(int paymentMethod) { + assert paymentMethod < SELECTED_METHOD_MAX; + RecordHistogram.recordEnumeratedHistogram("PaymentRequest.SelectedPaymentMethod", + paymentMethod, SELECTED_METHOD_MAX); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/NearbyMessageIntentService.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/NearbyMessageIntentService.java index 71a9c90..0371e6e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/NearbyMessageIntentService.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/NearbyMessageIntentService.java
@@ -20,7 +20,7 @@ public void onFound(Message message) { String url = PhysicalWebBleClient.getInstance().getUrlFromMessage(message); if (url != null) { - UrlManager.getInstance().addUrl(url); + UrlManager.getInstance().addUrl(new UrlInfo(url)); } } @@ -28,7 +28,7 @@ public void onLost(Message message) { String url = PhysicalWebBleClient.getInstance().getUrlFromMessage(message); if (url != null) { - UrlManager.getInstance().removeUrl(url); + UrlManager.getInstance().removeUrl(new UrlInfo(url)); } } };
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlInfo.java index 76a34fc..c05f3e0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlInfo.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlInfo.java
@@ -33,7 +33,7 @@ * Constructs a simple UrlInfo with only a URL. */ public UrlInfo(String url) { - this(url, -1.0, 0); + this(url, -1.0, System.currentTimeMillis()); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlManager.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlManager.java index 570a163c..09fba2d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlManager.java
@@ -182,15 +182,6 @@ } /** - * Add a URL to the store of URLs. - */ - // TODO(conleyo) we should remove this method after calling code only passes us a UrlInfo. - @VisibleForTesting - public void addUrl(String url) { - addUrl(new UrlInfo(url, -1.0, System.currentTimeMillis())); - } - - /** * Remove a URL to the store of URLs. * This method additionally updates the Physical Web notification. * @param urlInfo The URL to remove. @@ -209,15 +200,6 @@ } /** - * Remove a URL to the store of URLs. - */ - // TODO(conleyo) we should remove this method after calling code only passes us a UrlInfo. - @VisibleForTesting - public void removeUrl(String url) { - removeUrl(new UrlInfo(url)); - } - - /** * Get the list of URLs which are both nearby and resolved through PWS. * @return A set of nearby and resolved URLs, sorted by distance. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java index 8f75bc1b..6cb24ac 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -466,7 +466,7 @@ @Override public int getSystemWindowInsetLeft() { ChromeActivity activity = getActivity(); - if (activity != null) { + if (activity != null && activity.getInsetObserverView() != null) { return activity.getInsetObserverView().getSystemWindowInsetsLeft(); } return 0; @@ -475,7 +475,7 @@ @Override public int getSystemWindowInsetTop() { ChromeActivity activity = getActivity(); - if (activity != null) { + if (activity != null && activity.getInsetObserverView() != null) { return activity.getInsetObserverView().getSystemWindowInsetsTop(); } return 0; @@ -484,7 +484,7 @@ @Override public int getSystemWindowInsetRight() { ChromeActivity activity = getActivity(); - if (activity != null) { + if (activity != null && activity.getInsetObserverView() != null) { return activity.getInsetObserverView().getSystemWindowInsetsRight(); } return 0; @@ -1842,7 +1842,7 @@ assert false; mContentViewParent.removeAllViews(); } - mContentViewParent = new TabContentViewParent(mThemedApplicationContext); + mContentViewParent = new TabContentViewParent(mThemedApplicationContext, this); mContentViewParent.addView(cvc.getContainerView(), 0, new FrameLayout.LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabContentViewParent.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabContentViewParent.java index 71c2912c..865893d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabContentViewParent.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabContentViewParent.java
@@ -12,22 +12,52 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.banners.SwipableOverlayView; +import org.chromium.ui.UiUtils; import org.chromium.ui.base.DeviceFormFactor; /** - * Parent {@link FrameLayout} holding the infobar and content view of a tab. + * Parent {@link FrameLayout} holding the infobar and content of a tab. The content could be either + * a native page or a content view. */ public class TabContentViewParent extends FrameLayout { + private static final int CONTENT_INDEX = 0; + // A wrapper is needed because infobar's translation is controlled by SwipableOverlayView. // Setting infobar's translation directly from this class will cause UI flickering. private final FrameLayout mInfobarWrapper; private final Behavior<?> mBehavior = new SnackbarAwareBehavior(); - public TabContentViewParent(Context context) { + private EmptyTabObserver mTabObserver = new EmptyTabObserver() { + @Override + public void onContentChanged(Tab tab) { + // If the tab is frozen, both native page and content view are not ready. + if (tab.isFrozen()) return; + View viewToShow = null; + if (tab.getNativePage() != null) { + viewToShow = tab.getNativePage().getView(); + if (isShowing(viewToShow)) return; + + } else { + viewToShow = tab.getContentViewCore().getContainerView(); + if (isShowing(viewToShow)) return; + } + + removeCurrentContent(); + UiUtils.removeViewFromParent(viewToShow); + addView(viewToShow, CONTENT_INDEX, new FrameLayout.LayoutParams( + LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); + viewToShow.requestFocus(); + } + }; + + public TabContentViewParent(Context context, Tab tab) { super(context); mInfobarWrapper = new FrameLayout(context); + mInfobarWrapper.setFocusable(true); + mInfobarWrapper.setFocusableInTouchMode(true); addView(mInfobarWrapper, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); + tab.addObserver(mTabObserver); } /** @@ -50,6 +80,18 @@ mInfobarWrapper.setTranslationY(0f); } + /** + * @return Whether the given {@link View} is already in the view hierarchy. + */ + private boolean isShowing(View view) { + return view.getParent() == this; + } + + private void removeCurrentContent() { + // Native page or content view should always be at index 0. + if (getChildCount() > 1) removeViewAt(CONTENT_INDEX); + } + private static class SnackbarAwareBehavior extends CoordinatorLayout.Behavior<TabContentViewParent> { @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarControlContainer.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarControlContainer.java index 87227e2..2a5b580 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarControlContainer.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarControlContainer.java
@@ -8,6 +8,7 @@ import android.graphics.Canvas; import android.graphics.PorterDuff; import android.graphics.Rect; +import android.graphics.Region; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; @@ -16,6 +17,7 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.compositor.layouts.eventfilter.EdgeSwipeHandler; import org.chromium.chrome.browser.contextualsearch.SwipeRecognizer; +import org.chromium.chrome.browser.util.ViewUtils; import org.chromium.chrome.browser.widget.ClipDrawableProgressBar.DrawingInfo; import org.chromium.chrome.browser.widget.ControlContainer; import org.chromium.chrome.browser.widget.ToolbarProgressBar; @@ -133,6 +135,12 @@ protected boolean isReadyForCapture() { return mReadyForBitmapCapture; } + + @Override + public boolean gatherTransparentRegion(Region region) { + ViewUtils.gatherTransparentRegionsForOpaqueView(this, region); + return true; + } } private static class ToolbarViewResourceAdapter extends ViewResourceAdapter {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java index eb4eb4e..1cd6bba1d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
@@ -42,8 +42,6 @@ private static final String HERB_EXPERIMENT_NAME = "TabManagementExperiment"; private static final String HERB_EXPERIMENT_FLAVOR_PARAM = "type"; - public static final String MERGE_TABS_FLAG = "multi-instance-merge-tabs"; - private static Boolean sHasGoogleAccountAuthenticator; private static Boolean sHasRecognitionIntentHandler; private static Boolean sDocumentModeDisabled; @@ -262,8 +260,7 @@ * @return True if tab model merging for Android N+ is enabled. */ public static boolean isTabModelMergingEnabled() { - return Build.VERSION.SDK_INT > Build.VERSION_CODES.M - && CommandLine.getInstance().hasSwitch(MERGE_TABS_FLAG); + return Build.VERSION.SDK_INT > Build.VERSION_CODES.M; } private static native void nativeSetDocumentModeEnabled(boolean enabled);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/util/ViewUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/util/ViewUtils.java index da29da5..c612cbe 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/util/ViewUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/util/ViewUtils.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser.util; import android.graphics.Canvas; +import android.graphics.Region; import android.view.View; import android.view.ViewGroup; @@ -12,6 +13,8 @@ * View-related utility methods. */ public class ViewUtils { + private static final int[] sLocationTmp = new int[2]; + /** * Invalidates a view and all of its descendants. */ @@ -76,4 +79,17 @@ childView = (View) childView.getParent(); } } + + /** + * Helper for overriding {@link View#gatherTransparentRegions()} for views that are fully opaque + * and have children extending beyond their bounds. If the transparent region optimization is + * turned on (which is the case whenever the view hierarchy contains a SurfaceView somewhere), + * the children might otherwise confuse the SurfaceFlinger. + */ + public static void gatherTransparentRegionsForOpaqueView(View view, Region region) { + view.getLocationInWindow(sLocationTmp); + region.op(sLocationTmp[0], sLocationTmp[1], + sLocationTmp[0] + view.getRight() - view.getLeft(), + sLocationTmp[1] + view.getBottom() - view.getTop(), Region.Op.DIFFERENCE); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstaller.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstaller.java index 86aa4f5..fd0629e9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstaller.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstaller.java
@@ -4,17 +4,25 @@ package org.chromium.chrome.browser.webapps; +import android.content.ActivityNotFoundException; import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.provider.Settings; import org.chromium.base.ContextUtils; +import org.chromium.base.Log; import org.chromium.base.annotations.CalledByNative; -import org.chromium.chrome.browser.ChromeApplication; + +import java.io.File; /** * Java counterpart to webapk_installer.h * Contains functionality to install WebAPKs. */ -public abstract class WebApkInstaller { +public class WebApkInstaller { + private static final String TAG = "WebApkInstaller"; + /** * Installs a WebAPK. * @param filePath File to install. @@ -22,16 +30,40 @@ * @return True if the install was started. A "true" return value does not guarantee that the * install succeeds. */ - public abstract boolean installAsync(String filePath, String packageName); - @CalledByNative static boolean installAsyncFromNative(String filePath, String packageName) { - Context context = ContextUtils.getApplicationContext(); - WebApkInstaller apkInstaller = ((ChromeApplication) context).createWebApkInstaller(); - if (apkInstaller == null) { + if (!installingFromUnknownSourcesAllowed()) { + Log.e(TAG, + "WebAPK install failed because installation from unknown sources is disabled."); return false; } - apkInstaller.installAsync(filePath, packageName); + if (!new File(filePath).exists()) { + return false; + } + Intent intent = new Intent(Intent.ACTION_VIEW); + Uri fileUri = Uri.fromFile(new File(filePath)); + intent.setDataAndType(fileUri, "application/vnd.android.package-archive"); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + ContextUtils.getApplicationContext().startActivity(intent); + } catch (ActivityNotFoundException e) { + return false; + } return true; } + + /** + * Returns whether the user has enabled installing apps from sources other than the Google Play + * Store. + */ + private static boolean installingFromUnknownSourcesAllowed() { + Context context = ContextUtils.getApplicationContext(); + try { + return Settings.Secure.getInt( + context.getContentResolver(), Settings.Secure.INSTALL_NON_MARKET_APPS) + == 1; + } catch (Settings.SettingNotFoundException e) { + return false; + } + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableItemView.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableItemView.java index ca66a34..01a6f61 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableItemView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableItemView.java
@@ -22,13 +22,13 @@ * initially established via long-press. If a selection is already established, clicking on the item * will toggle its selection. * - * @param <E> The type of the unique identifier for this SelectableItem. + * @param <E> The type of the item associated with this SelectableItemView. */ public abstract class SelectableItemView<E> extends FrameLayout implements Checkable, OnClickListener, OnLongClickListener, SelectionObserver<E> { private SelectionDelegate<E> mSelectionDelegate; private SelectableItemHighlightView mHighlightView; - private E mId; + private E mItem; /** * Constructor for inflating from XML. @@ -60,11 +60,11 @@ } /** - * @param id The unique identifier for this SelectableItem. + * @param item The item associated with this SelectableItemView. */ - public void setId(E id) { - mId = id; - setChecked(mSelectionDelegate.isItemSelected(id)); + public void setItem(E item) { + mItem = item; + setChecked(mSelectionDelegate.isItemSelected(item)); } // FrameLayout implementations. @@ -83,7 +83,7 @@ protected void onAttachedToWindow() { super.onAttachedToWindow(); if (mSelectionDelegate != null) { - setChecked(mSelectionDelegate.isItemSelected(mId)); + setChecked(mSelectionDelegate.isItemSelected(mItem)); } } @@ -109,7 +109,7 @@ @Override public boolean onLongClick(View view) { assert view == this; - boolean checked = mSelectionDelegate.toggleSelectionForItem(mId); + boolean checked = mSelectionDelegate.toggleSelectionForItem(mItem); setChecked(checked); return true; } @@ -133,7 +133,7 @@ // SelectionObserver implementation. @Override public void onSelectionStateChange(List<E> selectedItems) { - setChecked(mSelectionDelegate.isItemSelected(mId)); + setChecked(mSelectionDelegate.isItemSelected(mItem)); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectionDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectionDelegate.java index f66b43e0..a0b8b66 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectionDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectionDelegate.java
@@ -13,7 +13,7 @@ /** * A generic delegate used to keep track of selected items. - * @param <E> The type of the unique identifier for selectable items this delegate interacts with. + * @param <E> The type of the selectable items this delegate interacts with. */ public class SelectionDelegate<E> {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectionToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectionToolbar.java index 7cdcf73..309490fd 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectionToolbar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectionToolbar.java
@@ -28,7 +28,7 @@ * A toolbar that changes its view depending on whether a selection is established. The XML inflated * for this class must include number_roll_view.xml. * - * @param <E> The type of the unique identifier for selectable items this toolbar interacts with. + * @param <E> The type of the selectable items this toolbar interacts with. */ public class SelectionToolbar<E> extends Toolbar implements SelectionObserver<E>, OnClickListener { /** No navigation button is displayed. **/
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni index 523cd96..64afd91 100644 --- a/chrome/android/java_sources.gni +++ b/chrome/android/java_sources.gni
@@ -315,10 +315,12 @@ "java/src/org/chromium/chrome/browser/download/DownloadSharedPreferenceEntry.java", "java/src/org/chromium/chrome/browser/download/DownloadSnackbarController.java", "java/src/org/chromium/chrome/browser/download/DownloadUmaStatsEntry.java", + "java/src/org/chromium/chrome/browser/download/DownloadUtils.java", "java/src/org/chromium/chrome/browser/download/OMADownloadHandler.java", "java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java", "java/src/org/chromium/chrome/browser/download/ui/DownloadFilter.java", "java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java", + "java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryItemWrapper.java", "java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java", "java/src/org/chromium/chrome/browser/download/ui/DownloadManagerUi.java", "java/src/org/chromium/chrome/browser/download/ui/DownloadManagerToolbar.java", @@ -541,7 +543,8 @@ "java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java", "java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsConfig.java", "java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsLauncher.java", - "java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsSource.java", + "java/src/org/chromium/chrome/browser/ntp/snippets/SuggestionsSource.java", + "java/src/org/chromium/chrome/browser/ntp/cards/ActionListItem.java", "java/src/org/chromium/chrome/browser/ntp/cards/AboveTheFoldListItem.java", "java/src/org/chromium/chrome/browser/ntp/cards/CardViewHolder.java", "java/src/org/chromium/chrome/browser/ntp/cards/DisplayStyleObserverAdapter.java", @@ -557,6 +560,7 @@ "java/src/org/chromium/chrome/browser/ntp/cards/SingleItemGroup.java", "java/src/org/chromium/chrome/browser/ntp/cards/SpacingListItem.java", "java/src/org/chromium/chrome/browser/ntp/cards/StatusListItem.java", + "java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsCategoryInfo.java", "java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java", "java/src/org/chromium/chrome/browser/offlinepages/DeviceConditions.java", "java/src/org/chromium/chrome/browser/offlinepages/BackgroundOfflinerTask.java", @@ -1058,6 +1062,7 @@ "javatests/src/org/chromium/chrome/browser/ChromeBackgroundServiceTest.java", "javatests/src/org/chromium/chrome/browser/ChromeBackupIntegrationTest.java", "javatests/src/org/chromium/chrome/browser/ContentViewFocusTest.java", + "javatests/src/org/chromium/chrome/browser/CrashTest.java", "javatests/src/org/chromium/chrome/browser/EncodingDetectionTest.java", "javatests/src/org/chromium/chrome/browser/FocusedEditableTextFieldZoomTest.java", "javatests/src/org/chromium/chrome/browser/GeolocationTest.java", @@ -1344,6 +1349,7 @@ "junit/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionControllerTest.java", "junit/src/org/chromium/chrome/browser/cookies/CanonicalCookieTest.java", "junit/src/org/chromium/chrome/browser/crash/LogcatExtractionCallableTest.java", + "junit/src/org/chromium/chrome/browser/download/DownloadSharedPreferenceEntryTest.java", "junit/src/org/chromium/chrome/browser/externalauth/ExternalAuthUtilsTest.java", "junit/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencerTest.java", "junit/src/org/chromium/chrome/browser/gcore/GoogleApiClientHelperTest.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/BluetoothChooserDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/BluetoothChooserDialogTest.java index b4fd142c..6c50bec 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/BluetoothChooserDialogTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/BluetoothChooserDialogTest.java
@@ -214,8 +214,8 @@ ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - mChooserDialog.addDevice("id-1", "Name 1"); - mChooserDialog.addDevice("id-2", "Name 2"); + mChooserDialog.addOrUpdateDevice("id-1", "Name 1"); + mChooserDialog.addOrUpdateDevice("id-2", "Name 2"); } });
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/CrashTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/CrashTest.java new file mode 100644 index 0000000..1a0b4af --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/CrashTest.java
@@ -0,0 +1,36 @@ +// 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. + +package org.chromium.chrome.browser; + +import android.test.suitebuilder.annotation.SmallTest; + +import org.chromium.base.test.util.DisabledTest; +import org.chromium.chrome.test.ChromeActivityTestCaseBase; + +/** + * The class contains a testcase that intentionally crashes. + */ +public class CrashTest extends ChromeActivityTestCaseBase<ChromeActivity> { + + public CrashTest() { + super(ChromeActivity.class); + } + + @Override + public void startMainActivity() { + // Don't launch activity automatically. + } + + /** + * Intentionally crashing the test. The testcase should be + * disabled the majority of time. + */ + @DisabledTest + @SmallTest + public void testIntentionalBrowserCrash() throws Exception { + startMainActivityFromLauncher(); + loadUrl("chrome://inducebrowsercrashforrealz"); + } +}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/InstantAppsHandlerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/InstantAppsHandlerTest.java index 634dc90..6aa05eb 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/InstantAppsHandlerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/InstantAppsHandlerTest.java
@@ -44,10 +44,7 @@ @Override public void tearDown() throws Exception { - SharedPreferences prefs = ContextUtils.getAppSharedPreferences(); - SharedPreferences.Editor editor = prefs.edit(); - editor.clear(); - editor.commit(); + ContextUtils.getAppSharedPreferences().edit().clear().apply(); super.tearDown(); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ItemChooserDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ItemChooserDialogTest.java index 696d278..5192546 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/ItemChooserDialogTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ItemChooserDialogTest.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser; import android.app.Dialog; +import android.test.MoreAsserts; import android.test.suitebuilder.annotation.SmallTest; import android.text.SpannableString; import android.view.View; @@ -132,8 +133,8 @@ assertFalse(button.isEnabled()); assertEquals(View.GONE, items.getVisibility()); - mChooserDialog.addItemToList(new ItemChooserDialog.ItemChooserRow("key", "key")); - mChooserDialog.addItemToList(new ItemChooserDialog.ItemChooserRow("key2", "key2")); + mChooserDialog.addOrUpdateItem(new ItemChooserDialog.ItemChooserRow("key", "key")); + mChooserDialog.addOrUpdateItem(new ItemChooserDialog.ItemChooserRow("key2", "key2")); // Two items showing, the empty view should be no more and the button // should now be enabled. @@ -190,8 +191,8 @@ Dialog dialog = mChooserDialog.getDialogForTesting(); assertTrue(dialog.isShowing()); - mChooserDialog.addItemToList(new ItemChooserDialog.ItemChooserRow("key", "key")); - mChooserDialog.addItemToList(new ItemChooserDialog.ItemChooserRow("key2", "key2")); + mChooserDialog.addOrUpdateItem(new ItemChooserDialog.ItemChooserRow("key", "key")); + mChooserDialog.addOrUpdateItem(new ItemChooserDialog.ItemChooserRow("key2", "key2")); // Disable one item and try to select it. mChooserDialog.setEnabled("key", false); @@ -203,7 +204,7 @@ } @SmallTest - public void testAddItemToListAndRemoveItemFromList() throws InterruptedException { + public void testAddOrUpdateItemAndRemoveItemFromList() throws InterruptedException { Dialog dialog = mChooserDialog.getDialogForTesting(); assertTrue(dialog.isShowing()); @@ -225,17 +226,30 @@ // Add item 1. ItemChooserDialog.ItemChooserRow item1 = - new ItemChooserDialog.ItemChooserRow("key1", "key1"); - mChooserDialog.addItemToList(item1); + new ItemChooserDialog.ItemChooserRow("key1", "desc1"); + mChooserDialog.addOrUpdateItem(item1); assertEquals(1, itemAdapter.getCount()); assertEquals(itemAdapter.getItem(0), item1); + // Add item 1 with different description. + ItemChooserDialog.ItemChooserRow item1_again = + new ItemChooserDialog.ItemChooserRow("key1", "desc1_again"); + mChooserDialog.addOrUpdateItem(item1_again); + assertEquals(1, itemAdapter.getCount()); + assertEquals(itemAdapter.getItem(0), item1); + // TODO(ortuno): Update item's desription and change to assertEquals. + // https://crbug.com/634366 + MoreAsserts.assertNotEqual(itemAdapter.getItem(0), item1_again); + // Add item 2. ItemChooserDialog.ItemChooserRow item2 = - new ItemChooserDialog.ItemChooserRow("key2", "key2"); - mChooserDialog.addItemToList(item2); + new ItemChooserDialog.ItemChooserRow("key2", "desc2"); + mChooserDialog.addOrUpdateItem(item2); assertEquals(2, itemAdapter.getCount()); assertEquals(itemAdapter.getItem(0), item1); + // TODO(ortuno): Update item's desription and change to assertEquals. + // https://crbug.com/634366 + MoreAsserts.assertNotEqual(itemAdapter.getItem(0), item1_again); assertEquals(itemAdapter.getItem(1), item2); mChooserDialog.setIdleState(); @@ -248,6 +262,9 @@ mChooserDialog.removeItemFromList(item2); assertEquals(1, itemAdapter.getCount()); // Make sure the remaining item is item 1. + // TODO(ortuno): Update item's desription and change to assertEquals. + // https://crbug.com/634366 + MoreAsserts.assertNotEqual(itemAdapter.getItem(0), item1_again); assertEquals(itemAdapter.getItem(0), item1); // The list should be visible with one item, it should not show @@ -285,14 +302,14 @@ // Add item 1. ItemChooserDialog.ItemChooserRow item1 = new ItemChooserDialog.ItemChooserRow("device_id_1", "same_device_name"); - mChooserDialog.addItemToList(item1); + mChooserDialog.addOrUpdateItem(item1); assertEquals(1, itemAdapter.getCount()); assertEquals(itemAdapter.getItem(0), item1); // Add item 2. ItemChooserDialog.ItemChooserRow item2 = new ItemChooserDialog.ItemChooserRow("device_id_2", "different_device_name"); - mChooserDialog.addItemToList(item2); + mChooserDialog.addOrUpdateItem(item2); assertEquals(2, itemAdapter.getCount()); assertEquals(itemAdapter.getItem(0), item1); assertEquals(itemAdapter.getItem(1), item2); @@ -300,7 +317,7 @@ // Add item 3. ItemChooserDialog.ItemChooserRow item3 = new ItemChooserDialog.ItemChooserRow("device_id_3", "same_device_name"); - mChooserDialog.addItemToList(item3); + mChooserDialog.addOrUpdateItem(item3); assertEquals(3, itemAdapter.getCount()); assertEquals(itemAdapter.getItem(0), item1); assertEquals(itemAdapter.getItem(1), item2);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java index 6820c46..7500681 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser; +import android.content.pm.ActivityInfo; import android.os.Environment; import android.test.suitebuilder.annotation.MediumTest; import android.test.suitebuilder.annotation.Smoke; @@ -176,8 +177,7 @@ @MediumTest @Feature({"Navigation"}) public void testNavigateLandscape() throws Exception { - // '0' is Landscape Mode. '1' is Portrait. - getActivity().setRequestedOrientation(0); + getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); String url = mTestServer.getURL("/chrome/test/data/android/navigate/simple.html"); String result = typeInOmniboxAndNavigate(url, "Simple"); assertEquals(expectedLocation(url), result);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/TabThemeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/TabThemeTest.java index 3e839214..3e67edf 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/TabThemeTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/TabThemeTest.java
@@ -7,6 +7,7 @@ import android.os.Environment; import android.test.suitebuilder.annotation.MediumTest; +import org.chromium.base.ThreadUtils; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Restriction; import org.chromium.chrome.browser.tab.Tab; @@ -17,6 +18,8 @@ import org.chromium.content_public.browser.WebContentsObserver; import org.chromium.net.test.EmbeddedTestServer; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; /** @@ -75,7 +78,7 @@ @MediumTest @Restriction(ChromeRestriction.RESTRICTION_TYPE_PHONE) public void testThemeColorIsCorrect() - throws InterruptedException, TimeoutException { + throws ExecutionException, InterruptedException, TimeoutException { EmbeddedTestServer testServer = EmbeddedTestServer.createAndStartFileServer( getInstrumentation().getContext(), Environment.getExternalStorageDirectory()); @@ -95,7 +98,13 @@ // Navigate to a native page from a themed page. loadUrl("chrome://newtab"); // WebContents does not set theme color for native pages, so don't wait for the call. - assertColorsEqual(tab.getNativePage().getThemeColor(), tab.getThemeColor()); + int nativePageThemeColor = ThreadUtils.runOnUiThreadBlocking(new Callable<Integer>() { + @Override + public Integer call() { + return tab.getNativePage().getThemeColor(); + } + }); + assertColorsEqual(nativePageThemeColor, tab.getThemeColor()); // Navigate to a themed page from a native page. curCallCount = themeColorHelper.getCallCount();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java index 16bd77d..548801c 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java
@@ -225,7 +225,7 @@ public boolean isSatisfied() { AppBannerManager manager = getActivity().getActivityTab().getAppBannerManager(); return mDetailsDelegate.mNumRetrieved == numExpected - && !manager.isFetcherActiveForTesting(); + && !manager.isActiveForTesting(); } }); } @@ -313,7 +313,7 @@ @Override public boolean isSatisfied() { AppBannerManager manager = getActivity().getActivityTab().getAppBannerManager(); - return !manager.isFetcherActiveForTesting(); + return !manager.isActiveForTesting(); } }); waitUntilNoInfoBarsExist(); @@ -325,7 +325,7 @@ @Override public boolean isSatisfied() { AppBannerManager manager = getActivity().getActivityTab().getAppBannerManager(); - return !manager.isFetcherActiveForTesting(); + return !manager.isActiveForTesting(); } }); waitUntilAppBannerInfoBarAppears(expectedTitle); @@ -484,7 +484,7 @@ @Override public boolean isSatisfied() { AppBannerManager manager = getActivity().getActivityTab().getAppBannerManager(); - return !manager.isFetcherActiveForTesting(); + return !manager.isActiveForTesting(); } }); waitUntilNoInfoBarsExist(); @@ -501,7 +501,7 @@ @Override public boolean isSatisfied() { AppBannerManager manager = getActivity().getActivityTab().getAppBannerManager(); - return !manager.isFetcherActiveForTesting(); + return !manager.isActiveForTesting(); } }); waitUntilAppBannerInfoBarAppears(WEB_APP_TITLE);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripTest.java index 59c22724..d3327d6 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripTest.java
@@ -8,6 +8,7 @@ import android.test.suitebuilder.annotation.LargeTest; import org.chromium.base.ThreadUtils; +import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.FlakyTest; import org.chromium.base.test.util.Restriction; @@ -636,6 +637,7 @@ * Test that selecting a tab that isn't currently visible causes the ScrollingStripStacker * to scroll to make it visible. */ + @DisabledTest(message = "crbug.com/635903") @LargeTest @Restriction(ChromeRestriction.RESTRICTION_TYPE_TABLET) @Feature({"TabStrip"})
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java index 57175d4..65b85df 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java
@@ -139,6 +139,7 @@ protected final String mSearchTerm; private final String mDisplayText; private final String mAlternateTerm; + private final String mMid; private final boolean mDoPreventPreload; private final int mStartAdjust; private final int mEndAdjust; @@ -155,15 +156,15 @@ * @param searchTerm The resolved search term. * @param displayText The display text. * @param alternateTerm The alternate text. + * @param mid The MID to specify a KP, or an empty string. * @param doPreventPreload Whether search preload should be prevented. * @param startAdjust The start adjustment of the selection. * @param endAdjust The end adjustment of the selection. * @param contextLanguage The language of the context determined by the server. */ FakeTapSearch(String nodeId, boolean isNetworkUnavailable, int responseCode, - String searchTerm, String displayText, String alternateTerm, - boolean doPreventPreload, int startAdjust, int endAdjust, - String contextLanguage) { + String searchTerm, String displayText, String alternateTerm, String mid, + boolean doPreventPreload, int startAdjust, int endAdjust, String contextLanguage) { super(nodeId); mIsNetworkUnavailable = isNetworkUnavailable; @@ -171,6 +172,7 @@ mSearchTerm = searchTerm; mDisplayText = displayText; mAlternateTerm = alternateTerm; + mMid = mid; mDoPreventPreload = doPreventPreload; mStartAdjust = startAdjust; mEndAdjust = endAdjust; @@ -244,10 +246,9 @@ @Override public void run() { if (!mDidFinishResolution) { - handleSearchTermResolutionResponse( - mIsNetworkUnavailable, mResponseCode, mSearchTerm, mDisplayText, - mAlternateTerm, mDoPreventPreload, mStartAdjust, mEndAdjust, - mContextLanguage); + handleSearchTermResolutionResponse(mIsNetworkUnavailable, mResponseCode, + mSearchTerm, mDisplayText, mAlternateTerm, mMid, mDoPreventPreload, + mStartAdjust, mEndAdjust, mContextLanguage); mActiveFakeTapSearch = null; mDidFinishResolution = true; @@ -272,16 +273,17 @@ * @param searchTerm * @param displayText * @param alternateTerm + * @param mid * @param doPreventPreload * @param startAdjust * @param endAdjust * @param contextLanguage */ FakeSlowResolveSearch(String nodeId, boolean isNetworkUnavailable, int responseCode, - String searchTerm, String displayText, String alternateTerm, + String searchTerm, String displayText, String alternateTerm, String mid, boolean doPreventPreload, int startAdjust, int endAdjust, String contextLanguage) { super(nodeId, isNetworkUnavailable, responseCode, searchTerm, displayText, - alternateTerm, doPreventPreload, startAdjust, endAdjust, contextLanguage); + alternateTerm, mid, doPreventPreload, startAdjust, endAdjust, contextLanguage); } @Override @@ -501,10 +503,11 @@ @Override public void handleSearchTermResolutionResponse(boolean isNetworkUnavailable, int responseCode, - String searchTerm, String displayText, String alternateTerm, boolean doPreventPreload, - int selectionStartAdjust, int selectionEndAdjust, String contextLanguage) { + String searchTerm, String displayText, String alternateTerm, String mid, + boolean doPreventPreload, int selectionStartAdjust, int selectionEndAdjust, + String contextLanguage) { mBaseManager.handleSearchTermResolutionResponse(isNetworkUnavailable, responseCode, - searchTerm, displayText, alternateTerm, doPreventPreload, selectionStartAdjust, + searchTerm, displayText, alternateTerm, mid, doPreventPreload, selectionStartAdjust, selectionEndAdjust, contextLanguage); } @@ -537,17 +540,17 @@ registerFakeLongPressSearch(new FakeLongPressSearch("term", "Term")); registerFakeLongPressSearch(new FakeLongPressSearch("resolution", "Resolution")); - registerFakeTapSearch(new FakeTapSearch("search", false, 200, - "Search", "Search", "alternate-term", false, 0, 0, "")); - registerFakeTapSearch(new FakeTapSearch("term", false, 200, - "Term", "Term", "alternate-term", false, 0, 0, "")); - registerFakeTapSearch(new FakeTapSearch("resolution", false, 200, - "Resolution", "Resolution", "alternate-term", false, 0, 0, "")); - registerFakeTapSearch(new FakeTapSearch("german", false, 200, - "Deutsche", "Deutsche", "alternate-term", false, 0, 0, "de")); + registerFakeTapSearch(new FakeTapSearch( + "search", false, 200, "Search", "Search", "alternate-term", "", false, 0, 0, "")); + registerFakeTapSearch(new FakeTapSearch( + "term", false, 200, "Term", "Term", "alternate-term", "", false, 0, 0, "")); + registerFakeTapSearch(new FakeTapSearch("resolution", false, 200, "Resolution", + "Resolution", "alternate-term", "", false, 0, 0, "")); + registerFakeTapSearch(new FakeTapSearch("german", false, 200, "Deutsche", "Deutsche", + "alternate-term", "", false, 0, 0, "de")); registerFakeSlowResolveSearch(new FakeSlowResolveSearch( - "search", false, 200, "Search", "Search", "alternate-term", false, 0, 0, "")); + "search", false, 200, "Search", "Search", "alternate-term", "", false, 0, 0, "")); } /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java index 7718d1a..c6707dcd 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
@@ -76,6 +76,7 @@ /** * Tests the Contextual Search Manager using instrumentation tests. */ +@CommandLineFlags.Add(ContextualSearchFieldTrial.SUPPRESSION_TAPS + "=1000") public class ContextualSearchManagerTest extends ChromeActivityTestCaseBase<ChromeActivity> { private static final String TEST_PAGE = @@ -320,20 +321,21 @@ private final String mSearchTerm; private final String mDisplayText; private final String mAlternateTerm; + private final String mMid; private final boolean mDoPreventPreload; private final int mStartAdjust; private final int mEndAdjust; private final String mContextLanguage; public FakeResponseOnMainThread(boolean isNetworkUnavailable, int responseCode, - String searchTerm, String displayText, String alternateTerm, - boolean doPreventPreload, int startAdjust, int endAdjudst, - String contextLanguage) { + String searchTerm, String displayText, String alternateTerm, String mid, + boolean doPreventPreload, int startAdjust, int endAdjudst, String contextLanguage) { mIsNetworkUnavailable = isNetworkUnavailable; mResponseCode = responseCode; mSearchTerm = searchTerm; mDisplayText = displayText; mAlternateTerm = alternateTerm; + mMid = mid; mDoPreventPreload = doPreventPreload; mStartAdjust = startAdjust; mEndAdjust = endAdjudst; @@ -343,8 +345,8 @@ @Override public void run() { mFakeServer.handleSearchTermResolutionResponse(mIsNetworkUnavailable, mResponseCode, - mSearchTerm, mDisplayText, mAlternateTerm, mDoPreventPreload, mStartAdjust, - mEndAdjust, mContextLanguage); + mSearchTerm, mDisplayText, mAlternateTerm, mMid, mDoPreventPreload, + mStartAdjust, mEndAdjust, mContextLanguage); } } @@ -355,7 +357,7 @@ private void fakeResponse(boolean isNetworkUnavailable, int responseCode, String searchTerm, String displayText, String alternateTerm, boolean doPreventPreload) { fakeResponse(isNetworkUnavailable, responseCode, searchTerm, displayText, alternateTerm, - doPreventPreload, 0, 0, ""); + null, doPreventPreload, 0, 0, ""); } /** @@ -363,11 +365,11 @@ * {@See ContextualSearchManager#handleSearchTermResolutionResponse}. */ private void fakeResponse(boolean isNetworkUnavailable, int responseCode, String searchTerm, - String displayText, String alternateTerm, boolean doPreventPreload, int startAdjust, - int endAdjust, String contextLanguage) { + String displayText, String alternateTerm, String mid, boolean doPreventPreload, + int startAdjust, int endAdjust, String contextLanguage) { if (mFakeServer.getSearchTermRequested() != null) { getInstrumentation().runOnMainSync(new FakeResponseOnMainThread(isNetworkUnavailable, - responseCode, searchTerm, displayText, alternateTerm, doPreventPreload, + responseCode, searchTerm, displayText, alternateTerm, mid, doPreventPreload, startAdjust, endAdjust, contextLanguage)); } } @@ -2081,7 +2083,7 @@ waitForPanelToPeek(); fakeResponse(false, 200, "Intelligence", "United States Intelligence", "alternate-term", - false, -14, 0, ""); + null, false, -14, 0, ""); waitForSelectionToBe("United States Intelligence"); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequestTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequestTest.java index 7351893..74d977127 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequestTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequestTest.java
@@ -28,9 +28,9 @@ getInstrumentation().runOnMainSync(new Runnable() { @Override public void run() { - mRequest = new ContextualSearchRequest("barack obama", "barack", true); + mRequest = new ContextualSearchRequest("barack obama", "barack", "", true); mNormalPriorityOnlyRequest = - new ContextualSearchRequest("woody allen", "allen", false); + new ContextualSearchRequest("woody allen", "allen", "", false); } }); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java index 453957d6..aedac95 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java
@@ -44,12 +44,12 @@ */ private static class MockContextualSearchRequest extends ContextualSearchRequest { public MockContextualSearchRequest(String term, String altTerm, boolean prefetch) { - super(term, altTerm, prefetch); + super(term, altTerm, "", prefetch); } @Override - protected Uri getUriTemplate(String query, @Nullable String alternateTerm, - boolean shouldPrefetch) { + protected Uri getUriTemplate( + String query, @Nullable String alternateTerm, String mid, boolean shouldPrefetch) { return Uri.parse(""); } } @@ -94,12 +94,13 @@ @Override public void startSearchTermResolutionRequest(String selection) { // Skip native calls and immediately "resolve" the search term. - onSearchTermResolutionResponse(true, 200, selection, selection, "", false, 0, 10, ""); + onSearchTermResolutionResponse( + true, 200, selection, selection, "", "", false, 0, 10, ""); } @Override - protected ContextualSearchRequest createContextualSearchRequest(String query, - String altTerm, boolean shouldPrefetch) { + protected ContextualSearchRequest createContextualSearchRequest( + String query, String altTerm, String mid, boolean shouldPrefetch) { return new MockContextualSearchRequest(query, altTerm, shouldPrefetch); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java index b38a2d0..01bf5655 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java
@@ -140,8 +140,10 @@ DownloadResumptionScheduler.setDownloadResumptionScheduler(scheduler); setupService(); Set<String> notifications = new HashSet<String>(); - notifications.add(new DownloadSharedPreferenceEntry(1, false, true, - UUID.randomUUID().toString(), "test1").getSharedPreferenceString()); + notifications.add( + new DownloadSharedPreferenceEntry(1, false, true, UUID.randomUUID().toString(), + "test1", DownloadSharedPreferenceEntry.ITEM_TYPE_DOWNLOAD) + .getSharedPreferenceString()); SharedPreferences sharedPrefs = ContextUtils.getAppSharedPreferences(); SharedPreferences.Editor editor = sharedPrefs.edit(); editor.putStringSet( @@ -183,10 +185,14 @@ Context mockContext = new AdvancedMockContext(getSystemContext()); getService().setContext(mockContext); Set<String> notifications = new HashSet<String>(); - notifications.add(new DownloadSharedPreferenceEntry(1, false, true, - UUID.randomUUID().toString(), "test1").getSharedPreferenceString()); - notifications.add(new DownloadSharedPreferenceEntry(2, false, true, - UUID.randomUUID().toString(), "test2").getSharedPreferenceString()); + notifications.add( + new DownloadSharedPreferenceEntry(1, false, true, UUID.randomUUID().toString(), + "test1", DownloadSharedPreferenceEntry.ITEM_TYPE_DOWNLOAD) + .getSharedPreferenceString()); + notifications.add( + new DownloadSharedPreferenceEntry(2, false, true, UUID.randomUUID().toString(), + "test2", DownloadSharedPreferenceEntry.ITEM_TYPE_DOWNLOAD) + .getSharedPreferenceString()); SharedPreferences sharedPrefs = ContextUtils.getAppSharedPreferences(); SharedPreferences.Editor editor = sharedPrefs.edit(); @@ -213,11 +219,13 @@ getService().setContext(mockContext); Set<String> notifications = new HashSet<String>(); String guid1 = UUID.randomUUID().toString(); - notifications.add(new DownloadSharedPreferenceEntry(3, false, true, guid1, "success") - .getSharedPreferenceString()); + notifications.add(new DownloadSharedPreferenceEntry(3, false, true, guid1, "success", + DownloadSharedPreferenceEntry.ITEM_TYPE_DOWNLOAD) + .getSharedPreferenceString()); String guid2 = UUID.randomUUID().toString(); - notifications.add(new DownloadSharedPreferenceEntry(4, false, true, guid2, "failed") - .getSharedPreferenceString()); + notifications.add(new DownloadSharedPreferenceEntry(4, false, true, guid2, "failed", + DownloadSharedPreferenceEntry.ITEM_TYPE_DOWNLOAD) + .getSharedPreferenceString()); SharedPreferences sharedPrefs = ContextUtils.getAppSharedPreferences(); SharedPreferences.Editor editor = sharedPrefs.edit(); editor.putStringSet( @@ -277,11 +285,13 @@ getService().setContext(mockContext); Set<String> notifications = new HashSet<String>(); String guid1 = UUID.randomUUID().toString(); - notifications.add(new DownloadSharedPreferenceEntry(3, false, false, guid1, "success") - .getSharedPreferenceString()); + notifications.add(new DownloadSharedPreferenceEntry(3, false, false, guid1, "success", + DownloadSharedPreferenceEntry.ITEM_TYPE_DOWNLOAD) + .getSharedPreferenceString()); String guid2 = UUID.randomUUID().toString(); - notifications.add(new DownloadSharedPreferenceEntry(4, false, true, guid2, "failed") - .getSharedPreferenceString()); + notifications.add(new DownloadSharedPreferenceEntry(4, false, true, guid2, "failed", + DownloadSharedPreferenceEntry.ITEM_TYPE_DOWNLOAD) + .getSharedPreferenceString()); SharedPreferences sharedPrefs = ContextUtils.getAppSharedPreferences(); SharedPreferences.Editor editor = sharedPrefs.edit(); editor.putStringSet( @@ -322,8 +332,9 @@ getService().setContext(mockContext); Set<String> notifications = new HashSet<String>(); String uuid = UUID.randomUUID().toString(); - notifications.add(new DownloadSharedPreferenceEntry(1, true, true, uuid, "test1") - .getSharedPreferenceString()); + notifications.add(new DownloadSharedPreferenceEntry(1, true, true, uuid, "test1", + DownloadSharedPreferenceEntry.ITEM_TYPE_DOWNLOAD) + .getSharedPreferenceString()); SharedPreferences sharedPrefs = ContextUtils.getAppSharedPreferences(); SharedPreferences.Editor editor = sharedPrefs.edit(); @@ -339,31 +350,6 @@ @SmallTest @Feature({"Download"}) - public void testParseDownloadNotifications() { - String uuid = UUID.randomUUID().toString(); - String notification = - DownloadSharedPreferenceEntry.VERSION + ",1,0,1," + uuid + ",test.pdf"; - DownloadSharedPreferenceEntry entry = - DownloadSharedPreferenceEntry.parseFromString(notification); - assertEquals(1, entry.notificationId); - assertEquals("test.pdf", entry.fileName); - assertFalse(entry.isOffTheRecord); - assertEquals(uuid, entry.downloadGuid); - - notification = DownloadSharedPreferenceEntry.VERSION + ",2,1,1," + uuid + ",test,2.pdf"; - entry = DownloadSharedPreferenceEntry.parseFromString(notification); - assertEquals(2, entry.notificationId); - assertEquals("test,2.pdf", entry.fileName); - assertTrue(entry.isOffTheRecord); - assertEquals(uuid, entry.downloadGuid); - - notification = "1,2,1,1," + uuid + ",test,2.pdf"; - entry = DownloadSharedPreferenceEntry.parseFromString(notification); - assertFalse(entry.isOffTheRecord); - } - - @SmallTest - @Feature({"Download"}) public void testFormatRemainingTime() { Context context = getSystemContext().getApplicationContext(); assertEquals("0 secs left", DownloadNotificationService.formatRemainingTime(context, 0));
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java index 395a2b8..6939474 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java
@@ -930,7 +930,6 @@ public void testLaunchWebApk_StayInSameWebApk() { CommandLine.getInstance().appendSwitch(ChromeSwitches.ENABLE_WEBAPK); checkUrl(WEBAPK_SCOPE + "/new.html") - .withReferrer(WEBAPK_SCOPE) .withWebApkPackageName(WEBAPK_PACKAGE_NAME) .expecting(OverrideUrlLoadingResult.NO_OVERRIDE, IGNORE); } @@ -953,7 +952,7 @@ @Override public List<ResolveInfo> queryIntentActivities(Intent intent) { - List<ResolveInfo> list = new ArrayList<ResolveInfo>(); + List<ResolveInfo> list = new ArrayList<>(); // TODO(yfriedman): We shouldn't have a separate global override just for tests - we // should mimic the appropriate intent resolution intead. if (mQueryIntentOverride != null) { @@ -1284,7 +1283,7 @@ private static class TestPackageManager extends MockPackageManager { @Override public List<ResolveInfo> queryIntentActivities(Intent intent, int flags) { - List<ResolveInfo> resolves = new ArrayList<ResolveInfo>(); + List<ResolveInfo> resolves = new ArrayList<>(); if (intent.getDataString().startsWith("market:")) { resolves.add(newResolveInfo("market", "market")); } else if (intent.getDataString().startsWith("http://m.youtube.com")
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/media/router/MockMediaRouteProvider.java b/chrome/android/javatests/src/org/chromium/chrome/browser/media/router/MockMediaRouteProvider.java index b567ee13..9b41ba0 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/media/router/MockMediaRouteProvider.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/media/router/MockMediaRouteProvider.java
@@ -177,8 +177,7 @@ if (mCloseRouteWithErrorOnSend) { mManager.onRouteClosedWithError(routeId, "Sending message failed. Closing the route."); } else { - // Sending a string enclosed by double quotes to behave like JSON.stringify(). - mManager.onMessage(routeId, "\"" + "Pong: " + message + "\""); + mManager.onMessage(routeId, "Pong: " + message); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMetricsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMetricsTest.java index 207d3bd..58c5659 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMetricsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMetricsTest.java
@@ -46,7 +46,7 @@ public void testSuccessCheckoutFunnel() throws InterruptedException, ExecutionException, TimeoutException { // Initiate a payment request. - triggerUIAndWait(mReadyToPay); + triggerUIAndWait("ccBuy", mReadyToPay); // Make sure sure that the "Initiated" and "Shown" events were logged. assertEquals(1, RecordHistogram.getHistogramValueCountForTesting( @@ -79,7 +79,7 @@ @MediumTest public void testAbortMetrics_AbortedByUser_CancelButton() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(mReadyToPay); + triggerUIAndWait("ccBuy", mReadyToPay); clickInShippingSummaryAndWait(R.id.payments_section, mReadyForInput); // Cancel the Payment Request. @@ -104,7 +104,7 @@ @MediumTest public void testAbortMetrics_AbortedByUser_XButton() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(mReadyToPay); + triggerUIAndWait("ccBuy", mReadyToPay); clickInShippingSummaryAndWait(R.id.payments_section, mReadyForInput); // Press the [X] button. @@ -122,7 +122,7 @@ @MediumTest public void testAbortMetrics_AbortedByUser_BackButton() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(mReadyToPay); + triggerUIAndWait("ccBuy", mReadyToPay); clickInShippingSummaryAndWait(R.id.payments_section, mReadyForInput); // Press the back button. @@ -147,7 +147,7 @@ @MediumTest public void testAbortMetrics_AbortedByUser_TabClosed() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(mReadyToPay); + triggerUIAndWait("ccBuy", mReadyToPay); clickInShippingSummaryAndWait(R.id.payments_section, mReadyForInput); // Press the back button. @@ -164,7 +164,7 @@ @MediumTest public void testAbortMetrics_AbortedByMerchant() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(mReadyToPay); + triggerUIAndWait("ccBuy", mReadyToPay); // Simulate an abort by the merchant. clickNodeAndWait("abort", mDismissed); @@ -182,9 +182,9 @@ @MediumTest public void testAbortMetrics_NoMatchingPaymentMethod() throws InterruptedException, ExecutionException, TimeoutException { - // Bob pay is supported but no instruments are present. - installPaymentApp(NO_INSTRUMENTS, DELAYED_RESPONSE); - triggerUIAndWait("noMatching", mShowFailed); + // Android Pay is supported but no instruments are present. + installPaymentApp("https://android.com/pay", NO_INSTRUMENTS, DELAYED_RESPONSE); + triggerUIAndWait("androidPayBuy", mShowFailed); expectResultContains(new String[] {"The payment method is not supported"}); assertOnlySpecificAbortMetricLogged( @@ -207,6 +207,39 @@ } /** + * Expect only the SELECTED_METHOD_CREDIT_CARD enum value to be logged for the + * "SelectedPaymentMethod" histogram when completing a Payment Request with a credit card. + */ + @MediumTest + public void testSelectedPaymentMethod_CreditCard() throws InterruptedException, + ExecutionException, TimeoutException { + // Complete a Payment Request with a credit card. + triggerUIAndWait("ccBuy", mReadyToPay); + clickAndWait(R.id.button_primary, mReadyForUnmaskInput); + setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", mReadyToUnmask); + clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, mDismissed); + + assertOnlySpecificSelectedPaymentMethodMetricLogged( + PaymentRequestMetrics.SELECTED_METHOD_CREDIT_CARD); + } + + /** + * Expect only the SELECTED_METHOD_ANDROID_PAY enum value to be logged for the + * "SelectedPaymentMethod" histogram when completing a Payment Request with Android Pay. + */ + @MediumTest + public void testSelectedPaymentMethod_AndroidPay() throws InterruptedException, + ExecutionException, TimeoutException { + // Complete a Payment Request with Android Pay. + installPaymentApp("https://android.com/pay", HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); + triggerUIAndWait("androidPayBuy", mReadyToPay); + clickAndWait(R.id.button_primary, mDismissed); + + assertOnlySpecificSelectedPaymentMethodMetricLogged( + PaymentRequestMetrics.SELECTED_METHOD_ANDROID_PAY); + } + + /** * Asserts that only the specified reason for abort is logged. * * @param abortReason The only bucket in the abort histogram that should have a record. @@ -218,4 +251,18 @@ "PaymentRequest.CheckoutFunnel.Aborted", i)); } } + + /** + * Asserts that only the specified selected payment method is logged. + * + * @param paymentMethod The only bucket in the selected payment method histogram that should + * have a record. + */ + private void assertOnlySpecificSelectedPaymentMethodMetricLogged(int paymentMethod) { + for (int i = 0; i < PaymentRequestMetrics.SELECTED_METHOD_MAX; ++i) { + assertEquals((i == paymentMethod ? 1 : 0), + RecordHistogram.getHistogramValueCountForTesting( + "PaymentRequest.SelectedPaymentMethod", i)); + } + } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndCardsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndCardsTest.java index 5a9b57f5..e15af20 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndCardsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndCardsTest.java
@@ -93,7 +93,7 @@ // Check the labesl of the instruments. int i = 0; if (instrumentPresence == HAVE_INSTRUMENTS) { - assertEquals("Bob Pay", getPaymentInstrumentLabel(i++)); + assertEquals("Test Pay", getPaymentInstrumentLabel(i++)); } // \u00A0\u22EF is a non-breaking space followed by a midline ellipsis. assertEquals("Visa\u00A0\u22EF1111\nJon Doe", getPaymentInstrumentLabel(i++));
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppTest.java index 7312837..b17d7e2 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppTest.java
@@ -66,7 +66,7 @@ @MediumTest public void testPaymentWithInstrumentsAppResponseAfterDismissShouldNotCrash() throws InterruptedException, ExecutionException, TimeoutException { - final BobPay app = installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); + final TestPay app = installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE); triggerUIAndWait(mReadyForInput); clickAndWait(R.id.close_button, mDismissed); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @@ -84,7 +84,7 @@ @MediumTest public void testPaymentAppNoInstrumentsResponseAfterDismissShouldNotCrash() throws InterruptedException, ExecutionException, TimeoutException { - final BobPay app = installPaymentApp(NO_INSTRUMENTS, IMMEDIATE_RESPONSE); + final TestPay app = installPaymentApp(NO_INSTRUMENTS, IMMEDIATE_RESPONSE); triggerUIAndWait(mShowFailed); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java index 242b7b4..b8768336 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java
@@ -119,6 +119,12 @@ triggerUIAndWait("buy", helper); } + protected void triggerUIAndWait(String nodeId, PaymentsCallbackHelper<PaymentRequestUI> helper) + throws InterruptedException, ExecutionException, TimeoutException { + triggerUIAndWait(nodeId, (CallbackHelper) helper); + mUI = helper.getTarget(); + } + protected void triggerUIAndWait(String nodeId, CallbackHelper helper) throws InterruptedException, ExecutionException, TimeoutException { startMainActivityWithURL(mTestFilePath); @@ -610,10 +616,25 @@ * or HAVE_INSTRUMENTS. * @param responseSpeed How quickly the app will respond to "get instruments" query. Either * IMMEDIATE_RESPONSE, DELAYED_RESPONSE, or NO_RESPONSE. - * @return The install payment app. + * @return The installed payment app. */ - protected BobPay installPaymentApp(final int instrumentPresence, final int responseSpeed) { - final BobPay app = new BobPay(instrumentPresence, responseSpeed); + protected TestPay installPaymentApp(final int instrumentPresence, final int responseSpeed) { + return installPaymentApp("https://bobpay.com", instrumentPresence, responseSpeed); + } + + /** + * Installs a payment app for testing. + * + * @param methodName The name of the payment method used in the payment app. + * @param instrumentPresence Whether the app has any payment instruments. Either NO_INSTRUMENTS + * or HAVE_INSTRUMENTS. + * @param responseSpeed How quickly the app will respond to "get instruments" query. Either + * IMMEDIATE_RESPONSE, DELAYED_RESPONSE, or NO_RESPONSE. + * @return The installed payment app. + */ + protected TestPay installPaymentApp(final String methodName, final int instrumentPresence, + final int responseSpeed) { + final TestPay app = new TestPay(methodName, instrumentPresence, responseSpeed); PaymentAppFactory.setAdditionalFactory(new PaymentAppFactoryAddition() { @Override public List<PaymentApp> create(WebContents webContents) { @@ -626,12 +647,14 @@ } /** A payment app implementation for test. */ - protected static class BobPay implements PaymentApp { + protected static class TestPay implements PaymentApp { + private final String mMethodName; private final int mInstrumentPresence; private final int mResponseSpeed; private InstrumentsCallback mCallback; - BobPay(int instrumentPresence, int responseSpeed) { + TestPay(String methodName, int instrumentPresence, int responseSpeed) { + mMethodName = methodName; mInstrumentPresence = instrumentPresence; mResponseSpeed = responseSpeed; } @@ -645,12 +668,14 @@ void respond() { final List<PaymentInstrument> instruments = new ArrayList<>(); - if (mInstrumentPresence == HAVE_INSTRUMENTS) instruments.add(new BobPayInstrument()); + if (mInstrumentPresence == HAVE_INSTRUMENTS) { + instruments.add(new TestPayInstrument(mMethodName)); + } Runnable instrumentsReady = new Runnable() { @Override public void run() { ThreadUtils.assertOnUiThread(); - mCallback.onInstrumentsReady(BobPay.this, instruments); + mCallback.onInstrumentsReady(TestPay.this, instruments); } }; if (mResponseSpeed == IMMEDIATE_RESPONSE) { @@ -663,32 +688,35 @@ @Override public Set<String> getSupportedMethodNames() { Set<String> methodNames = new HashSet<>(); - methodNames.add("https://bobpay.com"); + methodNames.add(mMethodName); return methodNames; } @Override public String getIdentifier() { - return "https://bobpay.com"; + return mMethodName; } } /** A payment instrument implementation for test. */ - private static class BobPayInstrument extends PaymentInstrument { - BobPayInstrument() { - super("https://bobpay.com", "Bob Pay", null, NO_ICON); + private static class TestPayInstrument extends PaymentInstrument { + private final String mMethodName; + + TestPayInstrument(String methodName) { + super(methodName, "Test Pay", null, NO_ICON); + mMethodName = methodName; } @Override public String getMethodName() { - return "https://bobpay.com"; + return mMethodName; } @Override public void getDetails(String merchantName, String origin, PaymentItem total, List<PaymentItem> cart, JSONObject details, DetailsCallback detailsCallback) { detailsCallback.onInstrumentDetailsReady( - "https://bobpay.com", "{\"transaction\": 1337}"); + mMethodName, "{\"transaction\": 1337}"); } @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivityTest.java index 1bf0039..14756b9 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivityTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivityTest.java
@@ -156,7 +156,7 @@ results.add(new PwsResult(url, url, null, title, desc, null)); mMockPwsClient.addPwsResults(results); mMockPwsClient.addPwsResults(results); - UrlManager.getInstance().addUrl(url); + UrlManager.getInstance().addUrl(new UrlInfo(url)); getInstrumentation().waitForIdleSync(); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/physicalweb/UrlManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/physicalweb/UrlManagerTest.java index e35cb24..64aa7de 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/physicalweb/UrlManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/physicalweb/UrlManagerTest.java
@@ -66,6 +66,22 @@ mMockPwsClient.addPwsResults(results); } + private void addUrlInfo1() { + mUrlManager.addUrl(new UrlInfo(URL1)); + } + + private void addUrlInfo2() { + mUrlManager.addUrl(new UrlInfo(URL2)); + } + + private void removeUrlInfo1() { + mUrlManager.removeUrl(new UrlInfo(URL1)); + } + + private void removeUrlInfo2() { + mUrlManager.removeUrl(new UrlInfo(URL2)); + } + private void addEmptyPwsResult() { mMockPwsClient.addPwsResults(new ArrayList<PwsResult>()); } @@ -80,14 +96,14 @@ addPwsResult2(); addPwsResult1(); addPwsResult2(); - mUrlManager.addUrl(URL1); - mUrlManager.addUrl(URL2); + addUrlInfo1(); + addUrlInfo2(); getInstrumentation().waitForIdleSync(); mUrlManager.clearAllUrls(); // Add some more URLs...this should not crash if we cleared correctly. - mUrlManager.addUrl(URL1); - mUrlManager.addUrl(URL2); + addUrlInfo1(); + addUrlInfo2(); getInstrumentation().waitForIdleSync(); List<UrlInfo> urlInfos = mUrlManager.getUrls(); assertEquals(2, urlInfos.size()); @@ -97,8 +113,8 @@ public void testClearNearbyUrlsWorks() { addPwsResult1(); addPwsResult2(); - mUrlManager.addUrl(URL1); - mUrlManager.addUrl(URL2); + addUrlInfo1(); + addUrlInfo2(); getInstrumentation().waitForIdleSync(); // Make sure that a notification was shown. @@ -128,7 +144,7 @@ public void testAddUrlWhileOnboardingMakesNotification() throws Exception { setOnboarding(); addPwsResult1(); - mUrlManager.addUrl(URL1); + addUrlInfo1(); getInstrumentation().waitForIdleSync(); // Make sure that a resolution was *not* attempted. @@ -147,7 +163,7 @@ @SmallTest public void testAddUrlNoResolutionDoesNothing() throws Exception { addEmptyPwsResult(); - mUrlManager.addUrl(URL1); + addUrlInfo1(); getInstrumentation().waitForIdleSync(); // Make sure that a resolution was attempted. @@ -169,7 +185,7 @@ @SmallTest public void testAddUrlWithResolutionMakesNotification() throws Exception { addPwsResult1(); - mUrlManager.addUrl(URL1); + addUrlInfo1(); getInstrumentation().waitForIdleSync(); // Make sure that a resolution was attempted. @@ -191,13 +207,13 @@ addPwsResult2(); // Adding one URL should fire a notification. - mUrlManager.addUrl(URL1); + addUrlInfo1(); getInstrumentation().waitForIdleSync(); assertEquals(1, mMockNotificationManagerProxy.getNotifications().size()); // Adding a second should not. mMockNotificationManagerProxy.cancelAll(); - mUrlManager.addUrl(URL2); + addUrlInfo2(); assertEquals(0, mMockNotificationManagerProxy.getNotifications().size()); } @@ -267,16 +283,16 @@ addPwsResult1(); addPwsResult2(); addPwsResult1(); - mUrlManager.addUrl(URL1); - mUrlManager.addUrl(URL2); - mUrlManager.removeUrl(URL1); + addUrlInfo1(); + addUrlInfo2(); + removeUrlInfo1(); getInstrumentation().waitForIdleSync(); // Make sure the cache is in the appropriate state assertTrue(mUrlManager.containsInAnyCache(URL1)); mMockNotificationManagerProxy.cancelAll(); - mUrlManager.addUrl(URL1); + addUrlInfo1(); getInstrumentation().waitForIdleSync(); // Make sure that no notification is shown. @@ -288,11 +304,11 @@ public void testAddUrlInCacheWithNoOthersMakesNotification() throws Exception { addPwsResult1(); addPwsResult1(); - mUrlManager.addUrl(URL1); - mUrlManager.removeUrl(URL1); + addUrlInfo1(); + removeUrlInfo1(); getInstrumentation().waitForIdleSync(); mMockNotificationManagerProxy.cancelAll(); - mUrlManager.addUrl(URL1); + addUrlInfo1(); getInstrumentation().waitForIdleSync(); // Make sure that a notification was shown. @@ -304,10 +320,10 @@ public void testAddUrlNotInCacheWithOthersMakesNotification() throws Exception { addPwsResult1(); addPwsResult2(); - mUrlManager.addUrl(URL1); + addUrlInfo1(); getInstrumentation().waitForIdleSync(); mMockNotificationManagerProxy.cancelAll(); - mUrlManager.addUrl(URL2); + addUrlInfo2(); getInstrumentation().waitForIdleSync(); // Make sure that a notification was shown. @@ -318,14 +334,14 @@ @SmallTest public void testRemoveOnlyUrlClearsNotification() throws Exception { addPwsResult1(); - mUrlManager.addUrl(URL1); + addUrlInfo1(); getInstrumentation().waitForIdleSync(); // Make sure that a notification was shown. List<NotificationEntry> notifications = mMockNotificationManagerProxy.getNotifications(); assertEquals(1, notifications.size()); - mUrlManager.removeUrl(URL1); + removeUrlInfo1(); // Make sure the URL was removed. List<UrlInfo> urls = mUrlManager.getUrls(true); @@ -339,7 +355,7 @@ @SmallTest public void testClearAllUrlsClearsNotification() throws Exception { addPwsResult1(); - mUrlManager.addUrl(URL1); + addUrlInfo1(); getInstrumentation().waitForIdleSync(); // Make sure that a notification was shown.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelMergingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelMergingTest.java index 96b1901..f1a2551 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelMergingTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelMergingTest.java
@@ -18,7 +18,6 @@ import org.chromium.base.ApplicationStatus.ActivityStateListener; import org.chromium.base.ContextUtils; import org.chromium.base.ThreadUtils; -import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.MinAndroidSdkLevel; import org.chromium.base.test.util.Restriction; @@ -28,7 +27,6 @@ import org.chromium.chrome.browser.multiwindow.MultiWindowUtilsTest; import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType; import org.chromium.chrome.browser.tabmodel.TabPersistentStoreTest.MockTabPersistentStoreObserver; -import org.chromium.chrome.browser.util.FeatureUtilities; import org.chromium.chrome.test.ChromeTabbedActivityTestBase; import org.chromium.chrome.test.util.ChromeRestriction; import org.chromium.chrome.test.util.ChromeTabUtils; @@ -42,7 +40,6 @@ */ @TargetApi(Build.VERSION_CODES.LOLLIPOP) @MinAndroidSdkLevel(24) -@CommandLineFlags.Add(FeatureUtilities.MERGE_TABS_FLAG) public class TabModelMergingTest extends ChromeTabbedActivityTestBase { private static final String TEST_URL_0 = UrlUtils.encodeHtmlDataUri("<html>test_url_0.</html>");
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreTest.java index 7b26c598..1047dfb 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreTest.java
@@ -14,7 +14,6 @@ import org.chromium.base.ContextUtils; import org.chromium.base.ThreadUtils; import org.chromium.base.test.util.AdvancedMockContext; -import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.MinAndroidSdkLevel; import org.chromium.chrome.browser.ChromeActivity; @@ -27,7 +26,6 @@ import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType; import org.chromium.chrome.browser.tabmodel.TabPersistentStore.TabPersistentStoreObserver; import org.chromium.chrome.browser.tabmodel.TestTabModelDirectory.TabModelMetaDataInfo; -import org.chromium.chrome.browser.util.FeatureUtilities; import org.chromium.chrome.browser.widget.OverviewListLayout; import org.chromium.chrome.test.util.browser.tabmodel.MockTabModelSelector; import org.chromium.content.browser.test.NativeLibraryTestBase; @@ -605,7 +603,6 @@ @SmallTest @Feature({"TabPersistentStore", "MultiWindow"}) @MinAndroidSdkLevel(24) - @CommandLineFlags.Add(FeatureUtilities.MERGE_TABS_FLAG) public void testDuplicateTabIdsOnColdStart() throws Exception { final TabModelMetaDataInfo info = TestTabModelDirectory.TAB_MODEL_METADATA_V5_NO_M18;
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionControllerTest.java index c061452..e4c1590 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionControllerTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionControllerTest.java
@@ -51,16 +51,26 @@ @Test @Feature({"ContextualSearchSelectionController"}) - public void testUrlWithAnchorAndNoSchema() { + public void testUrlWithNoScheme() { String testSentence = "This is a sentence about example.com/foo#bar."; // Select "foo". assertEquals("foo", testSentence.subSequence(37, 40)); - assertTrue(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 37, 40)); + assertFalse(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 37, 40)); + } + + @Test + @Feature({"ContextualSearchSelectionController"}) + public void testUrlWithAnchor() { + String testSentence = "This is a sentence about http://example.com/foo#bar."; + + // Select "foo". + assertEquals("foo", testSentence.subSequence(44, 47)); + assertTrue(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 44, 47)); // Select "bar". - assertEquals("bar", testSentence.subSequence(41, 44)); - assertTrue(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 41, 44)); + assertEquals("bar", testSentence.subSequence(48, 51)); + assertTrue(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 48, 51)); // Select "This". assertEquals("This", testSentence.subSequence(0, 4)); @@ -70,11 +80,11 @@ @Test @Feature({"ContextualSearchSelectionController"}) public void testUrlSurroundedByParens() { - String testSentence = "This is another sentence (example.com)."; + String testSentence = "This is another sentence (http://example.com)."; // Select "com". - assertEquals("com", testSentence.subSequence(34, 37)); - assertTrue(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 34, 37)); + assertEquals("com", testSentence.subSequence(41, 44)); + assertTrue(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 41, 44)); // Select "(". assertEquals("(", testSentence.subSequence(25, 26)); @@ -103,16 +113,36 @@ @Test @Feature({"ContextualSearchSelectionController"}) + public void testUrlWithFtpSchema() { + String testSentence = "ftp://some_text_file.txt"; + + // Select "text". + assertEquals("text", testSentence.subSequence(11, 15)); + assertTrue(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 11, 15)); + } + + @Test + @Feature({"ContextualSearchSelectionController"}) + public void testUrlWithSshSchema() { + String testSentence = "ssh://some_text_file.txt"; + + // Select "text". + assertEquals("text", testSentence.subSequence(11, 15)); + assertTrue(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 11, 15)); + } + + @Test + @Feature({"ContextualSearchSelectionController"}) public void testUrlWithPortAndQuery() { - String testSentence = "website.com:8080/html?query"; + String testSentence = "http://website.com:8080/html?query"; // Select "8080". - assertEquals("8080", testSentence.subSequence(12, 16)); - assertTrue(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 12, 16)); + assertEquals("8080", testSentence.subSequence(19, 23)); + assertTrue(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 19, 23)); // Select "query". - assertEquals("query", testSentence.subSequence(22, 27)); - assertTrue(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 22, 27)); + assertEquals("query", testSentence.subSequence(29, 34)); + assertTrue(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 29, 34)); } @Test @@ -122,7 +152,7 @@ // Select "0". assertEquals("0", testSentence.subSequence(4, 5)); - assertTrue(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 4, 5)); + assertFalse(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 4, 5)); } @Test @@ -142,7 +172,6 @@ // Select "syntax". assertEquals("weird", testSentence.subSequence(35, 40)); - // The selection looks like a URL, even though it's not. - assertTrue(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 35, 40)); + assertFalse(ContextualSearchSelectionController.isSelectionPartOfUrl(testSentence, 35, 40)); } }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/download/DownloadSharedPreferenceEntryTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/download/DownloadSharedPreferenceEntryTest.java new file mode 100644 index 0000000..a177efd8 --- /dev/null +++ b/chrome/android/junit/src/org/chromium/chrome/browser/download/DownloadSharedPreferenceEntryTest.java
@@ -0,0 +1,289 @@ +// 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. + +package org.chromium.chrome.browser.download; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.chromium.base.BaseChromiumApplication; +import org.chromium.base.test.shadows.ShadowMultiDex; +import org.chromium.base.test.util.Feature; +import org.chromium.testing.local.LocalRobolectricTestRunner; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +import java.util.UUID; + +/** Unit tests for {@link DownloadSharedPreferenceEntry}. */ +@RunWith(LocalRobolectricTestRunner.class) +@Config(manifest = Config.NONE, application = BaseChromiumApplication.class, + shadows = {ShadowMultiDex.class}) +public class DownloadSharedPreferenceEntryTest { + private String newUUID() { + return UUID.randomUUID().toString(); + } + + @Test + @Feature({"Download"}) + public void testParseFromStringVersion1() { + String uuid = newUUID(); + String notificationString = "1,2,1,1," + uuid + ",test,2.pdf"; + DownloadSharedPreferenceEntry entry = + DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(2, entry.notificationId); + assertFalse(entry.isOffTheRecord); + assertTrue(entry.canDownloadWhileMetered); + assertEquals(uuid, entry.downloadGuid); + assertEquals("test,2.pdf", entry.fileName); + assertEquals(DownloadSharedPreferenceEntry.ITEM_TYPE_DOWNLOAD, entry.itemType); + + String uuid2 = newUUID(); + notificationString = "1,3,0,0," + uuid2 + ",test,4.pdf"; + entry = DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(3, entry.notificationId); + assertTrue(entry.isOffTheRecord); + assertFalse(entry.canDownloadWhileMetered); + assertEquals(uuid2, entry.downloadGuid); + assertEquals("test,4.pdf", entry.fileName); + assertEquals(DownloadSharedPreferenceEntry.ITEM_TYPE_DOWNLOAD, entry.itemType); + } + + @Test + @Feature({"Download"}) + public void testParseFromStringVersion2() { + String uuid = newUUID(); + String notificationString = "2,2,0,1," + uuid + ",test,2.pdf"; + DownloadSharedPreferenceEntry entry = + DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(2, entry.notificationId); + assertFalse(entry.isOffTheRecord); + assertTrue(entry.canDownloadWhileMetered); + assertEquals(uuid, entry.downloadGuid); + assertEquals("test,2.pdf", entry.fileName); + assertEquals(DownloadSharedPreferenceEntry.ITEM_TYPE_DOWNLOAD, entry.itemType); + + String uuid2 = newUUID(); + notificationString = "2,3,1,0," + uuid2 + ",test,4.pdf"; + entry = DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(3, entry.notificationId); + assertTrue(entry.isOffTheRecord); + assertFalse(entry.canDownloadWhileMetered); + assertEquals(uuid2, entry.downloadGuid); + assertEquals("test,4.pdf", entry.fileName); + assertEquals(DownloadSharedPreferenceEntry.ITEM_TYPE_DOWNLOAD, entry.itemType); + } + + @Test + @Feature({"Download"}) + public void testParseFromStringVersion3_Download() { + String uuid = newUUID(); + String notificationString = "3,2,1,0,1," + uuid + ",test,2.pdf"; + DownloadSharedPreferenceEntry entry = + DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(2, entry.notificationId); + assertEquals(DownloadSharedPreferenceEntry.ITEM_TYPE_DOWNLOAD, entry.itemType); + assertFalse(entry.isOffTheRecord); + assertTrue(entry.canDownloadWhileMetered); + assertEquals(uuid, entry.downloadGuid); + assertEquals("test,2.pdf", entry.fileName); + + String uuid2 = newUUID(); + notificationString = "3,3,1,1,0," + uuid2 + ",test,4.pdf"; + entry = DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(3, entry.notificationId); + assertEquals(DownloadSharedPreferenceEntry.ITEM_TYPE_DOWNLOAD, entry.itemType); + assertTrue(entry.isOffTheRecord); + assertFalse(entry.canDownloadWhileMetered); + assertEquals(uuid2, entry.downloadGuid); + assertEquals("test,4.pdf", entry.fileName); + } + + @Test + @Feature({"Download"}) + public void testParseFromStringVersion3_OfflinePage() { + String uuid = newUUID(); + String notificationString = "3,2,2,0,1," + uuid + ",test,2.pdf"; + DownloadSharedPreferenceEntry entry = + DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(2, entry.notificationId); + assertEquals(DownloadSharedPreferenceEntry.ITEM_TYPE_OFFLINE_PAGE, entry.itemType); + assertFalse(entry.isOffTheRecord); + assertTrue(entry.canDownloadWhileMetered); + assertEquals(uuid, entry.downloadGuid); + assertEquals("test,2.pdf", entry.fileName); + + String uuid2 = newUUID(); + notificationString = "3,3,2,1,0," + uuid2 + ",test,4.pdf"; + entry = DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(3, entry.notificationId); + assertEquals(DownloadSharedPreferenceEntry.ITEM_TYPE_OFFLINE_PAGE, entry.itemType); + assertTrue(entry.isOffTheRecord); + assertFalse(entry.canDownloadWhileMetered); + assertEquals(uuid2, entry.downloadGuid); + assertEquals("test,4.pdf", entry.fileName); + } + + @Test + @Feature({"Download"}) + public void testGetSharedPreferencesString() { + String uuid = newUUID(); + String notificationString = "3,2,2,0,1," + uuid + ",test,2.pdf"; + DownloadSharedPreferenceEntry entry = + DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(notificationString, entry.getSharedPreferenceString()); + + String uuid2 = newUUID(); + notificationString = "3,3,2,1,0," + uuid2 + ",test,4.pdf"; + entry = DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(notificationString, entry.getSharedPreferenceString()); + } + + @Test + @Feature({"Download"}) + public void testParseFromStringInvalidVersion() { + String uuid = newUUID(); + // Version 0 is invalid. + String notificationString = "0,2,0,1," + uuid + ",test,2.pdf"; + DownloadSharedPreferenceEntry entry = + DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(DownloadSharedPreferenceEntry.INVALID_ENTRY, entry); + + // Version 4 is invalid. + notificationString = "4,2,0,1," + uuid + ",test,2.pdf"; + entry = DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(DownloadSharedPreferenceEntry.INVALID_ENTRY, entry); + + // Version number is missing. + notificationString = ",2,2,0,1," + uuid + ",test,2.pdf"; + entry = DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(DownloadSharedPreferenceEntry.INVALID_ENTRY, entry); + + // Not possible to parse version number. + notificationString = "xxx,2,2,0,1," + uuid + ",test,2.pdf"; + entry = DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(DownloadSharedPreferenceEntry.INVALID_ENTRY, entry); + } + + @Test + @Feature({"Download"}) + public void testParseFromStringNotEnoughValues() { + String uuid = newUUID(); + // Version 1 requires at least 6. + String notificationString = "1,2,0," + uuid + ",test,2.pdf"; + DownloadSharedPreferenceEntry entry = + DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(DownloadSharedPreferenceEntry.INVALID_ENTRY, entry); + + // Version 2 requires at least 6. + notificationString = "2,2,0," + uuid + ",test,2.pdf"; + entry = DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(DownloadSharedPreferenceEntry.INVALID_ENTRY, entry); + + // Version 3 requires at least 7. + notificationString = "3,2,2,0," + uuid + ",test,2.pdf"; + entry = DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(DownloadSharedPreferenceEntry.INVALID_ENTRY, entry); + } + + @Test + @Feature({"Download"}) + public void testParseFromStringFailedToParseNotificationId() { + String uuid = newUUID(); + // Notification ID missing in version 1. + String notificationString = "1,,1,0," + uuid + ",test,2.pdf"; + DownloadSharedPreferenceEntry entry = + DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(DownloadSharedPreferenceEntry.INVALID_ENTRY, entry); + + // Notification ID missing in version 2. + notificationString = "2,,1,0," + uuid + ",test,2.pdf"; + entry = DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(DownloadSharedPreferenceEntry.INVALID_ENTRY, entry); + + // Notification ID missing in version 3. + notificationString = "3,,2,0,1," + uuid + ",test,2.pdf"; + entry = DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(DownloadSharedPreferenceEntry.INVALID_ENTRY, entry); + + // Not able to parse notification ID in version 1. + notificationString = "1,xxx,0,1," + uuid + ",test,2.pdf"; + entry = DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(DownloadSharedPreferenceEntry.INVALID_ENTRY, entry); + + // Not able to parse notification ID in version 2. + notificationString = "2,xxx,1,0," + uuid + ",test,2.pdf"; + entry = DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(DownloadSharedPreferenceEntry.INVALID_ENTRY, entry); + + // Not able to parse notification ID in version 3. + notificationString = "3,xxx,2,0,1," + uuid + ",test,2.pdf"; + entry = DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(DownloadSharedPreferenceEntry.INVALID_ENTRY, entry); + } + + @Test + @Feature({"Download"}) + public void testParseFromStringFailedToParseItemType() { + String uuid = newUUID(); + // Item type is only present in version 3. (Position 3) + // Invalid item type. + String notificationString = "3,2,0,1,0," + uuid + ",test,2.pdf"; + DownloadSharedPreferenceEntry entry = + DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(DownloadSharedPreferenceEntry.INVALID_ENTRY, entry); + + // Invalid item type. + notificationString = "3,2,3,0,1," + uuid + ",test,2.pdf"; + entry = DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(DownloadSharedPreferenceEntry.INVALID_ENTRY, entry); + + // Not able to parse item type. + notificationString = "3,2,xxx,0,1," + uuid + ",test,2.pdf"; + entry = DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(DownloadSharedPreferenceEntry.INVALID_ENTRY, entry); + + // Missing item type. + notificationString = "3,2,,0,1," + uuid + ",test,2.pdf"; + entry = DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(DownloadSharedPreferenceEntry.INVALID_ENTRY, entry); + } + + @Test + @Feature({"Download"}) + public void testParseFromStringInvalidGuid() { + // GUID missing in version 1. + String notificationString = "1,2,1,0,,test,2.pdf"; + DownloadSharedPreferenceEntry entry = + DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(DownloadSharedPreferenceEntry.INVALID_ENTRY, entry); + + // GUID missing in version 2. + notificationString = "2,2,1,0,,test,2.pdf"; + entry = DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(DownloadSharedPreferenceEntry.INVALID_ENTRY, entry); + + // GUID missing in version 3. + notificationString = "3,2,2,0,1,,test,2.pdf"; + entry = DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(DownloadSharedPreferenceEntry.INVALID_ENTRY, entry); + + // Not able to parse GUID in version 1. + notificationString = "1,2,0,1,xxx,test,2.pdf"; + entry = DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(DownloadSharedPreferenceEntry.INVALID_ENTRY, entry); + + // Not able to parse GUID in version 2. + notificationString = "2,2,1,0,xxx,test,2.pdf"; + entry = DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(DownloadSharedPreferenceEntry.INVALID_ENTRY, entry); + + // Not able to parse GUID in version 3. + notificationString = "3,2,2,0,1,xxx,test,2.pdf"; + entry = DownloadSharedPreferenceEntry.parseFromString(notificationString); + assertEquals(DownloadSharedPreferenceEntry.INVALID_ENTRY, entry); + } +}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/download/OWNERS b/chrome/android/junit/src/org/chromium/chrome/browser/download/OWNERS new file mode 100644 index 0000000..cdeb51d5 --- /dev/null +++ b/chrome/android/junit/src/org/chromium/chrome/browser/download/OWNERS
@@ -0,0 +1 @@ +file://chrome/android/java/src/org/chromium/chrome/browser/download/OWNERS
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java index 77970749..8954a3d2 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
@@ -15,10 +15,10 @@ import org.chromium.base.test.util.Feature; import org.chromium.chrome.browser.ntp.snippets.CategoryStatus; import org.chromium.chrome.browser.ntp.snippets.CategoryStatus.CategoryStatusEnum; +import org.chromium.chrome.browser.ntp.snippets.ContentSuggestionsCardLayout; import org.chromium.chrome.browser.ntp.snippets.KnownCategories; -import org.chromium.chrome.browser.ntp.snippets.KnownCategories.KnownCategoriesEnum; import org.chromium.chrome.browser.ntp.snippets.SnippetArticleListItem; -import org.chromium.chrome.browser.ntp.snippets.SnippetsSource; +import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource; import org.chromium.testing.local.LocalRobolectricTestRunner; import org.junit.Before; import org.junit.Test; @@ -27,10 +27,11 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; - +import java.util.Set; /** * Unit tests for {@link NewTabPageAdapter}. @@ -38,46 +39,91 @@ @RunWith(LocalRobolectricTestRunner.class) @Config(manifest = Config.NONE) public class NewTabPageAdapterTest { - private static class FakeSnippetsSource implements SnippetsSource { - private SnippetsSource.SnippetsObserver mObserver; - private final Map<Integer, Integer> mCategoryStatus = new HashMap<>(); + /** + * Number of elements, not including content suggestions that are loaded + * in a populated recycler view. + * The 3 elements are: above-the-fold, header, bottom spacer + * TODO(dgn): Make this depend on the category info of the loaded sections + * instead of being a constant, as it needs to know if the MORE button is + * present for example. + */ + private static final int PERMANENT_ELEMENTS_COUNT = 3; - public void setStatusForCategory(@KnownCategoriesEnum int category, - @CategoryStatusEnum int status) { + /** + * Number of elements that are loaded in an empty recycler view + * The 5 elements are: above-the-fold, header, status card, progress + * indicator, bottom spacer. + */ + private static final int EMPTY_STATE_ELEMENTS_COUNT = 5; + + private static class FakeSnippetsSource implements SuggestionsSource { + private SuggestionsSource.Observer mObserver; + private final Map<Integer, List<SnippetArticleListItem>> mSuggestions = new HashMap<>(); + private final Map<Integer, Integer> mCategoryStatus = new HashMap<>(); + private final Map<Integer, SuggestionsCategoryInfo> mCategoryInfo = new HashMap<>(); + + public void setStatusForCategory(int category, @CategoryStatusEnum int status) { mCategoryStatus.put(category, status); if (mObserver != null) mObserver.onCategoryStatusChanged(category, status); } - public void setSnippetsForCategory(@KnownCategoriesEnum int category, - List<SnippetArticleListItem> snippets) { - mObserver.onSuggestionsReceived(category, snippets); + public void setSuggestionsForCategory( + int category, List<SnippetArticleListItem> suggestions) { + mSuggestions.put(category, suggestions); + if (mObserver != null) mObserver.onNewSuggestions(category); + } + + public void setInfoForCategory(int category, SuggestionsCategoryInfo info) { + mCategoryInfo.put(category, info); } @Override - public void discardSnippet(SnippetArticleListItem snippet) { + public void dismissSuggestion(SnippetArticleListItem suggestion) { throw new UnsupportedOperationException(); } @Override - public void fetchSnippetImage(SnippetArticleListItem snippet, Callback<Bitmap> callback) { + public void fetchSuggestionImage( + SnippetArticleListItem suggestion, Callback<Bitmap> callback) { throw new UnsupportedOperationException(); } @Override - public void getSnippedVisited(SnippetArticleListItem snippet, Callback<Boolean> callback) { + public void getSuggestionVisited( + SnippetArticleListItem suggestion, Callback<Boolean> callback) { throw new UnsupportedOperationException(); } @Override - public void setObserver(SnippetsObserver observer) { + public void setObserver(Observer observer) { mObserver = observer; } + @Override + public int[] getCategories() { + Set<Integer> ids = mCategoryStatus.keySet(); + int[] result = new int[ids.size()]; + int index = 0; + for (int id : ids) result[index++] = id; + return result; + } + @CategoryStatusEnum @Override - public int getCategoryStatus(@KnownCategoriesEnum int category) { + public int getCategoryStatus(int category) { return mCategoryStatus.get(category); } + + @Override + public SuggestionsCategoryInfo getCategoryInfo(int category) { + return mCategoryInfo.get(category); + } + + @Override + public List<SnippetArticleListItem> getSuggestionsForCategory(int category) { + List<SnippetArticleListItem> result = mSuggestions.get(category); + return result == null ? Collections.<SnippetArticleListItem>emptyList() : result; + } } private FakeSnippetsSource mSnippetsSource = new FakeSnippetsSource(); @@ -89,6 +135,9 @@ mSnippetsSource = new FakeSnippetsSource(); mSnippetsSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.INITIALIZING); + mSnippetsSource.setInfoForCategory( + KnownCategories.ARTICLES, new SuggestionsCategoryInfo("Articles for you", + ContentSuggestionsCardLayout.FULL_CARD)); mNtpAdapter = new NewTabPageAdapter(null, null, mSnippetsSource, null); } @@ -99,7 +148,7 @@ @Test @Feature({"Ntp"}) public void testSnippetLoading() { - assertEquals(5, mNtpAdapter.getItemCount()); + assertEquals(EMPTY_STATE_ELEMENTS_COUNT, mNtpAdapter.getItemCount()); assertEquals(NewTabPageListItem.VIEW_TYPE_ABOVE_THE_FOLD, mNtpAdapter.getItemViewType(0)); assertEquals(NewTabPageListItem.VIEW_TYPE_HEADER, mNtpAdapter.getItemViewType(1)); assertEquals(NewTabPageListItem.VIEW_TYPE_STATUS, mNtpAdapter.getItemViewType(2)); @@ -107,7 +156,7 @@ assertEquals(NewTabPageListItem.VIEW_TYPE_SPACING, mNtpAdapter.getItemViewType(4)); List<SnippetArticleListItem> snippets = createDummySnippets(); - mSnippetsSource.setSnippetsForCategory(KnownCategories.ARTICLES, snippets); + mSnippetsSource.setSuggestionsForCategory(KnownCategories.ARTICLES, snippets); List<NewTabPageListItem> loadedItems = new ArrayList<>(mNtpAdapter.getItems()); assertEquals(NewTabPageListItem.VIEW_TYPE_ABOVE_THE_FOLD, mNtpAdapter.getItemViewType(0)); @@ -117,9 +166,9 @@ mNtpAdapter.getItemViewType(loadedItems.size() - 1)); // The adapter should ignore any new incoming data. - mSnippetsSource.setSnippetsForCategory(KnownCategories.ARTICLES, - Arrays.asList(new SnippetArticleListItem[] { new SnippetArticleListItem( - "foo", "title1", "pub1", "txt1", "foo", "bar", 0, 0, 0) })); + mSnippetsSource.setSuggestionsForCategory(KnownCategories.ARTICLES, + Arrays.asList(new SnippetArticleListItem[] {new SnippetArticleListItem( + "foo", "title1", "pub1", "txt1", "foo", "bar", 0, 0, 0)})); assertEquals(loadedItems, mNtpAdapter.getItems()); } @@ -131,9 +180,9 @@ @Feature({"Ntp"}) public void testSnippetLoadingInitiallyEmpty() { // If we don't get anything, we should be in the same situation as the initial one. - mSnippetsSource.setSnippetsForCategory(KnownCategories.ARTICLES, - new ArrayList<SnippetArticleListItem>()); - assertEquals(5, mNtpAdapter.getItemCount()); + mSnippetsSource.setSuggestionsForCategory( + KnownCategories.ARTICLES, new ArrayList<SnippetArticleListItem>()); + assertEquals(EMPTY_STATE_ELEMENTS_COUNT, mNtpAdapter.getItemCount()); assertEquals(NewTabPageListItem.VIEW_TYPE_ABOVE_THE_FOLD, mNtpAdapter.getItemViewType(0)); assertEquals(NewTabPageListItem.VIEW_TYPE_HEADER, mNtpAdapter.getItemViewType(1)); assertEquals(NewTabPageListItem.VIEW_TYPE_STATUS, mNtpAdapter.getItemViewType(2)); @@ -142,7 +191,7 @@ // We should load new snippets when we get notified about them. List<SnippetArticleListItem> snippets = createDummySnippets(); - mSnippetsSource.setSnippetsForCategory(KnownCategories.ARTICLES, snippets); + mSnippetsSource.setSuggestionsForCategory(KnownCategories.ARTICLES, snippets); List<NewTabPageListItem> loadedItems = new ArrayList<>(mNtpAdapter.getItems()); assertEquals(NewTabPageListItem.VIEW_TYPE_ABOVE_THE_FOLD, mNtpAdapter.getItemViewType(0)); assertEquals(NewTabPageListItem.VIEW_TYPE_HEADER, mNtpAdapter.getItemViewType(1)); @@ -151,8 +200,7 @@ mNtpAdapter.getItemViewType(loadedItems.size() - 1)); // The adapter should ignore any new incoming data. - mSnippetsSource.setSnippetsForCategory( - KnownCategories.ARTICLES, + mSnippetsSource.setSuggestionsForCategory(KnownCategories.ARTICLES, Arrays.asList(new SnippetArticleListItem[] {new SnippetArticleListItem( "foo", "title1", "pub1", "txt1", "foo", "bar", 0, 0, 0)})); assertEquals(loadedItems, mNtpAdapter.getItems()); @@ -165,26 +213,26 @@ @Feature({"Ntp"}) public void testSnippetClearing() { List<SnippetArticleListItem> snippets = createDummySnippets(); - mSnippetsSource.setSnippetsForCategory(KnownCategories.ARTICLES, snippets); - assertEquals(3 + snippets.size(), mNtpAdapter.getItemCount()); + mSnippetsSource.setSuggestionsForCategory(KnownCategories.ARTICLES, snippets); + assertEquals(PERMANENT_ELEMENTS_COUNT + snippets.size(), mNtpAdapter.getItemCount()); // If we get told that snippets are enabled, we just leave the current // ones there and not clear. mSnippetsSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE); - assertEquals(3 + snippets.size(), mNtpAdapter.getItemCount()); + assertEquals(PERMANENT_ELEMENTS_COUNT + snippets.size(), mNtpAdapter.getItemCount()); // When snippets are disabled, we clear them and we should go back to // the situation with the status card. mSnippetsSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.SIGNED_OUT); - assertEquals(5, mNtpAdapter.getItemCount()); + assertEquals(EMPTY_STATE_ELEMENTS_COUNT, mNtpAdapter.getItemCount()); // The adapter should now be waiting for new snippets. mSnippetsSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE); - mSnippetsSource.setSnippetsForCategory(KnownCategories.ARTICLES, snippets); - assertEquals(3 + snippets.size(), mNtpAdapter.getItemCount()); + mSnippetsSource.setSuggestionsForCategory(KnownCategories.ARTICLES, snippets); + assertEquals(PERMANENT_ELEMENTS_COUNT + snippets.size(), mNtpAdapter.getItemCount()); } /** @@ -196,32 +244,32 @@ List<SnippetArticleListItem> snippets = createDummySnippets(); // By default, status is INITIALIZING, so we can load snippets - mSnippetsSource.setSnippetsForCategory(KnownCategories.ARTICLES, snippets); - assertEquals(3 + snippets.size(), mNtpAdapter.getItemCount()); + mSnippetsSource.setSuggestionsForCategory(KnownCategories.ARTICLES, snippets); + assertEquals(PERMANENT_ELEMENTS_COUNT + snippets.size(), mNtpAdapter.getItemCount()); // If we have snippets, we should not load the new list. snippets.add(new SnippetArticleListItem("https://site.com/url1", "title1", "pub1", "txt1", "https://site.com/url1", "https://amp.site.com/url1", 0, 0, 0)); - mSnippetsSource.setSnippetsForCategory(KnownCategories.ARTICLES, snippets); - assertEquals(3 + snippets.size() - 1, mNtpAdapter.getItemCount()); + mSnippetsSource.setSuggestionsForCategory(KnownCategories.ARTICLES, snippets); + assertEquals(PERMANENT_ELEMENTS_COUNT + snippets.size() - 1, mNtpAdapter.getItemCount()); // When snippets are disabled, we should not be able to load them mSnippetsSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.SIGNED_OUT); - mSnippetsSource.setSnippetsForCategory(KnownCategories.ARTICLES, snippets); - assertEquals(5, mNtpAdapter.getItemCount()); + mSnippetsSource.setSuggestionsForCategory(KnownCategories.ARTICLES, snippets); + assertEquals(EMPTY_STATE_ELEMENTS_COUNT, mNtpAdapter.getItemCount()); // INITIALIZING lets us load snippets still. mSnippetsSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.INITIALIZING); - mSnippetsSource.setSnippetsForCategory(KnownCategories.ARTICLES, snippets); - assertEquals(3 + snippets.size(), mNtpAdapter.getItemCount()); + mSnippetsSource.setSuggestionsForCategory(KnownCategories.ARTICLES, snippets); + assertEquals(PERMANENT_ELEMENTS_COUNT + snippets.size(), mNtpAdapter.getItemCount()); // The adapter should now be waiting for new snippets. mSnippetsSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE); - mSnippetsSource.setSnippetsForCategory(KnownCategories.ARTICLES, snippets); - assertEquals(3 + snippets.size(), mNtpAdapter.getItemCount()); + mSnippetsSource.setSuggestionsForCategory(KnownCategories.ARTICLES, snippets); + assertEquals(PERMANENT_ELEMENTS_COUNT + snippets.size(), mNtpAdapter.getItemCount()); } /**
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index 4ee80e02..e1d4c52 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -2438,7 +2438,10 @@ Enable accessibility features to make your device easier to use. </message> <message name="IDS_OPTIONS_SETTINGS_ACCESSIBILITY_SETTINGS" desc="Text of the link to open ChromeVox settings."> - Settings + ChromeVox Settings + </message> + <message name="IDS_OPTIONS_SETTINGS_ACCESSIBILITY_TALKBACK_SETTINGS" desc="Text of the link to open TalkBack settings."> + TalkBack Settings </message> <message name="IDS_OPTIONS_SETTINGS_ACCESSIBILITY_LARGE_CURSOR_DESCRIPTION" desc="In the settings tab, the text next to the checkbox for the large mouse cursor."> Show large mouse cursor
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 9d4dfcd..c5211bb 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -495,6 +495,9 @@ <message name="IDS_SAVE" desc="Used on a button to save information you are editing."> Save </message> + <message name="IDS_CONFIRM" desc="A button that lets the user confirm something."> + Confirm + </message> <message name="IDS_DISABLE" desc="Used for Disable on buttons"> Disable </message> @@ -1912,6 +1915,10 @@ desc="In the download notification, the text of 'Copy to clipboard' button, which is to copy the file content (eg. an image for image files) to the clipboard"> Copy to clipboard </message> + <message name="IDS_DOWNLOAD_NOTIFICATION_ANNOTATE" + desc="In the download notification, the text of the button that opens the file (if it is an image) in the Google Keep app so the user can annotate it"> + Annotate in Google Keep + </message> <!-- Download Context Menu Items --> <if expr="not is_android"> @@ -5795,12 +5802,6 @@ <message name="IDS_FLAGS_ASH_ENABLE_MIRRORED_SCREEN_DESCRIPTION" desc="Description for the flag to enable the mirrored screen mode."> Enable the mirrored screen mode. This mode flips the screen image horizontally. </message> - <message name="IDS_FLAGS_TOUCH_FEEDBACK_NAME" desc="Title for the flag for additional visual feedback for touch."> - Additional touch feedback on UI components - </message> - <message name="IDS_FLAGS_TOUCH_FEEDBACK_DESCRIPTION" desc="Description for the flag that disables additional visual feedback for touch."> - Certain UI components will display visual feedback upon touch interactions. - </message> <message name="IDS_FLAGS_MATERIAL_DESIGN_INK_DROP_ANIMATION_FAST" desc="Description for the flag that sets material design ink drop animation speed of fast."> Fast </message> @@ -13655,6 +13656,18 @@ Highly experimental performance mode where cross-site iframes are kept in a separate process from the top document. In this mode, iframes from different third-party sites will be allowed to share a process. </message> + <!-- Browser Task Scheduler --> + <message name="IDS_FLAGS_BROWSER_TASK_SCHEDULER_NAME" + desc="Name of about:flag option to control the availability of the browser task scheduler." + translateable="false"> + Browser Task Scheduler + </message> + <message name="IDS_FLAGS_BROWSER_TASK_SCHEDULER_DESCRIPTION" + desc="Description of about:flag option to control the availability of the browser task scheduler." + translateable="false"> + Enables the browser task scheduler to dispatch tasks instead of the existing worker pools. The browser task scheduler will only be used if variation parameters are available. + </message> + <!-- Windows 8 Metro mode. --> <if expr="is_win"> <message name="IDS_METRO_FLOW_DESCRIPTION" @@ -14751,12 +14764,6 @@ <message name="IDS_INTENT_PICKER_BUBBLE_VIEW_OPEN_WITH" desc="Message contained in a label used as a header for a list of applications from which the user will pick one."> Open with </message> - <message name="IDS_ENABLE_INTENT_PICKER" desc="Header for the Intent Picker feature on the chrome://flags list."> - Android apps intent picker. - </message> - <message name="IDS_ENABLE_INTENT_PICKER_DESCRIPTION" desc="Description for the ARC's intent picker feature."> - Enables an intent picker to provide a list of Android apps that can handle a given URL. - </message> </if> <!-- Strings describing Chrome security policy for DevTools security panel --> @@ -15096,21 +15103,18 @@ <message name="IDS_FLAGS_ENABLE_SCROLL_ANCHORING_DESCRIPTION" desc="Description of the scroll anchoring flag"> Adjusts scroll position to prevent visible jumps when offscreen content changes. </message> - <message name="IDS_FLAGS_ENABLE_ALL_BOOKMARKS_VIEW_CHOICE_DEFAULT" desc="Text to indicate that it'll use the platform settings to enable/disable all bookmarks view."> - Default - </message> - <message name="IDS_FLAGS_ENABLE_ALL_BOOKMARKS_VIEW_CHOICE_ENABLED" desc="Text to indicate the all bookmarks view is enabled."> - Enabled - </message> - <message name="IDS_FLAGS_ENABLE_ALL_BOOKMARKS_VIEW_CHOICE_DISABLED" desc="Text to indicate the all bookmarks view is disabled."> - Disabled - </message> <message name="IDS_FLAGS_ENABLE_ALL_BOOKMARKS_VIEW_NAME" desc="Name of the show all bookmarks view flag"> Enable "all bookmarks" section in bookmark manager. </message> <message name="IDS_FLAGS_SHOW_ALL_BOOKMARKS_VIEW_DESCRIPTION" desc="Description of the show all bookmarks view flag"> Enables the all bookmarks view as the default destination of the bookmark manager. </message> + <message name="IDS_FLAGS_ENABLE_DOWNLOADS_UI_NAME" desc="Name of the show downloads ui flag"> + Enable downloads manager UI in the app menu. + </message> + <message name="IDS_FLAGS_ENABLE_DOWNLOADS_UI_DESCRIPTION" desc="Description of the show downloads ui."> + Enable downloads manager UI in the app menu. + </message> <if expr="chromeos"> <message name="IDS_FLAGS_ENABLE_NATIVE_CUPS_NAME" desc="Name of the native cups flag."> @@ -15298,14 +15302,6 @@ </message> </if> - <if expr="is_android"> - <message name="IDS_FLAGS_MULTI_INSTANCE_MERGE_TABS_NAME" desc="Name of the flag to turn on auto-merging tabs in multi-instance mode." translateable="false"> - Multi-instance tab model merging - </message> - <message name="IDS_FLAGS_MULTI_INSTANCE_MERGE_TABS_DESCRIPTION" desc="Description of the flag to turn on auto-merging tabs in multi-instance mode." translateable="false"> - Enables automatic merging of tabs for Android N+ multi-instance mode. Note that this excludes merging on cold start because native flags aren't loaded in time. - </message> - </if> </messages> </release> </grit>
diff --git a/chrome/app/mash/BUILD.gn b/chrome/app/mash/BUILD.gn index 78d87f1..d49d1cc 100644 --- a/chrome/app/mash/BUILD.gn +++ b/chrome/app/mash/BUILD.gn
@@ -12,7 +12,6 @@ deps = [ "//ash/mus:lib", "//ash/resources", - "//ash/sysui:lib", "//ash/touch_hud/mus:lib", "//base:i18n", "//content/public/common", @@ -45,7 +44,6 @@ source = "chrome_mash_manifest.json" deps = [ "//ash/mus:manifest", - "//ash/sysui:manifest", "//ash/touch_hud/mus:manifest", "//mash/app_driver:manifest", "//mash/quick_launch:manifest", @@ -56,7 +54,6 @@ packaged_services = [ "app_driver", "ash", - "ash_sysui", "mash_session", "quick_launch", "task_viewer",
diff --git a/chrome/app/mash/mash_runner.cc b/chrome/app/mash/mash_runner.cc index 862e1ef..a2b3a0bd 100644 --- a/chrome/app/mash/mash_runner.cc +++ b/chrome/app/mash/mash_runner.cc
@@ -5,7 +5,6 @@ #include "chrome/app/mash/mash_runner.h" #include "ash/mus/window_manager_application.h" -#include "ash/sysui/sysui_application.h" #include "ash/touch_hud/mus/touch_hud_application.h" #include "base/at_exit.h" #include "base/bind.h" @@ -86,8 +85,6 @@ // TODO(sky): move this into mash. std::unique_ptr<shell::Service> CreateService( const std::string& name) { - if (name == "mojo:ash_sysui") - return base::WrapUnique(new ash::sysui::SysUIApplication); if (name == "mojo:ash") return base::WrapUnique(new ash::mus::WindowManagerApplication); if (name == "mojo:touch_hud")
diff --git a/chrome/app/mojo/chrome_manifest.json b/chrome/app/mojo/chrome_manifest.json index 0e1ab90b..85dda9b 100644 --- a/chrome/app/mojo/chrome_manifest.json +++ b/chrome/app/mojo/chrome_manifest.json
@@ -5,9 +5,9 @@ "capabilities": { "required": { "*": { "classes": [ "app" ] }, - "mojo:ash_sysui": { + "mojo:ash": { "interfaces": [ - "ash::sysui::mojom::WallpaperController", + "ash::mojom::WallpaperController", "mash::shelf::mojom::ShelfController" ] }
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp index 8f5f434..ef8bdc4 100644 --- a/chrome/app/settings_strings.grdp +++ b/chrome/app/settings_strings.grdp
@@ -1323,8 +1323,8 @@ <message name="IDS_SETTINGS_SITE_SETTINGS_BLOCK_MENU" desc="Label for the menu item to block permission for a particular site."> Block </message> - <message name="IDS_SETTINGS_SITE_SETTINGS_RESET_MENU" desc="Label for the menu item to reset the permission for a particular site (make it ask you again next time)."> - Reset to ask + <message name="IDS_SETTINGS_SITE_SETTINGS_RESET_MENU" desc="Label for the menu item to remove the permission for a particular site (make it ask you again next time)."> + Remove </message> <message name="IDS_SETTINGS_SITE_SETTINGS_SESSION_ONLY_MENU" desc="Label for the menu item to set cookies to be deleted on browser exit."> Clear on exit @@ -1384,56 +1384,56 @@ </message> <if expr="chromeos"> + <message name="IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_CHOOSE_PIN_TITLE" desc="Message shown below the title that tells the user to enter the initial PIN."> + Enter your PIN + </message> + <message name="IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_CONFIRM_PIN_TITLE" desc="Message shown below the title that tells the user to confirm their initial PIN entry."> + Confirm your PIN + </message> + <message name="IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_WEAK_PIN" desc="Message shown below the title that warns the user they have entered a PIN that is easy to guess."> + This PIN is easy to guess: + </message> + <message name="IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_TOO_SHORT" desc="Message shown below the title that tells the user that the PIN they entered needs to be at least four digits long."> + PIN must be at least 4 digits: + </message> + <message name="IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_MISMATCHED" desc="Message shown below the title that tells the user they have entered two different PIN values."> + PIN's don't match: + </message> + <message name="IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_CONTINUE_BUTTON" desc="A button that accepts the users initial PIN. The user will have to enter the PIN again after hitting this button to confirm that they entered it correctly."> + Continue + </message> <message name="IDS_SETTINGS_PEOPLE_ENABLE_SCREENLOCK" desc="The text on the checkbox to enable screenlocker for current user."> Require password to wake from sleep </message> - <message name="IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_TITLE" desc="Text on the people page which opens up the quick unlock subpage and the title of the quick unlock subpage."> - Configure quick unlock + <message name="IDS_SETTINGS_PEOPLE_LOCK_SCREEN_TITLE" desc="Text on the people page which opens up the quick unlock subpage and the title of the quick unlock subpage."> + Screen lock </message> - <message name="IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_CONFIRM_LOGIN" desc="Text above a password input field that tells the user they need to submit their password to configure these settings."> - Confirm your login to continue + <message name="IDS_SETTINGS_PEOPLE_LOCK_SCREEN_PASSWORD_ONLY" desc="Only the account password can be used to unlock the device."> + Password only </message> - <message name="IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_PASSWORD_LABEL" desc="An input box label that tells the user to enter their password in that input box."> - Password - </message> - <message name="IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_INVALID_PASSWORD" desc="Text on a password field that tells the user the password is incorrect."> - Not valid - </message> - <message name="IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_CHOOSE_UNLOCK_METHOD" desc="Text below the page title that tells the user to select a method to unlock the device. This is *only* for unlocking a device; it cannot be used to sign into a device."> - Choose the method you would like to use to log back in to your account: - </message> - <message name="IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_UNLOCK_METHOD_PASSWORD" desc="Only the account password can be used to unlock the device."> - Only password - </message> - <message name="IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_UNLOCK_METHOD_PIN_AND_PASSWORD" desc="The account password or a custom PIN can be used to unlock the device."> + <message name="IDS_SETTINGS_PEOPLE_LOCK_SCREEN_PIN_OR_PASSWORD" desc="The account password or a custom PIN can be used to unlock the device."> PIN or password </message> - <message name="IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_UNLOCK_METHOD_NONE" desc="After the device resumes, there will not be a lock screen and no password of any type will be required."> + <message name="IDS_SETTINGS_PEOPLE_LOCK_SCREEN_NONE" desc="Text on the people page which opens up the quick unlock subpage and the title of the quick unlock subpage."> None </message> - <message name="IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_CONFIGURE_PIN_BUTTON" desc="Button that is only shown when the user has selected PIN as their unlock method. This button opens up the configuration flow where the user selects the PIN they would like to use."> - Configure PIN + <message name="IDS_SETTINGS_PEOPLE_LOCK_SCREEN_CHANGE_PIN_BUTTON" desc="Button that the user can click to change an existing already-active PIN."> + Change PIN </message> - <message name="IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_CONFIGURE_PIN_CHOOSE_PIN_TITLE" desc="Message shown below the title that tells the user to enter the initial PIN."> - Choose your PIN: + <message name="IDS_SETTINGS_PEOPLE_LOCK_SCREEN_SETUP_PIN_BUTTON" desc="Button that is used to setup a new PIN when the user does not have a PIN yet."> + Setup PIN </message> - <message name="IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_CONFIGURE_PIN_CHOOSE_PIN_WEAK_PIN_WARNING" desc="Message shown below the title that warns the user they have entered a PIN that is easy to guess."> - This PIN is easy to guess: + <message name="IDS_SETTINGS_PEOPLE_PASSWORD_PROMPT_TITLE" desc="Title of the password prompt dialog popup."> + Confirm your password </message> - <message name="IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_CONFIGURE_PIN_CHOOSE_PIN_TOO_SHORT" desc="Message shown below the title that tells the user that the PIN they entered needs to be at least four digits long."> - PIN must be at least 4 digits: + <message name="IDS_SETTINGS_PEOPLE_PASSWORD_PROMPT_ENTER_PASSWORD" desc="Text above a password input field that tells the user they need to submit their password to configure these settings."> + Enter your password to set up screen lock. </message> - <message name="IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_CONFIGURE_PIN_CONTINUE_BUTTON" desc="A button that accepts the users initial PIN. The user will have to enter the PIN again after hitting this button to confirm that they entered it correctly."> - Continue + <message name="IDS_SETTINGS_PEOPLE_PASSWORD_PROMPT_PASSWORD_LABEL" desc="An input box label that tells the user to enter their password in that input box."> + Password </message> - <message name="IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_CONFIGURE_PIN_CONFIRM_PIN_TITLE" desc="Message shown below the title that tells the user to confirm their initial PIN entry."> - Confirm your PIN: - </message> - <message name="IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_CONFIGURE_PIN_MISMATCHED_PINS" desc="Message shown below the title that tells the user they have entered two different PIN values."> - PIN's don't match: - </message> - <message name="IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_CONFIGURE_PIN_BACK_BUTTON" desc="Button that goes from the confirm PIN screen to the initial PIN setup screen."> - Back + <message name="IDS_SETTINGS_PEOPLE_PASSWORD_PROMPT_INVALID_PASSWORD" desc="Text on a password field that tells the user the password is incorrect."> + Invalid password </message> <message name="IDS_SETTINGS_CHANGE_PICTURE_DIALOG_TITLE" desc="Title of the subpage shown when user wants to change his/her picture."> Change picture
diff --git a/chrome/app/theme/default_100_percent/common/infobar_media_stream_screen_share.png b/chrome/app/theme/default_100_percent/common/infobar_media_stream_screen_share.png new file mode 100644 index 0000000..810b14f --- /dev/null +++ b/chrome/app/theme/default_100_percent/common/infobar_media_stream_screen_share.png Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/notification_welcome_icon.png b/chrome/app/theme/default_100_percent/common/notification_welcome_icon.png index eefebf54..e665754 100644 --- a/chrome/app/theme/default_100_percent/common/notification_welcome_icon.png +++ b/chrome/app/theme/default_100_percent/common/notification_welcome_icon.png Binary files differ
diff --git a/chrome/app/theme/default_100_percent/cros/downloads/annotate.png b/chrome/app/theme/default_100_percent/cros/downloads/annotate.png new file mode 100644 index 0000000..2c6ed23 --- /dev/null +++ b/chrome/app/theme/default_100_percent/cros/downloads/annotate.png Binary files differ
diff --git a/chrome/app/theme/default_100_percent/cros/notification_screenshot_annotate.png b/chrome/app/theme/default_100_percent/cros/notification_screenshot_annotate.png new file mode 100644 index 0000000..2c6ed23 --- /dev/null +++ b/chrome/app/theme/default_100_percent/cros/notification_screenshot_annotate.png Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/infobar_media_stream_screen_share.png b/chrome/app/theme/default_200_percent/common/infobar_media_stream_screen_share.png new file mode 100644 index 0000000..d3a6c77 --- /dev/null +++ b/chrome/app/theme/default_200_percent/common/infobar_media_stream_screen_share.png Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/notification_welcome_icon.png b/chrome/app/theme/default_200_percent/common/notification_welcome_icon.png index 0161f895..10705ac 100644 --- a/chrome/app/theme/default_200_percent/common/notification_welcome_icon.png +++ b/chrome/app/theme/default_200_percent/common/notification_welcome_icon.png Binary files differ
diff --git a/chrome/app/theme/default_200_percent/cros/downloads/annotate.png b/chrome/app/theme/default_200_percent/cros/downloads/annotate.png new file mode 100644 index 0000000..b5129582 --- /dev/null +++ b/chrome/app/theme/default_200_percent/cros/downloads/annotate.png Binary files differ
diff --git a/chrome/app/theme/default_200_percent/cros/notification_screenshot_annotate.png b/chrome/app/theme/default_200_percent/cros/notification_screenshot_annotate.png new file mode 100644 index 0000000..b5129582 --- /dev/null +++ b/chrome/app/theme/default_200_percent/cros/notification_screenshot_annotate.png Binary files differ
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd index cf5be0f..f0119de8 100644 --- a/chrome/app/theme/theme_resources.grd +++ b/chrome/app/theme/theme_resources.grd
@@ -225,6 +225,7 @@ <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_BUTTON_RIGHT_TOP_NO_DD" file="common/download_button_right_top_no_dd.png" /> <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_BUTTON_RIGHT_TOP_P" file="common/download_button_right_top_pressed.png" /> <if expr="chromeos"> + <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_NOTIFICATION_MENU_ANNOTATE" file="cros/downloads/annotate.png" /> <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_NOTIFICATION_MENU_CANCEL" file="cros/downloads/cancel.png" /> <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_NOTIFICATION_MENU_DELETE" file="cros/downloads/delete.png" /> <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_NOTIFICATION_MENU_DOWNLOAD" file="cros/downloads/download.png" /> @@ -370,6 +371,7 @@ </if> <structure type="chrome_scaled_image" name="IDR_INFOBAR_MEDIA_STREAM_CAMERA" file="common/infobar_media_stream_camera.png" /> <structure type="chrome_scaled_image" name="IDR_INFOBAR_MEDIA_STREAM_MIC" file="common/infobar_media_stream_mic.png" /> + <structure type="chrome_scaled_image" name="IDR_INFOBAR_MEDIA_STREAM_SCREEN" file="common/infobar_media_stream_screen_share.png" /> <structure type="chrome_scaled_image" name="IDR_INFOBAR_MIDI" file="common/infobar_midi.png" /> <structure type="chrome_scaled_image" name="IDR_INFOBAR_MULTIPLE_DOWNLOADS" file="common/infobar_multiple_downloads.png" /> <structure type="chrome_scaled_image" name="IDR_INFOBAR_PLUGIN_CRASHED" file="common/infobar_plugin_crashed.png" /> @@ -443,6 +445,7 @@ <structure type="chrome_scaled_image" name="IDR_PORTAL_DETECTION_ALERT" file="cros/captive_portal_icon.png" /> <structure type="chrome_scaled_image" name="IDR_ARC_PLAY_STORE_NOTIFICATION" file="cros/notification_play_store.png" /> <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_EXTENSION_INSTALLED" file="common/notification_extension_installed.png" /> + <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_SCREENSHOT_ANNOTATE" file="cros/notification_screenshot_annotate.png" /> <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_SCREENSHOT_COPY_TO_CLIPBOARD" file="cros/notification_screenshot_copy_to_clipboard.png" /> </if> <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_WELCOME_ICON" file="common/notification_welcome_icon.png" />
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 93c0bd8..5d213c7 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -219,6 +219,10 @@ sources += rebase_path(gypi_values.chrome_browser_undo_sources, ".", "//chrome") + if (is_chromeos && use_cras) { + defines += [ "USE_CRAS" ] + } + if (!is_ios) { sources += rebase_path(gypi_values.chrome_browser_non_ios_sources, ".", "//chrome") @@ -1009,7 +1013,9 @@ "//chrome/browser/ui/webui/engagement:mojo_bindings__generator", "//chrome/browser/ui/webui/omnibox:mojo_bindings__generator", "//chrome/browser/ui/webui/plugins:mojo_bindings__generator", + "//chrome/browser/ui/webui/usb_internals:mojo_bindings__generator", "//url/mojo:url_mojom_gurl__generator", + "//url/mojo:url_mojom_origin__generator", ] } @@ -1323,6 +1329,7 @@ "//components/metrics:test_support", "//components/password_manager/content/public/interfaces", "//components/password_manager/core/browser:test_support", + "//components/translate/content/common", "//skia", "//testing/gtest", ]
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index a2b3f61..bd408e0 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -22,6 +22,7 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" +#include "base/task_scheduler/switches.h" #include "base/values.h" #include "build/build_config.h" #include "cc/base/switches.h" @@ -989,11 +990,6 @@ SINGLE_VALUE_TYPE(ash::switches::kAshEnableTouchViewTesting), }, { - "disable-touch-feedback", IDS_FLAGS_TOUCH_FEEDBACK_NAME, - IDS_FLAGS_TOUCH_FEEDBACK_DESCRIPTION, kOsCrOS, - SINGLE_DISABLE_VALUE_TYPE(switches::kDisableTouchFeedback), - }, - { "ash-enable-mirrored-screen", IDS_FLAGS_ASH_ENABLE_MIRRORED_SCREEN_NAME, IDS_FLAGS_ASH_ENABLE_MIRRORED_SCREEN_DESCRIPTION, kOsCrOS, SINGLE_VALUE_TYPE(ash::switches::kAshEnableMirroredScreen), @@ -1286,6 +1282,9 @@ {"enable-all-bookmarks-view", IDS_FLAGS_ENABLE_ALL_BOOKMARKS_VIEW_NAME, IDS_FLAGS_SHOW_ALL_BOOKMARKS_VIEW_DESCRIPTION, kOsAndroid, FEATURE_VALUE_TYPE(chrome::android::kAllBookmarksFeature)}, + {"enable-downloads-ui", IDS_FLAGS_ENABLE_DOWNLOADS_UI_NAME, + IDS_FLAGS_ENABLE_DOWNLOADS_UI_DESCRIPTION, kOsAndroid, + FEATURE_VALUE_TYPE(chrome::android::kDownloadsUiFeature)}, {"enable-accessibility-tab-switcher", IDS_FLAGS_ACCESSIBILITY_TAB_SWITCHER_NAME, IDS_FLAGS_ACCESSIBILITY_TAB_SWITCHER_DESCRIPTION, kOsAndroid, @@ -1906,7 +1905,7 @@ {"enable-ntp-offline-page-suggestions", IDS_FLAGS_ENABLE_NTP_OFFLINE_PAGE_SUGGESTIONS_NAME, IDS_FLAGS_ENABLE_NTP_OFFLINE_PAGE_SUGGESTIONS_DESCRIPTION, kOsAndroid, - FEATURE_VALUE_TYPE(chrome::android::kNTPOfflinePageSuggestionsFeature)}, + FEATURE_VALUE_TYPE(ntp_snippets::kOfflinePageSuggestionsFeature)}, {"enable-ntp-bookmark-suggestions", IDS_FLAGS_ENABLE_NTP_BOOKMARK_SUGGESTIONS_NAME, IDS_FLAGS_ENABLE_NTP_BOOKMARK_SUGGESTIONS_DESCRIPTION, kOsAndroid, @@ -2038,9 +2037,6 @@ kOsWin | kOsMac | kOsLinux | kOsAndroid, FEATURE_VALUE_TYPE(media::kNewAudioRenderingMixingStrategy)}, #if defined(OS_CHROMEOS) - {"enable-intent-picker", IDS_ENABLE_INTENT_PICKER, - IDS_ENABLE_INTENT_PICKER_DESCRIPTION, kOsCrOS, - SINGLE_VALUE_TYPE(switches::kEnableIntentPicker)}, {"files-quick-view", IDS_FLAGS_FILES_QUICK_VIEW_NAME, IDS_FLAGS_FILES_QUICK_VIEW_DESCRIPTION, kOsCrOS, ENABLE_DISABLE_VALUE_TYPE(chromeos::switches::kEnableFilesQuickView, @@ -2049,16 +2045,12 @@ IDS_FLAGS_QUICK_UNLOCK_PIN_DESCRIPTION, kOsCrOS, FEATURE_VALUE_TYPE(features::kQuickUnlockPin)}, #endif // defined(OS_CHROMEOS) -#if defined(OS_ANDROID) - {"multi-instance-merge-tabs", IDS_FLAGS_MULTI_INSTANCE_MERGE_TABS_NAME, - IDS_FLAGS_MULTI_INSTANCE_MERGE_TABS_DESCRIPTION, kOsAndroid, - SINGLE_VALUE_TYPE(switches::kMultiInstanceMergeTabs)}, - {"enable-web-payments", IDS_FLAGS_ENABLE_WEB_PAYMENTS_NAME, - IDS_FLAGS_ENABLE_WEB_PAYMENTS_DESCRIPTION, kOsAndroid, - FEATURE_VALUE_TYPE(features::kWebPayments)}, -#endif // defined(OS_ANDROID) - // NOTE: Adding new command-line switches requires adding corresponding - // entries to enum "LoginCustomFlags" in histograms.xml. See note in + {"browser-task-scheduler", IDS_FLAGS_BROWSER_TASK_SCHEDULER_NAME, + IDS_FLAGS_BROWSER_TASK_SCHEDULER_DESCRIPTION, kOsAll, + ENABLE_DISABLE_VALUE_TYPE(switches::kEnableBrowserTaskScheduler, + switches::kDisableBrowserTaskScheduler)}, + // NOTE: Adding new command-line switches requires adding corresponding + // entries to enum "LoginCustomFlags" in histograms.xml. See note in // histograms.xml and don't forget to run AboutFlagsHistogramTest unit test. };
diff --git a/chrome/browser/android/banners/app_banner_data_fetcher_android.cc b/chrome/browser/android/banners/app_banner_data_fetcher_android.cc deleted file mode 100644 index 3357f61..0000000 --- a/chrome/browser/android/banners/app_banner_data_fetcher_android.cc +++ /dev/null
@@ -1,121 +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 "chrome/browser/android/banners/app_banner_data_fetcher_android.h" - -#include <utility> - -#include "base/bind.h" -#include "base/callback.h" -#include "base/memory/ptr_util.h" -#include "chrome/browser/android/banners/app_banner_infobar_delegate_android.h" -#include "chrome/browser/android/shortcut_helper.h" -#include "chrome/browser/banners/app_banner_metrics.h" -#include "chrome/browser/infobars/infobar_service.h" -#include "chrome/browser/manifest/manifest_icon_selector.h" -#include "chrome/browser/ui/android/infobars/app_banner_infobar_android.h" -#include "third_party/skia/include/core/SkBitmap.h" - -namespace banners { - -AppBannerDataFetcherAndroid::AppBannerDataFetcherAndroid( - content::WebContents* web_contents, - base::WeakPtr<Delegate> weak_delegate, - int ideal_icon_size_in_dp, - int minimum_icon_size_in_dp, - int ideal_splash_image_size_in_dp, - int minimum_splash_image_size_in_dp, - bool is_debug_mode) - : AppBannerDataFetcher(web_contents, - weak_delegate, - ideal_icon_size_in_dp, - minimum_icon_size_in_dp, - is_debug_mode), - ideal_splash_image_size_in_dp_(ideal_splash_image_size_in_dp), - minimum_splash_image_size_in_dp_(minimum_splash_image_size_in_dp) {} - -AppBannerDataFetcherAndroid::~AppBannerDataFetcherAndroid() { -} - -std::string AppBannerDataFetcherAndroid::GetBannerType() { - return native_app_data_.is_null() - ? AppBannerDataFetcher::GetBannerType() : "android"; -} - -bool AppBannerDataFetcherAndroid::ContinueFetching( - const base::string16& app_title, - const std::string& app_package, - const base::android::JavaRef<jobject>& app_data, - const GURL& image_url) { - set_app_title(app_title); - native_app_package_ = app_package; - native_app_data_.Reset(app_data); - return FetchAppIcon(GetWebContents(), image_url); -} - -std::string AppBannerDataFetcherAndroid::GetAppIdentifier() { - return native_app_data_.is_null() - ? AppBannerDataFetcher::GetAppIdentifier() : native_app_package_; -} - -base::Closure AppBannerDataFetcherAndroid::FetchWebappSplashScreenImageCallback( - const std::string& webapp_id) { - content::WebContents* web_contents = GetWebContents(); - DCHECK(web_contents); - - GURL image_url = ManifestIconSelector::FindBestMatchingIcon( - manifest().icons, ideal_splash_image_size_in_dp_, - minimum_splash_image_size_in_dp_); - - return base::Bind(&ShortcutHelper::FetchSplashScreenImage, - web_contents, image_url, ideal_splash_image_size_in_dp_, - minimum_splash_image_size_in_dp_, webapp_id); -} - -bool AppBannerDataFetcherAndroid::IsWebAppInstalled( - content::BrowserContext* browser_context, - const GURL& start_url) { - // Check whether a WebAPK is installed in order to block showing the app - // banner if a WebAPK is installed even after a user clears Chrome's data. - // This function does not check whether a non-WebAPK web app is installed. - return ShortcutHelper::IsWebApkInstalled(start_url); -} - -void AppBannerDataFetcherAndroid::ShowBanner(const GURL& icon_url, - const SkBitmap* icon, - const base::string16& title, - const std::string& referrer) { - content::WebContents* web_contents = GetWebContents(); - DCHECK(web_contents); - - infobars::InfoBar* infobar = nullptr; - if (native_app_data_.is_null()) { - std::unique_ptr<AppBannerInfoBarDelegateAndroid> delegate( - new AppBannerInfoBarDelegateAndroid(event_request_id(), this, title, - icon_url, new SkBitmap(*icon), - manifest_url(), manifest())); - - infobar = new AppBannerInfoBarAndroid(std::move(delegate), - manifest().start_url); - if (infobar) { - RecordDidShowBanner("AppBanner.WebApp.Shown"); - TrackDisplayEvent(DISPLAY_EVENT_WEB_APP_BANNER_CREATED); - } - } else { - std::unique_ptr<AppBannerInfoBarDelegateAndroid> delegate( - new AppBannerInfoBarDelegateAndroid( - event_request_id(), title, new SkBitmap(*icon), native_app_data_, - native_app_package_, referrer)); - infobar = - new AppBannerInfoBarAndroid(std::move(delegate), native_app_data_); - if (infobar) { - RecordDidShowBanner("AppBanner.NativeApp.Shown"); - TrackDisplayEvent(DISPLAY_EVENT_NATIVE_APP_BANNER_CREATED); - } - } - InfoBarService::FromWebContents(web_contents) - ->AddInfoBar(base::WrapUnique(infobar)); -} - -} // namespace banners
diff --git a/chrome/browser/android/banners/app_banner_data_fetcher_android.h b/chrome/browser/android/banners/app_banner_data_fetcher_android.h deleted file mode 100644 index 5fc7ae0..0000000 --- a/chrome/browser/android/banners/app_banner_data_fetcher_android.h +++ /dev/null
@@ -1,65 +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 CHROME_BROWSER_ANDROID_BANNERS_APP_BANNER_DATA_FETCHER_ANDROID_H_ -#define CHROME_BROWSER_ANDROID_BANNERS_APP_BANNER_DATA_FETCHER_ANDROID_H_ - -#include "base/android/jni_android.h" -#include "base/callback_forward.h" -#include "base/macros.h" -#include "chrome/browser/banners/app_banner_data_fetcher.h" - -namespace banners { - -// Fetches data required to show a banner for the URL currently shown by the -// WebContents. Extends the regular fetch to add support for Android apps. -class AppBannerDataFetcherAndroid : public AppBannerDataFetcher { - public: - AppBannerDataFetcherAndroid(content::WebContents* web_contents, - base::WeakPtr<Delegate> weak_delegate, - int ideal_icon_size_in_dp, - int minimum_icon_size_in_dp, - int ideal_splash_image_size_in_dp, - int minimum_splash_image_size_in_dp, - bool is_debug_mode); - - // Saves information about the Android app being promoted by the current page, - // then continues the creation pipeline. - bool ContinueFetching(const base::string16& app_title, - const std::string& app_package, - const base::android::JavaRef<jobject>& app_data, - const GURL& image_url); - - // Returns a callback which fetches the splash screen image and stores it in - // WebappDataStorage. - base::Closure FetchWebappSplashScreenImageCallback( - const std::string& webapp_id); - - protected: - ~AppBannerDataFetcherAndroid() override; - - std::string GetBannerType() override; - std::string GetAppIdentifier() override; - - private: - bool IsWebAppInstalled(content::BrowserContext* browser_context, - const GURL& start_url) override; - - void ShowBanner(const GURL& icon_url, - const SkBitmap* icon, - const base::string16& title, - const std::string& referrer) override; - - base::android::ScopedJavaGlobalRef<jobject> native_app_data_; - std::string native_app_package_; - - int ideal_splash_image_size_in_dp_; - int minimum_splash_image_size_in_dp_; - - DISALLOW_COPY_AND_ASSIGN(AppBannerDataFetcherAndroid); -}; - -} // namespace banners - -#endif // CHROME_BROWSER_ANDROID_BANNERS_APP_BANNER_DATA_FETCHER_ANDROID_H_
diff --git a/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc b/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc index 643eb4ca..04b164f 100644 --- a/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc +++ b/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc
@@ -8,12 +8,13 @@ #include "base/android/jni_string.h" #include "base/guid.h" #include "base/location.h" +#include "base/memory/ptr_util.h" #include "base/strings/string16.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/android/shortcut_helper.h" #include "chrome/browser/android/shortcut_info.h" #include "chrome/browser/android/tab_android.h" -#include "chrome/browser/banners/app_banner_data_fetcher.h" +#include "chrome/browser/banners/app_banner_manager.h" #include "chrome/browser/banners/app_banner_metrics.h" #include "chrome/browser/banners/app_banner_settings_helper.h" #include "chrome/browser/browser_process.h" @@ -40,38 +41,38 @@ namespace banners { AppBannerInfoBarDelegateAndroid::AppBannerInfoBarDelegateAndroid( - int event_request_id, - scoped_refptr<AppBannerDataFetcherAndroid> data_fetcher, + base::WeakPtr<AppBannerManager> weak_manager, const base::string16& app_title, - const GURL& app_icon_url, - SkBitmap* app_icon, const GURL& manifest_url, - const content::Manifest& manifest) - : data_fetcher_(data_fetcher), + const content::Manifest& manifest, + const GURL& icon_url, + std::unique_ptr<SkBitmap> icon, + int event_request_id) + : weak_manager_(weak_manager), app_title_(app_title), - app_icon_url_(app_icon_url), - app_icon_(app_icon), - event_request_id_(event_request_id), manifest_url_(manifest_url), manifest_(manifest), + icon_url_(icon_url), + icon_(std::move(icon)), + event_request_id_(event_request_id), has_user_interaction_(false) { DCHECK(!manifest.IsEmpty()); CreateJavaDelegate(); } AppBannerInfoBarDelegateAndroid::AppBannerInfoBarDelegateAndroid( - int event_request_id, const base::string16& app_title, - SkBitmap* app_icon, const base::android::ScopedJavaGlobalRef<jobject>& native_app_data, + std::unique_ptr<SkBitmap> icon, const std::string& native_app_package, - const std::string& referrer) + const std::string& referrer, + int event_request_id) : app_title_(app_title), - app_icon_(app_icon), - event_request_id_(event_request_id), native_app_data_(native_app_data), + icon_(std::move(icon)), native_app_package_(native_app_package), referrer_(referrer), + event_request_id_(event_request_id), has_user_interaction_(false) { DCHECK(!native_app_data_.is_null()); CreateJavaDelegate(); @@ -124,7 +125,7 @@ web_contents->GetURL(), native_app_package_, AppBannerSettingsHelper::APP_BANNER_EVENT_DID_ADD_TO_HOMESCREEN, - AppBannerDataFetcher::GetCurrentTime()); + AppBannerManager::GetCurrentTime()); TrackInstallEvent(INSTALL_EVENT_NATIVE_APP_INSTALL_STARTED); rappor::SampleDomainAndRegistryFromGURL(g_browser_process->rappor_service(), @@ -174,7 +175,7 @@ } gfx::Image AppBannerInfoBarDelegateAndroid::GetIcon() const { - return gfx::Image::CreateFrom1xBitmap(*app_icon_.get()); + return gfx::Image::CreateFrom1xBitmap(*icon_.get()); } void AppBannerInfoBarDelegateAndroid::InfoBarDismissed() { @@ -253,19 +254,20 @@ web_contents, manifest_.start_url.spec(), AppBannerSettingsHelper::WEB); - ShortcutInfo info(GURL::EmptyGURL()); - info.UpdateFromManifest(manifest_); - info.manifest_url = manifest_url_; - info.icon_url = app_icon_url_; - info.UpdateSource(ShortcutInfo::SOURCE_APP_BANNER); + if (weak_manager_) { + ShortcutInfo info(GURL::EmptyGURL()); + info.UpdateFromManifest(manifest_); + info.manifest_url = manifest_url_; + info.icon_url = icon_url_; + info.UpdateSource(ShortcutInfo::SOURCE_APP_BANNER); - const std::string& uid = base::GenerateGUID(); - content::BrowserThread::PostTask( - content::BrowserThread::IO, FROM_HERE, - base::Bind(&ShortcutHelper::AddToLauncherInBackgroundWithSkBitmap, - web_contents->GetBrowserContext(), info, uid, - *app_icon_.get(), - data_fetcher_->FetchWebappSplashScreenImageCallback(uid))); + const std::string& uid = base::GenerateGUID(); + content::BrowserThread::PostTask( + content::BrowserThread::IO, FROM_HERE, + base::Bind(&ShortcutHelper::AddToLauncherInBackgroundWithSkBitmap, + web_contents->GetBrowserContext(), info, uid, *icon_.get(), + weak_manager_->FetchWebappSplashScreenImageCallback(uid))); + } SendBannerAccepted(web_contents, "web"); return true;
diff --git a/chrome/browser/android/banners/app_banner_infobar_delegate_android.h b/chrome/browser/android/banners/app_banner_infobar_delegate_android.h index d036a48..f678fb5 100644 --- a/chrome/browser/android/banners/app_banner_infobar_delegate_android.h +++ b/chrome/browser/android/banners/app_banner_infobar_delegate_android.h
@@ -7,8 +7,9 @@ #include "base/android/scoped_java_ref.h" #include "base/macros.h" +#include "base/memory/weak_ptr.h" #include "base/strings/string16.h" -#include "chrome/browser/android/banners/app_banner_data_fetcher_android.h" +#include "chrome/browser/banners/app_banner_manager.h" #include "components/infobars/core/confirm_infobar_delegate.h" #include "content/public/common/manifest.h" #include "ui/gfx/image/image.h" @@ -20,33 +21,33 @@ namespace infobars { class InfoBarManager; -} // namespace infobars +} class AppBannerInfoBar; namespace banners { -// Manages installation of an app being promoted by a webpage. +// Manages installation of an app being promoted by a page. class AppBannerInfoBarDelegateAndroid : public ConfirmInfoBarDelegate { public: // Delegate for promoting a web app. AppBannerInfoBarDelegateAndroid( - int event_request_id, - scoped_refptr<AppBannerDataFetcherAndroid> data_fetcher, + base::WeakPtr<AppBannerManager> weak_manager, const base::string16& app_title, - const GURL& app_icon_url, - SkBitmap* app_icon, const GURL& manifest_url, - const content::Manifest& manifest); + const content::Manifest& manifest, + const GURL& icon_url, + std::unique_ptr<SkBitmap> icon, + int event_request_id); // Delegate for promoting an Android app. AppBannerInfoBarDelegateAndroid( - int event_request_id, const base::string16& app_title, - SkBitmap* app_icon, const base::android::ScopedJavaGlobalRef<jobject>& native_app_data, + std::unique_ptr<SkBitmap> icon, const std::string& native_app_package, - const std::string& referrer); + const std::string& referrer, + int event_request_id); ~AppBannerInfoBarDelegateAndroid() override; @@ -82,19 +83,20 @@ base::android::ScopedJavaGlobalRef<jobject> java_delegate_; // Used to fetch the splash screen icon for webapps. - scoped_refptr<AppBannerDataFetcherAndroid> data_fetcher_; + base::WeakPtr<AppBannerManager> weak_manager_; base::string16 app_title_; - GURL app_icon_url_; - std::unique_ptr<SkBitmap> app_icon_; - - int event_request_id_; GURL manifest_url_; content::Manifest manifest_; base::android::ScopedJavaGlobalRef<jobject> native_app_data_; + + GURL icon_url_; + std::unique_ptr<SkBitmap> icon_; + std::string native_app_package_; std::string referrer_; + int event_request_id_; bool has_user_interaction_; DISALLOW_COPY_AND_ASSIGN(AppBannerInfoBarDelegateAndroid);
diff --git a/chrome/browser/android/banners/app_banner_manager_android.cc b/chrome/browser/android/banners/app_banner_manager_android.cc index 7a46174..a0456b2d 100644 --- a/chrome/browser/android/banners/app_banner_manager_android.cc +++ b/chrome/browser/android/banners/app_banner_manager_android.cc
@@ -2,22 +2,30 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <utility> + #include "chrome/browser/android/banners/app_banner_manager_android.h" #include "base/android/jni_android.h" #include "base/android/jni_string.h" -#include "chrome/browser/android/banners/app_banner_data_fetcher_android.h" +#include "base/memory/ptr_util.h" +#include "base/strings/utf_string_conversions.h" +#include "chrome/browser/android/banners/app_banner_infobar_delegate_android.h" #include "chrome/browser/android/shortcut_helper.h" #include "chrome/browser/banners/app_banner_metrics.h" +#include "chrome/browser/infobars/infobar_service.h" +#include "chrome/browser/manifest/manifest_icon_downloader.h" +#include "chrome/browser/manifest/manifest_icon_selector.h" +#include "chrome/browser/ui/android/infobars/app_banner_infobar_android.h" #include "chrome/common/chrome_constants.h" #include "content/public/browser/web_contents.h" #include "content/public/common/frame_navigate_params.h" #include "jni/AppBannerManager_jni.h" +#include "third_party/skia/include/core/SkBitmap.h" using base::android::ConvertJavaStringToUTF8; using base::android::ConvertJavaStringToUTF16; using base::android::ConvertUTF8ToJavaString; -using base::android::ConvertUTF16ToJavaString; using base::android::JavaParamRef; using base::android::ScopedJavaLocalRef; @@ -46,15 +54,33 @@ java_banner_manager_.Reset(); } +base::Closure AppBannerManagerAndroid::FetchWebappSplashScreenImageCallback( + const std::string& webapp_id) { + content::WebContents* contents = web_contents(); + DCHECK(contents); + + int ideal_splash_image_size_in_dp = + ShortcutHelper::GetIdealSplashImageSizeInDp(); + int minimum_splash_image_size_in_dp = + ShortcutHelper::GetMinimumSplashImageSizeInDp(); + GURL image_url = ManifestIconSelector::FindBestMatchingIcon( + manifest_.icons, ideal_splash_image_size_in_dp, + minimum_splash_image_size_in_dp); + + return base::Bind(&ShortcutHelper::FetchSplashScreenImage, contents, + image_url, ideal_splash_image_size_in_dp, + minimum_splash_image_size_in_dp, webapp_id); +} + const base::android::ScopedJavaGlobalRef<jobject>& AppBannerManagerAndroid::GetJavaBannerManager() const { return java_banner_manager_; } -bool AppBannerManagerAndroid::IsFetcherActive( +bool AppBannerManagerAndroid::IsActiveForTesting( JNIEnv* env, const JavaParamRef<jobject>& obj) { - return AppBannerManager::IsFetcherActive(); + return is_active(); } bool AppBannerManagerAndroid::OnAppDetailsRetrieved( @@ -64,16 +90,15 @@ const JavaParamRef<jstring>& japp_title, const JavaParamRef<jstring>& japp_package, const JavaParamRef<jstring>& jicon_url) { - AppBannerDataFetcherAndroid* android_fetcher = - static_cast<AppBannerDataFetcherAndroid*>(data_fetcher().get()); - if (!CheckFetcherMatchesContents(android_fetcher->is_debug_mode())) - return false; + native_app_data_.Reset(japp_data); + app_title_ = ConvertJavaStringToUTF16(env, japp_title); + native_app_package_ = ConvertJavaStringToUTF8(env, japp_package); + icon_url_ = GURL(ConvertJavaStringToUTF8(env, jicon_url)); - GURL image_url = GURL(ConvertJavaStringToUTF8(env, jicon_url)); - - return android_fetcher->ContinueFetching( - ConvertJavaStringToUTF16(env, japp_title), - ConvertJavaStringToUTF8(env, japp_package), japp_data, image_url); + return ManifestIconDownloader::Download( + web_contents(), icon_url_, GetIdealIconSizeInDp(), + GetMinimumIconSizeInDp(), + base::Bind(&AppBannerManager::OnAppIconFetched, GetWeakPtr())); } void AppBannerManagerAndroid::RequestAppBanner(const GURL& validated_url, @@ -85,22 +110,106 @@ AppBannerManager::RequestAppBanner(validated_url, is_debug_mode); } -AppBannerDataFetcher* AppBannerManagerAndroid::CreateAppBannerDataFetcher( - base::WeakPtr<Delegate> weak_delegate, - bool is_debug_mode) { - return new AppBannerDataFetcherAndroid( - web_contents(), weak_delegate, - ShortcutHelper::GetIdealHomescreenIconSizeInDp(), - ShortcutHelper::GetMinimumHomescreenIconSizeInDp(), - ShortcutHelper::GetIdealSplashImageSizeInDp(), - ShortcutHelper::GetMinimumSplashImageSizeInDp(), is_debug_mode); +std::string AppBannerManagerAndroid::GetAppIdentifier() { + return native_app_data_.is_null() ? AppBannerManager::GetAppIdentifier() + : native_app_package_; } -bool AppBannerManagerAndroid::HandleNonWebApp(const std::string& platform, +std::string AppBannerManagerAndroid::GetBannerType() { + return native_app_data_.is_null() ? AppBannerManager::GetBannerType() + : "android"; +} + +int AppBannerManagerAndroid::GetIdealIconSizeInDp() { + return ShortcutHelper::GetIdealHomescreenIconSizeInDp(); +} + +int AppBannerManagerAndroid::GetMinimumIconSizeInDp() { + return ShortcutHelper::GetMinimumHomescreenIconSizeInDp(); +} + +bool AppBannerManagerAndroid::IsWebAppInstalled( + content::BrowserContext* browser_context, + const GURL& start_url) { + // Returns true if a WebAPK is installed. Does not check whether a non-WebAPK + // web app is installed: this is detected by the content settings check in + // AppBannerSettingsHelper::ShouldShowBanner (due to the lack of an API to + // detect what is and isn't on the Android homescreen). + // This method will still detect the presence of a WebAPK even if Chrome's + // data is cleared. + return ShortcutHelper::IsWebApkInstalled(start_url); +} + +void AppBannerManagerAndroid::PerformInstallableCheck() { + // Check if the manifest prefers that we show a native app banner. If so, call + // to Java to verify the details. + if (manifest_.prefer_related_applications && + manifest_.related_applications.size()) { + for (const auto& application : manifest_.related_applications) { + std::string platform = base::UTF16ToUTF8(application.platform.string()); + std::string id = base::UTF16ToUTF8(application.id.string()); + if (CanHandleNonWebApp(platform, application.url, id)) + return; + } + } + + // No native app banner was requested. Continue checking for a web app banner. + AppBannerManager::PerformInstallableCheck(); +} + +void AppBannerManagerAndroid::OnAppIconFetched(const SkBitmap& bitmap) { + if (bitmap.drawsNothing()) { + ReportError(web_contents(), NO_ICON_AVAILABLE); + Stop(); + } + + if (!is_active()) + return; + + icon_.reset(new SkBitmap(bitmap)); + SendBannerPromptRequest(); +} + +void AppBannerManagerAndroid::ShowBanner() { + content::WebContents* contents = web_contents(); + DCHECK(contents); + + infobars::InfoBar* infobar = nullptr; + if (native_app_data_.is_null()) { + std::unique_ptr<AppBannerInfoBarDelegateAndroid> delegate( + new AppBannerInfoBarDelegateAndroid( + GetWeakPtr(), app_title_, manifest_url_, manifest_, icon_url_, + std::move(icon_), event_request_id())); + + infobar = new AppBannerInfoBarAndroid(std::move(delegate), + manifest_.start_url); + if (infobar) { + RecordDidShowBanner("AppBanner.WebApp.Shown"); + TrackDisplayEvent(DISPLAY_EVENT_WEB_APP_BANNER_CREATED); + } + } else { + std::unique_ptr<AppBannerInfoBarDelegateAndroid> delegate( + new AppBannerInfoBarDelegateAndroid( + app_title_, native_app_data_, std::move(icon_), native_app_package_, + referrer_, event_request_id())); + infobar = + new AppBannerInfoBarAndroid(std::move(delegate), native_app_data_); + if (infobar) { + RecordDidShowBanner("AppBanner.NativeApp.Shown"); + TrackDisplayEvent(DISPLAY_EVENT_NATIVE_APP_BANNER_CREATED); + } + } + + if (infobar) { + InfoBarService::FromWebContents(contents)->AddInfoBar( + base::WrapUnique(infobar)); + } +} + +bool AppBannerManagerAndroid::CanHandleNonWebApp(const std::string& platform, const GURL& url, - const std::string& id, - bool is_debug_mode) { - if (!CheckPlatformAndId(platform, id, is_debug_mode)) + const std::string& id) { + if (!CheckPlatformAndId(platform, id)) return false; banners::TrackDisplayEvent(DISPLAY_EVENT_NATIVE_APP_BANNER_REQUESTED); @@ -112,13 +221,11 @@ std::string id_from_app_url = ExtractQueryValueForName(url, kIdName); if (id_from_app_url.size() && id != id_from_app_url) { - banners::OutputDeveloperNotShownMessage( - web_contents(), banners::kIgnoredIdsDoNotMatch, is_debug_mode); + ReportError(web_contents(), IDS_DO_NOT_MATCH); return false; } - std::string referrer = - ExtractQueryValueForName(url, kReferrerName); + std::string referrer = ExtractQueryValueForName(url, kReferrerName); // Attach the chrome_inline referrer value, prefixed with "&" if the referrer // is non empty. @@ -128,15 +235,12 @@ referrer.append("&").append(kPlayInlineReferrer); ScopedJavaLocalRef<jstring> jurl( - ConvertUTF8ToJavaString(env, data_fetcher()->validated_url().spec())); - ScopedJavaLocalRef<jstring> jpackage( - ConvertUTF8ToJavaString(env, id)); - ScopedJavaLocalRef<jstring> jreferrer( - ConvertUTF8ToJavaString(env, referrer)); + ConvertUTF8ToJavaString(env, validated_url_.spec())); + ScopedJavaLocalRef<jstring> jpackage(ConvertUTF8ToJavaString(env, id)); + ScopedJavaLocalRef<jstring> jreferrer(ConvertUTF8ToJavaString(env, referrer)); Java_AppBannerManager_fetchAppDetails( - env, java_banner_manager_.obj(), jurl.obj(), - jpackage.obj(), jreferrer.obj(), - ShortcutHelper::GetIdealHomescreenIconSizeInDp()); + env, java_banner_manager_.obj(), jurl.obj(), jpackage.obj(), + jreferrer.obj(), GetIdealIconSizeInDp()); return true; } @@ -146,32 +250,14 @@ Java_AppBannerManager_create(env, reinterpret_cast<intptr_t>(this))); } -bool AppBannerManagerAndroid::CheckFetcherMatchesContents(bool is_debug_mode) { - if (!web_contents()) - return false; - - if (!data_fetcher() || - data_fetcher()->validated_url() != web_contents()->GetURL()) { - banners::OutputDeveloperNotShownMessage( - web_contents(), banners::kUserNavigatedBeforeBannerShown, - is_debug_mode); - return false; - } - return true; -} - bool AppBannerManagerAndroid::CheckPlatformAndId(const std::string& platform, - const std::string& id, - bool is_debug_mode) { + const std::string& id) { if (platform != kPlayPlatform) { - banners::OutputDeveloperNotShownMessage( - web_contents(), banners::kIgnoredNotSupportedOnAndroid, platform, - is_debug_mode); + ReportError(web_contents(), PLATFORM_NOT_SUPPORTED_ON_ANDROID); return false; } if (id.empty()) { - banners::OutputDeveloperNotShownMessage( - web_contents(), banners::kIgnoredNoId, is_debug_mode); + ReportError(web_contents(), NO_ID_SPECIFIED); return false; } return true; @@ -230,7 +316,7 @@ void SetTimeDeltaForTesting(JNIEnv* env, const JavaParamRef<jclass>& clazz, jint days) { - AppBannerDataFetcher::SetTimeDeltaForTesting(days); + AppBannerManager::SetTimeDeltaForTesting(days); } } // namespace banners
diff --git a/chrome/browser/android/banners/app_banner_manager_android.h b/chrome/browser/android/banners/app_banner_manager_android.h index d7f67684..67b2d126 100644 --- a/chrome/browser/android/banners/app_banner_manager_android.h +++ b/chrome/browser/android/banners/app_banner_manager_android.h
@@ -5,19 +5,26 @@ #ifndef CHROME_BROWSER_ANDROID_BANNERS_APP_BANNER_MANAGER_ANDROID_H_ #define CHROME_BROWSER_ANDROID_BANNERS_APP_BANNER_MANAGER_ANDROID_H_ -#include "base/android/jni_android.h" -#include "base/android/jni_weak_ref.h" +#include "base/android/scoped_java_ref.h" +#include "base/callback_forward.h" #include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "chrome/browser/android/banners/app_banner_data_fetcher_android.h" -#include "chrome/browser/banners/app_banner_debug_log.h" #include "chrome/browser/banners/app_banner_manager.h" #include "content/public/browser/web_contents_user_data.h" namespace banners { -class AppBannerDataFetcherAndroid; // Extends the AppBannerManager to support native Android apps. +// This class owns a Java-side AppBannerManager which is used to interface with +// the Java runtime for fetching native app data and installing them when +// requested. +// A site requests a native app banner by setting "prefer_related_applications" +// to true in its manifest, and providing at least one related application for +// the "play" platform with a Play Store ID. +// This class uses that information to request the app's metadata, including an +// icon. If successful, the icon is downloaded and the native app banner shown. +// Otherwise, if no related applications were detected, or their manifest +// entries were invalid, this class falls back to trying to verify if a web app +// banner is suitable. class AppBannerManagerAndroid : public AppBannerManager, public content::WebContentsUserData<AppBannerManagerAndroid> { @@ -25,12 +32,13 @@ explicit AppBannerManagerAndroid(content::WebContents* web_contents); ~AppBannerManagerAndroid() override; + // Returns a reference to the Java-side AppBannerManager owned by this object. const base::android::ScopedJavaGlobalRef<jobject>& GetJavaBannerManager() const; - // Return whether a BitmapFetcher is active. - bool IsFetcherActive(JNIEnv* env, - const base::android::JavaParamRef<jobject>& jobj); + // Returns true if this object is currently active. + bool IsActiveForTesting(JNIEnv* env, + const base::android::JavaParamRef<jobject>& jobj); // Called when the Java-side has retrieved information for the app. // Returns |false| if an icon fetch couldn't be kicked off. @@ -42,40 +50,64 @@ const base::android::JavaParamRef<jstring>& japp_package, const base::android::JavaParamRef<jstring>& jicon_url); + // AppBannerManager overrides. void RequestAppBanner(const GURL& validated_url, bool is_debug_mode) override; + // Returns a callback which fetches the splash screen image and stores it in + // a WebappDataStorage. + base::Closure FetchWebappSplashScreenImageCallback( + const std::string& webapp_id) override; + // Registers native methods. static bool Register(JNIEnv* env); protected: - AppBannerDataFetcher* CreateAppBannerDataFetcher( - base::WeakPtr<AppBannerDataFetcher::Delegate> weak_delegate, - bool is_debug_mode) override; + // AppBannerManager overrides. + std::string GetAppIdentifier() override; + std::string GetBannerType() override; + int GetIdealIconSizeInDp() override; + int GetMinimumIconSizeInDp() override; + bool IsWebAppInstalled(content::BrowserContext* browser_context, + const GURL& start_url) override; + + void PerformInstallableCheck() override; + void OnAppIconFetched(const SkBitmap& bitmap) override; + void ShowBanner() override; private: friend class content::WebContentsUserData<AppBannerManagerAndroid>; - // AppBannerDataFetcher::Delegate overrides. - bool HandleNonWebApp(const std::string& platform, - const GURL& url, - const std::string& id, - bool is_debug_mode) override; - + // Creates the Java-side AppBannerManager. void CreateJavaBannerManager(); - bool CheckFetcherMatchesContents(bool is_debug_mode); + // Returns true if |platform| and |id| are valid for querying the Play Store. bool CheckPlatformAndId(const std::string& platform, - const std::string& id, - bool is_debug_mode); + const std::string& id); + // Returns the query value for |name| in |url|, e.g. example.com?name=value. std::string ExtractQueryValueForName(const GURL& url, const std::string& name); - // AppBannerManager on the Java side. + // Returns true if |platform|, |url|, and |id| are consistent and can be used + // to query the Play Store for a native app. The query may not necessarily + // succeed (e.g. |id| doesn't map to anything), but if this method returns + // true, only a native app banner may be shown, and the web app banner flow + // will not be run. + bool CanHandleNonWebApp(const std::string& platform, + const GURL& url, + const std::string& id); + + // The Java-side AppBannerManager. base::android::ScopedJavaGlobalRef<jobject> java_banner_manager_; + // Java-side object containing data about a native app. + base::android::ScopedJavaGlobalRef<jobject> native_app_data_; + + // App package name for a native app banner. + std::string native_app_package_; + DISALLOW_COPY_AND_ASSIGN(AppBannerManagerAndroid); -}; // class AppBannerManagerAndroid +}; } // namespace banners
diff --git a/chrome/browser/android/blimp/blimp_client_context_factory.cc b/chrome/browser/android/blimp/blimp_client_context_factory.cc index f070d66..dd63089c 100644 --- a/chrome/browser/android/blimp/blimp_client_context_factory.cc +++ b/chrome/browser/android/blimp/blimp_client_context_factory.cc
@@ -35,7 +35,9 @@ content::BrowserContext* context) const { return blimp::client::BlimpClientContext::Create( content::BrowserThread::GetTaskRunnerForThread( - content::BrowserThread::IO)); + content::BrowserThread::IO), + content::BrowserThread::GetTaskRunnerForThread( + content::BrowserThread::FILE)); } content::BrowserContext* BlimpClientContextFactory::GetBrowserContextToUse(
diff --git a/chrome/browser/android/blimp/chrome_blimp_client_context_delegate.cc b/chrome/browser/android/blimp/chrome_blimp_client_context_delegate.cc index 278df786..dc1ca4e3 100644 --- a/chrome/browser/android/blimp/chrome_blimp_client_context_delegate.cc +++ b/chrome/browser/android/blimp/chrome_blimp_client_context_delegate.cc
@@ -27,3 +27,7 @@ blimp::client::BlimpContents* blimp_contents) { AttachProfileToBlimpContents(blimp_contents, profile_); } + +void ChromeBlimpClientContextDelegate::OnAssignmentConnectionAttempted( + blimp::client::AssignmentRequestResult result, + const blimp::client::Assignment& assignment) {}
diff --git a/chrome/browser/android/blimp/chrome_blimp_client_context_delegate.h b/chrome/browser/android/blimp/chrome_blimp_client_context_delegate.h index c41765d..4e37ab60 100644 --- a/chrome/browser/android/blimp/chrome_blimp_client_context_delegate.h +++ b/chrome/browser/android/blimp/chrome_blimp_client_context_delegate.h
@@ -31,6 +31,9 @@ // BlimpClientContextDelegate implementation. void AttachBlimpContentsHelpers( blimp::client::BlimpContents* blimp_contents) override; + void OnAssignmentConnectionAttempted( + blimp::client::AssignmentRequestResult result, + const blimp::client::Assignment& assignment) override; private: // The profile this delegate is used for.
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc index db8d66b9..8de418c 100644 --- a/chrome/browser/android/chrome_feature_list.cc +++ b/chrome/browser/android/chrome_feature_list.cc
@@ -35,13 +35,13 @@ &features::kSimplifiedFullscreenUI, &features::kWebPayments, &kAllBookmarksFeature, + &kDownloadsUiFeature, &kAndroidPayIntegrationV1, &kImportantSitesInCBD, &ntp_snippets::kContentSuggestionsFeature, &kNTPFakeOmniboxTextFeature, &kNTPMaterialDesign, &kNTPOfflinePagesFeature, - &kNTPOfflinePageSuggestionsFeature, &kNTPToolbarFeature, &kPhysicalWebFeature, &kPhysicalWebIgnoreOtherClientsFeature, @@ -59,6 +59,9 @@ const base::Feature kAllBookmarksFeature{"AllBookmarks", base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kDownloadsUiFeature{"DownloadsUi", + base::FEATURE_DISABLED_BY_DEFAULT}; + const base::Feature kImportantSitesInCBD{"ImportantSitesInCBD", base::FEATURE_DISABLED_BY_DEFAULT}; @@ -68,9 +71,6 @@ const base::Feature kNTPOfflinePagesFeature{"NTPOfflinePages", base::FEATURE_DISABLED_BY_DEFAULT}; -const base::Feature kNTPOfflinePageSuggestionsFeature{ - "NTPOfflinePageSuggestions", base::FEATURE_DISABLED_BY_DEFAULT}; - const base::Feature kNTPToolbarFeature{"NTPToolbar", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h index 9be979d..2ac8136 100644 --- a/chrome/browser/android/chrome_feature_list.h +++ b/chrome/browser/android/chrome_feature_list.h
@@ -13,11 +13,11 @@ namespace android { extern const base::Feature kAllBookmarksFeature; +extern const base::Feature kDownloadsUiFeature; extern const base::Feature kAndroidPayIntegrationV1; extern const base::Feature kImportantSitesInCBD; extern const base::Feature kNTPMaterialDesign; extern const base::Feature kNTPOfflinePagesFeature; -extern const base::Feature kNTPOfflinePageSuggestionsFeature; extern const base::Feature kNTPToolbarFeature; extern const base::Feature kNTPFakeOmniboxTextFeature; extern const base::Feature kPhysicalWebFeature;
diff --git a/chrome/browser/android/contextualsearch/contextual_search_delegate.cc b/chrome/browser/android/contextualsearch/contextual_search_delegate.cc index 7b70a1b..bf28538 100644 --- a/chrome/browser/android/contextualsearch/contextual_search_delegate.cc +++ b/chrome/browser/android/contextualsearch/contextual_search_delegate.cc
@@ -41,6 +41,7 @@ const char kContextualSearchResponseSelectedTextParam[] = "selected_text"; const char kContextualSearchResponseSearchTermParam[] = "search_term"; const char kContextualSearchResponseLanguageParam[] = "lang"; +const char kContextualSearchResponseMidParam[] = "mid"; const char kContextualSearchResponseResolvedTermParam[] = "resolved_term"; const char kContextualSearchPreventPreload[] = "prevent_preload"; const char kContextualSearchMentions[] = "mentions"; @@ -156,6 +157,7 @@ std::string search_term; std::string display_text; std::string alternate_term; + std::string mid; std::string prevent_preload; int mention_start = 0; int mention_end = 0; @@ -164,7 +166,7 @@ std::string context_language; DecodeSearchTermFromJsonResponse( - json_string, &search_term, &display_text, &alternate_term, + json_string, &search_term, &display_text, &alternate_term, &mid, &prevent_preload, &mention_start, &mention_end, &context_language); if (mention_start != 0 || mention_end != 0) { // Sanity check that our selection is non-zero and it is less than @@ -184,7 +186,7 @@ } bool is_invalid = response_code == net::URLFetcher::RESPONSE_CODE_INVALID; return std::unique_ptr<ResolvedSearchTerm>(new ResolvedSearchTerm( - is_invalid, response_code, search_term, display_text, alternate_term, + is_invalid, response_code, search_term, display_text, alternate_term, mid, prevent_preload == kDoPreventPreloadValue, start_adjust, end_adjust, context_language)); } @@ -430,6 +432,7 @@ std::string* search_term, std::string* display_text, std::string* alternate_term, + std::string* mid, std::string* prevent_preload, int* mention_start, int* mention_end, @@ -456,6 +459,7 @@ display_text)) { *display_text = *search_term; } + dict->GetString(kContextualSearchResponseMidParam, mid); // Extract mentions for selection expansion. if (!field_trial_->IsDecodeMentionsDisabled()) {
diff --git a/chrome/browser/android/contextualsearch/contextual_search_delegate.h b/chrome/browser/android/contextualsearch/contextual_search_delegate.h index 588baf38..7c6f2810 100644 --- a/chrome/browser/android/contextualsearch/contextual_search_delegate.h +++ b/chrome/browser/android/contextualsearch/contextual_search_delegate.h
@@ -188,6 +188,7 @@ std::string* search_term, std::string* display_text, std::string* alternate_term, + std::string* mid, std::string* prevent_preload, int* mention_start, int* mention_end,
diff --git a/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc b/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc index 8b174bb..0fc6473 100644 --- a/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc +++ b/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc
@@ -57,6 +57,7 @@ is_invalid_ = true; response_code_ = -1; search_term_ = "invalid"; + mid_ = ""; display_text_ = "unknown"; context_language_ = ""; } @@ -170,6 +171,7 @@ std::string search_term() { return search_term_; } std::string display_text() { return display_text_; } std::string alternate_term() { return alternate_term_; } + std::string mid() { return mid_; } bool do_prevent_preload() { return prevent_preload_; } std::string after_text() { return after_text_; } int start_adjust() { return start_adjust_; } @@ -187,6 +189,7 @@ search_term_ = resolved_search_term.search_term; display_text_ = resolved_search_term.display_text; alternate_term_ = resolved_search_term.alternate_term; + mid_ = resolved_search_term.mid; prevent_preload_ = resolved_search_term.prevent_preload; start_adjust_ = resolved_search_term.selection_start_adjust; end_adjust_ = resolved_search_term.selection_end_adjust; @@ -209,6 +212,7 @@ std::string search_term_; std::string display_text_; std::string alternate_term_; + std::string mid_; bool prevent_preload_; int start_adjust_; int end_adjust_; @@ -242,6 +246,7 @@ EXPECT_EQ(200, response_code()); EXPECT_EQ("obama", search_term()); EXPECT_EQ("Barack Obama", display_text()); + EXPECT_EQ("/m/02mjmr", mid()); EXPECT_FALSE(do_prevent_preload()); } @@ -259,6 +264,7 @@ EXPECT_EQ(200, response_code()); EXPECT_EQ("obama", search_term()); EXPECT_EQ("Barack Obama", display_text()); + EXPECT_EQ("/m/02mjmr", mid()); EXPECT_FALSE(do_prevent_preload()); } @@ -274,6 +280,7 @@ EXPECT_EQ(200, response_code()); EXPECT_EQ("obama", search_term()); EXPECT_EQ("obama", display_text()); + EXPECT_EQ("/m/02mjmr", mid()); EXPECT_FALSE(do_prevent_preload()); } @@ -289,6 +296,7 @@ EXPECT_EQ(200, response_code()); EXPECT_EQ("obama", search_term()); EXPECT_EQ("obama", display_text()); + EXPECT_EQ("/m/02mjmr", mid()); EXPECT_TRUE(do_prevent_preload()); } @@ -302,6 +310,7 @@ EXPECT_EQ(200, response_code()); EXPECT_EQ("", search_term()); EXPECT_EQ("", display_text()); + EXPECT_EQ("", mid()); EXPECT_FALSE(do_prevent_preload()); } @@ -491,16 +500,18 @@ std::string search_term; std::string display_text; std::string alternate_term; + std::string mid; std::string prevent_preload; int mention_start; int mention_end; std::string context_language; delegate_->DecodeSearchTermFromJsonResponse( json_with_escape, &search_term, &display_text, &alternate_term, - &prevent_preload, &mention_start, &mention_end, &context_language); + &mid, &prevent_preload, &mention_start, &mention_end, &context_language); EXPECT_EQ("obama", search_term); EXPECT_EQ("Barack Obama", display_text); EXPECT_EQ("barack obama", alternate_term); + EXPECT_EQ("/m/02mjmr", mid); EXPECT_EQ("", prevent_preload); EXPECT_EQ("", context_language); } @@ -518,6 +529,7 @@ EXPECT_EQ(200, response_code()); EXPECT_EQ("obama", search_term()); EXPECT_EQ("obama", display_text()); + EXPECT_EQ("/m/02mjmr", mid()); EXPECT_TRUE(do_prevent_preload()); EXPECT_EQ("de", context_language()); }
diff --git a/chrome/browser/android/contextualsearch/contextual_search_manager.cc b/chrome/browser/android/contextualsearch/contextual_search_manager.cc index 090ba40b..8c6299cf 100644 --- a/chrome/browser/android/contextualsearch/contextual_search_manager.cc +++ b/chrome/browser/android/contextualsearch/contextual_search_manager.cc
@@ -131,13 +131,16 @@ base::android::ScopedJavaLocalRef<jstring> j_alternate_term = base::android::ConvertUTF8ToJavaString( env, resolved_search_term.alternate_term.c_str()); + base::android::ScopedJavaLocalRef<jstring> j_mid = + base::android::ConvertUTF8ToJavaString(env, + resolved_search_term.mid.c_str()); base::android::ScopedJavaLocalRef<jstring> j_context_language = base::android::ConvertUTF8ToJavaString( env, resolved_search_term.context_language.c_str()); Java_ContextualSearchManager_onSearchTermResolutionResponse( env, java_manager_.obj(), resolved_search_term.is_invalid, resolved_search_term.response_code, j_search_term.obj(), - j_display_text.obj(), j_alternate_term.obj(), + j_display_text.obj(), j_alternate_term.obj(), j_mid.obj(), resolved_search_term.prevent_preload, resolved_search_term.selection_start_adjust, resolved_search_term.selection_end_adjust, j_context_language.obj());
diff --git a/chrome/browser/android/contextualsearch/resolved_search_term.cc b/chrome/browser/android/contextualsearch/resolved_search_term.cc index 7aa01bf..63fe4756 100644 --- a/chrome/browser/android/contextualsearch/resolved_search_term.cc +++ b/chrome/browser/android/contextualsearch/resolved_search_term.cc
@@ -12,6 +12,7 @@ search_term(""), display_text(""), alternate_term(""), + mid(""), prevent_preload(false), selection_start_adjust(0), selection_end_adjust(0), @@ -22,6 +23,7 @@ const std::string& search_term, const std::string& display_text, const std::string& alternate_term, + const std::string& mid, bool prevent_preload, int selection_start_adjust, int selection_end_adjust, @@ -31,6 +33,7 @@ search_term(search_term), display_text(display_text), alternate_term(alternate_term), + mid(mid), prevent_preload(prevent_preload), selection_start_adjust(selection_start_adjust), selection_end_adjust(selection_end_adjust),
diff --git a/chrome/browser/android/contextualsearch/resolved_search_term.h b/chrome/browser/android/contextualsearch/resolved_search_term.h index 37eb166..695cc4d 100644 --- a/chrome/browser/android/contextualsearch/resolved_search_term.h +++ b/chrome/browser/android/contextualsearch/resolved_search_term.h
@@ -20,6 +20,7 @@ const std::string& search_term, const std::string& display_text, const std::string& alternate_term, + const std::string& mid, bool prevent_preload, int selection_start_adjust, int selection_end_adjust, @@ -32,6 +33,7 @@ const std::string search_term; const std::string display_text; const std::string alternate_term; + const std::string mid; // Mid (entity ID), or empty. const bool prevent_preload; const int selection_start_adjust; const int selection_end_adjust;
diff --git a/chrome/browser/android/download/download_manager_service.cc b/chrome/browser/android/download/download_manager_service.cc index fce1a417..f7aab95 100644 --- a/chrome/browser/android/download/download_manager_service.cc +++ b/chrome/browser/android/download/download_manager_service.cc
@@ -102,6 +102,18 @@ EnqueueDownloadAction(download_guid, PAUSE); } +void DownloadManagerService::RemoveDownload( + JNIEnv* env, + jobject obj, + const JavaParamRef<jstring>& jdownload_guid, + bool is_off_the_record) { + std::string download_guid = ConvertJavaStringToUTF8(env, jdownload_guid); + if (is_history_query_complete_ || is_off_the_record) + RemoveDownloadInternal(download_guid, is_off_the_record); + else + EnqueueDownloadAction(download_guid, REMOVE); +} + void DownloadManagerService::GetAllDownloads(JNIEnv* env, const JavaParamRef<jobject>& obj) { if (is_history_query_complete_) @@ -227,6 +239,20 @@ } } pending_actions_.clear(); + + // Monitor all DownloadItems for changes. + content::DownloadManager* manager = GetDownloadManager(false); + if (manager) + original_notifier_.reset(new AllDownloadItemNotifier(manager, this)); +} + +void DownloadManagerService::OnDownloadRemoved( + content::DownloadManager* manager, content::DownloadItem* item) { + JNIEnv* env = base::android::AttachCurrentThread(); + Java_DownloadManagerService_onDownloadItemRemoved( + env, + java_ref_.obj(), + ConvertUTF8ToJavaString(env, item->GetGuid()).obj()); } void DownloadManagerService::ResumeDownloadInternal( @@ -275,6 +301,16 @@ } } +void DownloadManagerService::RemoveDownloadInternal( + const std::string& download_guid, bool is_off_the_record) { + content::DownloadManager* manager = GetDownloadManager(is_off_the_record); + if (!manager) + return; + content::DownloadItem* item = manager->GetDownloadByGuid(download_guid); + if (item) + item->Remove(); +} + void DownloadManagerService::EnqueueDownloadAction( const std::string& download_guid, DownloadAction action) { @@ -295,6 +331,9 @@ case CANCEL: iter->second = action; break; + case REMOVE: + iter->second = action; + break; case INITIALIZE_UI: iter->second = action; break;
diff --git a/chrome/browser/android/download/download_manager_service.h b/chrome/browser/android/download/download_manager_service.h index 75f56606..738a7976 100644 --- a/chrome/browser/android/download/download_manager_service.h +++ b/chrome/browser/android/download/download_manager_service.h
@@ -13,6 +13,7 @@ #include "base/callback.h" #include "base/macros.h" #include "chrome/browser/android/download/download_controller.h" +#include "chrome/browser/download/all_download_item_notifier.h" #include "chrome/browser/download/download_history.h" #include "content/public/browser/download_manager.h" @@ -24,7 +25,8 @@ // Native side of DownloadManagerService.java. The native object is owned by its // Java object. -class DownloadManagerService : public DownloadHistory::Observer { +class DownloadManagerService : public AllDownloadItemNotifier::Observer, + public DownloadHistory::Observer { public: // JNI registration. static bool RegisterDownloadManagerService(JNIEnv* env); @@ -59,6 +61,12 @@ const JavaParamRef<jstring>& jdownload_guid, bool is_off_the_record); + // Called to remove a download item that has GUID equal to |jdownload_guid|. + void RemoveDownload(JNIEnv* env, + jobject obj, + const JavaParamRef<jstring>& jdownload_guid, + bool is_off_the_record); + // Returns information about the item that has GUID equal to |jdownload_guid|. void GetDownloadInfoFor(JNIEnv* env, jobject obj, @@ -72,6 +80,10 @@ // DownloadHistory::Observer methods. void OnHistoryQueryComplete() override; + // AllDownloadItemNotifier::Observer methods. + void OnDownloadRemoved( + content::DownloadManager* manager, content::DownloadItem* item) override; + protected: // Called to get the content::DownloadManager instance. virtual content::DownloadManager* GetDownloadManager(bool is_off_the_record); @@ -92,6 +104,10 @@ void PauseDownloadInternal(const std::string& download_guid, bool is_off_the_record); + // Helper function to remove a download. + void RemoveDownloadInternal(const std::string& download_guid, + bool is_off_the_record); + // Helper function to send info about all downloads to the Java-side. void GetAllDownloadsInternal(); @@ -110,7 +126,7 @@ bool is_history_query_complete_; - enum DownloadAction { RESUME, PAUSE, CANCEL, INITIALIZE_UI, UNKNOWN }; + enum DownloadAction { RESUME, PAUSE, CANCEL, REMOVE, INITIALIZE_UI, UNKNOWN }; using PendingDownloadActions = std::map<std::string, DownloadAction>; PendingDownloadActions pending_actions_; @@ -120,6 +136,8 @@ ResumeCallback resume_callback_for_testing_; + std::unique_ptr<AllDownloadItemNotifier> original_notifier_; + DISALLOW_COPY_AND_ASSIGN(DownloadManagerService); };
diff --git a/chrome/browser/android/ntp/ntp_snippets_bridge.cc b/chrome/browser/android/ntp/ntp_snippets_bridge.cc index a8d487da..5818ae0 100644 --- a/chrome/browser/android/ntp/ntp_snippets_bridge.cc +++ b/chrome/browser/android/ntp/ntp_snippets_bridge.cc
@@ -30,17 +30,20 @@ using base::android::JavaParamRef; using base::android::ScopedJavaGlobalRef; using base::android::ScopedJavaLocalRef; +using base::android::ToJavaIntArray; using ntp_snippets::Category; +using ntp_snippets::CategoryInfo; using ntp_snippets::CategoryStatus; using ntp_snippets::KnownCategories; +using ntp_snippets::ContentSuggestion; namespace { -void SnippetVisitedHistoryRequestCallback( - base::android::ScopedJavaGlobalRef<jobject> callback, - bool success, - const history::URLRow& row, - const history::VisitVector& visitVector) { +void URLVisitedHistoryRequestCallback( + base::android::ScopedJavaGlobalRef<jobject> callback, + bool success, + const history::URLRow& row, + const history::VisitVector& visitVector) { bool visited = success && row.visit_count() != 0; base::android::RunCallbackAndroid(callback, visited); } @@ -58,9 +61,16 @@ const JavaParamRef<jclass>& caller, jboolean j_force_request) { Profile* profile = ProfileManager::GetLastUsedProfile(); - ContentSuggestionsServiceFactory::GetForProfile(profile) - ->ntp_snippets_service() - ->FetchSnippets(j_force_request); + ntp_snippets::NTPSnippetsService* service = + ContentSuggestionsServiceFactory::GetForProfile(profile) + ->ntp_snippets_service(); + + // Can be null if the feature has been disabled but the scheduler has not been + // unregistered yet. The next start should unregister it. + if (!service) + return; + + service->FetchSnippets(j_force_request); } // Reschedules the fetching of snippets. Used to support different fetching @@ -68,9 +78,16 @@ static void RescheduleFetching(JNIEnv* env, const JavaParamRef<jclass>& caller) { Profile* profile = ProfileManager::GetLastUsedProfile(); - ContentSuggestionsServiceFactory::GetForProfile(profile) - ->ntp_snippets_service() - ->RescheduleFetching(); + ntp_snippets::NTPSnippetsService* service = + ContentSuggestionsServiceFactory::GetForProfile(profile) + ->ntp_snippets_service(); + + // Can be null if the feature has been disabled but the scheduler has not been + // unregistered yet. The next start should unregister it. + if (!service) + return; + + service->RescheduleFetching(); } NTPSnippetsBridge::NTPSnippetsBridge(JNIEnv* env, @@ -93,94 +110,108 @@ const JavaParamRef<jobject>& obj, const JavaParamRef<jobject>& j_observer) { observer_.Reset(env, j_observer); - OnNewSuggestions(); } -void NTPSnippetsBridge::FetchImage(JNIEnv* env, - const JavaParamRef<jobject>& obj, - const JavaParamRef<jstring>& snippet_id, - const JavaParamRef<jobject>& j_callback) { - base::android::ScopedJavaGlobalRef<jobject> callback(j_callback); - content_suggestions_service_->FetchSuggestionImage( - ConvertJavaStringToUTF8(env, snippet_id), - base::Bind(&NTPSnippetsBridge::OnImageFetched, - weak_ptr_factory_.GetWeakPtr(), callback)); -} - -void NTPSnippetsBridge::DiscardSnippet(JNIEnv* env, - const JavaParamRef<jobject>& obj, - const JavaParamRef<jstring>& id) { - content_suggestions_service_->DismissSuggestion( - ConvertJavaStringToUTF8(env, id)); -} - -void NTPSnippetsBridge::SnippetVisited(JNIEnv* env, - const JavaParamRef<jobject>& obj, - const JavaParamRef<jobject>& jcallback, - const JavaParamRef<jstring>& jurl) { - base::android::ScopedJavaGlobalRef<jobject> callback(jcallback); - - history_service_->QueryURL( - GURL(ConvertJavaStringToUTF8(env, jurl)), - false, - base::Bind(&SnippetVisitedHistoryRequestCallback, callback), - &tracker_); +ScopedJavaLocalRef<jintArray> NTPSnippetsBridge::GetCategories( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj) { + std::vector<int> category_ids; + for (Category category : content_suggestions_service_->GetCategories()) { + category_ids.push_back(category.id()); + } + return ToJavaIntArray(env, category_ids); } int NTPSnippetsBridge::GetCategoryStatus(JNIEnv* env, const JavaParamRef<jobject>& obj, jint category) { return static_cast<int>(content_suggestions_service_->GetCategoryStatus( - content_suggestions_service_->category_factory()->FromKnownCategory( - KnownCategories::ARTICLES))); + content_suggestions_service_->category_factory()->FromIDValue(category))); +} + +base::android::ScopedJavaLocalRef<jobject> NTPSnippetsBridge::GetCategoryInfo( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj, + jint category) { + base::Optional<CategoryInfo> info = + content_suggestions_service_->GetCategoryInfo( + content_suggestions_service_->category_factory()->FromIDValue( + category)); + if (!info) + return base::android::ScopedJavaLocalRef<jobject>(env, nullptr); + return Java_SnippetsBridge_createSuggestionsCategoryInfo( + env, ConvertUTF16ToJavaString(env, info->title()).obj(), + static_cast<int>(info->card_layout())); +} + +ScopedJavaLocalRef<jobject> NTPSnippetsBridge::GetSuggestionsForCategory( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj, + jint category) { + const std::vector<ContentSuggestion>& suggestions = + content_suggestions_service_->GetSuggestionsForCategory( + content_suggestions_service_->category_factory()->FromIDValue( + category)); + ScopedJavaLocalRef<jobject> result = + Java_SnippetsBridge_createSuggestionList(env); + for (const ContentSuggestion& suggestion : suggestions) { + Java_SnippetsBridge_addSuggestion( + env, result.obj(), ConvertUTF8ToJavaString(env, suggestion.id()).obj(), + ConvertUTF16ToJavaString(env, suggestion.title()).obj(), + ConvertUTF16ToJavaString(env, suggestion.publisher_name()).obj(), + ConvertUTF16ToJavaString(env, suggestion.snippet_text()).obj(), + ConvertUTF8ToJavaString(env, suggestion.url().spec()).obj(), + ConvertUTF8ToJavaString(env, suggestion.amp_url().spec()).obj(), + suggestion.publish_date().ToJavaTime(), suggestion.score()); + } + return result; +} + +void NTPSnippetsBridge::FetchSuggestionImage( + JNIEnv* env, + const JavaParamRef<jobject>& obj, + const JavaParamRef<jstring>& suggestion_id, + const JavaParamRef<jobject>& j_callback) { + base::android::ScopedJavaGlobalRef<jobject> callback(j_callback); + content_suggestions_service_->FetchSuggestionImage( + ConvertJavaStringToUTF8(env, suggestion_id), + base::Bind(&NTPSnippetsBridge::OnImageFetched, + weak_ptr_factory_.GetWeakPtr(), callback)); +} + +void NTPSnippetsBridge::DismissSuggestion( + JNIEnv* env, + const JavaParamRef<jobject>& obj, + const JavaParamRef<jstring>& suggestion_id) { + content_suggestions_service_->DismissSuggestion( + ConvertJavaStringToUTF8(env, suggestion_id)); +} + +void NTPSnippetsBridge::GetURLVisited(JNIEnv* env, + const JavaParamRef<jobject>& obj, + const JavaParamRef<jobject>& jcallback, + const JavaParamRef<jstring>& jurl) { + base::android::ScopedJavaGlobalRef<jobject> callback(jcallback); + + history_service_->QueryURL( + GURL(ConvertJavaStringToUTF8(env, jurl)), false, + base::Bind(&URLVisitedHistoryRequestCallback, callback), &tracker_); } NTPSnippetsBridge::~NTPSnippetsBridge() {} -void NTPSnippetsBridge::OnNewSuggestions() { +void NTPSnippetsBridge::OnNewSuggestions(Category category) { if (observer_.is_null()) return; - // Show all suggestions from all categories, even though we currently display - // them in a single section on the UI. - // TODO(pke): This is only for debugging new sections and will be replaced - // with proper multi-section UI support. JNIEnv* env = base::android::AttachCurrentThread(); - ScopedJavaLocalRef<jobject> suggestions = - Java_SnippetsBridge_createSuggestionList(env); - for (Category category : - content_suggestions_service_->GetCategories()) { - if (content_suggestions_service_->GetCategoryStatus(category) != - CategoryStatus::AVAILABLE) { - continue; - } - for (const ntp_snippets::ContentSuggestion& suggestion : - content_suggestions_service_->GetSuggestionsForCategory(category)) { - Java_SnippetsBridge_addSuggestion( - env, suggestions.obj(), - ConvertUTF8ToJavaString(env, suggestion.id()).obj(), - ConvertUTF16ToJavaString(env, suggestion.title()).obj(), - ConvertUTF16ToJavaString(env, suggestion.publisher_name()).obj(), - ConvertUTF16ToJavaString(env, suggestion.snippet_text()).obj(), - ConvertUTF8ToJavaString(env, suggestion.url().spec()).obj(), - ConvertUTF8ToJavaString(env, suggestion.amp_url().spec()).obj(), - suggestion.publish_date().ToJavaTime(), suggestion.score()); - } - } - - // TODO(mvanouwerkerk): Do not hard code ARTICLES. - Java_SnippetsBridge_onSuggestionsAvailable( - env, observer_.obj(), - static_cast<int>( - content_suggestions_service_->category_factory()->FromKnownCategory( - KnownCategories::ARTICLES).id()), - suggestions.obj()); + Java_SnippetsBridge_onNewSuggestions(env, observer_.obj(), + static_cast<int>(category.id())); } void NTPSnippetsBridge::OnCategoryStatusChanged(Category category, CategoryStatus new_status) { - // TODO(mvanouwerkerk): Do not hard code ARTICLES. - if (!category.IsKnownCategory(KnownCategories::ARTICLES)) + if (observer_.is_null()) return; JNIEnv* env = base::android::AttachCurrentThread();
diff --git a/chrome/browser/android/ntp/ntp_snippets_bridge.h b/chrome/browser/android/ntp/ntp_snippets_bridge.h index 5c2715d..dcc124ae 100644 --- a/chrome/browser/android/ntp/ntp_snippets_bridge.h +++ b/chrome/browser/android/ntp/ntp_snippets_bridge.h
@@ -33,35 +33,49 @@ const base::android::JavaParamRef<jobject>& obj, const base::android::JavaParamRef<jobject>& j_observer); - void FetchImage(JNIEnv* env, - const base::android::JavaParamRef<jobject>& obj, - const base::android::JavaParamRef<jstring>& snippet_id, - const base::android::JavaParamRef<jobject>& j_callback); + base::android::ScopedJavaLocalRef<jintArray> GetCategories( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj); - // Discards the snippet with the given ID. - void DiscardSnippet(JNIEnv* env, - const base::android::JavaParamRef<jobject>& obj, - const base::android::JavaParamRef<jstring>& snippet_id); - - // Checks if the URL has been visited. - void SnippetVisited(JNIEnv* env, - const base::android::JavaParamRef<jobject>& obj, - const base::android::JavaParamRef<jobject>& callback, - const base::android::JavaParamRef<jstring>& jurl); - - // Returns the status of |category|. - // See CategoryStatus for more info. int GetCategoryStatus(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj, jint category); + base::android::ScopedJavaLocalRef<jobject> GetCategoryInfo( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj, + jint category); + + base::android::ScopedJavaLocalRef<jobject> GetSuggestionsForCategory( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj, + jint category); + + void FetchSuggestionImage( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj, + const base::android::JavaParamRef<jstring>& suggestion_id, + const base::android::JavaParamRef<jobject>& j_callback); + + void DismissSuggestion( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj, + const base::android::JavaParamRef<jstring>& suggestion_id); + + // Checks if the URL has been visited. The callback will not be called + // synchronously. + void GetURLVisited(JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj, + const base::android::JavaParamRef<jobject>& callback, + const base::android::JavaParamRef<jstring>& jurl); + static bool Register(JNIEnv* env); private: ~NTPSnippetsBridge() override; // ContentSuggestionsService::Observer overrides - void OnNewSuggestions() override; + void OnNewSuggestions(ntp_snippets::Category category) override; void OnCategoryStatusChanged( ntp_snippets::Category category, ntp_snippets::CategoryStatus new_status) override;
diff --git a/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.cc b/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.cc index 33e120f..4ae4a7e 100644 --- a/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.cc +++ b/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.cc
@@ -55,7 +55,8 @@ JNIEnv* env, const JavaParamRef<jobject>& obj, DownloadUIAdapter* download_ui_adapter) - : download_ui_adapter_(download_ui_adapter) { + : weak_java_ref_(env, obj), + download_ui_adapter_(download_ui_adapter) { DCHECK(download_ui_adapter_); download_ui_adapter_->AddObserver(this); }
diff --git a/chrome/browser/android/offline_pages/offline_page_tab_helper.cc b/chrome/browser/android/offline_pages/offline_page_tab_helper.cc index f5140d8..0bb07c2 100644 --- a/chrome/browser/android/offline_pages/offline_page_tab_helper.cc +++ b/chrome/browser/android/offline_pages/offline_page_tab_helper.cc
@@ -274,10 +274,10 @@ } // If the page is being loaded on a slow network, only use the offline page - // if it was created within the past day. + // if it was created within the past 7 days. if (result == RedirectResult::REDIRECTED_ON_PROHIBITIVELY_SLOW_NETWORK && delegate_->Now() - selected_page->creation_time > - base::TimeDelta::FromDays(1)) { + base::TimeDelta::FromDays(7)) { ReportRedirectResultUMA( RedirectResult::PAGE_NOT_FRESH_ON_PROHIBITIVELY_SLOW_NETWORK); return;
diff --git a/chrome/browser/android/offline_pages/offline_page_tab_helper_unittest.cc b/chrome/browser/android/offline_pages/offline_page_tab_helper_unittest.cc index 5270cbd9..aa8b76d0 100644 --- a/chrome/browser/android/offline_pages/offline_page_tab_helper_unittest.cc +++ b/chrome/browser/android/offline_pages/offline_page_tab_helper_unittest.cc
@@ -400,7 +400,7 @@ EXPECT_EQ(offline_url(), item->GetOfflineURL()); EXPECT_EQ(online_url(), item->url); - clock()->Advance(base::TimeDelta::FromDays(2)); + clock()->Advance(base::TimeDelta::FromDays(8)); StartLoad(kTestPageUrl); // Gives a chance to run delayed task to do redirection. RunUntilIdle();
diff --git a/chrome/browser/android/recently_closed_tabs_bridge.cc b/chrome/browser/android/recently_closed_tabs_bridge.cc index e27a1229..121bd16 100644 --- a/chrome/browser/android/recently_closed_tabs_bridge.cc +++ b/chrome/browser/android/recently_closed_tabs_bridge.cc
@@ -25,14 +25,12 @@ namespace { void AddTabToList(JNIEnv* env, - sessions::TabRestoreService::Entry* entry, + const sessions::TabRestoreService::Tab& tab, jobject jtabs_list) { - const sessions::TabRestoreService::Tab* tab = - static_cast<sessions::TabRestoreService::Tab*>(entry); const sessions::SerializedNavigationEntry& current_navigation = - tab->navigations.at(tab->current_navigation_index); + tab.navigations.at(tab.current_navigation_index); Java_RecentlyClosedBridge_pushTab( - env, jtabs_list, entry->id, + env, jtabs_list, tab.id, ConvertUTF16ToJavaString(env, current_navigation.title()).obj(), ConvertUTF8ToJavaString(env, current_navigation.virtual_url().spec()) .obj()); @@ -43,14 +41,13 @@ jobject jtabs_list, int max_tab_count) { int added_count = 0; - for (sessions::TabRestoreService::Entries::const_iterator it = - entries.begin(); - it != entries.end() && added_count < max_tab_count; ++it) { - sessions::TabRestoreService::Entry* entry = *it; + for (const auto& entry : entries) { DCHECK_EQ(entry->type, sessions::TabRestoreService::TAB); if (entry->type == sessions::TabRestoreService::TAB) { - AddTabToList(env, entry, jtabs_list); - ++added_count; + auto& tab = static_cast<const sessions::TabRestoreService::Tab&>(*entry); + AddTabToList(env, tab, jtabs_list); + if (++added_count == max_tab_count) + break; } } }
diff --git a/chrome/browser/android/resource_id.h b/chrome/browser/android/resource_id.h index ce0020b..b49d9be 100644 --- a/chrome/browser/android/resource_id.h +++ b/chrome/browser/android/resource_id.h
@@ -22,6 +22,8 @@ LINK_RESOURCE_ID(IDR_INFOBAR_AUTOFILL_CC, R.drawable.infobar_autofill_cc) LINK_RESOURCE_ID(IDR_INFOBAR_MEDIA_STREAM_CAMERA, R.drawable.infobar_camera) LINK_RESOURCE_ID(IDR_INFOBAR_MEDIA_STREAM_MIC, R.drawable.infobar_microphone) +LINK_RESOURCE_ID(IDR_INFOBAR_MEDIA_STREAM_SCREEN, + R.drawable.infobar_screen_share) LINK_RESOURCE_ID(IDR_INFOBAR_MIDI, R.drawable.infobar_midi) LINK_RESOURCE_ID(IDR_INFOBAR_MULTIPLE_DOWNLOADS, R.drawable.infobar_multiple_downloads)
diff --git a/chrome/browser/android/shortcut_helper.cc b/chrome/browser/android/shortcut_helper.cc index 8d8066c..7ab5602 100644 --- a/chrome/browser/android/shortcut_helper.cc +++ b/chrome/browser/android/shortcut_helper.cc
@@ -236,10 +236,11 @@ } // static -SkBitmap ShortcutHelper::FinalizeLauncherIcon(const SkBitmap& bitmap, - const GURL& url, - bool* is_generated) { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); +SkBitmap ShortcutHelper::FinalizeLauncherIconInBackground( + const SkBitmap& bitmap, + const GURL& url, + bool* is_generated) { + DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); JNIEnv* env = base::android::AttachCurrentThread(); ScopedJavaLocalRef<jobject> result;
diff --git a/chrome/browser/android/shortcut_helper.h b/chrome/browser/android/shortcut_helper.h index c41bba64..f24995df 100644 --- a/chrome/browser/android/shortcut_helper.h +++ b/chrome/browser/android/shortcut_helper.h
@@ -102,9 +102,10 @@ // Returns the given icon, modified to match the launcher requirements. // This method may generate an entirely new icon; if this is the case, // |is_generated| will be set to |true|. - static SkBitmap FinalizeLauncherIcon(const SkBitmap& icon, - const GURL& url, - bool* is_generated); + // Must be called on a background worker thread. + static SkBitmap FinalizeLauncherIconInBackground(const SkBitmap& icon, + const GURL& url, + bool* is_generated); // Returns true if WebAPKs are enabled and there is a WebAPK installed which // can handle |url|.
diff --git a/chrome/browser/android/webapk/webapk_installer.cc b/chrome/browser/android/webapk/webapk_installer.cc index 79a12d0..3764492c2 100644 --- a/chrome/browser/android/webapk/webapk_installer.cc +++ b/chrome/browser/android/webapk/webapk_installer.cc
@@ -22,6 +22,7 @@ #include "chrome/common/chrome_switches.h" #include "components/version_info/version_info.h" #include "content/public/browser/browser_thread.h" +#include "content/public/common/manifest_util.h" #include "jni/WebApkInstaller_jni.h" #include "net/http/http_status_code.h" #include "net/url_request/url_fetcher.h" @@ -253,7 +254,11 @@ web_app_manifest->set_short_name( base::UTF16ToUTF8(shortcut_info_.short_name)); web_app_manifest->set_start_url(shortcut_info_.url.spec()); - // TODO(pkotwicz): Add "display mode" and "orientation" to proto. + web_app_manifest->set_orientation( + content::WebScreenOrientationLockTypeToString( + shortcut_info_.orientation)); + web_app_manifest->set_display_mode( + content::WebDisplayModeToString(shortcut_info_.display)); web_app_manifest->set_background_color( ColorToString(shortcut_info_.background_color)); web_app_manifest->set_theme_color(ColorToString(shortcut_info_.theme_color));
diff --git a/chrome/browser/android/webapk/webapk_installer_unittest.cc b/chrome/browser/android/webapk/webapk_installer_unittest.cc index cfc004f..fee301c 100644 --- a/chrome/browser/android/webapk/webapk_installer_unittest.cc +++ b/chrome/browser/android/webapk/webapk_installer_unittest.cc
@@ -78,7 +78,7 @@ // WebApkInstaller owns itself. WebApkInstaller* installer = new TestWebApkInstaller(info, SkBitmap()); - installer->SetTimeoutMs(20); + installer->SetTimeoutMs(100); installer->InstallAsyncWithURLRequestContextGetter( url_request_context_getter_.get(), base::Bind(&WebApkInstallerRunner::OnCompleted,
diff --git a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc index 0ffe0ad..9915636f 100644 --- a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc +++ b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc
@@ -211,19 +211,18 @@ if (!web_contents() || !weak_observer_ || is_icon_saved_) return; - content::BrowserThread::PostTask( - content::BrowserThread::IO, + content::BrowserThread::GetBlockingPool()->PostWorkerTaskWithShutdownBehavior( FROM_HERE, - base::Bind(&AddToHomescreenDataFetcher::CreateLauncherIcon, - this, - bitmap_result)); + base::Bind(&AddToHomescreenDataFetcher::CreateLauncherIconInBackground, + this, shortcut_info_.url, bitmap_result), + base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); } -void AddToHomescreenDataFetcher::CreateLauncherIcon( +void AddToHomescreenDataFetcher::CreateLauncherIconInBackground( + const GURL& page_url, const favicon_base::FaviconRawBitmapResult& bitmap_result) { - if (!web_contents() || !weak_observer_) return; + DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); SkBitmap icon_bitmap; if (bitmap_result.is_valid()) { gfx::PNGCodec::Decode(bitmap_result.bitmap_data->front(), @@ -233,15 +232,14 @@ bool is_generated = false; if (weak_observer_) { - icon_bitmap = weak_observer_->FinalizeLauncherIcon(icon_bitmap, - shortcut_info_.url, - &is_generated); + icon_bitmap = weak_observer_->FinalizeLauncherIconInBackground( + icon_bitmap, page_url, &is_generated); } - shortcut_info_.icon_url = is_generated ? GURL() : bitmap_result.icon_url; + GURL icon_url = is_generated ? GURL() : bitmap_result.icon_url; content::BrowserThread::PostTask( content::BrowserThread::UI, FROM_HERE, - base::Bind(&AddToHomescreenDataFetcher::NotifyObserver, this, + base::Bind(&AddToHomescreenDataFetcher::NotifyObserver, this, icon_url, icon_bitmap)); } @@ -251,16 +249,17 @@ FetchFavicon(); return; } - shortcut_info_.icon_url = icon_url; - NotifyObserver(icon); + NotifyObserver(icon_url, icon); } -void AddToHomescreenDataFetcher::NotifyObserver(const SkBitmap& bitmap) { +void AddToHomescreenDataFetcher::NotifyObserver(const GURL& icon_url, + const SkBitmap& bitmap) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); if (!web_contents() || !weak_observer_ || is_icon_saved_) return; is_icon_saved_ = true; + shortcut_info_.icon_url = icon_url; shortcut_icon_ = bitmap; is_ready_ = true; weak_observer_->OnDataAvailable(shortcut_info_, shortcut_icon_);
diff --git a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h index d02b945..55ca890e 100644 --- a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h +++ b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h
@@ -44,9 +44,9 @@ // Converts the icon into one that can be used on the Android Home screen. // |is_generated| is an out-param that indicates whether the icon was // generated by Chrome. - virtual SkBitmap FinalizeLauncherIcon(const SkBitmap& icon, - const GURL& url, - bool* is_generated) = 0; + virtual SkBitmap FinalizeLauncherIconInBackground(const SkBitmap& icon, + const GURL& url, + bool* is_generated) = 0; // Called when all the data needed to create a shortcut is available. virtual void OnDataAvailable(const ShortcutInfo& info, @@ -91,8 +91,11 @@ void OnFaviconFetched( const favicon_base::FaviconRawBitmapResult& bitmap_result); - // Creates the launcher icon from the given bitmap. - void CreateLauncherIcon( + // Creates the launcher icon from the given bitmap and page URL. The page URL + // is used to generate an icon if there is no bitmap in |bitmap_result| or the + // bitmap is not large enough. + void CreateLauncherIconInBackground( + const GURL& page_url, const favicon_base::FaviconRawBitmapResult& bitmap_result); // Callback run after an attempt to download manifest icon has been made. May @@ -100,7 +103,7 @@ void OnManifestIconFetched(const GURL& icon_url, const SkBitmap& icon); // Notifies the observer that the shortcut data is all available. - void NotifyObserver(const SkBitmap& icon); + void NotifyObserver(const GURL& icon_url, const SkBitmap& icon); // Looks up the original, online URL of the site requested. The URL from the // WebContents may be an offline page or a distilled article which is not
diff --git a/chrome/browser/android/webapps/add_to_homescreen_dialog_helper.cc b/chrome/browser/android/webapps/add_to_homescreen_dialog_helper.cc index a1e7c81..709b6ef5 100644 --- a/chrome/browser/android/webapps/add_to_homescreen_dialog_helper.cc +++ b/chrome/browser/android/webapps/add_to_homescreen_dialog_helper.cc
@@ -85,13 +85,14 @@ delete this; } -SkBitmap AddToHomescreenDialogHelper::FinalizeLauncherIcon( - const SkBitmap& bitmap, - const GURL& url, - bool* is_generated) { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); +SkBitmap AddToHomescreenDialogHelper::FinalizeLauncherIconInBackground( + const SkBitmap& bitmap, + const GURL& url, + bool* is_generated) { + DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); - return ShortcutHelper::FinalizeLauncherIcon(bitmap, url, is_generated); + return ShortcutHelper::FinalizeLauncherIconInBackground(bitmap, url, + is_generated); } void AddToHomescreenDialogHelper::AddShortcut(
diff --git a/chrome/browser/android/webapps/add_to_homescreen_dialog_helper.h b/chrome/browser/android/webapps/add_to_homescreen_dialog_helper.h index 3effb7b..3b1de6a 100644 --- a/chrome/browser/android/webapps/add_to_homescreen_dialog_helper.h +++ b/chrome/browser/android/webapps/add_to_homescreen_dialog_helper.h
@@ -47,9 +47,9 @@ // AddToHomescreenDataFetcher::Observer void OnUserTitleAvailable(const base::string16& user_title) override; void OnDataAvailable(const ShortcutInfo& info, const SkBitmap& icon) override; - SkBitmap FinalizeLauncherIcon(const SkBitmap& icon, - const GURL& url, - bool* is_generated) override; + SkBitmap FinalizeLauncherIconInBackground(const SkBitmap& icon, + const GURL& url, + bool* is_generated) override; private: virtual ~AddToHomescreenDialogHelper();
diff --git a/chrome/browser/apps/app_window_registry_util.cc b/chrome/browser/apps/app_window_registry_util.cc index adce2d2..d7689938 100644 --- a/chrome/browser/apps/app_window_registry_util.cc +++ b/chrome/browser/apps/app_window_registry_util.cc
@@ -84,7 +84,7 @@ // Ask each app window to close, but cater for windows removing or // rearranging themselves in the ordered window list in response. AppWindowList window_list_copy(registry->app_windows()); - for (const auto& window : window_list_copy) { + for (auto* window : window_list_copy) { // Ensure window is still valid. if (ContainsValue(registry->app_windows(), window)) window->GetBaseWindow()->Close();
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc index 68bb927..7810d070 100644 --- a/chrome/browser/apps/guest_view/web_view_browsertest.cc +++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -174,7 +174,7 @@ bool OnMenuShown(const content::NotificationSource& source, const content::NotificationDetails& details) { ++num_times_shown_; - auto context_menu = content::Source<RenderViewContextMenu>(source).ptr(); + auto* context_menu = content::Source<RenderViewContextMenu>(source).ptr(); base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&RenderViewContextMenuBase::Cancel, base::Unretained(context_menu))); @@ -2097,7 +2097,7 @@ static bool ContextMenuNotificationCallback( const content::NotificationSource& source, const content::NotificationDetails& details) { - auto context_menu = content::Source<RenderViewContextMenu>(source).ptr(); + auto* context_menu = content::Source<RenderViewContextMenu>(source).ptr(); base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&RenderViewContextMenuBase::Cancel, base::Unretained(context_menu))); @@ -2644,7 +2644,7 @@ download_manager, 2, content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL)); - for (auto& download : downloads) { + for (auto* download : downloads) { ASSERT_TRUE(download->CanResume()); EXPECT_EQ(content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED, download->GetLastReason()); @@ -2654,7 +2654,7 @@ completion_observer->WaitForFinished(); std::set<std::string> cookies; - for (auto& download : downloads) { + for (auto* download : downloads) { ASSERT_EQ(content::DownloadItem::COMPLETE, download->GetState()); ASSERT_TRUE(base::PathExists(download->GetTargetFilePath())); std::string content; @@ -2758,7 +2758,7 @@ // try to talk to the old EmbeddedTestServer instance. We need to update the // URL to point to the new instance, which should only differ by the port // number. - for (auto& download : saved_downloads) { + for (auto* download : saved_downloads) { const std::string port_string = base::UintToString(embedded_test_server()->port()); url::Replacements<char> replacements; @@ -2785,7 +2785,7 @@ download_manager, 2, content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL)); - for (auto& download : downloads) { + for (auto* download : downloads) { ASSERT_TRUE(download->CanResume()); ASSERT_TRUE( temporary_download_dir.path().IsParent(download->GetTargetFilePath())); @@ -3181,7 +3181,7 @@ IN_PROC_BROWSER_TEST_P(WebViewTest, Shim_TestCloseNewWindowCleanup) { TestHelper("testCloseNewWindowCleanup", "web_view/shim", NEEDS_TEST_SERVER); - auto gvm = GetGuestViewManager(); + auto* gvm = GetGuestViewManager(); gvm->WaitForLastGuestDeleted(); ASSERT_EQ(gvm->num_embedder_processes_destroyed(), 0); }
diff --git a/chrome/browser/banners/app_banner_data_fetcher.cc b/chrome/browser/banners/app_banner_data_fetcher.cc deleted file mode 100644 index 3cc2811..0000000 --- a/chrome/browser/banners/app_banner_data_fetcher.cc +++ /dev/null
@@ -1,496 +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 "chrome/browser/banners/app_banner_data_fetcher.h" - -#include "base/bind.h" -#include "base/command_line.h" -#include "base/lazy_instance.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "chrome/browser/banners/app_banner_debug_log.h" -#include "chrome/browser/banners/app_banner_metrics.h" -#include "chrome/browser/banners/app_banner_settings_helper.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/manifest/manifest_icon_downloader.h" -#include "chrome/browser/manifest/manifest_icon_selector.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/common/chrome_switches.h" -#include "chrome/common/render_messages.h" -#include "components/rappor/rappor_utils.h" -#include "content/public/browser/browser_context.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/navigation_details.h" -#include "content/public/browser/render_frame_host.h" -#include "content/public/browser/service_worker_context.h" -#include "content/public/browser/storage_partition.h" -#include "net/base/load_flags.h" -#include "third_party/WebKit/public/platform/WebDisplayMode.h" -#include "third_party/WebKit/public/platform/modules/app_banner/WebAppBannerPromptReply.h" - -namespace { - -base::LazyInstance<base::TimeDelta> gTimeDeltaForTesting = - LAZY_INSTANCE_INITIALIZER; -int gCurrentRequestID = -1; -const char kPngExtension[] = ".png"; - -// The requirement for now is an image/png that is at least 144x144. -const int kIconMinimumSize = 144; -bool DoesManifestContainRequiredIcon(const content::Manifest& manifest) { - for (const auto& icon : manifest.icons) { - // The type field is optional. If it isn't present, fall back on checking - // the src extension, and allow the icon if the extension ends with png. - if (!base::EqualsASCII(icon.type.string(), "image/png") && - !(icon.type.is_null() && - base::EndsWith(icon.src.ExtractFileName(), kPngExtension, - base::CompareCase::INSENSITIVE_ASCII))) - continue; - - for (const auto& size : icon.sizes) { - if (size.IsEmpty()) // "any" - return true; - if (size.width() >= kIconMinimumSize && size.height() >= kIconMinimumSize) - return true; - } - } - - return false; -} - -} // anonymous namespace - -namespace banners { - -// static -base::Time AppBannerDataFetcher::GetCurrentTime() { - return base::Time::Now() + gTimeDeltaForTesting.Get(); -} - -// static -void AppBannerDataFetcher::SetTimeDeltaForTesting(int days) { - gTimeDeltaForTesting.Get() = base::TimeDelta::FromDays(days); -} - -AppBannerDataFetcher::AppBannerDataFetcher(content::WebContents* web_contents, - base::WeakPtr<Delegate> delegate, - int ideal_icon_size_in_dp, - int minimum_icon_size_in_dp, - bool is_debug_mode) - : WebContentsObserver(web_contents), - weak_delegate_(delegate), - ideal_icon_size_in_dp_(ideal_icon_size_in_dp), - minimum_icon_size_in_dp_(minimum_icon_size_in_dp), - is_active_(false), - was_canceled_by_page_(false), - page_requested_prompt_(false), - is_debug_mode_(is_debug_mode || - base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kBypassAppBannerEngagementChecks)), - event_request_id_(-1) { - DCHECK(minimum_icon_size_in_dp <= ideal_icon_size_in_dp); -} - -void AppBannerDataFetcher::Start(const GURL& validated_url, - ui::PageTransition transition_type) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - - content::WebContents* web_contents = GetWebContents(); - DCHECK(web_contents); - - is_active_ = true; - was_canceled_by_page_ = false; - page_requested_prompt_ = false; - transition_type_ = transition_type; - validated_url_ = validated_url; - referrer_.erase(); - web_contents->GetManifest( - base::Bind(&AppBannerDataFetcher::OnDidGetManifest, this)); -} - -void AppBannerDataFetcher::Cancel() { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - if (is_active_) { - FOR_EACH_OBSERVER(Observer, observer_list_, - OnDecidedWhetherToShow(this, false)); - if (was_canceled_by_page_ && !page_requested_prompt_) { - TrackBeforeInstallEvent( - BEFORE_INSTALL_EVENT_PROMPT_NOT_CALLED_AFTER_PREVENT_DEFAULT); - } - - is_active_ = false; - was_canceled_by_page_ = false; - page_requested_prompt_ = false; - referrer_.erase(); - } -} - -void AppBannerDataFetcher::ReplaceWebContents( - content::WebContents* web_contents) { - Observe(web_contents); -} - -void AppBannerDataFetcher::AddObserverForTesting(Observer* observer) { - observer_list_.AddObserver(observer); -} - -void AppBannerDataFetcher::RemoveObserverForTesting(Observer* observer) { - observer_list_.RemoveObserver(observer); -} - -void AppBannerDataFetcher::WebContentsDestroyed() { - Cancel(); - Observe(nullptr); -} - -void AppBannerDataFetcher::DidNavigateMainFrame( - const content::LoadCommittedDetails& details, - const content::FrameNavigateParams& params) { - if (!details.is_in_page) - Cancel(); -} - -bool AppBannerDataFetcher::OnMessageReceived( - const IPC::Message& message, content::RenderFrameHost* render_frame_host) { - bool handled = true; - - IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(AppBannerDataFetcher, message, - render_frame_host) - IPC_MESSAGE_HANDLER(ChromeViewHostMsg_AppBannerPromptReply, - OnBannerPromptReply) - IPC_MESSAGE_HANDLER(ChromeViewHostMsg_RequestShowAppBanner, - OnRequestShowAppBanner) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - - return handled; -} - -void AppBannerDataFetcher::OnBannerPromptReply( - content::RenderFrameHost* render_frame_host, - int request_id, - blink::WebAppBannerPromptReply reply, - std::string referrer) { - content::WebContents* web_contents = GetWebContents(); - if (!CheckFetcherIsStillAlive(web_contents) || - request_id != event_request_id_) { - Cancel(); - return; - } - - // The renderer might have requested the prompt to be canceled. - // They may request that it is redisplayed later, so don't Cancel() here. - // However, log that the cancelation was requested, so Cancel() can be - // called if a redisplay isn't asked for. - // - // The redisplay request may be received before the Cancel prompt reply - // *after* if it is made before the beforeinstallprompt event handler - // concludes (e.g. in the event handler itself), so allow the pipeline - // to continue in this case. - // - // Stash the referrer for the case where the banner is redisplayed. - if (reply == blink::WebAppBannerPromptReply::Cancel && - !page_requested_prompt_) { - TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_PREVENT_DEFAULT_CALLED); - was_canceled_by_page_ = true; - referrer_ = referrer; - OutputDeveloperNotShownMessage(web_contents, kRendererRequestCancel, - is_debug_mode_); - return; - } - - // If we haven't yet returned, but either of |was_canceled_by_page_| or - // |page_requested_prompt_| is true, the page has requested a delayed showing - // of the prompt. Otherwise, the prompt was never canceled by the page. - if (was_canceled_by_page_ || page_requested_prompt_) { - TrackBeforeInstallEvent( - BEFORE_INSTALL_EVENT_PROMPT_CALLED_AFTER_PREVENT_DEFAULT); - was_canceled_by_page_ = false; - } else { - TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_NO_ACTION); - } - - AppBannerSettingsHelper::RecordMinutesFromFirstVisitToShow( - web_contents, validated_url_, GetAppIdentifier(), GetCurrentTime()); - - // Definitely going to show the banner now. - FOR_EACH_OBSERVER(Observer, observer_list_, - OnDecidedWhetherToShow(this, true)); - - TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_COMPLETE); - ShowBanner(app_icon_url_, app_icon_.get(), app_title_, referrer); - is_active_ = false; -} - -void AppBannerDataFetcher::OnRequestShowAppBanner( - content::RenderFrameHost* render_frame_host, - int request_id) { - if (was_canceled_by_page_) { - // Simulate an "OK" from the website to restart the banner display pipeline. - // Don't reset |was_canceled_by_page_| yet for metrics purposes. - OnBannerPromptReply(render_frame_host, request_id, - blink::WebAppBannerPromptReply::None, referrer_); - } else { - // Log that the prompt request was made for when we get the prompt reply. - page_requested_prompt_ = true; - } -} - -AppBannerDataFetcher::~AppBannerDataFetcher() { - FOR_EACH_OBSERVER(Observer, observer_list_, OnFetcherDestroyed(this)); -} - -std::string AppBannerDataFetcher::GetBannerType() { - return "web"; -} - -content::WebContents* AppBannerDataFetcher::GetWebContents() { - if (!web_contents() || web_contents()->IsBeingDestroyed()) - return nullptr; - return web_contents(); -} - -std::string AppBannerDataFetcher::GetAppIdentifier() { - DCHECK(!manifest_.IsEmpty()); - return manifest_.start_url.spec(); -} - -void AppBannerDataFetcher::RecordDidShowBanner(const std::string& event_name) { - content::WebContents* web_contents = GetWebContents(); - DCHECK(web_contents); - - AppBannerSettingsHelper::RecordBannerEvent( - web_contents, validated_url_, GetAppIdentifier(), - AppBannerSettingsHelper::APP_BANNER_EVENT_DID_SHOW, - GetCurrentTime()); - rappor::SampleDomainAndRegistryFromGURL(g_browser_process->rappor_service(), - event_name, - web_contents->GetURL()); -} - -void AppBannerDataFetcher::OnDidGetManifest( - const GURL& manifest_url, - const content::Manifest& manifest) { - content::WebContents* web_contents = GetWebContents(); - if (!CheckFetcherIsStillAlive(web_contents)) { - Cancel(); - return; - } - if (manifest_url.is_empty()) { - OutputDeveloperNotShownMessage(web_contents, kNoManifest, is_debug_mode_); - Cancel(); - return; - } - if (manifest.IsEmpty()) { - OutputDeveloperNotShownMessage(web_contents, kManifestEmpty, - is_debug_mode_); - Cancel(); - return; - } - - if (manifest.prefer_related_applications && - manifest.related_applications.size()) { - for (const auto& application : manifest.related_applications) { - std::string platform = base::UTF16ToUTF8(application.platform.string()); - std::string id = base::UTF16ToUTF8(application.id.string()); - if (weak_delegate_->HandleNonWebApp(platform, application.url, id, - is_debug_mode_)) - return; - } - } - - if (!IsManifestValidForWebApp(manifest, web_contents, is_debug_mode_)) { - Cancel(); - return; - } - - // Since the manifest is valid, one of short name or name must be non-null. - // Prefer name if it isn't null. - manifest_url_ = manifest_url; - manifest_ = manifest; - app_title_ = (manifest_.name.is_null()) ? manifest_.short_name.string() - : manifest_.name.string(); - - if (IsWebAppInstalled(web_contents->GetBrowserContext(), - manifest.start_url) && - !is_debug_mode_) { - Cancel(); - return; - } - - banners::TrackDisplayEvent(DISPLAY_EVENT_WEB_APP_BANNER_REQUESTED); - - // Check to see if there is a single service worker controlling this page - // and the manifest's start url. - Profile* profile = - Profile::FromBrowserContext(web_contents->GetBrowserContext()); - content::StoragePartition* storage_partition = - content::BrowserContext::GetStoragePartition( - profile, web_contents->GetSiteInstance()); - DCHECK(storage_partition); - - storage_partition->GetServiceWorkerContext()->CheckHasServiceWorker( - validated_url_, manifest.start_url, - base::Bind(&AppBannerDataFetcher::OnDidCheckHasServiceWorker, - this)); -} - -void AppBannerDataFetcher::OnDidCheckHasServiceWorker( - bool has_service_worker) { - content::WebContents* web_contents = GetWebContents(); - if (!CheckFetcherIsStillAlive(web_contents)) { - Cancel(); - return; - } - - if (!has_service_worker) { - TrackDisplayEvent(DISPLAY_EVENT_LACKS_SERVICE_WORKER); - OutputDeveloperNotShownMessage(web_contents, kNoMatchingServiceWorker, - is_debug_mode_); - Cancel(); - return; - } - - OnHasServiceWorker(web_contents); -} - -void AppBannerDataFetcher::OnHasServiceWorker( - content::WebContents* web_contents) { - GURL icon_url = ManifestIconSelector::FindBestMatchingIcon( - manifest_.icons, ideal_icon_size_in_dp_, minimum_icon_size_in_dp_); - - if (icon_url.is_empty()) { - OutputDeveloperNotShownMessage( - web_contents, - kNoIconMatchingRequirements, - base::IntToString(ManifestIconSelector::ConvertIconSizeFromDpToPx( - minimum_icon_size_in_dp_)), - is_debug_mode_); - Cancel(); - } else if (!FetchAppIcon(web_contents, icon_url)) { - OutputDeveloperNotShownMessage(web_contents, kCannotDownloadIcon, - is_debug_mode_); - Cancel(); - } -} - -bool AppBannerDataFetcher::FetchAppIcon(content::WebContents* web_contents, - const GURL& icon_url) { - app_icon_url_ = icon_url; - return ManifestIconDownloader::Download( - web_contents, icon_url, ideal_icon_size_in_dp_, minimum_icon_size_in_dp_, - base::Bind(&AppBannerDataFetcher::OnAppIconFetched, this)); -} - -void AppBannerDataFetcher::OnAppIconFetched(const SkBitmap& bitmap) { - if (!is_active_) return; - - content::WebContents* web_contents = GetWebContents(); - if (!CheckFetcherIsStillAlive(web_contents)) { - Cancel(); - return; - } - if (bitmap.drawsNothing()) { - OutputDeveloperNotShownMessage(web_contents, kNoIconAvailable, - is_debug_mode_); - Cancel(); - return; - } - - RecordCouldShowBanner(); - if (!is_debug_mode_ && !CheckIfShouldShowBanner()) { - // At this point, the only possible case is that the banner has been added - // to the homescreen, given all of the other checks that have been made. - Cancel(); - return; - } - - app_icon_.reset(new SkBitmap(bitmap)); - event_request_id_ = ++gCurrentRequestID; - - TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_CREATED); - web_contents->GetMainFrame()->Send( - new ChromeViewMsg_AppBannerPromptRequest( - web_contents->GetMainFrame()->GetRoutingID(), - event_request_id_, - GetBannerType())); -} - -bool AppBannerDataFetcher::IsWebAppInstalled( - content::BrowserContext* browser_context, - const GURL& start_url) { - return false; -} - -void AppBannerDataFetcher::RecordCouldShowBanner() { - content::WebContents* web_contents = GetWebContents(); - DCHECK(web_contents); - - AppBannerSettingsHelper::RecordBannerCouldShowEvent( - web_contents, validated_url_, GetAppIdentifier(), - GetCurrentTime(), transition_type_); -} - -bool AppBannerDataFetcher::CheckIfShouldShowBanner() { - content::WebContents* web_contents = GetWebContents(); - DCHECK(web_contents); - - return AppBannerSettingsHelper::ShouldShowBanner( - web_contents, validated_url_, GetAppIdentifier(), GetCurrentTime()); -} - -bool AppBannerDataFetcher::CheckFetcherIsStillAlive( - content::WebContents* web_contents) { - if (!is_active_) { - OutputDeveloperNotShownMessage( - web_contents, kUserNavigatedBeforeBannerShown, is_debug_mode_); - return false; - } - if (!web_contents) { - return false; // We cannot show a message if |web_contents| is null - } - return true; -} - -// static -bool AppBannerDataFetcher::IsManifestValidForWebApp( - const content::Manifest& manifest, - content::WebContents* web_contents, - bool is_debug_mode) { - if (manifest.IsEmpty()) { - OutputDeveloperNotShownMessage(web_contents, kManifestEmpty, is_debug_mode); - return false; - } - if (!manifest.start_url.is_valid()) { - OutputDeveloperNotShownMessage(web_contents, kStartURLNotValid, - is_debug_mode); - return false; - } - if ((manifest.name.is_null() || manifest.name.string().empty()) && - (manifest.short_name.is_null() || manifest.short_name.string().empty())) { - OutputDeveloperNotShownMessage( - web_contents, kManifestMissingNameOrShortName, is_debug_mode); - return false; - } - - // TODO(dominickn,mlamouri): when Chrome supports "minimal-ui", it should be - // accepted. If we accept it today, it would fallback to "browser" and make - // this check moot. See https://crbug.com/604390 - if (manifest.display != blink::WebDisplayModeStandalone && - manifest.display != blink::WebDisplayModeFullscreen) { - OutputDeveloperNotShownMessage( - web_contents, kManifestDisplayStandaloneFullscreen, is_debug_mode); - return false; - } - - if (!DoesManifestContainRequiredIcon(manifest)) { - OutputDeveloperNotShownMessage(web_contents, kManifestMissingSuitableIcon, - is_debug_mode); - return false; - } - return true; -} - -} // namespace banners
diff --git a/chrome/browser/banners/app_banner_data_fetcher.h b/chrome/browser/banners/app_banner_data_fetcher.h deleted file mode 100644 index e5b259ae..0000000 --- a/chrome/browser/banners/app_banner_data_fetcher.h +++ /dev/null
@@ -1,218 +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 CHROME_BROWSER_BANNERS_APP_BANNER_DATA_FETCHER_H_ -#define CHROME_BROWSER_BANNERS_APP_BANNER_DATA_FETCHER_H_ - -#include <memory> - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/observer_list.h" -#include "base/time/time.h" -#include "chrome/common/web_application_info.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/web_contents.h" -#include "content/public/browser/web_contents_observer.h" -#include "content/public/common/manifest.h" -#include "third_party/WebKit/public/platform/modules/app_banner/WebAppBannerPromptReply.h" - -namespace chrome { -class BitmapFetcher; -} // namespace chrome - -namespace infobars { -class InfoBar; -} // namespace infobars - -namespace banners { -class AppBannerDataFetcher; - -// Fetches data required to show a web app banner for the URL currently shown by -// the WebContents. -class AppBannerDataFetcher : public base::RefCountedThreadSafe< - AppBannerDataFetcher, - content::BrowserThread::DeleteOnUIThread>, - public content::WebContentsObserver { - public: - class Observer { - public: - virtual void OnDecidedWhetherToShow(AppBannerDataFetcher* fetcher, - bool will_show) = 0; - virtual void OnFetcherDestroyed(AppBannerDataFetcher* fetcher) = 0; - }; - - class Delegate { - public: - // Called to handle a non-web app. Returns |true| if the non-web app can be - // handled, and the fetcher needs to remain active and wait for a callback. - virtual bool HandleNonWebApp(const std::string& platform, - const GURL& url, - const std::string& id, - bool is_debug_mode) = 0; - }; - - // Returns the current time. - static base::Time GetCurrentTime(); - - // Fast-forwards the current time for testing. - static void SetTimeDeltaForTesting(int days); - - AppBannerDataFetcher(content::WebContents* web_contents, - base::WeakPtr<Delegate> weak_delegate, - int ideal_icon_size_in_dp, - int minimum_icon_size_in_dp, - bool is_debug_mode); - - // Begins creating a banner for the URL being displayed by the Delegate's - // WebContents. - void Start(const GURL& validated_url, ui::PageTransition transition_type); - - // Stops the pipeline when any asynchronous calls return. - void Cancel(); - - // Replaces the WebContents that is being observed. - void ReplaceWebContents(content::WebContents* web_contents); - - // Adds an observer to the list. - void AddObserverForTesting(Observer* observer); - - // Removes an observer from the list. - void RemoveObserverForTesting(Observer* observer); - - // Returns whether or not the pipeline has been stopped. - bool is_active() { return is_active_; } - - // Returns whether the beforeinstallprompt Javascript event was canceled. - bool was_canceled_by_page() { return was_canceled_by_page_; } - - // Returns whether the page has validly requested that the banner be shown - // by calling prompt() on the beforeinstallprompt Javascript event. - bool page_requested_prompt() { return page_requested_prompt_; } - - // Returns true when it was created by the user action in DevTools or - // "bypass-app-banner-engagement-checks" flag is set. - bool is_debug_mode() const { return is_debug_mode_; } - - // Returns the type of transition which triggered this fetch. - ui::PageTransition transition_type() { return transition_type_; } - - // Returns the URL that kicked off the banner data retrieval. - const GURL& validated_url() { return validated_url_; } - - // WebContentsObserver overrides. - void WebContentsDestroyed() override; - void DidNavigateMainFrame( - const content::LoadCommittedDetails& details, - const content::FrameNavigateParams& params) override; - bool OnMessageReceived(const IPC::Message& message, - content::RenderFrameHost* render_frame_host) override; - - protected: - ~AppBannerDataFetcher() override; - - // Return a string describing what type of banner is being created. Used when - // alerting websites that a banner is about to be created. - virtual std::string GetBannerType(); - - // Called after the manager sends a message to the renderer regarding its - // intention to show a prompt. The renderer will send a message back with the - // opportunity to cancel. - void OnBannerPromptReply(content::RenderFrameHost* render_frame_host, - int request_id, - blink::WebAppBannerPromptReply reply, - std::string referrer); - - // Called when the client has prevented a banner from being shown, and is - // now requesting that it be shown later. - void OnRequestShowAppBanner(content::RenderFrameHost* render_frame_host, - int request_id); - - content::WebContents* GetWebContents(); - virtual std::string GetAppIdentifier(); - const GURL& manifest_url() { return manifest_url_; } - const content::Manifest& manifest() { return manifest_; } - void set_app_title(const base::string16& title) { app_title_ = title; } - int event_request_id() { return event_request_id_; } - - // Fetches the icon at the given URL asynchronously, returning |false| if a - // load could not be started. - bool FetchAppIcon(content::WebContents* web_contents, const GURL& url); - - // Records that a banner was shown. The |event_name| corresponds to the RAPPOR - // metric being recorded. - void RecordDidShowBanner(const std::string& event_name); - - private: - // Callbacks for data retrieval. - void OnDidGetManifest(const GURL& manifest_url, - const content::Manifest& manifest); - void OnDidCheckHasServiceWorker(bool has_service_worker); - void OnAppIconFetched(const SkBitmap& bitmap); - - // Called when it is determined that the webapp has fulfilled the initial - // criteria of having a manifest and a service worker. - void OnHasServiceWorker(content::WebContents* web_contents); - - // Returns whether the given web app has already been installed. - virtual bool IsWebAppInstalled(content::BrowserContext* browser_context, - const GURL& start_url); - - // Record that the banner could be shown at this point, if the triggering - // heuristic allowed. - void RecordCouldShowBanner(); - - // Creates a banner for the app using the given icon. - virtual void ShowBanner(const GURL& icon_url, - const SkBitmap* icon, - const base::string16& title, - const std::string& referrer) = 0; - - // Returns whether the banner should be shown. - bool CheckIfShouldShowBanner(); - - // Returns whether the fetcher is active and web contents have not been - // closed. - bool CheckFetcherIsStillAlive(content::WebContents* web_contents); - - // Returns whether the given Manifest is following the requirements to show - // a web app banner. - static bool IsManifestValidForWebApp(const content::Manifest& manifest, - content::WebContents* web_contents, - bool is_debug_mode); - - const base::WeakPtr<Delegate> weak_delegate_; - const int ideal_icon_size_in_dp_; - const int minimum_icon_size_in_dp_; - base::ObserverList<Observer> observer_list_; - bool is_active_; - bool was_canceled_by_page_; - bool page_requested_prompt_; - const bool is_debug_mode_; - ui::PageTransition transition_type_; - int event_request_id_; - GURL app_icon_url_; - std::unique_ptr<SkBitmap> app_icon_; - std::string referrer_; - - GURL validated_url_; - base::string16 app_title_; - - // The URL of the Web app manifest. - GURL manifest_url_; - - content::Manifest manifest_; - - friend struct content::BrowserThread::DeleteOnThread< - content::BrowserThread::UI>; - friend class base::DeleteHelper<AppBannerDataFetcher>; - friend class AppBannerDataFetcherUnitTest; - friend class base::RefCounted<AppBannerDataFetcher>; - DISALLOW_COPY_AND_ASSIGN(AppBannerDataFetcher); -}; - -} // namespace banners - -#endif // CHROME_BROWSER_BANNERS_APP_BANNER_DATA_FETCHER_H_
diff --git a/chrome/browser/banners/app_banner_data_fetcher_browsertest.cc b/chrome/browser/banners/app_banner_data_fetcher_browsertest.cc deleted file mode 100644 index cb57b897..0000000 --- a/chrome/browser/banners/app_banner_data_fetcher_browsertest.cc +++ /dev/null
@@ -1,349 +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 "chrome/browser/banners/app_banner_data_fetcher.h" - -#include "base/command_line.h" -#include "base/location.h" -#include "base/run_loop.h" -#include "base/single_thread_task_runner.h" -#include "base/task_runner.h" -#include "base/test/histogram_tester.h" -#include "base/threading/thread_task_runner_handle.h" -#include "chrome/browser/banners/app_banner_data_fetcher_desktop.h" -#include "chrome/browser/banners/app_banner_metrics.h" -#include "chrome/browser/banners/app_banner_settings_helper.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/tabs/tab_strip_model.h" -#include "chrome/common/chrome_switches.h" -#include "chrome/test/base/in_process_browser_test.h" -#include "chrome/test/base/ui_test_utils.h" -#include "content/public/common/content_switches.h" -#include "content/public/test/test_navigation_observer.h" -#include "net/test/embedded_test_server/embedded_test_server.h" - -namespace banners { - -class TestObserver : public AppBannerDataFetcher::Observer { - public: - TestObserver(AppBannerDataFetcher* fetcher, base::Closure quit_closure) - : fetcher_(fetcher), - quit_closure_(quit_closure) { - fetcher_->AddObserverForTesting(this); - } - - virtual ~TestObserver() { - if (fetcher_) - fetcher_->RemoveObserverForTesting(this); - } - - void OnDecidedWhetherToShow(AppBannerDataFetcher* fetcher, - bool will_show) override { - base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure_); - ASSERT_FALSE(will_show_.get()); - will_show_.reset(new bool(will_show)); - } - - void OnFetcherDestroyed(AppBannerDataFetcher* fetcher) override { - base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure_); - fetcher_ = nullptr; - } - - bool will_show() { return will_show_.get() && *will_show_; } - - private: - AppBannerDataFetcher* fetcher_; - base::Closure quit_closure_; - std::unique_ptr<bool> will_show_; -}; - -class AppBannerDataFetcherBrowserTest : public InProcessBrowserTest, - public AppBannerDataFetcher::Delegate { - public: - AppBannerDataFetcherBrowserTest() : weak_factory_(this) { - } - - void SetUpOnMainThread() override { - AppBannerSettingsHelper::SetEngagementWeights(1, 1); - AppBannerSettingsHelper::SetTotalEngagementToTrigger(2); - ASSERT_TRUE(embedded_test_server()->Start()); - InProcessBrowserTest::SetUpOnMainThread(); - } - - bool HandleNonWebApp(const std::string& platform, - const GURL& url, - const std::string& id, - bool is_debug_mode) override { - base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure_); - non_web_platform_ = platform; - return false; - } - - void SetUpCommandLine(base::CommandLine* command_line) override { - command_line->AppendSwitch( - switches::kEnableExperimentalWebPlatformFeatures); - // Make sure app banners are disabled in the browser, otherwise they will - // interfere with the test. - command_line->AppendSwitch(switches::kDisableAddToShelf); - } - - protected: - void RunFetcher(const GURL& url, - const std::string& expected_non_web_platform, - ui::PageTransition transition, - bool expected_to_show) { - content::WebContents* web_contents = - browser()->tab_strip_model()->GetActiveWebContents(); - scoped_refptr<AppBannerDataFetcherDesktop> fetcher( - new AppBannerDataFetcherDesktop( - web_contents, weak_factory_.GetWeakPtr(), 128, 128, false)); - - base::HistogramTester histograms; - base::RunLoop run_loop; - quit_closure_ = run_loop.QuitClosure(); - std::unique_ptr<TestObserver> observer( - new TestObserver(fetcher.get(), run_loop.QuitClosure())); - fetcher->Start(url, transition); - run_loop.Run(); - - EXPECT_EQ(expected_non_web_platform, non_web_platform_); - EXPECT_EQ(expected_to_show, observer->will_show()); - ASSERT_FALSE(fetcher->is_active()); - - // If showing the banner, ensure that the minutes histogram is recorded. - histograms.ExpectTotalCount(banners::kMinutesHistogram, - (observer->will_show() ? 1 : 0)); - } - - void RunBannerTest(const std::string& manifest_page, - ui::PageTransition transition, - unsigned int unshown_repetitions, - bool expectation) { - std::string valid_page(manifest_page); - GURL test_url = embedded_test_server()->GetURL(valid_page); - content::WebContents* web_contents = - browser()->tab_strip_model()->GetActiveWebContents(); - - for (unsigned int i = 0; i < unshown_repetitions; ++i) { - ui_test_utils::NavigateToURL(browser(), test_url); - RunFetcher(web_contents->GetURL(), std::string(), transition, false); - AppBannerDataFetcher::SetTimeDeltaForTesting(i+1); - } - - // On the final loop, check whether the banner triggered or not as expected. - ui_test_utils::NavigateToURL(browser(), test_url); - RunFetcher(web_contents->GetURL(), std::string(), transition, expectation); - } - - private: - std::string non_web_platform_; - base::Closure quit_closure_; - base::WeakPtrFactory<AppBannerDataFetcherBrowserTest> weak_factory_; -}; - -IN_PROC_BROWSER_TEST_F(AppBannerDataFetcherBrowserTest, - WebAppBannerCreatedDirect) { - RunBannerTest("/banners/manifest_test_page.html", ui::PAGE_TRANSITION_TYPED, - 1, true); -} - -IN_PROC_BROWSER_TEST_F(AppBannerDataFetcherBrowserTest, - WebAppBannerCreatedDirectLargerTotal) { - AppBannerSettingsHelper::SetTotalEngagementToTrigger(4); - RunBannerTest("/banners/manifest_test_page.html", ui::PAGE_TRANSITION_TYPED, - 3, true); -} - -IN_PROC_BROWSER_TEST_F(AppBannerDataFetcherBrowserTest, - WebAppBannerCreatedDirectSmallerTotal) { - AppBannerSettingsHelper::SetTotalEngagementToTrigger(1); - RunBannerTest("/banners/manifest_test_page.html", ui::PAGE_TRANSITION_TYPED, - 0, true); -} - -IN_PROC_BROWSER_TEST_F(AppBannerDataFetcherBrowserTest, - WebAppBannerCreatedDirectSingle) { - AppBannerSettingsHelper::SetEngagementWeights(2, 1); - RunBannerTest("/banners/manifest_test_page.html", - ui::PAGE_TRANSITION_GENERATED, 0, true); -} - -IN_PROC_BROWSER_TEST_F(AppBannerDataFetcherBrowserTest, - WebAppBannerCreatedDirectMultiple) { - AppBannerSettingsHelper::SetEngagementWeights(0.5, 1); - RunBannerTest("/banners/manifest_test_page.html", - ui::PAGE_TRANSITION_GENERATED, 3, true); -} - -IN_PROC_BROWSER_TEST_F(AppBannerDataFetcherBrowserTest, - WebAppBannerCreatedDirectMultipleLargerTotal) { - AppBannerSettingsHelper::SetEngagementWeights(0.5, 1); - AppBannerSettingsHelper::SetTotalEngagementToTrigger(3); - RunBannerTest("/banners/manifest_test_page.html", - ui::PAGE_TRANSITION_GENERATED, 5, true); -} - -IN_PROC_BROWSER_TEST_F(AppBannerDataFetcherBrowserTest, - WebAppBannerCreatedDirectMultipleSmallerTotal) { - AppBannerSettingsHelper::SetEngagementWeights(0.5, 1); - AppBannerSettingsHelper::SetTotalEngagementToTrigger(1); - RunBannerTest("/banners/manifest_test_page.html", - ui::PAGE_TRANSITION_GENERATED, 1, true); -} - -IN_PROC_BROWSER_TEST_F(AppBannerDataFetcherBrowserTest, - WebAppBannerCreatedIndirect) { - RunBannerTest("/banners/manifest_test_page.html", ui::PAGE_TRANSITION_LINK, - 1, true); -} - -IN_PROC_BROWSER_TEST_F(AppBannerDataFetcherBrowserTest, - WebAppBannerCreatedIndirectLargerTotal) { - AppBannerSettingsHelper::SetTotalEngagementToTrigger(5); - RunBannerTest("/banners/manifest_test_page.html", ui::PAGE_TRANSITION_LINK, - 4, true); -} - -IN_PROC_BROWSER_TEST_F(AppBannerDataFetcherBrowserTest, - WebAppBannerCreatedIndirectSmallerTotal) { - AppBannerSettingsHelper::SetTotalEngagementToTrigger(1); - RunBannerTest("/banners/manifest_test_page.html", ui::PAGE_TRANSITION_LINK, - 0, true); -} - -IN_PROC_BROWSER_TEST_F(AppBannerDataFetcherBrowserTest, - WebAppBannerCreatedIndirectSingle) { - AppBannerSettingsHelper::SetEngagementWeights(1, 3); - RunBannerTest("/banners/manifest_test_page.html", ui::PAGE_TRANSITION_RELOAD, - 0, true); -} - -IN_PROC_BROWSER_TEST_F(AppBannerDataFetcherBrowserTest, - WebAppBannerCreatedIndirectMultiple) { - AppBannerSettingsHelper::SetEngagementWeights(1, 0.5); - RunBannerTest("/banners/manifest_test_page.html", ui::PAGE_TRANSITION_LINK, - 3, true); -} - -IN_PROC_BROWSER_TEST_F(AppBannerDataFetcherBrowserTest, - WebAppBannerCreatedIndirectMultipleLargerTotal) { - AppBannerSettingsHelper::SetEngagementWeights(1, 0.5); - AppBannerSettingsHelper::SetTotalEngagementToTrigger(4); - RunBannerTest("/banners/manifest_test_page.html", ui::PAGE_TRANSITION_LINK, - 7, true); -} - -IN_PROC_BROWSER_TEST_F(AppBannerDataFetcherBrowserTest, - WebAppBannerCreatedVarious) { - AppBannerSettingsHelper::SetEngagementWeights(0.5, 0.25); - - std::string valid_page("/banners/manifest_test_page.html"); - GURL test_url = embedded_test_server()->GetURL(valid_page); - content::WebContents* web_contents = - browser()->tab_strip_model()->GetActiveWebContents(); - - // Add a direct nav on day 1. - ui_test_utils::NavigateToURL(browser(), test_url); - RunFetcher(web_contents->GetURL(), std::string(), ui::PAGE_TRANSITION_TYPED, - false); - - // Add an indirect nav on day 1 which is ignored. - ui_test_utils::NavigateToURL(browser(), test_url); - RunFetcher(web_contents->GetURL(), std::string(), ui::PAGE_TRANSITION_LINK, - false); - AppBannerDataFetcher::SetTimeDeltaForTesting(1); - - // Add an indirect nav on day 2. - ui_test_utils::NavigateToURL(browser(), test_url); - RunFetcher(web_contents->GetURL(), std::string(), - ui::PAGE_TRANSITION_MANUAL_SUBFRAME, false); - - // Add a direct nav on day 2 which overrides. - ui_test_utils::NavigateToURL(browser(), test_url); - RunFetcher(web_contents->GetURL(), std::string(), - ui::PAGE_TRANSITION_GENERATED, false); - AppBannerDataFetcher::SetTimeDeltaForTesting(2); - - // Add a direct nav on day 3. - ui_test_utils::NavigateToURL(browser(), test_url); - RunFetcher(web_contents->GetURL(), std::string(), - ui::PAGE_TRANSITION_GENERATED, false); - AppBannerDataFetcher::SetTimeDeltaForTesting(3); - - // Add an indirect nav on day 4. - ui_test_utils::NavigateToURL(browser(), test_url); - RunFetcher(web_contents->GetURL(), std::string(), - ui::PAGE_TRANSITION_FORM_SUBMIT, false); - - // Add a direct nav on day 4 which should trigger the banner. - ui_test_utils::NavigateToURL(browser(), test_url); - RunFetcher(web_contents->GetURL(), std::string(), - ui::PAGE_TRANSITION_TYPED, true); -} - -IN_PROC_BROWSER_TEST_F(AppBannerDataFetcherBrowserTest, - WebAppBannerNoTypeInManifest) { - RunBannerTest("/banners/manifest_no_type_test_page.html", - ui::PAGE_TRANSITION_TYPED, 1, true); -} - -IN_PROC_BROWSER_TEST_F(AppBannerDataFetcherBrowserTest, - WebAppBannerNoTypeInManifestCapsExtension) { - RunBannerTest("/banners/manifest_no_type_caps_test_page.html", - ui::PAGE_TRANSITION_TYPED, 1, true); -} - -IN_PROC_BROWSER_TEST_F(AppBannerDataFetcherBrowserTest, PlayAppManifest) { - std::string valid_page("/banners/play_app_test_page.html"); - GURL test_url = embedded_test_server()->GetURL(valid_page); - content::WebContents* web_contents = - browser()->tab_strip_model()->GetActiveWebContents(); - - // Native banners do not require the SW, so we can just load the URL. - ui_test_utils::NavigateToURL(browser(), test_url); - std::string play_platform("play"); - RunFetcher(web_contents->GetURL(), play_platform, ui::PAGE_TRANSITION_TYPED, - false); - - // The logic to get the details for a play app banner are only on android - // builds, so this test does not check that the banner is shown. -} - -IN_PROC_BROWSER_TEST_F(AppBannerDataFetcherBrowserTest, NoManifest) { - RunBannerTest("/banners/no_manifest_test_page.html", - ui::PAGE_TRANSITION_TYPED, 1, false); -} - -IN_PROC_BROWSER_TEST_F(AppBannerDataFetcherBrowserTest, MissingManifest) { - RunBannerTest("/banners/manifest_bad_link.html", - ui::PAGE_TRANSITION_TYPED, 1, false); -} - -IN_PROC_BROWSER_TEST_F(AppBannerDataFetcherBrowserTest, CancelBannerDirect) { - RunBannerTest("/banners/cancel_test_page.html", ui::PAGE_TRANSITION_TYPED, 1, - false); -} - -IN_PROC_BROWSER_TEST_F(AppBannerDataFetcherBrowserTest, CancelBannerIndirect) { - AppBannerSettingsHelper::SetEngagementWeights(1, 0.5); - RunBannerTest("/banners/cancel_test_page.html", ui::PAGE_TRANSITION_TYPED, 3, - false); -} - -IN_PROC_BROWSER_TEST_F(AppBannerDataFetcherBrowserTest, PromptBanner) { - RunBannerTest("/banners/prompt_test_page.html", ui::PAGE_TRANSITION_TYPED, 1, - true); -} - -IN_PROC_BROWSER_TEST_F(AppBannerDataFetcherBrowserTest, PromptBannerInHandler) { - RunBannerTest("/banners/prompt_in_handler_test_page.html", - ui::PAGE_TRANSITION_TYPED, 1, true); -} - -IN_PROC_BROWSER_TEST_F(AppBannerDataFetcherBrowserTest, WebAppBannerInIFrame) { - RunBannerTest("/banners/iframe_test_page.html", ui::PAGE_TRANSITION_TYPED, 1, - false); -} - -} // namespace banners
diff --git a/chrome/browser/banners/app_banner_data_fetcher_desktop.cc b/chrome/browser/banners/app_banner_data_fetcher_desktop.cc deleted file mode 100644 index ebe43c5..0000000 --- a/chrome/browser/banners/app_banner_data_fetcher_desktop.cc +++ /dev/null
@@ -1,100 +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 "chrome/browser/banners/app_banner_data_fetcher_desktop.h" - -#include "chrome/browser/banners/app_banner_infobar_delegate_desktop.h" -#include "chrome/browser/banners/app_banner_metrics.h" -#include "chrome/browser/banners/app_banner_settings_helper.h" -#include "chrome/browser/extensions/bookmark_app_helper.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/common/render_messages.h" -#include "chrome/common/web_application_info.h" -#include "content/public/browser/render_frame_host.h" - -namespace infobars { -class InfoBar; -} // namespace infobars - -namespace banners { - -AppBannerDataFetcherDesktop::AppBannerDataFetcherDesktop( - content::WebContents* web_contents, - base::WeakPtr<Delegate> weak_delegate, - int ideal_icon_size_in_dp, - int minimum_icon_size_in_dp, - bool is_debug_mode) - : AppBannerDataFetcher(web_contents, - weak_delegate, - ideal_icon_size_in_dp, - minimum_icon_size_in_dp, - is_debug_mode) {} - -AppBannerDataFetcherDesktop::~AppBannerDataFetcherDesktop() { -} - -bool AppBannerDataFetcherDesktop::IsWebAppInstalled( - content::BrowserContext* browser_context, - const GURL& start_url) { - return extensions::BookmarkAppHelper::BookmarkOrHostedAppInstalled( - browser_context, start_url); -} - -void AppBannerDataFetcherDesktop::ShowBanner(const GURL& icon_url, - const SkBitmap* icon, - const base::string16& title, - const std::string& referrer) { - content::WebContents* web_contents = GetWebContents(); - DCHECK(web_contents && !manifest().IsEmpty()); - - Profile* profile = - Profile::FromBrowserContext(web_contents->GetBrowserContext()); - WebApplicationInfo web_app_info; - - bookmark_app_helper_.reset( - new extensions::BookmarkAppHelper(profile, web_app_info, web_contents)); - - // This differs from the Android infobar creation, which has an explicit - // InfoBarAndroid class interfacing with Java. On Android, the data fetcher - // calls the InfoBarService to show the banner. On desktop, an InfoBar class - // is not required, so the InfoBarService call is made within the delegate. - infobars::InfoBar* infobar = AppBannerInfoBarDelegateDesktop::Create( - make_scoped_refptr(this), web_contents, manifest(), - bookmark_app_helper_.get(), event_request_id()); - if (infobar) { - RecordDidShowBanner("AppBanner.WebApp.Shown"); - TrackDisplayEvent(DISPLAY_EVENT_WEB_APP_BANNER_CREATED); - } -} - -void AppBannerDataFetcherDesktop::FinishCreateBookmarkApp( - const extensions::Extension* extension, - const WebApplicationInfo& web_app_info) { - content::WebContents* web_contents = GetWebContents(); - if (web_contents) { - // A null extension pointer indicates that the bookmark app install was - // not successful. - if (extension == nullptr) { - web_contents->GetMainFrame()->Send( - new ChromeViewMsg_AppBannerDismissed( - web_contents->GetMainFrame()->GetRoutingID(), - event_request_id())); - - AppBannerSettingsHelper::RecordBannerDismissEvent( - web_contents, manifest().start_url.spec(), - AppBannerSettingsHelper::WEB); - } else { - web_contents->GetMainFrame()->Send( - new ChromeViewMsg_AppBannerAccepted( - web_contents->GetMainFrame()->GetRoutingID(), - event_request_id(), "web")); - - AppBannerSettingsHelper::RecordBannerInstallEvent( - web_contents, manifest().start_url.spec(), - AppBannerSettingsHelper::WEB); - } - } -} - -} // namespace banners
diff --git a/chrome/browser/banners/app_banner_data_fetcher_desktop.h b/chrome/browser/banners/app_banner_data_fetcher_desktop.h deleted file mode 100644 index 0b594da3..0000000 --- a/chrome/browser/banners/app_banner_data_fetcher_desktop.h +++ /dev/null
@@ -1,53 +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 CHROME_BROWSER_BANNERS_APP_BANNER_DATA_FETCHER_DESKTOP_H_ -#define CHROME_BROWSER_BANNERS_APP_BANNER_DATA_FETCHER_DESKTOP_H_ - -#include "base/macros.h" -#include "chrome/browser/banners/app_banner_data_fetcher.h" - -namespace extensions { -class BookmarkAppHelper; -class Extension; -} // namespace extensions - -namespace banners { - -// Fetches data required to show a banner for the URL currently shown by the -// WebContents. Extends the regular fetch to support desktop web apps. -class AppBannerDataFetcherDesktop : public AppBannerDataFetcher { - public: - AppBannerDataFetcherDesktop(content::WebContents* web_contents, - base::WeakPtr<Delegate> weak_delegate, - int ideal_icon_size_in_dp, - int minimum_icon_size_in_dp, - bool is_debug_mode); - - // Callback for finishing bookmark app creation - void FinishCreateBookmarkApp(const extensions::Extension* extension, - const WebApplicationInfo& web_app_info); - - protected: - ~AppBannerDataFetcherDesktop() override; - - private: - // AppBannerDataFetcher override. - bool IsWebAppInstalled(content::BrowserContext* browser_context, - const GURL& start_url) override; - - // AppBannerDataFetcher override. - void ShowBanner(const GURL& icon_url, - const SkBitmap* icon, - const base::string16& title, - const std::string& referrer) override; - - std::unique_ptr<extensions::BookmarkAppHelper> bookmark_app_helper_; - - DISALLOW_COPY_AND_ASSIGN(AppBannerDataFetcherDesktop); -}; - -} // namespace banners - -#endif // CHROME_BROWSER_BANNERS_APP_BANNER_DATA_FETCHER_DESKTOP_H_
diff --git a/chrome/browser/banners/app_banner_data_fetcher_unittest.cc b/chrome/browser/banners/app_banner_data_fetcher_unittest.cc deleted file mode 100644 index 1de8aef..0000000 --- a/chrome/browser/banners/app_banner_data_fetcher_unittest.cc +++ /dev/null
@@ -1,148 +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 "chrome/browser/banners/app_banner_data_fetcher.h" - -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/WebKit/public/platform/WebDisplayMode.h" - -namespace banners { - -class AppBannerDataFetcherUnitTest : public testing::Test { - public: - AppBannerDataFetcherUnitTest() { } - - protected: - static base::NullableString16 ToNullableUTF16(const std::string& str) { - return base::NullableString16(base::UTF8ToUTF16(str), false); - } - - static content::Manifest GetValidManifest() { - content::Manifest manifest; - manifest.name = ToNullableUTF16("foo"); - manifest.short_name = ToNullableUTF16("bar"); - manifest.start_url = GURL("http://example.com"); - manifest.display = blink::WebDisplayModeStandalone; - - content::Manifest::Icon icon; - icon.type = ToNullableUTF16("image/png"); - icon.sizes.push_back(gfx::Size(144, 144)); - manifest.icons.push_back(icon); - - return manifest; - } - - static bool IsManifestValid(const content::Manifest& manifest) { - // The second argument is the web_contents pointer, which is used for - // developer debug logging to the console. The logging is skipped inside the - // method if a null web_contents pointer is provided, so this is safe. - // The third argument is the is_debug_mode boolean value, which is true only - // when it is triggered by the developer's action in DevTools. - return AppBannerDataFetcher::IsManifestValidForWebApp(manifest, nullptr, - false); - } -}; - -TEST_F(AppBannerDataFetcherUnitTest, EmptyManifestIsInvalid) { - content::Manifest manifest; - EXPECT_FALSE(IsManifestValid(manifest)); -} - -TEST_F(AppBannerDataFetcherUnitTest, CheckMinimalValidManifest) { - content::Manifest manifest = GetValidManifest(); - EXPECT_TRUE(IsManifestValid(manifest)); -} - -TEST_F(AppBannerDataFetcherUnitTest, ManifestRequiresNameORShortName) { - content::Manifest manifest = GetValidManifest(); - - manifest.name = base::NullableString16(); - EXPECT_TRUE(IsManifestValid(manifest)); - - manifest.name = ToNullableUTF16("foo"); - manifest.short_name = base::NullableString16(); - EXPECT_TRUE(IsManifestValid(manifest)); - - manifest.name = base::NullableString16(); - EXPECT_FALSE(IsManifestValid(manifest)); -} - -TEST_F(AppBannerDataFetcherUnitTest, ManifestRequiresNonEmptyNameORShortName) { - content::Manifest manifest = GetValidManifest(); - - manifest.name = ToNullableUTF16(""); - EXPECT_TRUE(IsManifestValid(manifest)); - - manifest.name = ToNullableUTF16("foo"); - manifest.short_name = ToNullableUTF16(""); - EXPECT_TRUE(IsManifestValid(manifest)); - - manifest.name = ToNullableUTF16(""); - EXPECT_FALSE(IsManifestValid(manifest)); -} - -TEST_F(AppBannerDataFetcherUnitTest, ManifestRequiresValidStartURL) { - content::Manifest manifest = GetValidManifest(); - - manifest.start_url = GURL(); - EXPECT_FALSE(IsManifestValid(manifest)); - - manifest.start_url = GURL("/"); - EXPECT_FALSE(IsManifestValid(manifest)); -} - -TEST_F(AppBannerDataFetcherUnitTest, ManifestRequiresImagePNG) { - content::Manifest manifest = GetValidManifest(); - - manifest.icons[0].type = ToNullableUTF16("image/gif"); - EXPECT_FALSE(IsManifestValid(manifest)); - manifest.icons[0].type = base::NullableString16(); - EXPECT_FALSE(IsManifestValid(manifest)); -} - -TEST_F(AppBannerDataFetcherUnitTest, ManifestRequiresMinimalSize) { - content::Manifest manifest = GetValidManifest(); - - // The icon MUST be 144x144 size at least. - manifest.icons[0].sizes[0] = gfx::Size(1, 1); - EXPECT_FALSE(IsManifestValid(manifest)); - - // If one of the sizes match the requirement, it should be accepted. - manifest.icons[0].sizes.push_back(gfx::Size(144, 144)); - EXPECT_TRUE(IsManifestValid(manifest)); - - // Higher than the required size is okay. - manifest.icons[0].sizes[1] = gfx::Size(200, 200); - EXPECT_TRUE(IsManifestValid(manifest)); - - // Non-square is okay. - manifest.icons[0].sizes[1] = gfx::Size(144, 200); - EXPECT_TRUE(IsManifestValid(manifest)); - - // The representation of the keyword 'any' should be recognized. - manifest.icons[0].sizes[1] = gfx::Size(0, 0); - EXPECT_TRUE(IsManifestValid(manifest)); -} - -TEST_F(AppBannerDataFetcherUnitTest, ManifestDisplayStandaloneFullscreen) { - content::Manifest manifest = GetValidManifest(); - - manifest.display = blink::WebDisplayModeUndefined; - EXPECT_FALSE(IsManifestValid(manifest)); - - manifest.display = blink::WebDisplayModeBrowser; - EXPECT_FALSE(IsManifestValid(manifest)); - - manifest.display = blink::WebDisplayModeMinimalUi; - EXPECT_FALSE(IsManifestValid(manifest)); - - manifest.display = blink::WebDisplayModeStandalone; - EXPECT_TRUE(IsManifestValid(manifest)); - - manifest.display = blink::WebDisplayModeFullscreen; - EXPECT_TRUE(IsManifestValid(manifest)); -} - -} // namespace banners
diff --git a/chrome/browser/banners/app_banner_debug_log.cc b/chrome/browser/banners/app_banner_debug_log.cc deleted file mode 100644 index dac19e0..0000000 --- a/chrome/browser/banners/app_banner_debug_log.cc +++ /dev/null
@@ -1,135 +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 "chrome/browser/banners/app_banner_debug_log.h" - -#include "base/strings/stringprintf.h" -#include "content/public/browser/render_frame_host.h" -#include "content/public/browser/web_contents.h" - -namespace banners { - -static const char kRendererRequestCancelMessage[] = - "page has requested the banner prompt be cancelled"; -static const char kManifestEmptyMessage[] = - "manifest could not be fetched, is empty, or could not be parsed"; -static const char kNoManifestMessage[] = - "site has no manifest <link> URL"; -static const char kNoIconMatchingRequirementsMessage[] = - "%spx square icon is required, but no supplied icon is at least this size"; -static const char kCannotDownloadIconMessage[] = - "could not download the specified icon"; -static const char kNoMatchingServiceWorkerMessage[] = - "no matching service worker detected. You may need to reload the page, or " - "check that the service worker for the current page also controls the " - "start URL from the manifest"; -static const char kNoIconAvailableMessage[] = - "no icon available to display"; -static const char kUserNavigatedBeforeBannerShownMessage[] = - "the user navigated before the banner could be shown"; -static const char kStartURLNotValidMessage[] = - "start URL in manifest is not valid"; -static const char kManifestDisplayStandaloneFullscreenMessage[] = - "manifest display property must be set to 'standalone' or 'fullscreen'"; -static const char kManifestMissingNameOrShortNameMessage[] = - "one of manifest name or short name must be specified"; -static const char kManifestMissingSuitableIconMessage[] = - "manifest does not contain a suitable icon - PNG format of at least " - "144x144px is required, and the sizes attribute must be set"; -static const char kNotLoadedInMainFrameMessage[] = - "page not loaded in the main frame"; -static const char kNotServedFromSecureOriginMessage[] = - "page not served from a secure origin"; -// The leading space is intentional as another string is prepended. -static const char kIgnoredNotSupportedOnAndroidMessage[] = - "%s application is not supported on Android"; -static const char kIgnoredNoIdMessage[] = - "no Play store ID provided"; -static const char kIgnoredIdsDoNotMatchMessage[] = - "a Play app URL and Play store ID were specified in the manifest, but they" - " do not match"; - -void OutputDeveloperNotShownMessage(content::WebContents* web_contents, - OutputDeveloperMessageCode code, - bool is_debug_mode) { - OutputDeveloperNotShownMessage(web_contents, code, std::string(), - is_debug_mode); -} - -void OutputDeveloperNotShownMessage(content::WebContents* web_contents, - OutputDeveloperMessageCode code, - const std::string& param, - bool is_debug_mode) { - if (!is_debug_mode || !web_contents) - return; - - const char* pattern; - content::ConsoleMessageLevel severity = content::CONSOLE_MESSAGE_LEVEL_ERROR; - switch (code) { - case kRendererRequestCancel: - pattern = kRendererRequestCancelMessage; - severity = content::CONSOLE_MESSAGE_LEVEL_LOG; - break; - case kManifestEmpty: - pattern = kManifestEmptyMessage; - break; - case kNoManifest: - pattern = kNoManifestMessage; - break; - case kNoIconMatchingRequirements: - pattern = kNoIconMatchingRequirementsMessage; - break; - case kCannotDownloadIcon: - pattern = kCannotDownloadIconMessage; - break; - case kNoMatchingServiceWorker: - pattern = kNoMatchingServiceWorkerMessage; - break; - case kNoIconAvailable: - pattern = kNoIconAvailableMessage; - break; - case kUserNavigatedBeforeBannerShown: - pattern = kUserNavigatedBeforeBannerShownMessage; - severity = content::CONSOLE_MESSAGE_LEVEL_WARNING; - break; - case kStartURLNotValid: - pattern = kStartURLNotValidMessage; - break; - case kManifestDisplayStandaloneFullscreen: - pattern = kManifestDisplayStandaloneFullscreenMessage; - break; - case kManifestMissingNameOrShortName: - pattern = kManifestMissingNameOrShortNameMessage; - break; - case kManifestMissingSuitableIcon: - pattern = kManifestMissingSuitableIconMessage; - break; - case kNotLoadedInMainFrame: - pattern = kNotLoadedInMainFrameMessage; - break; - case kNotServedFromSecureOrigin: - pattern = kNotServedFromSecureOriginMessage; - break; - case kIgnoredNotSupportedOnAndroid: - pattern = kIgnoredNotSupportedOnAndroidMessage; - severity = content::CONSOLE_MESSAGE_LEVEL_WARNING; - break; - case kIgnoredNoId: - pattern = kIgnoredNoIdMessage; - break; - case kIgnoredIdsDoNotMatch: - pattern = kIgnoredIdsDoNotMatchMessage; - break; - default: - NOTREACHED(); - return; - } - std::string message = param.empty() ? - pattern : base::StringPrintf(pattern, param.c_str()); - web_contents->GetMainFrame()->AddMessageToConsole( - severity, "App banner not shown: " + message); - -} - -} // namespace banners
diff --git a/chrome/browser/banners/app_banner_debug_log.h b/chrome/browser/banners/app_banner_debug_log.h deleted file mode 100644 index 2a8d80a..0000000 --- a/chrome/browser/banners/app_banner_debug_log.h +++ /dev/null
@@ -1,53 +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 CHROME_BROWSER_BANNERS_APP_BANNER_DEBUG_LOG_H_ -#define CHROME_BROWSER_BANNERS_APP_BANNER_DEBUG_LOG_H_ - -#include <string> - -namespace content { -class WebContents; -} // namespace content - -namespace banners { - -// Error message strings used to notify developers via the console. - -enum OutputDeveloperMessageCode { - kRendererRequestCancel, - kManifestEmpty, - kNoManifest, - kNoIconMatchingRequirements, - kCannotDownloadIcon, - kNoMatchingServiceWorker, - kNoIconAvailable, - kUserNavigatedBeforeBannerShown, - kStartURLNotValid, - kManifestDisplayStandaloneFullscreen, - kManifestMissingNameOrShortName, - kManifestMissingSuitableIcon, - kNotLoadedInMainFrame, - kNotServedFromSecureOrigin, - kIgnoredNotSupportedOnAndroid, - kIgnoredNoId, - kIgnoredIdsDoNotMatch, -}; - -// Logs a message to the main console if a banner could not be shown -// and the engagement checks have been bypassed. -void OutputDeveloperNotShownMessage(content::WebContents* web_contents, - OutputDeveloperMessageCode code, - bool is_debug_mode); - -// Logs a message to the main console if a banner could not be shown -// and the engagement checks have been bypassed. -void OutputDeveloperNotShownMessage(content::WebContents* web_contents, - OutputDeveloperMessageCode code, - const std::string& param, - bool is_debug_mode); - -} // namespace banners - -#endif // CHROME_BROWSER_BANNERS_APP_BANNER_DEBUG_LOG_H_
diff --git a/chrome/browser/banners/app_banner_infobar_delegate_desktop.cc b/chrome/browser/banners/app_banner_infobar_delegate_desktop.cc index 62f6cf1..8603275 100644 --- a/chrome/browser/banners/app_banner_infobar_delegate_desktop.cc +++ b/chrome/browser/banners/app_banner_infobar_delegate_desktop.cc
@@ -4,13 +4,15 @@ #include "chrome/browser/banners/app_banner_infobar_delegate_desktop.h" +#include "base/bind.h" #include "build/build_config.h" -#include "chrome/browser/banners/app_banner_data_fetcher_desktop.h" +#include "chrome/browser/banners/app_banner_manager.h" #include "chrome/browser/banners/app_banner_metrics.h" #include "chrome/browser/banners/app_banner_settings_helper.h" #include "chrome/browser/extensions/bookmark_app_helper.h" #include "chrome/browser/infobars/infobar_service.h" #include "chrome/common/render_messages.h" +#include "chrome/common/web_application_info.h" #include "chrome/grit/generated_resources.h" #include "components/infobars/core/infobar.h" #include "content/public/browser/render_frame_host.h" @@ -22,14 +24,14 @@ namespace banners { AppBannerInfoBarDelegateDesktop::AppBannerInfoBarDelegateDesktop( - scoped_refptr<AppBannerDataFetcherDesktop> fetcher, - const content::Manifest& web_manifest, + base::WeakPtr<AppBannerManager> weak_manager, extensions::BookmarkAppHelper* bookmark_app_helper, + const content::Manifest& manifest, int event_request_id) : ConfirmInfoBarDelegate(), - fetcher_(fetcher), - web_manifest_(web_manifest), + weak_manager_(weak_manager), bookmark_app_helper_(bookmark_app_helper), + manifest_(manifest), event_request_id_(event_request_id), has_user_interaction_(false) { } @@ -41,17 +43,17 @@ // static infobars::InfoBar* AppBannerInfoBarDelegateDesktop::Create( - scoped_refptr<AppBannerDataFetcherDesktop> fetcher, content::WebContents* web_contents, - const content::Manifest& web_manifest, + base::WeakPtr<AppBannerManager> weak_manager, extensions::BookmarkAppHelper* bookmark_app_helper, + const content::Manifest& manifest, int event_request_id) { InfoBarService* infobar_service = InfoBarService::FromWebContents(web_contents); return infobar_service->AddInfoBar(infobar_service->CreateConfirmInfoBar( std::unique_ptr<ConfirmInfoBarDelegate>( - new AppBannerInfoBarDelegateDesktop( - fetcher, web_manifest, bookmark_app_helper, event_request_id)))); + new AppBannerInfoBarDelegateDesktop(weak_manager, bookmark_app_helper, + manifest, event_request_id)))); } infobars::InfoBarDelegate::Type @@ -89,9 +91,9 @@ has_user_interaction_ = true; bookmark_app_helper_->CreateFromAppBanner( - base::Bind(&AppBannerDataFetcherDesktop::FinishCreateBookmarkApp, - fetcher_), - web_manifest_); + base::Bind(&AppBannerManager::DidFinishCreatingBookmarkApp, + weak_manager_), + manifest_); return true; } @@ -107,16 +109,13 @@ content::WebContents* web_contents = InfoBarService::WebContentsFromInfoBar(infobar()); if (web_contents) { - fetcher_.get()->Cancel(); - web_contents->GetMainFrame()->Send( new ChromeViewMsg_AppBannerDismissed( web_contents->GetMainFrame()->GetRoutingID(), event_request_id_)); AppBannerSettingsHelper::RecordBannerDismissEvent( - web_contents, web_manifest_.start_url.spec(), - AppBannerSettingsHelper::WEB); + web_contents, manifest_.start_url.spec(), AppBannerSettingsHelper::WEB); } }
diff --git a/chrome/browser/banners/app_banner_infobar_delegate_desktop.h b/chrome/browser/banners/app_banner_infobar_delegate_desktop.h index bf4fc21..3891d3d 100644 --- a/chrome/browser/banners/app_banner_infobar_delegate_desktop.h +++ b/chrome/browser/banners/app_banner_infobar_delegate_desktop.h
@@ -5,29 +5,28 @@ #ifndef CHROME_BROWSER_BANNERS_APP_BANNER_INFOBAR_DELEGATE_DESKTOP_H_ #define CHROME_BROWSER_BANNERS_APP_BANNER_INFOBAR_DELEGATE_DESKTOP_H_ -#include <memory> - #include "base/macros.h" +#include "base/memory/weak_ptr.h" #include "base/strings/string16.h" #include "components/infobars/core/confirm_infobar_delegate.h" #include "content/public/common/manifest.h" namespace content { class WebContents; -} // namespace content +} namespace extensions { class BookmarkAppHelper; class Extension; -} // namespace extensions +} namespace infobars { class InfoBar; -} // namespace infobars +} namespace banners { -class AppBannerDataFetcherDesktop; +class AppBannerManager; class AppBannerInfoBarDelegateDesktop : public ConfirmInfoBarDelegate { @@ -35,10 +34,10 @@ ~AppBannerInfoBarDelegateDesktop() override; static infobars::InfoBar* Create( - scoped_refptr<AppBannerDataFetcherDesktop> fetcher, content::WebContents* web_contents, - const content::Manifest& web_manifest, + base::WeakPtr<AppBannerManager> weak_manager, extensions::BookmarkAppHelper* bookmark_app_helper, + const content::Manifest& manifest, int event_request_id); // ConfirmInfoBarDelegate overrides. @@ -54,15 +53,15 @@ protected: AppBannerInfoBarDelegateDesktop( - scoped_refptr<AppBannerDataFetcherDesktop> fetcher, - const content::Manifest& web_manifest, + base::WeakPtr<AppBannerManager> weak_manager, extensions::BookmarkAppHelper* bookmark_app_helper, + const content::Manifest& manifest, int event_request_id); private: - scoped_refptr<AppBannerDataFetcherDesktop> fetcher_; - content::Manifest web_manifest_; + base::WeakPtr<AppBannerManager> weak_manager_; extensions::BookmarkAppHelper* bookmark_app_helper_; + content::Manifest manifest_; int event_request_id_; bool has_user_interaction_;
diff --git a/chrome/browser/banners/app_banner_manager.cc b/chrome/browser/banners/app_banner_manager.cc index 4e8aac3..2757f5cb5 100644 --- a/chrome/browser/banners/app_banner_manager.cc +++ b/chrome/browser/banners/app_banner_manager.cc
@@ -4,75 +4,104 @@ #include "chrome/browser/banners/app_banner_manager.h" -#include "chrome/browser/banners/app_banner_data_fetcher.h" -#include "chrome/browser/banners/app_banner_debug_log.h" +#include "base/bind.h" +#include "base/callback.h" +#include "base/command_line.h" +#include "base/strings/string_number_conversions.h" +#include "base/time/time.h" +#include "chrome/browser/banners/app_banner_metrics.h" #include "chrome/browser/banners/app_banner_settings_helper.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/engagement/site_engagement_service.h" +#include "chrome/browser/installable/installable_logging.h" +#include "chrome/browser/installable/installable_manager.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/render_messages.h" +#include "components/rappor/rappor_utils.h" #include "content/public/browser/navigation_handle.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" -#include "content/public/common/frame_navigate_params.h" #include "content/public/common/origin_util.h" +#include "third_party/WebKit/public/platform/modules/app_banner/WebAppBannerPromptReply.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" namespace { + bool gDisableSecureCheckForTesting = false; +int gCurrentRequestID = -1; +base::LazyInstance<base::TimeDelta> gTimeDeltaForTesting = + LAZY_INSTANCE_INITIALIZER; + +// Returns |size_in_px| in dp, i.e. divided by the current device scale factor. +int ConvertIconSizeFromPxToDp(int size_in_px) { + return size_in_px / + display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor(); +} + +InstallableParams ParamsToGetManifest() { + return InstallableParams(); +} + +// Returns an InstallableParams object that requests all checks necessary for +// a web app banner. +InstallableParams ParamsToPerformInstallableCheck(int ideal_icon_size_in_dp, + int minimum_icon_size_in_dp) { + InstallableParams params; + params.ideal_icon_size_in_dp = ideal_icon_size_in_dp; + params.minimum_icon_size_in_dp = minimum_icon_size_in_dp; + params.check_installable = true; + params.fetch_valid_icon = true; + + return params; +} + } // anonymous namespace namespace banners { +// static void AppBannerManager::DisableSecureSchemeCheckForTesting() { gDisableSecureCheckForTesting = true; } +// static +base::Time AppBannerManager::GetCurrentTime() { + return base::Time::Now() + gTimeDeltaForTesting.Get(); +} + +// static +void AppBannerManager::SetTimeDeltaForTesting(int days) { + gTimeDeltaForTesting.Get() = base::TimeDelta::FromDays(days); +} + +// static void AppBannerManager::SetEngagementWeights(double direct_engagement, double indirect_engagement) { AppBannerSettingsHelper::SetEngagementWeights(direct_engagement, indirect_engagement); } +// static bool AppBannerManager::URLsAreForTheSamePage(const GURL& first, const GURL& second) { return first.GetWithEmptyPath() == second.GetWithEmptyPath() && first.path() == second.path() && first.query() == second.query(); } -AppBannerManager::AppBannerManager(content::WebContents* web_contents) - : content::WebContentsObserver(web_contents), - SiteEngagementObserver(nullptr), - data_fetcher_(nullptr), - banner_request_queued_(false), - load_finished_(false), - weak_factory_(this) { - AppBannerSettingsHelper::UpdateFromFieldTrial(); -} - -AppBannerManager::~AppBannerManager() { - CancelActiveFetcher(); -} - -void AppBannerManager::ReplaceWebContents(content::WebContents* web_contents) { - content::WebContentsObserver::Observe(web_contents); - if (data_fetcher_.get()) - data_fetcher_.get()->ReplaceWebContents(web_contents); -} - -bool AppBannerManager::IsFetcherActive() { - return data_fetcher_ && data_fetcher_->is_active(); -} - void AppBannerManager::RequestAppBanner(const GURL& validated_url, bool is_debug_mode) { content::WebContents* contents = web_contents(); if (contents->GetMainFrame()->GetParent()) { - OutputDeveloperNotShownMessage(contents, kNotLoadedInMainFrame, - is_debug_mode); + ReportError(contents, NOT_IN_MAIN_FRAME); return; } - if (data_fetcher_.get() && data_fetcher_->is_active() && - URLsAreForTheSamePage(data_fetcher_->validated_url(), validated_url) && - !is_debug_mode) { + // Don't start a redundant banner request. + if (is_active_ && + URLsAreForTheSamePage(validated_url, contents->GetLastCommittedURL())) { return; } @@ -80,20 +109,204 @@ // URL is invalid. if (!content::IsOriginSecure(validated_url) && !gDisableSecureCheckForTesting) { - OutputDeveloperNotShownMessage(contents, kNotServedFromSecureOrigin, - is_debug_mode); + ReportError(contents, NOT_FROM_SECURE_ORIGIN); return; } - // Kick off the data retrieval pipeline. - data_fetcher_ = - CreateAppBannerDataFetcher(weak_factory_.GetWeakPtr(), is_debug_mode); - data_fetcher_->Start(validated_url, last_transition_type_); + is_debug_mode_ = is_debug_mode; + is_active_ = true; + + // We start by requesting the manifest from the InstallableManager. The + // default-constructed params will have all other fields as false. + manager_->GetData( + ParamsToGetManifest(), + base::Bind(&AppBannerManager::OnDidGetManifest, GetWeakPtr())); } -void AppBannerManager::DidStartNavigation( - content::NavigationHandle* navigation_handle) { - if (!navigation_handle->IsInMainFrame()) +base::Closure AppBannerManager::FetchWebappSplashScreenImageCallback( + const std::string& webapp_id) { + return base::Closure(); +} + +AppBannerManager::AppBannerManager(content::WebContents* web_contents) + : content::WebContentsObserver(web_contents), + SiteEngagementObserver(nullptr), + manager_(nullptr), + event_request_id_(-1), + is_active_(false), + banner_request_queued_(false), + load_finished_(false), + was_canceled_by_page_(false), + page_requested_prompt_(false), + is_debug_mode_(false), + weak_factory_(this) { + // Ensure the InstallableManager exists since we have a hard dependency on it. + InstallableManager::CreateForWebContents(web_contents); + manager_ = InstallableManager::FromWebContents(web_contents); + DCHECK(manager_); + + AppBannerSettingsHelper::UpdateFromFieldTrial(); +} + +AppBannerManager::~AppBannerManager() { } + +std::string AppBannerManager::GetAppIdentifier() { + DCHECK(!manifest_.IsEmpty()); + return manifest_.start_url.spec(); +} + +std::string AppBannerManager::GetBannerType() { + return "web"; +} + +std::string AppBannerManager::GetErrorParam(InstallableErrorCode code) { + if (code == NO_ACCEPTABLE_ICON || code == MANIFEST_MISSING_SUITABLE_ICON) { + return base::IntToString(InstallableManager::GetMinimumIconSizeInPx()); + } + + return std::string(); +} + +int AppBannerManager::GetIdealIconSizeInDp() { + return ConvertIconSizeFromPxToDp( + InstallableManager::GetMinimumIconSizeInPx()); +} + +int AppBannerManager::GetMinimumIconSizeInDp() { + return ConvertIconSizeFromPxToDp( + InstallableManager::GetMinimumIconSizeInPx()); +} + +base::WeakPtr<AppBannerManager> AppBannerManager::GetWeakPtr() { + return weak_factory_.GetWeakPtr(); +} + +bool AppBannerManager::IsDebugMode() const { + return is_debug_mode_ || + base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kBypassAppBannerEngagementChecks); +} + +bool AppBannerManager::IsWebAppInstalled( + content::BrowserContext* browser_context, + const GURL& start_url) { + return false; +} + +void AppBannerManager::OnDidGetManifest(const InstallableData& data) { + if (data.error_code != NO_ERROR_DETECTED) { + ReportError(web_contents(), data.error_code); + Stop(); + } + + if (!is_active_) + return; + + DCHECK(!data.manifest_url.is_empty()); + DCHECK(!data.manifest.IsEmpty()); + + manifest_url_ = data.manifest_url; + manifest_ = data.manifest; + app_title_ = (manifest_.name.is_null()) ? manifest_.short_name.string() + : manifest_.name.string(); + + PerformInstallableCheck(); +} + +void AppBannerManager::PerformInstallableCheck() { + if (IsWebAppInstalled(web_contents()->GetBrowserContext(), + manifest_.start_url) && + !IsDebugMode()) { + Stop(); + } + + if (!is_active_) + return; + + // Fetch and verify the other required information. + manager_->GetData(ParamsToPerformInstallableCheck(GetIdealIconSizeInDp(), + GetMinimumIconSizeInDp()), + base::Bind(&AppBannerManager::OnDidPerformInstallableCheck, + GetWeakPtr())); +} + +void AppBannerManager::OnDidPerformInstallableCheck( + const InstallableData& data) { + if (data.is_installable) + TrackDisplayEvent(DISPLAY_EVENT_WEB_APP_BANNER_REQUESTED); + + if (data.error_code != NO_ERROR_DETECTED) { + if (data.error_code == NO_MATCHING_SERVICE_WORKER) + TrackDisplayEvent(DISPLAY_EVENT_LACKS_SERVICE_WORKER); + + ReportError(web_contents(), data.error_code); + Stop(); + } + + if (!is_active_) + return; + + DCHECK(data.is_installable); + DCHECK(!data.icon_url.is_empty()); + DCHECK(data.icon); + + icon_url_ = data.icon_url; + icon_.reset(new SkBitmap(*data.icon)); + + SendBannerPromptRequest(); +} + +void AppBannerManager::RecordDidShowBanner(const std::string& event_name) { + content::WebContents* contents = web_contents(); + DCHECK(contents); + + AppBannerSettingsHelper::RecordBannerEvent( + contents, validated_url_, GetAppIdentifier(), + AppBannerSettingsHelper::APP_BANNER_EVENT_DID_SHOW, + GetCurrentTime()); + rappor::SampleDomainAndRegistryFromGURL(g_browser_process->rappor_service(), + event_name, + contents->GetLastCommittedURL()); +} + +void AppBannerManager::ReportError(content::WebContents* web_contents, + InstallableErrorCode code) { + if (IsDebugMode()) + LogErrorToConsole(web_contents, code, GetErrorParam(code)); +} + +void AppBannerManager::Stop() { + if (was_canceled_by_page_ && !page_requested_prompt_) { + TrackBeforeInstallEvent( + BEFORE_INSTALL_EVENT_PROMPT_NOT_CALLED_AFTER_PREVENT_DEFAULT); + } + + is_active_ = false; + was_canceled_by_page_ = false; + page_requested_prompt_ = false; + referrer_.erase(); +} + +void AppBannerManager::SendBannerPromptRequest() { + RecordCouldShowBanner(); + + // Given all of the other checks that have been made, the only possible reason + // for stopping now is that the app has been added to the homescreen. + if (!IsDebugMode() && !CheckIfShouldShowBanner()) + Stop(); + + if (!is_active_) + return; + + TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_CREATED); + event_request_id_ = ++gCurrentRequestID; + content::RenderFrameHost* frame = web_contents()->GetMainFrame(); + frame->Send(new ChromeViewMsg_AppBannerPromptRequest( + frame->GetRoutingID(), event_request_id_, GetBannerType())); +} + +void AppBannerManager::DidStartNavigation(content::NavigationHandle* handle) { + if (!handle->IsInMainFrame()) return; load_finished_ = false; @@ -107,10 +320,13 @@ } } -void AppBannerManager::DidFinishNavigation( - content::NavigationHandle* navigation_handle) { - if (navigation_handle->HasCommitted()) - last_transition_type_ = navigation_handle->GetPageTransition(); +void AppBannerManager::DidFinishNavigation(content::NavigationHandle* handle) { + if (handle->IsInMainFrame() && handle->HasCommitted()) { + last_transition_type_ = handle->GetPageTransition(); + active_media_players_.clear(); + if (is_active_) + Stop(); + } } void AppBannerManager::DidFinishLoad( @@ -121,12 +337,11 @@ return; load_finished_ = true; + validated_url_ = validated_url; if (!AppBannerSettingsHelper::ShouldUseSiteEngagementScore() || banner_request_queued_) { banner_request_queued_ = false; - // The third argument is the is_debug_mode boolean value, which is true only - // when it is triggered by the developer's action in DevTools. RequestAppBanner(validated_url, false /* is_debug_mode */); } } @@ -141,11 +356,8 @@ active_media_players_.end()); } -bool AppBannerManager::HandleNonWebApp(const std::string& platform, - const GURL& url, - const std::string& id, - bool is_debug_mode) { - return false; +void AppBannerManager::WebContentsDestroyed() { + Stop(); } void AppBannerManager::OnEngagementIncreased(content::WebContents* contents, @@ -172,10 +384,99 @@ } } -void AppBannerManager::CancelActiveFetcher() { - if (data_fetcher_) { - data_fetcher_->Cancel(); - data_fetcher_ = nullptr; +void AppBannerManager::RecordCouldShowBanner() { + content::WebContents* contents = web_contents(); + DCHECK(contents); + + AppBannerSettingsHelper::RecordBannerCouldShowEvent( + contents, validated_url_, GetAppIdentifier(), + GetCurrentTime(), last_transition_type_); +} + +bool AppBannerManager::CheckIfShouldShowBanner() { + content::WebContents* contents = web_contents(); + DCHECK(contents); + + return AppBannerSettingsHelper::ShouldShowBanner( + contents, validated_url_, GetAppIdentifier(), GetCurrentTime()); +} + +bool AppBannerManager::OnMessageReceived( + const IPC::Message& message, + content::RenderFrameHost* render_frame_host) { + bool handled = true; + + IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(AppBannerManager, message, render_frame_host) + IPC_MESSAGE_HANDLER(ChromeViewHostMsg_AppBannerPromptReply, + OnBannerPromptReply) + IPC_MESSAGE_HANDLER(ChromeViewHostMsg_RequestShowAppBanner, + OnRequestShowAppBanner) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + + return handled; +} + +void AppBannerManager::OnBannerPromptReply( + content::RenderFrameHost* render_frame_host, + int request_id, + blink::WebAppBannerPromptReply reply, + std::string referrer) { + content::WebContents* contents = web_contents(); + if (request_id != event_request_id_) + return; + + // The renderer might have requested the prompt to be canceled. + // They may request that it is redisplayed later, so don't Stop() here. + // However, log that the cancelation was requested, so Stop() can be + // called if a redisplay isn't asked for. + // + // We use the additional page_requested_prompt_ variable because the redisplay + // request may be received *before* the Cancel prompt reply (e.g. if redisplay + // is requested in the beforeinstallprompt event handler). + referrer_ = referrer; + if (reply == blink::WebAppBannerPromptReply::Cancel && + !page_requested_prompt_) { + TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_PREVENT_DEFAULT_CALLED); + was_canceled_by_page_ = true; + ReportError(contents, RENDERER_CANCELLED); + return; + } + + // If we haven't yet returned, but either of |was_canceled_by_page_| or + // |page_requested_prompt_| is true, the page has requested a delayed showing + // of the prompt. Otherwise, the prompt was never canceled by the page. + if (was_canceled_by_page_ || page_requested_prompt_) { + TrackBeforeInstallEvent( + BEFORE_INSTALL_EVENT_PROMPT_CALLED_AFTER_PREVENT_DEFAULT); + was_canceled_by_page_ = false; + } else { + TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_NO_ACTION); + } + + AppBannerSettingsHelper::RecordMinutesFromFirstVisitToShow( + contents, validated_url_, GetAppIdentifier(), GetCurrentTime()); + + DCHECK(!manifest_url_.is_empty()); + DCHECK(!manifest_.IsEmpty()); + DCHECK(!icon_url_.is_empty()); + DCHECK(icon_.get()); + TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_COMPLETE); + ShowBanner(); + is_active_ = false; +} + +void AppBannerManager::OnRequestShowAppBanner( + content::RenderFrameHost* render_frame_host, + int request_id) { + if (was_canceled_by_page_) { + // Simulate a non-canceled OnBannerPromptReply to show the delayed banner. + // Don't reset |was_canceled_by_page_| yet for metrics purposes. + OnBannerPromptReply(render_frame_host, request_id, + blink::WebAppBannerPromptReply::None, referrer_); + } else { + // Log that the prompt request was made for when we get the prompt reply. + page_requested_prompt_ = true; } }
diff --git a/chrome/browser/banners/app_banner_manager.h b/chrome/browser/banners/app_banner_manager.h index 20969abb..a022de1 100644 --- a/chrome/browser/banners/app_banner_manager.h +++ b/chrome/browser/banners/app_banner_manager.h
@@ -8,105 +8,263 @@ #include <memory> #include <vector> +#include "base/callback_forward.h" #include "base/macros.h" -#include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" -#include "chrome/browser/banners/app_banner_data_fetcher.h" #include "chrome/browser/engagement/site_engagement_observer.h" +#include "chrome/browser/installable/installable_logging.h" +#include "chrome/browser/installable/installable_manager.h" #include "content/public/browser/web_contents_observer.h" #include "third_party/WebKit/public/platform/modules/app_banner/WebAppBannerPromptReply.h" -namespace banners { -class AppBannerDataFetcher; +class SkBitmap; +struct WebApplicationInfo; -/** - * Creates an app banner. - * - * Hooks the wiring together for getting the data for a particular app. - * Monitors at most one app at a time, tracking the info for the most recently - * requested app. Any work in progress for other apps is discarded. - */ +namespace content { +class RenderFrameHost; +class WebContents; +} + +// This forward declaration exists solely for the DidFinishCreatingBookmarkApp +// callback, implemented and called on desktop platforms only. +namespace extensions { +class Extension; +} + +namespace banners { + +// Coordinates the creation of an app banner, from detecting eligibility to +// fetching data and creating the infobar. Sites declare that they want an app +// banner using the web app manifest. One web/native app may occupy the pipeline +// at a time; navigation resets the manager and discards any work in progress. +// +// This class contains the generic functionality shared between all platforms, +// as well as no-op callbacks that the platform-specific implementations pass to +// base::Bind. This allows a WeakPtrFactory to be housed in this class. +// +// The InstallableManager fetches and validate a site's eligibility for banners. +// The manager is first called to fetch the manifest, so we can verify whether +// the site is already installed (and on Android, divert the flow to a +// native app banner if requested). The second call completes the checking for a +// web app banner (checking manifest validity, service worker, and icon). class AppBannerManager : public content::WebContentsObserver, - public AppBannerDataFetcher::Delegate, public SiteEngagementObserver { public: static void DisableSecureSchemeCheckForTesting(); + // Returns the current time. + static base::Time GetCurrentTime(); + + // Fast-forwards the current time for testing. + static void SetTimeDeltaForTesting(int days); + + // Sets the weights applied to direct and indirect navigations for triggering + // the banner. Deprecated and will be removed when app banners fully migrates + // to using site engagement as a trigger. static void SetEngagementWeights(double direct_engagement, double indirect_engagement); // Returns whether or not the URLs match for everything except for the ref. static bool URLsAreForTheSamePage(const GURL& first, const GURL& second); - // Requests an app banner. Set |is_debug_mode| when it is triggered by the - // developer's action in DevTools. + // Requests an app banner. If |is_debug_mode| is true, any failure in the + // pipeline will be reported to the devtools console. virtual void RequestAppBanner(const GURL& validated_url, bool is_debug_mode); - ~AppBannerManager() override; + // Overridden and passed through base::Bind on desktop platforms. Called when + // the bookmark app install initiated by a banner has completed. Not used on + // Android. + virtual void DidFinishCreatingBookmarkApp( + const extensions::Extension* extension, + const WebApplicationInfo& web_app_info) { } + + // Overridden and passed through base::Bind on Android. Called when the + // download of a native app's icon is complete, as native banners use an icon + // provided from the Play Store rather than the web manifest. Not used on + // desktop platforms. + virtual void OnAppIconFetched(const SkBitmap& bitmap) { } + + // Overridden and passed through base::Bind on Android. Called after a web app + // banner was successfully used to add a web app to homescreen to kick off an + // asynchronous fetch of a splash screen icon. Not used on desktop platforms. + virtual base::Closure FetchWebappSplashScreenImageCallback( + const std::string& webapp_id); protected: explicit AppBannerManager(content::WebContents* web_contents); + ~AppBannerManager() override; - void ReplaceWebContents(content::WebContents* web_contents); + // Return a string identifying this app for metrics. + virtual std::string GetAppIdentifier(); - // Creates an AppBannerDataFetcher, which constructs an app banner. - virtual AppBannerDataFetcher* CreateAppBannerDataFetcher( - base::WeakPtr<AppBannerDataFetcher::Delegate> weak_delegate, - bool is_debug_mode) = 0; + // Return a string describing what type of banner is being created. Used when + // alerting websites that a banner is about to be created. + virtual std::string GetBannerType(); - // Return whether the AppBannerDataFetcher is active. - bool IsFetcherActive(); + // Returns a string parameter for a devtools console message corresponding to + // |code|. Returns the empty string if |code| requires no parameter. + std::string GetErrorParam(InstallableErrorCode code); - scoped_refptr<AppBannerDataFetcher> data_fetcher() { return data_fetcher_; } + // Returns the ideal and minimum icon sizes required for being installable. + virtual int GetIdealIconSizeInDp(); + virtual int GetMinimumIconSizeInDp(); - private: - // WebContentsObserver overrides. - void DidStartNavigation( - content::NavigationHandle* navigation_handle) override; - void DidFinishNavigation( - content::NavigationHandle* navigation_handle) override; + // Returns a WeakPtr to this object. Exposed so subclasses/infobars may + // may bind callbacks without needing their own WeakPtrFactory. + base::WeakPtr<AppBannerManager> GetWeakPtr(); + + // Returns true if |is_debug_mode_| is true or the + // kBypassAppBannerEngagementChecks flag is set. + bool IsDebugMode() const; + + // Returns true if the webapp at |start_url| has already been installed. + virtual bool IsWebAppInstalled(content::BrowserContext* browser_context, + const GURL& start_url); + + // Callback invoked by the InstallableManager once it has fetched the page's + // manifest. + void OnDidGetManifest(const InstallableData& result); + + // Run at the conclusion of OnDidGetManifest. For web app banners, this calls + // back to the InstallableManager to continue checking criteria. For native + // app banners, this checks whether native apps are preferred in the manifest, + // and calls to Java to verify native app details. If a native banner isn't or + // can't be requested, it continues with the web app banner checks. + virtual void PerformInstallableCheck(); + + // Callback invoked by the InstallableManager once it has finished checking + // all other installable properties. + void OnDidPerformInstallableCheck(const InstallableData& result); + + // Records that a banner was shown. The |event_name| corresponds to the RAPPOR + // metric being recorded. + void RecordDidShowBanner(const std::string& event_name); + + // Logs an error message corresponding to |code| to the devtools console + // attached to |web_contents|. Does nothing if IsDebugMode() returns false. + void ReportError(content::WebContents* web_contents, + InstallableErrorCode code); + + // Stops the banner pipeline. Any callback currently running will terminate + // the next time they check |is_active_|. + virtual void Stop(); + + // Sends a message to the renderer that the page has met the requirements to + // show a banner. The page can respond to cancel the banner (and possibly + // display it later), or otherwise allow it to be shown. This is virtual to + // allow tests to mock out the renderer IPC. + virtual void SendBannerPromptRequest(); + + // content::WebContentsObserver overrides. + void DidStartNavigation(content::NavigationHandle* handle) override; + void DidFinishNavigation(content::NavigationHandle* handle) override; void DidFinishLoad(content::RenderFrameHost* render_frame_host, const GURL& validated_url) override; void MediaStartedPlaying(const MediaPlayerId& id) override; void MediaStoppedPlaying(const MediaPlayerId& id) override; - - // AppBannerDataFetcher::Delegate overrides. - bool HandleNonWebApp(const std::string& platform, - const GURL& url, - const std::string& id, - bool is_debug_mode) override; + void WebContentsDestroyed() override; // SiteEngagementObserver overrides. void OnEngagementIncreased(content::WebContents* web_contents, const GURL& url, double score) override; - // Cancels an active DataFetcher, stopping its banners from appearing. - void CancelActiveFetcher(); + // Subclass accessors for private fields which should not be changed outside + // this class. + InstallableManager* manager() const { return manager_; } + int event_request_id() const { return event_request_id_; } + bool is_active() const { return is_active_; } + + // The title to display in the banner. + base::string16 app_title_; + + // The URL for which the banner check is being conducted. + GURL validated_url_; + + // The URL of the manifest. + GURL manifest_url_; + + // The manifest object. + content::Manifest manifest_; + + // The URL of the icon. + GURL icon_url_; + + // The icon object. + std::unique_ptr<SkBitmap> icon_; + + // The referrer string (if any) specified in the app URL. Used only for native + // app banners. + std::string referrer_; + + private: + friend class AppBannerManagerTest; + + // Record that the banner could be shown at this point, if the triggering + // heuristic allowed. + void RecordCouldShowBanner(); + + // Creates a banner for the app. Overridden by subclasses as the infobar is + // platform-specific. + virtual void ShowBanner() = 0; + + // Returns true if the banner should be shown. + bool CheckIfShouldShowBanner(); + + bool OnMessageReceived(const IPC::Message& message, + content::RenderFrameHost* render_frame_host) override; + + // Called after the manager sends a message to the renderer regarding its + // intention to show a prompt. The renderer will send a message back with the + // opportunity to cancel. + void OnBannerPromptReply(content::RenderFrameHost* render_frame_host, + int request_id, + blink::WebAppBannerPromptReply reply, + std::string referrer); + + // Called when the client has prevented a banner from being shown, and is + // now requesting that it be shown later. + void OnRequestShowAppBanner(content::RenderFrameHost* render_frame_host, + int request_id); // The type of navigation made to the page ui::PageTransition last_transition_type_; // Fetches the data required to display a banner for the current page. - scoped_refptr<AppBannerDataFetcher> data_fetcher_; + InstallableManager* manager_; + + // A monotonically increasing id to verify the response to the + // beforeinstallprompt event from the renderer. + int event_request_id_; // We do not want to trigger a banner when the manager is attached to // a WebContents that is playing video. Banners triggering on a site in the // background will appear when the tab is reactivated. std::vector<MediaPlayerId> active_media_players_; + // Whether we are currently working on whether to show a banner. + bool is_active_; + // If a banner is requested before the page has finished loading, defer // triggering the pipeline until the load is complete. bool banner_request_queued_; bool load_finished_; - // A weak pointer is used as the lifetime of the ServiceWorkerContext is - // longer than the lifetime of this banner manager. The banner manager - // might be gone when calls sent to the ServiceWorkerContext are completed. + // Record whether the page decides to defer showing the banner, and if it + // requests for it to be shown later on. + bool was_canceled_by_page_; + bool page_requested_prompt_; + + // Whether we should be logging errors to the console for this request. + bool is_debug_mode_; + + // The concrete subclasses of this class are expected to have their lifetimes + // scoped to the WebContents which they are observing. This allows us to use + // weak pointers for callbacks. base::WeakPtrFactory<AppBannerManager> weak_factory_; DISALLOW_COPY_AND_ASSIGN(AppBannerManager); -}; // class AppBannerManager +}; } // namespace banners
diff --git a/chrome/browser/banners/app_banner_manager_browsertest.cc b/chrome/browser/banners/app_banner_manager_browsertest.cc new file mode 100644 index 0000000..c4a174a --- /dev/null +++ b/chrome/browser/banners/app_banner_manager_browsertest.cc
@@ -0,0 +1,353 @@ +// 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 "chrome/browser/banners/app_banner_manager.h" + +#include "base/command_line.h" +#include "base/run_loop.h" +#include "base/single_thread_task_runner.h" +#include "base/task_runner.h" +#include "base/test/histogram_tester.h" +#include "base/threading/thread_task_runner_handle.h" +#include "chrome/browser/banners/app_banner_manager.h" +#include "chrome/browser/banners/app_banner_metrics.h" +#include "chrome/browser/banners/app_banner_settings_helper.h" +#include "chrome/browser/installable/installable_manager.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/ui_test_utils.h" +#include "content/public/common/content_switches.h" +#include "net/test/embedded_test_server/embedded_test_server.h" + +namespace banners { + +// All calls to RequestAppBanner should terminate in one of Stop() (not showing +// banner) or ShowBanner(). This browser test uses this and overrides those two +// methods to capture this information. +class AppBannerManagerTest : public AppBannerManager { + public: + explicit AppBannerManagerTest(content::WebContents* web_contents) + : AppBannerManager(web_contents) {} + ~AppBannerManagerTest() override {} + + bool will_show() { return will_show_.get() && *will_show_; } + + bool is_active() { return AppBannerManager::is_active(); } + + // Set the page transition of each banner request. + void set_page_transition_(ui::PageTransition transition) { + last_transition_type_ = transition; + } + + using AppBannerManager::RequestAppBanner; + void RequestAppBanner(const GURL& validated_url, + bool is_debug_mode, + base::Closure quit_closure) { + will_show_.reset(nullptr); + quit_closure_ = quit_closure; + AppBannerManager::RequestAppBanner(validated_url, is_debug_mode); + } + + protected: + void Stop() override { + AppBannerManager::Stop(); + ASSERT_FALSE(will_show_.get()); + will_show_.reset(new bool(false)); + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure_); + } + + void ShowBanner() override { + ASSERT_FALSE(will_show_.get()); + will_show_.reset(new bool(true)); + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure_); + } + + void DidStartNavigation(content::NavigationHandle* handle) override { + // Do nothing to ensure we never observe the site engagement service. + } + + void DidFinishLoad(content::RenderFrameHost* render_frame_host, + const GURL& validated_url) override { + // Do nothing else to ensure the banner pipeline doesn't start. + validated_url_ = validated_url; + } + + private: + base::Closure quit_closure_; + std::unique_ptr<bool> will_show_; +}; + +class AppBannerManagerBrowserTest : public InProcessBrowserTest { + public: + void SetUpOnMainThread() override { + AppBannerSettingsHelper::SetEngagementWeights(1, 1); + AppBannerSettingsHelper::SetTotalEngagementToTrigger(2); + ASSERT_TRUE(embedded_test_server()->Start()); + InProcessBrowserTest::SetUpOnMainThread(); + } + + void SetUpCommandLine(base::CommandLine* command_line) override { + // Make sure app banners are disabled in the browser, otherwise they will + // interfere with the test. + command_line->AppendSwitch(switches::kDisableAddToShelf); + } + + protected: + void RequestAppBanner(AppBannerManagerTest* manager, + const GURL& url, + base::RunLoop& run_loop, + ui::PageTransition transition, + bool expected_to_show) { + base::HistogramTester histograms; + manager->set_page_transition_(transition); + manager->RequestAppBanner(url, false, run_loop.QuitClosure()); + run_loop.Run(); + + EXPECT_EQ(expected_to_show, manager->will_show()); + ASSERT_FALSE(manager->is_active()); + + // If showing the banner, ensure that the minutes histogram is recorded. + histograms.ExpectTotalCount(banners::kMinutesHistogram, + (manager->will_show() ? 1 : 0)); + } + + void RunBannerTest(const std::string& url, + ui::PageTransition transition, + unsigned int unshown_repetitions, + bool expectation) { + std::string valid_page(url); + GURL test_url = embedded_test_server()->GetURL(valid_page); + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + std::unique_ptr<AppBannerManagerTest> manager( + new AppBannerManagerTest(web_contents)); + + for (unsigned int i = 0; i < unshown_repetitions; ++i) { + ui_test_utils::NavigateToURL(browser(), test_url); + base::RunLoop run_loop; + RequestAppBanner(manager.get(), web_contents->GetLastCommittedURL(), + run_loop, transition, false); + AppBannerManager::SetTimeDeltaForTesting(i + 1); + } + + // On the final loop, check whether the banner triggered or not as expected. + ui_test_utils::NavigateToURL(browser(), test_url); + base::RunLoop run_loop; + RequestAppBanner(manager.get(), web_contents->GetLastCommittedURL(), + run_loop, transition, expectation); + } +}; +IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, WebAppBannerCreatedDirect) { + RunBannerTest("/banners/manifest_test_page.html", ui::PAGE_TRANSITION_TYPED, + 1, true); +} + +IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, + WebAppBannerCreatedDirectLargerTotal) { + AppBannerSettingsHelper::SetTotalEngagementToTrigger(4); + RunBannerTest("/banners/manifest_test_page.html", ui::PAGE_TRANSITION_TYPED, + 3, true); +} + +IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, + WebAppBannerCreatedDirectSmallerTotal) { + AppBannerSettingsHelper::SetTotalEngagementToTrigger(1); + RunBannerTest("/banners/manifest_test_page.html", ui::PAGE_TRANSITION_TYPED, + 0, true); +} + +IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, + WebAppBannerCreatedDirectSingle) { + AppBannerSettingsHelper::SetEngagementWeights(2, 1); + RunBannerTest("/banners/manifest_test_page.html", + ui::PAGE_TRANSITION_GENERATED, 0, true); +} + +IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, + WebAppBannerCreatedDirectMultiple) { + AppBannerSettingsHelper::SetEngagementWeights(0.5, 1); + RunBannerTest("/banners/manifest_test_page.html", + ui::PAGE_TRANSITION_GENERATED, 3, true); +} + +IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, + WebAppBannerCreatedDirectMultipleLargerTotal) { + AppBannerSettingsHelper::SetEngagementWeights(0.5, 1); + AppBannerSettingsHelper::SetTotalEngagementToTrigger(3); + RunBannerTest("/banners/manifest_test_page.html", + ui::PAGE_TRANSITION_GENERATED, 5, true); +} + +IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, + WebAppBannerCreatedDirectMultipleSmallerTotal) { + AppBannerSettingsHelper::SetEngagementWeights(0.5, 1); + AppBannerSettingsHelper::SetTotalEngagementToTrigger(1); + RunBannerTest("/banners/manifest_test_page.html", + ui::PAGE_TRANSITION_GENERATED, 1, true); +} + +IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, + WebAppBannerCreatedIndirect) { + RunBannerTest("/banners/manifest_test_page.html", ui::PAGE_TRANSITION_LINK, 1, + true); +} + +IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, + WebAppBannerCreatedIndirectLargerTotal) { + AppBannerSettingsHelper::SetTotalEngagementToTrigger(5); + RunBannerTest("/banners/manifest_test_page.html", ui::PAGE_TRANSITION_LINK, 4, + true); +} + +IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, + WebAppBannerCreatedIndirectSmallerTotal) { + AppBannerSettingsHelper::SetTotalEngagementToTrigger(1); + RunBannerTest("/banners/manifest_test_page.html", ui::PAGE_TRANSITION_LINK, 0, + true); +} + +IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, + WebAppBannerCreatedIndirectSingle) { + AppBannerSettingsHelper::SetEngagementWeights(1, 3); + RunBannerTest("/banners/manifest_test_page.html", ui::PAGE_TRANSITION_RELOAD, + 0, true); +} + +IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, + WebAppBannerCreatedIndirectMultiple) { + AppBannerSettingsHelper::SetEngagementWeights(1, 0.5); + RunBannerTest("/banners/manifest_test_page.html", ui::PAGE_TRANSITION_LINK, 3, + true); +} + +IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, + WebAppBannerCreatedIndirectMultipleLargerTotal) { + AppBannerSettingsHelper::SetEngagementWeights(1, 0.5); + AppBannerSettingsHelper::SetTotalEngagementToTrigger(4); + RunBannerTest("/banners/manifest_test_page.html", ui::PAGE_TRANSITION_LINK, 7, + true); +} + +IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, + WebAppBannerCreatedVarious) { + AppBannerSettingsHelper::SetEngagementWeights(0.5, 0.25); + + std::string valid_page("/banners/manifest_test_page.html"); + GURL test_url = embedded_test_server()->GetURL(valid_page); + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + + std::unique_ptr<AppBannerManagerTest> manager( + new AppBannerManagerTest(web_contents)); + + // Add a direct nav on day 1. + { + base::RunLoop run_loop; + ui_test_utils::NavigateToURL(browser(), test_url); + RequestAppBanner(manager.get(), web_contents->GetLastCommittedURL(), + run_loop, ui::PAGE_TRANSITION_TYPED, false); + } + + // Add an indirect nav on day 1 which is ignored. + { + base::RunLoop run_loop; + ui_test_utils::NavigateToURL(browser(), test_url); + RequestAppBanner(manager.get(), web_contents->GetLastCommittedURL(), + run_loop, ui::PAGE_TRANSITION_LINK, false); + AppBannerManager::SetTimeDeltaForTesting(1); + } + + // Add an indirect nav on day 2. + { + base::RunLoop run_loop; + ui_test_utils::NavigateToURL(browser(), test_url); + RequestAppBanner(manager.get(), web_contents->GetLastCommittedURL(), + run_loop, ui::PAGE_TRANSITION_MANUAL_SUBFRAME, false); + } + + // Add a direct nav on day 2 which overrides. + { + base::RunLoop run_loop; + ui_test_utils::NavigateToURL(browser(), test_url); + RequestAppBanner(manager.get(), web_contents->GetLastCommittedURL(), + run_loop, ui::PAGE_TRANSITION_GENERATED, false); + AppBannerManager::SetTimeDeltaForTesting(2); + } + + // Add a direct nav on day 3. + { + base::RunLoop run_loop; + ui_test_utils::NavigateToURL(browser(), test_url); + RequestAppBanner(manager.get(), web_contents->GetLastCommittedURL(), + run_loop, ui::PAGE_TRANSITION_GENERATED, false); + AppBannerManager::SetTimeDeltaForTesting(3); + } + + // Add an indirect nav on day 4. + { + base::RunLoop run_loop; + ui_test_utils::NavigateToURL(browser(), test_url); + RequestAppBanner(manager.get(), web_contents->GetLastCommittedURL(), + run_loop, ui::PAGE_TRANSITION_FORM_SUBMIT, false); + } + // Add a direct nav on day 4 which should trigger the banner. + { + base::RunLoop run_loop; + ui_test_utils::NavigateToURL(browser(), test_url); + RequestAppBanner(manager.get(), web_contents->GetLastCommittedURL(), + run_loop, ui::PAGE_TRANSITION_TYPED, true); + } +} + +IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, + WebAppBannerNoTypeInManifest) { + RunBannerTest("/banners/manifest_no_type_test_page.html", + ui::PAGE_TRANSITION_TYPED, 1, true); +} + +IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, + WebAppBannerNoTypeInManifestCapsExtension) { + RunBannerTest("/banners/manifest_no_type_caps_test_page.html", + ui::PAGE_TRANSITION_TYPED, 1, true); +} + +IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, NoManifest) { + RunBannerTest("/banners/no_manifest_test_page.html", + ui::PAGE_TRANSITION_TYPED, 1, false); +} + +IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, MissingManifest) { + RunBannerTest("/banners/manifest_bad_link.html", ui::PAGE_TRANSITION_TYPED, 1, + false); +} + +IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, CancelBannerDirect) { + RunBannerTest("/banners/cancel_test_page.html", ui::PAGE_TRANSITION_TYPED, 1, + false); +} + +IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, CancelBannerIndirect) { + AppBannerSettingsHelper::SetEngagementWeights(1, 0.5); + RunBannerTest("/banners/cancel_test_page.html", ui::PAGE_TRANSITION_TYPED, 3, + false); +} + +IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, PromptBanner) { + RunBannerTest("/banners/prompt_test_page.html", ui::PAGE_TRANSITION_TYPED, 1, + true); +} + +IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, PromptBannerInHandler) { + RunBannerTest("/banners/prompt_in_handler_test_page.html", + ui::PAGE_TRANSITION_TYPED, 1, true); +} + +IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, WebAppBannerInIFrame) { + RunBannerTest("/banners/iframe_test_page.html", ui::PAGE_TRANSITION_TYPED, 1, + false); +} + +} // namespace banners
diff --git a/chrome/browser/banners/app_banner_manager_desktop.cc b/chrome/browser/banners/app_banner_manager_desktop.cc index 01b8e80f..bab306a 100644 --- a/chrome/browser/banners/app_banner_manager_desktop.cc +++ b/chrome/browser/banners/app_banner_manager_desktop.cc
@@ -5,17 +5,19 @@ #include "chrome/browser/banners/app_banner_manager_desktop.h" #include "base/command_line.h" +#include "base/strings/string_number_conversions.h" #include "build/build_config.h" -#include "chrome/browser/banners/app_banner_data_fetcher_desktop.h" +#include "chrome/browser/banners/app_banner_infobar_delegate_desktop.h" +#include "chrome/browser/banners/app_banner_metrics.h" +#include "chrome/browser/banners/app_banner_settings_helper.h" +#include "chrome/browser/extensions/bookmark_app_helper.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/common/chrome_switches.h" +#include "chrome/common/render_messages.h" +#include "chrome/common/web_application_info.h" +#include "content/public/browser/render_frame_host.h" #include "extensions/common/constants.h" -namespace { -// TODO(dominickn) Identify the best minimum icon size to guarantee the best -// user experience. -int kMinimumIconSize = extension_misc::EXTENSION_ICON_LARGE; -} // anonymous namespace - DEFINE_WEB_CONTENTS_USER_DATA_KEY(banners::AppBannerManagerDesktop); namespace banners { @@ -30,17 +32,87 @@ #endif } -AppBannerDataFetcher* AppBannerManagerDesktop::CreateAppBannerDataFetcher( - base::WeakPtr<AppBannerDataFetcher::Delegate> weak_delegate, - bool is_debug_mode) { - return new AppBannerDataFetcherDesktop(web_contents(), weak_delegate, - kMinimumIconSize, kMinimumIconSize, - is_debug_mode); -} - AppBannerManagerDesktop::AppBannerManagerDesktop( content::WebContents* web_contents) - : AppBannerManager(web_contents) { + : AppBannerManager(web_contents) { } + +AppBannerManagerDesktop::~AppBannerManagerDesktop() { } + +void AppBannerManagerDesktop::DidFinishCreatingBookmarkApp( + const extensions::Extension* extension, + const WebApplicationInfo& web_app_info) { + content::WebContents* contents = web_contents(); + if (contents) { + // A null extension pointer indicates that the bookmark app install was + // not successful. + if (extension == nullptr) { + contents->GetMainFrame()->Send(new ChromeViewMsg_AppBannerDismissed( + contents->GetMainFrame()->GetRoutingID(), event_request_id())); + + AppBannerSettingsHelper::RecordBannerDismissEvent( + contents, GetAppIdentifier(), AppBannerSettingsHelper::WEB); + } else { + contents->GetMainFrame()->Send(new ChromeViewMsg_AppBannerAccepted( + contents->GetMainFrame()->GetRoutingID(), event_request_id(), + GetBannerType())); + + AppBannerSettingsHelper::RecordBannerInstallEvent( + contents, GetAppIdentifier(), AppBannerSettingsHelper::WEB); + } + } +} + +bool AppBannerManagerDesktop::IsWebAppInstalled( + content::BrowserContext* browser_context, + const GURL& start_url) { + return extensions::BookmarkAppHelper::BookmarkOrHostedAppInstalled( + browser_context, start_url); +} + +void AppBannerManagerDesktop::ShowBanner() { + content::WebContents* contents = web_contents(); + DCHECK(contents && !manifest_.IsEmpty()); + + Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext()); + WebApplicationInfo web_app_info; + + bookmark_app_helper_.reset( + new extensions::BookmarkAppHelper(profile, web_app_info, contents)); + + // This differs from Android, where there is a concrete + // AppBannerInfoBarAndroid class to interface with Java, and the manager calls + // the InfoBarService to show the banner. On desktop, an InfoBar class + // is not required, and the delegate calls the InfoBarService. + infobars::InfoBar* infobar = AppBannerInfoBarDelegateDesktop::Create( + contents, GetWeakPtr(), bookmark_app_helper_.get(), manifest_, + event_request_id()); + if (infobar) { + RecordDidShowBanner("AppBanner.WebApp.Shown"); + TrackDisplayEvent(DISPLAY_EVENT_WEB_APP_BANNER_CREATED); + } +} + +void AppBannerManagerDesktop::DidFinishLoad( + content::RenderFrameHost* render_frame_host, + const GURL& validated_url) { + // Explicitly forbid banners from triggering on navigation unless this is + // enabled. + if (!IsEnabled()) + return; + + AppBannerManager::DidFinishLoad(render_frame_host, validated_url); +} + +void AppBannerManagerDesktop::OnEngagementIncreased( + content::WebContents* web_contents, + const GURL& url, + double score) { + // Explicitly forbid banners from triggering on navigation unless this is + // enabled. + if (!IsEnabled()) + return; + + AppBannerManager::OnEngagementIncreased(web_contents, url, score); } } // namespace banners
diff --git a/chrome/browser/banners/app_banner_manager_desktop.h b/chrome/browser/banners/app_banner_manager_desktop.h index c45a821..1ee201c 100644 --- a/chrome/browser/banners/app_banner_manager_desktop.h +++ b/chrome/browser/banners/app_banner_manager_desktop.h
@@ -10,24 +10,44 @@ #include "base/macros.h" #include "content/public/browser/web_contents_user_data.h" +namespace extensions { +class BookmarkAppHelper; +} + namespace banners { +// Manages web app banners for desktop platforms. class AppBannerManagerDesktop : public AppBannerManager, public content::WebContentsUserData<AppBannerManagerDesktop> { - public: static bool IsEnabled(); - protected: - AppBannerDataFetcher* CreateAppBannerDataFetcher( - base::WeakPtr<AppBannerDataFetcher::Delegate> weak_delegate, - bool is_debug_mode) override; - private: - explicit AppBannerManagerDesktop(content::WebContents* web_contents); friend class content::WebContentsUserData<AppBannerManagerDesktop>; + explicit AppBannerManagerDesktop(content::WebContents* web_contents); + ~AppBannerManagerDesktop() override; + + // AppBannerManager overrides. + void DidFinishCreatingBookmarkApp( + const extensions::Extension* extension, + const WebApplicationInfo& web_app_info) override; + bool IsWebAppInstalled(content::BrowserContext* browser_context, + const GURL& start_url) override; + void ShowBanner() override; + + // content::WebContentsObserver override. + void DidFinishLoad(content::RenderFrameHost* render_frame_host, + const GURL& validated_url) override; + + // SiteEngagementObserver override. + void OnEngagementIncreased(content::WebContents* web_contents, + const GURL& url, + double score) override; + + std::unique_ptr<extensions::BookmarkAppHelper> bookmark_app_helper_; + DISALLOW_COPY_AND_ASSIGN(AppBannerManagerDesktop); };
diff --git a/chrome/browser/banners/app_banner_manager_emulation.cc b/chrome/browser/banners/app_banner_manager_emulation.cc deleted file mode 100644 index 1fb27f4..0000000 --- a/chrome/browser/banners/app_banner_manager_emulation.cc +++ /dev/null
@@ -1,47 +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 "chrome/browser/banners/app_banner_manager_emulation.h" - -#include "base/command_line.h" -#include "build/build_config.h" -#include "chrome/browser/banners/app_banner_data_fetcher_desktop.h" -#include "ui/display/display.h" -#include "ui/display/screen.h" - -namespace { - -// We need to provide web developers with the guidance on the minimum icon -// size they should list in the manifest. Since the size depends on the -// device, we pick the baseline being a Nexus 5X-alike device. -// We make it clear in the 'add to home screen' emulation UI that the -// size does not correspond to the currently emulated device, but rather is -// a generic baseline. -const int kMinimumIconSize = 144; - -} // anonymous namespace - -DEFINE_WEB_CONTENTS_USER_DATA_KEY(banners::AppBannerManagerEmulation); - -namespace banners { - -AppBannerDataFetcher* AppBannerManagerEmulation::CreateAppBannerDataFetcher( - base::WeakPtr<AppBannerDataFetcher::Delegate> weak_delegate, - bool is_debug_mode) { - - // Divide by the current screen density as the data fetcher will multiply - // it back in when trying to fetch an appropriate icon - int size = kMinimumIconSize / display::Screen::GetScreen()-> - GetPrimaryDisplay().device_scale_factor(); - - return new AppBannerDataFetcherDesktop(web_contents(), weak_delegate, - size, size, is_debug_mode); -} - -AppBannerManagerEmulation::AppBannerManagerEmulation( - content::WebContents* web_contents) - : AppBannerManager(web_contents) { -} - -} // namespace banners
diff --git a/chrome/browser/banners/app_banner_manager_emulation.h b/chrome/browser/banners/app_banner_manager_emulation.h deleted file mode 100644 index da272f02..0000000 --- a/chrome/browser/banners/app_banner_manager_emulation.h +++ /dev/null
@@ -1,33 +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 CHROME_BROWSER_BANNERS_APP_BANNER_MANAGER_EMULATION_H_ -#define CHROME_BROWSER_BANNERS_APP_BANNER_MANAGER_EMULATION_H_ - -#include "chrome/browser/banners/app_banner_manager.h" - -#include "base/macros.h" -#include "content/public/browser/web_contents_user_data.h" - -namespace banners { - -class AppBannerManagerEmulation - : public AppBannerManager, - public content::WebContentsUserData<AppBannerManagerEmulation> { - - protected: - AppBannerDataFetcher* CreateAppBannerDataFetcher( - base::WeakPtr<AppBannerDataFetcher::Delegate> weak_delegate, - bool is_debug_mode) override; - - private: - explicit AppBannerManagerEmulation(content::WebContents* web_contents); - friend class content::WebContentsUserData<AppBannerManagerEmulation>; - - DISALLOW_COPY_AND_ASSIGN(AppBannerManagerEmulation); -}; - -} // namespace banners - -#endif // CHROME_BROWSER_BANNERS_APP_BANNER_MANAGER_EMULATION_H_
diff --git a/chrome/browser/banners/app_banner_settings_helper.cc b/chrome/browser/banners/app_banner_settings_helper.cc index 820ad3a..ad25487 100644 --- a/chrome/browser/banners/app_banner_settings_helper.cc +++ b/chrome/browser/banners/app_banner_settings_helper.cc
@@ -15,7 +15,7 @@ #include "base/metrics/field_trial.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" -#include "chrome/browser/banners/app_banner_data_fetcher.h" +#include "chrome/browser/banners/app_banner_manager.h" #include "chrome/browser/banners/app_banner_metrics.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" @@ -220,7 +220,7 @@ AppBannerSettingsHelper::RecordBannerEvent( web_contents, web_contents->GetURL(), package_name_or_start_url, AppBannerSettingsHelper::APP_BANNER_EVENT_DID_ADD_TO_HOMESCREEN, - banners::AppBannerDataFetcher::GetCurrentTime()); + banners::AppBannerManager::GetCurrentTime()); rappor::SampleDomainAndRegistryFromGURL( g_browser_process->rappor_service(), @@ -238,7 +238,7 @@ AppBannerSettingsHelper::RecordBannerEvent( web_contents, web_contents->GetURL(), package_name_or_start_url, AppBannerSettingsHelper::APP_BANNER_EVENT_DID_BLOCK, - banners::AppBannerDataFetcher::GetCurrentTime()); + banners::AppBannerManager::GetCurrentTime()); rappor::SampleDomainAndRegistryFromGURL( g_browser_process->rappor_service(),
diff --git a/chrome/browser/browser_process.h b/chrome/browser/browser_process.h index 28a55ae..cf3a3a96 100644 --- a/chrome/browser/browser_process.h +++ b/chrome/browser/browser_process.h
@@ -201,7 +201,10 @@ virtual IntranetRedirectDetector* intranet_redirect_detector() = 0; - // Returns the locale used by the application. + // Returns the locale used by the application. It is the IETF language tag, + // defined in BCP 47. The region subtag is not included when it adds no + // distinguishing information to the language tag (e.g. both "en-US" and "fr" + // are correct here). virtual const std::string& GetApplicationLocale() = 0; virtual void SetApplicationLocale(const std::string& locale) = 0;
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd index 794861f..4e3f92b 100644 --- a/chrome/browser/browser_resources.grd +++ b/chrome/browser/browser_resources.grd
@@ -299,6 +299,7 @@ <include name="IDR_OMNIBOX_CSS" file="resources\omnibox\omnibox.css" type="BINDATA" /> <include name="IDR_OMNIBOX_JS" file="resources\omnibox\omnibox.js" type="BINDATA" /> <include name="IDR_OMNIBOX_MOJO_JS" file="${root_gen_dir}\chrome\browser\ui\webui\omnibox\omnibox.mojom.js" use_base_dir="false" type="BINDATA"/> + <include name="IDR_ORIGIN_MOJO_JS" file="${root_gen_dir}\url\mojo\origin.mojom.js" use_base_dir="false" type="BINDATA"/> <if expr="enable_plugins"> <include name="IDR_PLUGINS_HTML" file="resources\plugins.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" /> <include name="IDR_PLUGINS_JS" file="resources\plugins.js" type="BINDATA" /> @@ -371,6 +372,10 @@ <include name="IDR_UBER_FRAME_HTML" file="resources\uber\uber_frame.html" flattenhtml="true" type="BINDATA" /> <include name="IDR_UBER_FRAME_JS" file="resources\uber\uber_frame.js" flattenhtml="true" type="BINDATA" /> <include name="IDR_UBER_UTILS_JS" file="resources\uber\uber_utils.js" type="BINDATA" /> + <include name="IDR_USB_INTERNALS_CSS" file="resources\usb_internals\usb_internals.css" type="BINDATA" /> + <include name="IDR_USB_INTERNALS_HTML" file="resources\usb_internals\usb_internals.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" /> + <include name="IDR_USB_INTERNALS_JS" file="resources\usb_internals\usb_internals.js" type="BINDATA" /> + <include name="IDR_USB_INTERNALS_MOJO_JS" file="${root_gen_dir}\chrome\browser\ui\webui\usb_internals\usb_internals.mojom.js" use_base_dir="false" type="BINDATA"/> <include name="IDR_USER_ACTIONS_HTML" file="resources\user_actions\user_actions.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" /> <include name="IDR_USER_ACTIONS_CSS" file="resources\user_actions\user_actions.css" type="BINDATA" /> <include name="IDR_USER_ACTIONS_JS" file="resources\user_actions\user_actions.js" type="BINDATA" />
diff --git a/chrome/browser/browsing_data/browsing_data_remover.cc b/chrome/browser/browsing_data/browsing_data_remover.cc index 4b4325239..cf73ad4c 100644 --- a/chrome/browser/browsing_data/browsing_data_remover.cc +++ b/chrome/browser/browsing_data/browsing_data_remover.cc
@@ -32,6 +32,7 @@ #include "chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.h" #include "chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings_factory.h" #include "chrome/browser/password_manager/password_store_factory.h" +#include "chrome/browser/permissions/permission_decision_auto_blocker.h" #include "chrome/browser/prerender/prerender_manager.h" #include "chrome/browser/prerender/prerender_manager_factory.h" #include "chrome/browser/profiles/profile.h" @@ -798,6 +799,8 @@ HostContentSettingsMapFactory::GetForProfile(profile_), CONTENT_SETTINGS_TYPE_APP_BANNER, base::Bind(&ForwardPrimaryPatternCallback, same_pattern_filter)); + + PermissionDecisionAutoBlocker::RemoveCountsByUrl(profile_, filter); } if (remove_mask & REMOVE_PASSWORDS) {
diff --git a/chrome/browser/browsing_data/browsing_data_remover_unittest.cc b/chrome/browser/browsing_data/browsing_data_remover_unittest.cc index 3fa5213..3364e1d 100644 --- a/chrome/browser/browsing_data/browsing_data_remover_unittest.cc +++ b/chrome/browser/browsing_data/browsing_data_remover_unittest.cc
@@ -41,6 +41,7 @@ #include "chrome/browser/favicon/favicon_service_factory.h" #include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/password_manager/password_store_factory.h" +#include "chrome/browser/permissions/permission_decision_auto_blocker.h" #include "chrome/browser/safe_browsing/safe_browsing_service.h" #include "chrome/common/pref_names.h" #include "chrome/test/base/testing_browser_process.h" @@ -72,6 +73,7 @@ #include "content/public/browser/cookie_store_factory.h" #include "content/public/browser/dom_storage_context.h" #include "content/public/browser/local_storage_usage_info.h" +#include "content/public/browser/permission_type.h" #include "content/public/browser/storage_partition.h" #include "content/public/test/mock_download_manager.h" #include "content/public/test/test_browser_thread.h" @@ -1021,6 +1023,36 @@ DISALLOW_COPY_AND_ASSIGN(RemovePasswordsTester); }; +class RemovePermissionPromptCountsTest { + public: + explicit RemovePermissionPromptCountsTest(TestingProfile* profile) + : blocker_(new PermissionDecisionAutoBlocker(profile)) {} + + int GetDismissCount(const GURL& url, content::PermissionType permission) { + return blocker_->GetActionCountForTest(url, permission, + PermissionDecisionAutoBlocker::kPromptDismissCountKey); + } + + int GetIgnoreCount(const GURL& url, content::PermissionType permission) { + return blocker_->GetActionCountForTest(url, permission, + PermissionDecisionAutoBlocker::kPromptIgnoreCountKey); + } + + int RecordIgnore(const GURL& url, content::PermissionType permission) { + return blocker_->RecordIgnore(url, permission); + } + + bool ShouldChangeDismissalToBlock(const GURL& url, + content::PermissionType permission) { + return blocker_->ShouldChangeDismissalToBlock(url, permission); + } + + private: + std::unique_ptr<PermissionDecisionAutoBlocker> blocker_; + + DISALLOW_COPY_AND_ASSIGN(RemovePermissionPromptCountsTest); +}; + // Test Class ---------------------------------------------------------------- class BrowsingDataRemoverTest : public testing::Test { @@ -2599,6 +2631,112 @@ host_settings[0].primary_pattern); } +TEST_F(BrowsingDataRemoverTest, ClearPermissionPromptCounts) { + RemovePermissionPromptCountsTest tester(GetProfile()); + + RegistrableDomainFilterBuilder filter_builder_1( + RegistrableDomainFilterBuilder::WHITELIST); + filter_builder_1.AddRegisterableDomain(kTestRegisterableDomain1); + + RegistrableDomainFilterBuilder filter_builder_2( + RegistrableDomainFilterBuilder::BLACKLIST); + filter_builder_2.AddRegisterableDomain(kTestRegisterableDomain1); + + { + // Test REMOVE_HISTORY. + EXPECT_EQ(1, tester.RecordIgnore(kOrigin1, + content::PermissionType::GEOLOCATION)); + EXPECT_EQ(2, tester.RecordIgnore(kOrigin1, + content::PermissionType::GEOLOCATION)); + EXPECT_EQ(1, tester.RecordIgnore(kOrigin1, + content::PermissionType::NOTIFICATIONS)); + tester.ShouldChangeDismissalToBlock(kOrigin1, + content::PermissionType::MIDI_SYSEX); + EXPECT_EQ(1, tester.RecordIgnore(kOrigin2, + content::PermissionType::DURABLE_STORAGE)); + tester.ShouldChangeDismissalToBlock(kOrigin2, + content::PermissionType::NOTIFICATIONS); + + BlockUntilOriginDataRemoved(browsing_data::LAST_HOUR, + BrowsingDataRemover::REMOVE_SITE_USAGE_DATA, + filter_builder_1); + + // kOrigin1 should be gone, but kOrigin2 remains. + EXPECT_EQ(0, tester.GetIgnoreCount(kOrigin1, + content::PermissionType::GEOLOCATION)); + EXPECT_EQ(0, tester.GetIgnoreCount(kOrigin1, + content::PermissionType::NOTIFICATIONS)); + EXPECT_EQ(0, tester.GetDismissCount(kOrigin1, + content::PermissionType::MIDI_SYSEX)); + EXPECT_EQ(1, tester.GetIgnoreCount( + kOrigin2, content::PermissionType::DURABLE_STORAGE)); + EXPECT_EQ(1, tester.GetDismissCount( + kOrigin2, content::PermissionType::NOTIFICATIONS)); + + BlockUntilBrowsingDataRemoved(browsing_data::LAST_HOUR, + BrowsingDataRemover::REMOVE_HISTORY, false); + + // Everything should be gone. + EXPECT_EQ(0, tester.GetIgnoreCount(kOrigin1, + content::PermissionType::GEOLOCATION)); + EXPECT_EQ(0, tester.GetIgnoreCount(kOrigin1, + content::PermissionType::NOTIFICATIONS)); + EXPECT_EQ(0, tester.GetDismissCount(kOrigin1, + content::PermissionType::MIDI_SYSEX)); + EXPECT_EQ(0, tester.GetIgnoreCount( + kOrigin2, content::PermissionType::DURABLE_STORAGE)); + EXPECT_EQ(0, tester.GetDismissCount( + kOrigin2, content::PermissionType::NOTIFICATIONS)); + } + { + // Test REMOVE_SITE_DATA. + EXPECT_EQ(1, tester.RecordIgnore(kOrigin1, + content::PermissionType::GEOLOCATION)); + EXPECT_EQ(2, tester.RecordIgnore(kOrigin1, + content::PermissionType::GEOLOCATION)); + EXPECT_EQ(1, tester.RecordIgnore(kOrigin1, + content::PermissionType::NOTIFICATIONS)); + tester.ShouldChangeDismissalToBlock(kOrigin1, + content::PermissionType::MIDI_SYSEX); + EXPECT_EQ(1, tester.RecordIgnore(kOrigin2, + content::PermissionType::DURABLE_STORAGE)); + tester.ShouldChangeDismissalToBlock(kOrigin2, + content::PermissionType::NOTIFICATIONS); + + BlockUntilOriginDataRemoved(browsing_data::LAST_HOUR, + BrowsingDataRemover::REMOVE_SITE_USAGE_DATA, + filter_builder_2); + + // kOrigin2 should be gone, but kOrigin1 remains. + EXPECT_EQ(2, tester.GetIgnoreCount(kOrigin1, + content::PermissionType::GEOLOCATION)); + EXPECT_EQ(1, tester.GetIgnoreCount(kOrigin1, + content::PermissionType::NOTIFICATIONS)); + EXPECT_EQ(1, tester.GetDismissCount(kOrigin1, + content::PermissionType::MIDI_SYSEX)); + EXPECT_EQ(0, tester.GetIgnoreCount( + kOrigin2, content::PermissionType::DURABLE_STORAGE)); + EXPECT_EQ(0, tester.GetDismissCount( + kOrigin2, content::PermissionType::NOTIFICATIONS)); + + BlockUntilBrowsingDataRemoved(browsing_data::LAST_HOUR, + BrowsingDataRemover::REMOVE_SITE_USAGE_DATA, + false); + + // Everything should be gone. + EXPECT_EQ(0, tester.GetIgnoreCount(kOrigin1, + content::PermissionType::GEOLOCATION)); + EXPECT_EQ(0, tester.GetIgnoreCount(kOrigin1, + content::PermissionType::NOTIFICATIONS)); + EXPECT_EQ(0, tester.GetDismissCount(kOrigin1, + content::PermissionType::MIDI_SYSEX)); + EXPECT_EQ(0, tester.GetIgnoreCount( + kOrigin2, content::PermissionType::DURABLE_STORAGE)); + EXPECT_EQ(0, tester.GetDismissCount( + kOrigin2, content::PermissionType::NOTIFICATIONS)); + } +} + class MultipleTasksObserver { public: // A simple implementation of BrowsingDataRemover::Observer.
diff --git a/chrome/browser/budget_service/budget.proto b/chrome/browser/budget_service/budget.proto index a2145538..e0c76e1 100644 --- a/chrome/browser/budget_service/budget.proto +++ b/chrome/browser/budget_service/budget.proto
@@ -9,14 +9,10 @@ // Chrome requires this. option optimize_for = LITE_RUNTIME; -// Next available id: 3 +// Next available id: 2 message Budget { - // How much budget the origin needs to accumulate before it will be allowed to - // perform another budget action. - optional double debt = 1; - // The sequence of budget chunks and their expiration times. - repeated BudgetChunk budget = 2; + repeated BudgetChunk budget = 1; } // Next available id: 3 @@ -24,7 +20,7 @@ // The amount of budget remaining in this chunk. optional double amount = 1; - // The timestamp when the budget expires. Format is double to integrate with - // Site Engagement and Blink and is the number of seconds since Jan 1, 1970. - optional double expiration = 2; + // The timestamp when the budget expires. This stores the internal value + // needed to construct a base::Time object. + optional int64 expiration = 2; }
diff --git a/chrome/browser/budget_service/budget_database.cc b/chrome/browser/budget_service/budget_database.cc index 587ed44..aaada96 100644 --- a/chrome/browser/budget_service/budget_database.cc +++ b/chrome/browser/budget_service/budget_database.cc
@@ -47,7 +47,7 @@ DCHECK_EQ(origin.GetOrigin(), origin); // If this origin is already in the cache, immediately return the data. - if (budget_map_.find(origin.spec()) != budget_map_.end()) { + if (IsCached(origin)) { BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(&BudgetDatabase::DidGetBudget, weak_ptr_factory_.GetWeakPtr(), origin, @@ -69,56 +69,23 @@ const StoreBudgetCallback& callback) { DCHECK_EQ(origin.GetOrigin(), origin); - // Look up the origin in our cache. Adding budget without first querying the - // existing budget is not suported. - DCHECK_GT(budget_map_.count(origin.spec()), 0U); - + // Add a new chunk of budget for the origin at the default expiration time. base::Time expiration = clock_->Now() + base::TimeDelta::FromHours(kBudgetDurationInHours); - budget_map_[origin.spec()].second.push_back( - std::make_pair(amount, expiration.ToInternalValue())); + budget_map_[origin.spec()].emplace_back(amount, expiration); // Now that the cache is updated, write the data to the database. WriteCachedValuesToDatabase(origin, callback); } -void BudgetDatabase::WriteCachedValuesToDatabase( - const GURL& origin, - const StoreBudgetCallback& callback) { - // Create the data structures that are passed to the ProtoDatabase. - std::unique_ptr< - leveldb_proto::ProtoDatabase<budget_service::Budget>::KeyEntryVector> - entries(new leveldb_proto::ProtoDatabase< - budget_service::Budget>::KeyEntryVector()); - std::unique_ptr<std::vector<std::string>> keys_to_remove( - new std::vector<std::string>()); - - // Each operation can either update the existing budget or remove the origin's - // budget information. - if (budget_map_.find(origin.spec()) == budget_map_.end()) { - // If the origin doesn't exist in the cache, this is a remove operation. - keys_to_remove->push_back(origin.spec()); - } else { - // Build the Budget proto object. - budget_service::Budget budget; - const BudgetInfo& info = budget_map_[origin.spec()]; - budget.set_debt(info.first); - for (const auto& chunk : info.second) { - budget_service::BudgetChunk* budget_chunk = budget.add_budget(); - budget_chunk->set_amount(chunk.first); - budget_chunk->set_expiration(chunk.second); - } - entries->push_back(std::make_pair(origin.spec(), budget)); - } - - // Send the updates to the database. - db_->UpdateEntries(std::move(entries), std::move(keys_to_remove), callback); -} - void BudgetDatabase::OnDatabaseInit(bool success) { // TODO(harkness): Consider caching the budget database now? } +bool BudgetDatabase::IsCached(const GURL& origin) const { + return budget_map_.find(origin.spec()) != budget_map_.end(); +} + void BudgetDatabase::AddToCache( const GURL& origin, const AddToCacheCallback& callback, @@ -133,12 +100,12 @@ // Add the data to the cache, converting from the proto format to an STL // format which is better for removing things from the list. BudgetChunks chunks; - for (const auto& chunk : budget_proto->budget()) - chunks.push_back(std::make_pair(chunk.amount(), chunk.expiration())); + for (const auto& chunk : budget_proto->budget()) { + chunks.emplace_back(chunk.amount(), + base::Time::FromInternalValue(chunk.expiration())); + } - DCHECK(budget_proto->has_debt()); - budget_map_[origin.spec()] = - std::make_pair(budget_proto->debt(), std::move(chunks)); + budget_map_[origin.spec()] = std::move(chunks); callback.Run(success); } @@ -149,32 +116,89 @@ // If the database wasn't able to read the information, return the // failure and an empty BudgetExpectation. if (!success) { - callback.Run(success, 0, BudgetExpectation()); + callback.Run(success, BudgetExpectation()); return; } - // Otherwise, build up the BudgetExpection. This is different from the format + // First, cleanup any expired budget chunks for the origin. + CleanupExpiredBudget(origin); + + // Now, build up the BudgetExpection. This is different from the format // in which the cache stores the data. The cache stores chunks of budget and // when that budget expires. The BudgetExpectation describes a set of times // and the budget at those times. - const BudgetInfo& info = budget_map_[origin.spec()]; BudgetExpectation expectation; double total = 0; - // Starting with the chunks that expire the farthest in the future, build up - // the budget expectations for those future times. - for (const auto& chunk : base::Reversed(info.second)) { - expectation.push_front(std::make_pair(total, chunk.second)); - total += chunk.first; + if (IsCached(origin)) { + // Starting with the chunks that expire the farthest in the future, build up + // the budget expectations for those future times. + const BudgetChunks& chunks = budget_map_[origin.spec()]; + for (const auto& chunk : base::Reversed(chunks)) { + expectation.emplace_front(total, chunk.expiration); + total += chunk.amount; + } } - // Always add one entry at the front of the list for the total budget right - // now. - expectation.push_front(std::make_pair(total, 0)); + // Always add one entry at the front of the list for the total budget now. + expectation.emplace_front(total, clock_->Now()); - callback.Run(true /* success */, info.first, expectation); + callback.Run(true /* success */, expectation); } void BudgetDatabase::SetClockForTesting(std::unique_ptr<base::Clock> clock) { clock_ = std::move(clock); } + +void BudgetDatabase::WriteCachedValuesToDatabase( + const GURL& origin, + const StoreBudgetCallback& callback) { + // First, cleanup any expired budget chunks for the origin. + CleanupExpiredBudget(origin); + + // Create the data structures that are passed to the ProtoDatabase. + std::unique_ptr< + leveldb_proto::ProtoDatabase<budget_service::Budget>::KeyEntryVector> + entries(new leveldb_proto::ProtoDatabase< + budget_service::Budget>::KeyEntryVector()); + std::unique_ptr<std::vector<std::string>> keys_to_remove( + new std::vector<std::string>()); + + // Each operation can either update the existing budget or remove the origin's + // budget information. + if (IsCached(origin)) { + // Build the Budget proto object. + budget_service::Budget budget; + const BudgetChunks& chunks = budget_map_[origin.spec()]; + for (const auto& chunk : chunks) { + budget_service::BudgetChunk* budget_chunk = budget.add_budget(); + budget_chunk->set_amount(chunk.amount); + budget_chunk->set_expiration(chunk.expiration.ToInternalValue()); + } + entries->push_back(std::make_pair(origin.spec(), budget)); + } else { + // If the origin doesn't exist in the cache, this is a remove operation. + keys_to_remove->push_back(origin.spec()); + } + + // Send the updates to the database. + db_->UpdateEntries(std::move(entries), std::move(keys_to_remove), callback); +} + +void BudgetDatabase::CleanupExpiredBudget(const GURL& origin) { + if (!IsCached(origin)) + return; + + base::Time now = clock_->Now(); + + BudgetChunks& chunks = budget_map_[origin.spec()]; + auto cleanup_iter = chunks.begin(); + + // This relies on the list of chunks being in timestamp order. + while (cleanup_iter != chunks.end() && cleanup_iter->expiration <= now) + cleanup_iter = chunks.erase(cleanup_iter); + + // If the entire budget is empty now, cleanup the map. + if (chunks.empty()) + budget_map_.erase(origin.spec()); +}
diff --git a/chrome/browser/budget_service/budget_database.h b/chrome/browser/budget_service/budget_database.h index 0e70b34..6583fb4 100644 --- a/chrome/browser/budget_service/budget_database.h +++ b/chrome/browser/budget_service/budget_database.h
@@ -18,6 +18,7 @@ namespace base { class Clock; class SequencedTaskRunner; +class Time; } namespace budget_service { @@ -30,15 +31,28 @@ // assigned to an origin. The class uses an underlying LevelDB. class BudgetDatabase { public: + // Data structure to hold information about the cumulative amount of budget + // at a particular point in time in the future. The budget described by a + // BudgetStatus represents the budget from zero or more BudgetChunk objects. + struct BudgetStatus { + BudgetStatus(double budget_at, base::Time time) + : budget_at(budget_at), time(time) {} + BudgetStatus(const BudgetStatus& other) + : budget_at(other.budget_at), time(other.time) {} + + double budget_at; + base::Time time; + }; + // Data structure for returing the budget decay expectations to the caller. - using BudgetExpectation = std::list<std::pair<double, double>>; + using BudgetExpectation = std::list<BudgetStatus>; // Callback for setting a budget value. using StoreBudgetCallback = base::Callback<void(bool success)>; // Callback for getting a list of all budget chunks. - using GetBudgetDetailsCallback = base::Callback< - void(bool success, double debt, const BudgetExpectation& expectation)>; + using GetBudgetDetailsCallback = + base::Callback<void(bool success, const BudgetExpectation& expectation)>; // The database_dir specifies the location of the budget information on // disk. The task_runner is used by the ProtoDatabase to handle all blocking @@ -47,15 +61,15 @@ const scoped_refptr<base::SequencedTaskRunner>& task_runner); ~BudgetDatabase(); - // Get the full budget expectation for the origin. This will return any - // debt as well as a sequence of time points and the expected budget at - // those times. + // Get the full budget expectation for the origin. This will return a + // sequence of time points and the expected budget at those times. void GetBudgetDetails(const GURL& origin, const GetBudgetDetailsCallback& callback); // Add budget for an origin. The caller specifies the amount, and the method // adds the amount to the cache with the correct expiration. Callback is - // invoked only after the newly cached value is written to storage. + // invoked only after the newly cached value is written to storage. This + // should only be called after the budget has been read from the database. void AddBudget(const GURL& origin, double amount, const StoreBudgetCallback& callback); @@ -66,14 +80,27 @@ // Used to allow tests to change time for testing. void SetClockForTesting(std::unique_ptr<base::Clock> clock); + // Holds information about individual pieces of awarded budget. There is a + // one-to-one mapping of these to the chunks in the underlying database. + struct BudgetChunk { + BudgetChunk(double amount, base::Time expiration) + : amount(amount), expiration(expiration) {} + BudgetChunk(const BudgetChunk& other) + : amount(other.amount), expiration(other.expiration) {} + + double amount; + base::Time expiration; + }; + // Data structure for caching budget information. - using BudgetChunks = std::vector<std::pair<double, double>>; - using BudgetInfo = std::pair<double, BudgetChunks>; + using BudgetChunks = std::vector<BudgetChunk>; using AddToCacheCallback = base::Callback<void(bool success)>; void OnDatabaseInit(bool success); + bool IsCached(const GURL& origin) const; + void AddToCache(const GURL& origin, const AddToCacheCallback& callback, bool success, @@ -86,11 +113,13 @@ void WriteCachedValuesToDatabase(const GURL& origin, const StoreBudgetCallback& callback); + void CleanupExpiredBudget(const GURL& origin); + // The database for storing budget information. std::unique_ptr<leveldb_proto::ProtoDatabase<budget_service::Budget>> db_; // Cached data for the origins which have been loaded. - std::unordered_map<std::string, BudgetInfo> budget_map_; + std::unordered_map<std::string, BudgetChunks> budget_map_; // The clock used to vend times. std::unique_ptr<base::Clock> clock_;
diff --git a/chrome/browser/budget_service/budget_database_unittest.cc b/chrome/browser/budget_service/budget_database_unittest.cc index f10a2ba..a8b7930 100644 --- a/chrome/browser/budget_service/budget_database_unittest.cc +++ b/chrome/browser/budget_service/budget_database_unittest.cc
@@ -54,10 +54,8 @@ void GetBudgetDetailsComplete( base::Closure run_loop_closure, bool success, - double debt, const BudgetDatabase::BudgetExpectation& expectation) { success_ = success; - debt_ = debt; expectation_ = expectation; run_loop_closure.Run(); } @@ -84,6 +82,9 @@ return clock; } + // Query the database to check if the origin is in the cache. + bool IsCached(const GURL& origin) { return db_.IsCached(origin); } + protected: bool success_; @@ -92,7 +93,6 @@ std::unique_ptr<budget_service::Budget> budget_; TestingProfile profile_; BudgetDatabase db_; - double debt_ = 0; BudgetDatabase::BudgetExpectation expectation_; }; @@ -101,6 +101,7 @@ base::SimpleTestClock* clock = SetClockForTesting(); base::TimeDelta expiration( base::TimeDelta::FromHours(kDefaultExpirationInHours)); + base::Time starting_time = clock->Now(); base::Time expiration_time = clock->Now() + expiration; // Add two budget chunks with different expirations (default expiration and @@ -121,19 +122,43 @@ auto iter = expected_value.begin(); // First value should be [total_budget, now] - EXPECT_EQ(kDefaultBudget1 + kDefaultBudget2, iter->first); - // TODO(harkness): This will be "now" in the final version. For now, it's - // just 0. - EXPECT_EQ(0, iter->second); + EXPECT_EQ(kDefaultBudget1 + kDefaultBudget2, iter->budget_at); + EXPECT_EQ(clock->Now(), iter->time); // The next value should be the budget after the first chunk expires. iter++; - EXPECT_EQ(kDefaultBudget2, iter->first); - EXPECT_EQ(expiration_time.ToInternalValue(), iter->second); + EXPECT_EQ(kDefaultBudget2, iter->budget_at); + EXPECT_EQ(expiration_time, iter->time); // The final value gives the budget of 0.0 after the second chunk expires. expiration_time += base::TimeDelta::FromDays(1); iter++; - EXPECT_EQ(0, iter->first); - EXPECT_EQ(expiration_time.ToInternalValue(), iter->second); + EXPECT_EQ(0, iter->budget_at); + EXPECT_EQ(expiration_time, iter->time); + + // Advance the time until the first chunk of budget should be expired. + clock->SetNow(starting_time + + base::TimeDelta::FromHours(kDefaultExpirationInHours)); + + // Get the new budget and check that kDefaultBudget1 has been removed. + GetBudgetDetails(); + iter = expectation().begin(); + ASSERT_EQ(2U, expectation().size()); + EXPECT_EQ(kDefaultBudget2, iter->budget_at); + iter++; + EXPECT_EQ(0, iter->budget_at); + + // Advace the time until both chunks of budget should be expired. + clock->SetNow(starting_time + + base::TimeDelta::FromHours(kDefaultExpirationInHours) + + base::TimeDelta::FromDays(1)); + + GetBudgetDetails(); + iter = expectation().begin(); + ASSERT_EQ(1U, expectation().size()); + EXPECT_EQ(0, iter->budget_at); + + // Now that the entire budget has expired, check that the entry in the map + // has been removed. + EXPECT_FALSE(IsCached(origin)); }
diff --git a/chrome/browser/chrome_browser_field_trials_desktop.cc b/chrome/browser/chrome_browser_field_trials_desktop.cc index d5ee04e..b955ed8 100644 --- a/chrome/browser/chrome_browser_field_trials_desktop.cc +++ b/chrome/browser/chrome_browser_field_trials_desktop.cc
@@ -26,13 +26,6 @@ "StabilityDebugging", base::FEATURE_DISABLED_BY_DEFAULT }; -void SetupLightSpeedTrials() { - if (!variations::GetVariationParamValue("LightSpeed", "NoGpu").empty()) { - base::CommandLine::ForCurrentProcess()->AppendSwitch( - switches::kDisableGpu); - } -} - void SetupStunProbeTrial() { #if defined(ENABLE_WEBRTC) std::map<std::string, std::string> params; @@ -80,7 +73,6 @@ void SetupDesktopFieldTrials(const base::CommandLine& parsed_command_line) { prerender::ConfigurePrerender(parsed_command_line); - SetupLightSpeedTrials(); SetupStunProbeTrial(); SetupStabilityDebugging(); }
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc index 7dfd3bd..262d91c 100644 --- a/chrome/browser/chrome_browser_main.cc +++ b/chrome/browser/chrome_browser_main.cc
@@ -7,6 +7,8 @@ #include <stddef.h> #include <stdint.h> +#include <algorithm> +#include <map> #include <set> #include <string> #include <utility> @@ -21,6 +23,7 @@ #include "base/feature_list.h" #include "base/files/file_path.h" #include "base/files/file_util.h" +#include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/metrics/field_trial.h" #include "base/metrics/histogram_macros.h" @@ -33,6 +36,10 @@ #include "base/strings/sys_string_conversions.h" #include "base/strings/utf_string_conversions.h" #include "base/sys_info.h" +#include "base/task_scheduler/scheduler_worker_pool_params.h" +#include "base/task_scheduler/switches.h" +#include "base/task_scheduler/task_scheduler.h" +#include "base/task_scheduler/task_traits.h" #include "base/threading/platform_thread.h" #include "base/time/default_tick_clock.h" #include "base/time/time.h" @@ -317,6 +324,136 @@ } #endif // !defined(OS_ANDROID) && !defined(OS_CHROMEOS) +enum WorkerPoolType : size_t { + BACKGROUND_WORKER_POOL = 0, + BACKGROUND_FILE_IO_WORKER_POOL, + FOREGROUND_WORKER_POOL, + FOREGROUND_FILE_IO_WORKER_POOL, + WORKER_POOL_COUNT // Always last. +}; + +struct WorkerPoolVariationValues { + int threads = 0; + base::TimeDelta detach_period; +}; + +// Converts |pool_descriptor| to a WorkerPoolVariationValues. Returns a default +// WorkerPoolVariationValues on failure. +// +// |pool_descriptor| is a semi-colon separated value string with the following +// items: +// 1. Minimum Thread Count (int) +// 2. Maximum Thread Count (int) +// 3. Thread Count Multiplier (double) +// 4. Thread Count Offset (int) +// 5. Detach Time in Milliseconds (milliseconds) +// Additional values may appear as necessary and will be ignored. +WorkerPoolVariationValues StringToWorkerPoolVariationValues( + const base::StringPiece pool_descriptor) { + const std::vector<std::string> tokens = + SplitString(pool_descriptor, ";", + base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); + int minimum; + int maximum; + double multiplier; + int offset; + int detach_milliseconds; + // Checking for a size greater than the expected amount allows us to be + // forward compatible if we add more variation values. + if (tokens.size() >= 5 && + base::StringToInt(tokens[0], &minimum) && + base::StringToInt(tokens[1], &maximum) && + base::StringToDouble(tokens[2], &multiplier) && + base::StringToInt(tokens[3], &offset) && + base::StringToInt(tokens[4], &detach_milliseconds)) { + const int num_of_cores = base::SysInfo::NumberOfProcessors(); + const int threads = std::ceil<int>(num_of_cores * multiplier) + offset; + WorkerPoolVariationValues values; + values.threads = std::min(maximum, std::max(minimum, threads)); + values.detach_period = + base::TimeDelta::FromMilliseconds(detach_milliseconds); + return values; + } + DLOG(ERROR) << "Invalid Worker Pool Descriptor: " << pool_descriptor; + return WorkerPoolVariationValues(); +} + +// Returns the worker pool index for |traits| defaulting to +// FOREGROUND_WORKER_POOL or FOREGROUND_FILE_IO_WORKER_POOL on unknown +// priorities. +size_t WorkerPoolIndexForTraits(const base::TaskTraits& traits) { + const bool is_background = + traits.priority() == base::TaskPriority::BACKGROUND; + if (traits.with_file_io()) { + return is_background ? BACKGROUND_FILE_IO_WORKER_POOL + : FOREGROUND_FILE_IO_WORKER_POOL; + } + return is_background ? BACKGROUND_WORKER_POOL : FOREGROUND_WORKER_POOL; +} + +// Initializes the Default Browser Task Scheduler if there is a valid variation +// parameter for the field trial. +void MaybeInitializeTaskScheduler() { + static constexpr char kFieldTrialName[] = "BrowserScheduler"; + std::map<std::string, std::string> variation_params; + if (!variations::GetVariationParams(kFieldTrialName, &variation_params)) { + DCHECK(!base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableBrowserTaskScheduler)) + << "The Browser Task Scheduler remains disabled with " + << switches::kEnableBrowserTaskScheduler + << " because there is no available variation param for this build or " + " the task scheduler is disabled in chrome://flags."; + return; + } + + using ThreadPriority = base::ThreadPriority; + using IORestriction = base::SchedulerWorkerPoolParams::IORestriction; + struct SchedulerWorkerPoolPredefinedParams { + const char* name; + ThreadPriority priority_hint; + IORestriction io_restriction; + }; + static const SchedulerWorkerPoolPredefinedParams kAllPredefinedParams[] = { + {"Background", ThreadPriority::BACKGROUND, IORestriction::DISALLOWED}, + {"BackgroundFileIO", ThreadPriority::BACKGROUND, IORestriction::ALLOWED}, + {"Foreground", ThreadPriority::NORMAL, IORestriction::DISALLOWED}, + {"ForegroundFileIO", ThreadPriority::NORMAL, IORestriction::ALLOWED}, + }; + static_assert(arraysize(kAllPredefinedParams) == WORKER_POOL_COUNT, + "Mismatched Worker Pool Types and Predefined Parameters"); + + std::vector<base::SchedulerWorkerPoolParams> params_vector; + for (const auto& predefined_params : kAllPredefinedParams) { + const auto pair = variation_params.find(predefined_params.name); + if (pair == variation_params.end()) { + DLOG(ERROR) << "Missing Worker Pool Configuration: " + << predefined_params.name; + return; + } + + const WorkerPoolVariationValues variation_values = + StringToWorkerPoolVariationValues(pair->second); + + if (variation_values.threads <= 0 || + variation_values.detach_period.is_zero()) { + DLOG(ERROR) << "Invalid Worker Pool Configuration: " << + predefined_params.name << " [" << pair->second << "]"; + return; + } + + params_vector.emplace_back(predefined_params.name, + predefined_params.priority_hint, + predefined_params.io_restriction, + variation_values.threads, + variation_values.detach_period); + } + + DCHECK_EQ(WORKER_POOL_COUNT, params_vector.size()); + + base::TaskScheduler::CreateAndSetDefaultTaskScheduler( + params_vector, base::Bind(WorkerPoolIndexForTraits)); +} + // Returns the new local state object, guaranteed non-NULL. // |local_state_task_runner| must be a shutdown-blocking task runner. PrefService* InitializeLocalState( @@ -1210,6 +1347,8 @@ // IOThread's initialization which happens in BrowserProcess:PreCreateThreads. SetupMetricsAndFieldTrials(); + MaybeInitializeTaskScheduler(); + // ChromeOS needs ResourceBundle::InitSharedInstance to be called before this. browser_process_->PreCreateThreads();
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 43b30a4..a868c5e 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -83,6 +83,7 @@ #include "chrome/browser/sync_file_system/local/sync_file_system_backend.h" #include "chrome/browser/tab_contents/tab_util.h" #include "chrome/browser/tracing/chrome_tracing_delegate.h" +#include "chrome/browser/translate/chrome_translate_client.h" #include "chrome/browser/ui/blocked_content/blocked_window_params.h" #include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h" #include "chrome/browser/ui/browser_navigator.h" @@ -188,6 +189,7 @@ #elif defined(OS_MACOSX) #include "chrome/browser/chrome_browser_main_mac.h" #elif defined(OS_CHROMEOS) +#include "chrome/browser/chromeos/arc/arc_auth_service.h" #include "chrome/browser/chromeos/arc/arc_navigation_throttle.h" #include "chrome/browser/chromeos/attestation/platform_verification_impl.h" #include "chrome/browser/chromeos/chrome_browser_main_chromeos.h" @@ -737,13 +739,6 @@ .compare("Disabled"); } -#if defined(OS_CHROMEOS) -bool IsIntentPickerEnabled() { - return base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableIntentPicker); -} -#endif - } // namespace ChromeContentBrowserClient::ChromeContentBrowserClient() @@ -1136,18 +1131,6 @@ #endif } -bool ChromeContentBrowserClient::IsIllegalOrigin( - content::ResourceContext* resource_context, - int child_process_id, - const GURL& origin) { -#if defined(ENABLE_EXTENSIONS) - return ChromeContentBrowserClientExtensionsPart::IsIllegalOrigin( - resource_context, child_process_id, origin); -#else - return false; -#endif -} - bool ChromeContentBrowserClient::ShouldAllowOpenURL( content::SiteInstance* site_instance, const GURL& url) { GURL from_url = site_instance->GetSiteURL(); @@ -2282,6 +2265,9 @@ void ChromeContentBrowserClient::ResourceDispatcherHostCreated() { DCHECK_CURRENTLY_ON(BrowserThread::UI); + for (size_t i = 0; i < extra_parts_.size(); ++i) + extra_parts_[i]->ResourceDispatcherHostCreated(); + return g_browser_process->ResourceDispatcherHostCreated(); } @@ -2834,11 +2820,14 @@ base::Bind(&CreateWebUsbChooserService, render_frame_host)); } - // Register mojo CredentialManager service only for main frame. if (!render_frame_host->GetParent()) { + // Register mojo CredentialManager interface only for main frame. registry->AddInterface( base::Bind(&ChromePasswordManagerClient::BindCredentialManager, render_frame_host)); + // Register mojo ContentTranslateDriver interface only for main frame. + registry->AddInterface(base::Bind( + &ChromeTranslateClient::BindContentTranslateDriver, render_frame_host)); } registry->AddInterface( @@ -2961,7 +2950,8 @@ // TODO(djacobo): Support incognito mode by showing an aditional dialog as a // warning that the selected app is not in incognito mode. - if (IsIntentPickerEnabled() && + const arc::ArcAuthService* auth_service = arc::ArcAuthService::Get(); + if (auth_service && auth_service->IsArcEnabled() && !handle->GetWebContents()->GetBrowserContext()->IsOffTheRecord()) { prerender::PrerenderContents* prerender_contents = prerender::PrerenderContents::FromWebContents(
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h index fc5b98eb..5d294cf 100644 --- a/chrome/browser/chrome_content_browser_client.h +++ b/chrome/browser/chrome_content_browser_client.h
@@ -87,9 +87,6 @@ bool IsHandledURL(const GURL& url) override; bool CanCommitURL(content::RenderProcessHost* process_host, const GURL& url) override; - bool IsIllegalOrigin(content::ResourceContext* resource_context, - int child_process_id, - const GURL& origin) override; bool ShouldAllowOpenURL(content::SiteInstance* site_instance, const GURL& url) override; void OverrideOpenURLParams(content::SiteInstance* site_instance,
diff --git a/chrome/browser/chrome_content_browser_client_parts.h b/chrome/browser/chrome_content_browser_client_parts.h index 046327e..cf55561 100644 --- a/chrome/browser/chrome_content_browser_client_parts.h +++ b/chrome/browser/chrome_content_browser_client_parts.h
@@ -60,6 +60,9 @@ base::CommandLine* command_line, content::RenderProcessHost* process, Profile* profile) {} + + // Called when the ResourceDispatcherHost is created. + virtual void ResourceDispatcherHostCreated() {} }; #endif // CHROME_BROWSER_CHROME_CONTENT_BROWSER_CLIENT_PARTS_H_
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index a4bfb97..6f23ba9 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -43,7 +43,7 @@ "//ash", "//ash:ash_with_content", "//ash/public/interfaces", - "//ash/sysui/public/interfaces", + "//ash/public/interfaces", "//build/linux:fontconfig", "//chrome/browser/devtools", "//chrome/browser/extensions",
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.cc b/chrome/browser/chromeos/accessibility/accessibility_manager.cc index 30f50be..8dee3337 100644 --- a/chrome/browser/chromeos/accessibility/accessibility_manager.cc +++ b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
@@ -227,9 +227,7 @@ render_view_host->GetRoutingID(), done_cb); } - - extension_service->component_loader()->AddComponentFromDir( - GetChromeVoxPath(), extension_misc::kChromeVoxExtensionId, done_cb); + extension_service->component_loader()->AddChromeVoxExtension(done_cb); } void InjectChromeVoxContentScript(
diff --git a/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc b/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc index 8c9d98d..cc3dcb5a 100644 --- a/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc +++ b/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc
@@ -295,13 +295,9 @@ ::testing::Values(kTestAsNormalUser, kTestAsGuestUser)); -// TODO(crbug.com/630031): Flaky on ASan LSan bot. -#if defined(ADDRESS_SANITIZER) -#define MAYBE_EnableSpokenFeedback DISABLED_EnableSpokenFeedback -#else -#define MAYBE_EnableSpokenFeedback EnableSpokenFeedback -#endif // defined(ADDRESS_SANITIZER) -IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, MAYBE_EnableSpokenFeedback) { +// TODO(tommi): Flakily hitting HasOneRef DCHECK in +// AudioOutputResampler::Shutdown, see crbug.com/630031. +IN_PROC_BROWSER_TEST_P(SpokenFeedbackTest, DISABLED_EnableSpokenFeedback) { EnableChromeVox(); }
diff --git a/chrome/browser/chromeos/arc/arc_auth_service.cc b/chrome/browser/chromeos/arc/arc_auth_service.cc index 105058e7..aa330059 100644 --- a/chrome/browser/chromeos/arc/arc_auth_service.cc +++ b/chrome/browser/chromeos/arc/arc_auth_service.cc
@@ -153,9 +153,9 @@ // static void ArcAuthService::RegisterProfilePrefs( user_prefs::PrefRegistrySyncable* registry) { - registry->RegisterBooleanPref( - prefs::kArcEnabled, false, - user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); + // TODO(dspaid): Implement a mechanism to allow this to sync on first boot + // only. + registry->RegisterBooleanPref(prefs::kArcEnabled, false); registry->RegisterBooleanPref(prefs::kArcSignedIn, false); registry->RegisterBooleanPref(prefs::kArcBackupRestoreEnabled, true); registry->RegisterBooleanPref(prefs::kArcLocationServiceEnabled, true); @@ -519,6 +519,9 @@ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK(profile_); + // TODO(dspaid): Move code from OnSyncedPrefChanged into this method. + OnSyncedPrefChanged(prefs::kArcEnabled, IsArcManaged()); + const bool arc_enabled = IsArcEnabled(); FOR_EACH_OBSERVER(Observer, observer_list_, OnOptInEnabled(arc_enabled));
diff --git a/chrome/browser/chromeos/chrome_interface_factory.cc b/chrome/browser/chromeos/chrome_interface_factory.cc index 344d404..bd79722 100644 --- a/chrome/browser/chromeos/chrome_interface_factory.cc +++ b/chrome/browser/chromeos/chrome_interface_factory.cc
@@ -6,7 +6,7 @@ #include <memory> -#include "ash/sysui/public/interfaces/wallpaper.mojom.h" +#include "ash/public/interfaces/wallpaper.mojom.h" #include "base/lazy_instance.h" #include "base/memory/weak_ptr.h" #include "base/threading/thread_checker.h" @@ -113,7 +113,7 @@ launchable_->ProcessRequest(std::move(request)); } - void BindRequest(ash::sysui::mojom::WallpaperManagerRequest request) { + void BindRequest(ash::mojom::WallpaperManagerRequest request) { if (!wallpaper_manager_) wallpaper_manager_.reset(new ChromeWallpaperManager); wallpaper_manager_->ProcessRequest(std::move(request)); @@ -156,7 +156,7 @@ main_thread_task_runner_); FactoryImpl::AddFactory<mash::mojom::Launchable>(registry, main_thread_task_runner_); - FactoryImpl::AddFactory<ash::sysui::mojom::WallpaperManager>( + FactoryImpl::AddFactory<ash::mojom::WallpaperManager>( registry, main_thread_task_runner_); FactoryImpl::AddFactory<app_list::mojom::AppListPresenter>( registry, main_thread_task_runner_);
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc index 44b02c8..7a8ec39 100644 --- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc +++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
@@ -12,9 +12,10 @@ #include "ash/common/ash_constants.h" #include "ash/common/ash_switches.h" #include "ash/desktop_background/desktop_background_controller.h" +#include "ash/public/interfaces/wallpaper.mojom.h" #include "ash/shell.h" -#include "ash/sysui/public/interfaces/wallpaper.mojom.h" #include "base/bind.h" +#include "base/bind_helpers.h" #include "base/command_line.h" #include "base/files/file_enumerator.h" #include "base/files/file_path.h" @@ -170,6 +171,16 @@ return wallpaper::WallpaperFilesId::FromString(result); } +// Returns true if HashWallpaperFilesIdStr will not assert(). +bool CanGetFilesId() { + return SystemSaltGetter::Get()->GetRawSalt(); +} + +// Call |closure| when HashWallpaperFilesIdStr will not assert(). +void CallWhenCanGetFilesId(const base::Closure& closure) { + SystemSaltGetter::Get()->AddOnSystemSaltReady(closure); +} + void SetKnownUserWallpaperFilesId( const AccountId& account_id, const wallpaper::WallpaperFilesId& wallpaper_files_id) { @@ -177,23 +188,23 @@ wallpaper_files_id.id()); } -ash::sysui::mojom::WallpaperLayout WallpaperLayoutToMojo( +ash::mojom::WallpaperLayout WallpaperLayoutToMojo( wallpaper::WallpaperLayout layout) { switch (layout) { case wallpaper::WALLPAPER_LAYOUT_CENTER: - return ash::sysui::mojom::WallpaperLayout::CENTER; + return ash::mojom::WallpaperLayout::CENTER; case wallpaper::WALLPAPER_LAYOUT_CENTER_CROPPED: - return ash::sysui::mojom::WallpaperLayout::CENTER_CROPPED; + return ash::mojom::WallpaperLayout::CENTER_CROPPED; case wallpaper::WALLPAPER_LAYOUT_STRETCH: - return ash::sysui::mojom::WallpaperLayout::STRETCH; + return ash::mojom::WallpaperLayout::STRETCH; case wallpaper::WALLPAPER_LAYOUT_TILE: - return ash::sysui::mojom::WallpaperLayout::TILE; + return ash::mojom::WallpaperLayout::TILE; case wallpaper::NUM_WALLPAPER_LAYOUT: NOTREACHED(); - return ash::sysui::mojom::WallpaperLayout::CENTER; + return ash::mojom::WallpaperLayout::CENTER; } NOTREACHED(); - return ash::sysui::mojom::WallpaperLayout::CENTER; + return ash::mojom::WallpaperLayout::CENTER; } // A helper to set the wallpaper image for Ash and Mash. @@ -202,8 +213,8 @@ if (chrome::IsRunningInMash()) { shell::Connector* connector = content::MojoShellConnection::GetForProcess()->GetConnector(); - ash::sysui::mojom::WallpaperControllerPtr wallpaper_controller; - connector->ConnectToInterface("mojo:ash_sysui", &wallpaper_controller); + ash::mojom::WallpaperControllerPtr wallpaper_controller; + connector->ConnectToInterface("mojo:ash", &wallpaper_controller); wallpaper_controller->SetWallpaper(*image.bitmap(), WallpaperLayoutToMojo(layout)); return; @@ -881,6 +892,14 @@ void WallpaperManager::SetPolicyControlledWallpaper( const AccountId& account_id, std::unique_ptr<user_manager::UserImage> user_image) { + if (!CanGetFilesId()) { + CallWhenCanGetFilesId( + base::Bind(&WallpaperManager::SetPolicyControlledWallpaper, + weak_factory_.GetWeakPtr(), account_id, + base::Passed(std::move(user_image)))); + return; + } + const wallpaper::WallpaperFilesId wallpaper_files_id = GetFilesId(account_id); if (!wallpaper_files_id.is_valid())
diff --git a/chrome/browser/chromeos/printing/printer_pref_manager.cc b/chrome/browser/chromeos/printing/printer_pref_manager.cc index 6c5ed0b..00a63f12 100644 --- a/chrome/browser/chromeos/printing/printer_pref_manager.cc +++ b/chrome/browser/chromeos/printing/printer_pref_manager.cc
@@ -104,4 +104,14 @@ UpdatePrinterPref(profile_, printer->id(), std::move(updated_printer)); } +bool PrinterPrefManager::RemovePrinter(const std::string& printer_id) { + DCHECK(!printer_id.empty()); + ListPrefUpdate update(profile_->GetPrefs(), prefs::kPrintingDevices); + base::ListValue* printer_list = update.Get(); + DCHECK(printer_list) << "Printer preference not registered"; + base::DictionaryValue* printer = FindPrinterPref(printer_list, printer_id); + + return printer && printer_list->Remove(*printer, nullptr); +} + } // namespace chromeos
diff --git a/chrome/browser/chromeos/printing/printer_pref_manager.h b/chrome/browser/chromeos/printing/printer_pref_manager.h index 75d9930..710616d 100644 --- a/chrome/browser/chromeos/printing/printer_pref_manager.h +++ b/chrome/browser/chromeos/printing/printer_pref_manager.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_CHROMEOS_PRINTING_PRINTER_PREF_MANAGER_H_ #include <memory> +#include <string> #include <vector> #include "chromeos/printing/printer_configuration.h" @@ -34,6 +35,10 @@ // empty id to add a new printer. void RegisterPrinter(std::unique_ptr<Printer> printer); + // Remove printer from preferences with the id |printer_id|. Returns true if + // the printer was successfully removed. + bool RemovePrinter(const std::string& printer_id); + private: Profile* profile_; };
diff --git a/chrome/browser/chromeos/printing/printer_pref_manager_unittest.cc b/chrome/browser/chromeos/printing/printer_pref_manager_unittest.cc new file mode 100644 index 0000000..0e67421 --- /dev/null +++ b/chrome/browser/chromeos/printing/printer_pref_manager_unittest.cc
@@ -0,0 +1,81 @@ +// 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 "chrome/browser/chromeos/printing/printer_pref_manager.h" + +#include <memory> +#include <utility> + +#include "base/memory/ptr_util.h" +#include "chrome/browser/chromeos/printing/printer_pref_manager_factory.h" +#include "chrome/test/base/testing_profile.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace chromeos { + +namespace { + +const char kPrinterId[] = "UUID-UUID-UUID-PRINTER"; +const char kUri[] = "ipps://printer.chromium.org/ipp/print"; + +} // namespace + +TEST(PrinterPrefManagerTest, AddPrinter) { + std::unique_ptr<Profile> profile = base::MakeUnique<TestingProfile>(); + PrinterPrefManager* manager = + PrinterPrefManagerFactory::GetForBrowserContext(profile.get()); + + manager->RegisterPrinter(base::MakeUnique<Printer>(kPrinterId)); + + auto printers = manager->GetPrinters(); + ASSERT_EQ(1U, printers.size()); + EXPECT_EQ(kPrinterId, printers[0]->id()); +} + +TEST(PrinterPrefManagerTest, UpdatePrinterAssignsId) { + std::unique_ptr<Profile> profile = base::MakeUnique<TestingProfile>(); + PrinterPrefManager* manager = + PrinterPrefManagerFactory::GetForBrowserContext(profile.get()); + + manager->RegisterPrinter(base::MakeUnique<Printer>()); + + auto printers = manager->GetPrinters(); + ASSERT_EQ(1U, printers.size()); + EXPECT_FALSE(printers[0]->id().empty()); +} + +TEST(PrinterPrefManagerTest, UpdatePrinter) { + std::unique_ptr<Profile> profile = base::MakeUnique<TestingProfile>(); + PrinterPrefManager* manager = + PrinterPrefManagerFactory::GetForBrowserContext(profile.get()); + + manager->RegisterPrinter(base::MakeUnique<Printer>(kPrinterId)); + std::unique_ptr<Printer> updated_printer = + base::MakeUnique<Printer>(kPrinterId); + updated_printer->set_uri(kUri); + manager->RegisterPrinter(std::move(updated_printer)); + + auto printers = manager->GetPrinters(); + ASSERT_EQ(1U, printers.size()); + EXPECT_EQ(kUri, printers[0]->uri()); +} + +TEST(PrinterPrefManagerTest, RemovePrinter) { + std::unique_ptr<Profile> profile = base::MakeUnique<TestingProfile>(); + PrinterPrefManager* manager = + PrinterPrefManagerFactory::GetForBrowserContext(profile.get()); + + manager->RegisterPrinter(base::MakeUnique<Printer>("OtherUUID")); + manager->RegisterPrinter(base::MakeUnique<Printer>(kPrinterId)); + manager->RegisterPrinter(base::MakeUnique<Printer>()); + + manager->RemovePrinter(kPrinterId); + + auto printers = manager->GetPrinters(); + ASSERT_EQ(2U, printers.size()); + EXPECT_NE(kPrinterId, printers.at(0)->id()); + EXPECT_NE(kPrinterId, printers.at(1)->id()); +} + +} // namespace chromeos
diff --git a/chrome/browser/download/download_commands.cc b/chrome/browser/download/download_commands.cc index eb2ca17..a3d2fad 100644 --- a/chrome/browser/download/download_commands.cc +++ b/chrome/browser/download/download_commands.cc
@@ -38,6 +38,10 @@ #include "chrome/browser/ui/pdf/adobe_reader_info_win.h" #endif +#if defined(OS_CHROMEOS) +#include "chrome/browser/chromeos/note_taking_app_utils.h" +#endif // defined(OS_CHROMEOS) + namespace { // Maximum size (compressed) of image to be copied to the clipboard. If the @@ -142,6 +146,8 @@ return IDR_NOTIFICATION_WELCOME_LEARN_MORE; case COPY_TO_CLIPBOARD: return IDR_DOWNLOAD_NOTIFICATION_MENU_COPY_TO_CLIPBOARD; + case ANNOTATE: + return IDR_DOWNLOAD_NOTIFICATION_MENU_ANNOTATE; case OPEN_WHEN_COMPLETE: case ALWAYS_OPEN_TYPE: case PLATFORM_OPEN: @@ -195,6 +201,8 @@ case COPY_TO_CLIPBOARD: return (download_item_->GetState() == content::DownloadItem::COMPLETE && download_item_->GetReceivedBytes() <= kMaxImageClipboardSize); + case ANNOTATE: + return download_item_->GetState() == content::DownloadItem::COMPLETE; case DISCARD: case KEEP: case LEARN_MORE_SCANNING: @@ -230,6 +238,7 @@ case LEARN_MORE_SCANNING: case LEARN_MORE_INTERRUPTED: case COPY_TO_CLIPBOARD: + case ANNOTATE: return false; } return false; @@ -346,6 +355,15 @@ case COPY_TO_CLIPBOARD: CopyFileAsImageToClipboard(); break; + case ANNOTATE: +#if defined(OS_CHROMEOS) + if (DownloadItemModel(download_item_).HasSupportedImageMimeType()) { + chromeos::LaunchNoteTakingAppForNewNote( + Profile::FromBrowserContext(download_item_->GetBrowserContext()), + download_item_->GetTargetFilePath()); + } +#endif // defined(OS_CHROMEOS) + break; } }
diff --git a/chrome/browser/download/download_commands.h b/chrome/browser/download/download_commands.h index f76ca06..06fb554d 100644 --- a/chrome/browser/download/download_commands.h +++ b/chrome/browser/download/download_commands.h
@@ -28,6 +28,7 @@ LEARN_MORE_SCANNING, // Show information about download scanning. LEARN_MORE_INTERRUPTED, // Show information about interrupted downloads. COPY_TO_CLIPBOARD, // Copy the contents to the clipboard. + ANNOTATE, // Open an app to annotate the image. }; // |download_item| must outlive DownloadCommands.
diff --git a/chrome/browser/download/download_shelf_context_menu.cc b/chrome/browser/download/download_shelf_context_menu.cc index 0b9fc60..93063b2 100644 --- a/chrome/browser/download/download_shelf_context_menu.cc +++ b/chrome/browser/download/download_shelf_context_menu.cc
@@ -150,7 +150,8 @@ id = IDS_DOWNLOAD_MENU_LEARN_MORE_INTERRUPTED; break; case DownloadCommands::COPY_TO_CLIPBOARD: - // This command is implemented only for Donwload Notification. + case DownloadCommands::ANNOTATE: + // These commands are implemented only for the Download notification. NOTREACHED(); break; }
diff --git a/chrome/browser/download/notification/download_item_notification.cc b/chrome/browser/download/notification/download_item_notification.cc index e98e7d0..ca6916c 100644 --- a/chrome/browser/download/notification/download_item_notification.cc +++ b/chrome/browser/download/notification/download_item_notification.cc
@@ -45,6 +45,10 @@ #include "ui/message_center/message_center.h" #include "ui/message_center/message_center_style.h" +#if defined(OS_CHROMEOS) +#include "chrome/browser/chromeos/note_taking_app_utils.h" +#endif // defined(OS_CHROMEOS) + using base::UserMetricsAction; namespace { @@ -164,6 +168,10 @@ content::RecordAction( UserMetricsAction("DownloadNotification.Button_CopyToClipboard")); break; + case DownloadCommands::ANNOTATE: + content::RecordAction( + UserMetricsAction("DownloadNotification.Button_Annotate")); + break; } } @@ -643,8 +651,13 @@ break; case content::DownloadItem::COMPLETE: actions->push_back(DownloadCommands::SHOW_IN_FOLDER); - if (!notification_->image().IsEmpty()) + if (!notification_->image().IsEmpty()) { actions->push_back(DownloadCommands::COPY_TO_CLIPBOARD); +#if defined(OS_CHROMEOS) + if (chromeos::IsNoteTakingAppAvailable(profile())) + actions->push_back(DownloadCommands::ANNOTATE); +#endif // defined(OS_CHROMEOS) + } break; case content::DownloadItem::MAX_DOWNLOAD_STATE: NOTREACHED(); @@ -732,6 +745,9 @@ case DownloadCommands::COPY_TO_CLIPBOARD: id = IDS_DOWNLOAD_NOTIFICATION_COPY_TO_CLIPBOARD; break; + case DownloadCommands::ANNOTATE: + id = IDS_DOWNLOAD_NOTIFICATION_ANNOTATE; + break; case DownloadCommands::ALWAYS_OPEN_TYPE: case DownloadCommands::PLATFORM_OPEN: case DownloadCommands::LEARN_MORE_INTERRUPTED:
diff --git a/chrome/browser/extensions/api/sessions/sessions_api.cc b/chrome/browser/extensions/api/sessions/sessions_api.cc index e9e9d731..72854c2 100644 --- a/chrome/browser/extensions/api/sessions/sessions_api.cc +++ b/chrome/browser/extensions/api/sessions/sessions_api.cc
@@ -44,6 +44,8 @@ namespace extensions { +namespace { + namespace GetRecentlyClosed = api::sessions::GetRecentlyClosed; namespace GetDevices = api::sessions::GetDevices; namespace Restore = api::sessions::Restore; @@ -79,7 +81,7 @@ const std::string& session_id, int index, bool pinned, - int selected_index, + bool active, const Extension* extension) { tabs::Tab tab_struct; @@ -98,12 +100,7 @@ } tab_struct.index = index; tab_struct.pinned = pinned; - // Note: |selected_index| from the sync sessions model is what we call - // "active" in extensions terminology. "selected" is deprecated because it's - // not clear whether it means "active" (user can see) or "highlighted" (user - // has highlighted, since you can select tabs without bringing them into the - // foreground). - tab_struct.active = index == selected_index; + tab_struct.active = active; ExtensionTabUtil::ScrubTabForExtension(extension, nullptr, &tab_struct); return tab_struct; } @@ -140,64 +137,54 @@ return session_struct; } -bool is_tab_entry(const sessions::TabRestoreService::Entry* entry) { - return entry->type == sessions::TabRestoreService::TAB; +bool is_window_entry(const sessions::TabRestoreService::Entry& entry) { + return entry.type == sessions::TabRestoreService::WINDOW; } -bool is_window_entry(const sessions::TabRestoreService::Entry* entry) { - return entry->type == sessions::TabRestoreService::WINDOW; -} +} // namespace tabs::Tab SessionsGetRecentlyClosedFunction::CreateTabModel( const sessions::TabRestoreService::Tab& tab, - int session_id, - int selected_index) { + bool active) { return CreateTabModelHelper(GetProfile(), tab.navigations[tab.current_navigation_index], - base::IntToString(session_id), - tab.tabstrip_index, - tab.pinned, - selected_index, - extension()); + base::IntToString(tab.id), tab.tabstrip_index, + tab.pinned, active, extension()); } std::unique_ptr<windows::Window> SessionsGetRecentlyClosedFunction::CreateWindowModel( - const sessions::TabRestoreService::Window& window, - int session_id) { + const sessions::TabRestoreService::Window& window) { DCHECK(!window.tabs.empty()); - std::unique_ptr<std::vector<tabs::Tab>> tabs(new std::vector<tabs::Tab>()); - for (size_t i = 0; i < window.tabs.size(); ++i) { - tabs->push_back(CreateTabModel(window.tabs[i], window.tabs[i].id, - window.selected_tab_index)); - } + auto tabs = base::MakeUnique<std::vector<tabs::Tab>>(); + for (const auto& tab : window.tabs) + tabs->push_back( + CreateTabModel(*tab, tab->tabstrip_index == window.selected_tab_index)); - return CreateWindowModelHelper(std::move(tabs), base::IntToString(session_id), + return CreateWindowModelHelper(std::move(tabs), base::IntToString(window.id), windows::WINDOW_TYPE_NORMAL, windows::WINDOW_STATE_NORMAL); } std::unique_ptr<api::sessions::Session> SessionsGetRecentlyClosedFunction::CreateSessionModel( - const sessions::TabRestoreService::Entry* entry) { + const sessions::TabRestoreService::Entry& entry) { std::unique_ptr<tabs::Tab> tab; std::unique_ptr<windows::Window> window; - switch (entry->type) { + switch (entry.type) { case sessions::TabRestoreService::TAB: tab.reset(new tabs::Tab(CreateTabModel( - *static_cast<const sessions::TabRestoreService::Tab*>(entry), - entry->id, -1))); + static_cast<const sessions::TabRestoreService::Tab&>(entry), false))); break; case sessions::TabRestoreService::WINDOW: window = CreateWindowModel( - *static_cast<const sessions::TabRestoreService::Window*>(entry), - entry->id); + static_cast<const sessions::TabRestoreService::Window&>(entry)); break; default: NOTREACHED(); } - return CreateSessionModelHelper(entry->timestamp.ToTimeT(), std::move(tab), + return CreateSessionModelHelper(entry.timestamp.ToTimeT(), std::move(tab), std::move(window)); } @@ -227,9 +214,8 @@ // List of entries. They are ordered from most to least recent. // We prune the list to contain max 25 entries at any time and removes // uninteresting entries. - for (const sessions::TabRestoreService::Entry* entry : - tab_restore_service->entries()) { - result.push_back(std::move(*CreateSessionModel(entry))); + for (const auto& entry : tab_restore_service->entries()) { + result.push_back(std::move(*CreateSessionModel(*entry))); } results_ = GetRecentlyClosed::Results::Create(result); @@ -240,16 +226,11 @@ const std::string& session_tag, const sessions::SessionTab& tab, int tab_index, - int selected_index) { + bool active) { std::string session_id = SessionId(session_tag, tab.tab_id.id()).ToString(); return CreateTabModelHelper( - GetProfile(), - tab.navigations[tab.normalized_navigation_index()], - session_id, - tab_index, - tab.pinned, - selected_index, - extension()); + GetProfile(), tab.navigations[tab.normalized_navigation_index()], + session_id, tab_index, tab.pinned, active, extension()); } std::unique_ptr<windows::Window> SessionsGetDevicesFunction::CreateWindowModel( @@ -278,7 +259,7 @@ std::unique_ptr<std::vector<tabs::Tab>> tabs(new std::vector<tabs::Tab>()); for (size_t i = 0; i < tabs_in_window.size(); ++i) { tabs->push_back(CreateTabModel(session_tag, *tabs_in_window[i], i, - window.selected_tab_index)); + window.selected_tab_index == (int)i)); } std::string session_id = @@ -437,14 +418,15 @@ bool SessionsRestoreFunction::RestoreMostRecentlyClosed(Browser* browser) { sessions::TabRestoreService* tab_restore_service = TabRestoreServiceFactory::GetForProfile(GetProfile()); - sessions::TabRestoreService::Entries entries = tab_restore_service->entries(); + const sessions::TabRestoreService::Entries& entries = + tab_restore_service->entries(); if (entries.empty()) { SetError(kNoRecentlyClosedSessionsError); return false; } - bool is_window = is_window_entry(entries.front()); + bool is_window = is_window_entry(*entries.front()); sessions::LiveTabContext* context = BrowserLiveTabContext::FindContextForWebContents( browser->tab_strip_model()->GetActiveWebContents()); @@ -467,7 +449,8 @@ Browser* browser) { sessions::TabRestoreService* tab_restore_service = TabRestoreServiceFactory::GetForProfile(GetProfile()); - sessions::TabRestoreService::Entries entries = tab_restore_service->entries(); + const sessions::TabRestoreService::Entries& entries = + tab_restore_service->entries(); if (entries.empty()) { SetInvalidIdError(session_id.ToString()); @@ -476,12 +459,11 @@ // Check if the recently closed list contains an entry with the provided id. bool is_window = false; - for (sessions::TabRestoreService::Entries::iterator it = entries.begin(); - it != entries.end(); ++it) { - if ((*it)->id == session_id.id()) { - // The only time a full window is being restored is if the entry ID + for (const auto& entry : entries) { + if (entry->id == session_id.id()) { + // A full window is being restored only if the entry ID // matches the provided ID and the entry type is Window. - is_window = is_window_entry(*it); + is_window = is_window_entry(*entry); break; } }
diff --git a/chrome/browser/extensions/api/sessions/sessions_api.h b/chrome/browser/extensions/api/sessions/sessions_api.h index cd1afeb..6bdc9dd 100644 --- a/chrome/browser/extensions/api/sessions/sessions_api.h +++ b/chrome/browser/extensions/api/sessions/sessions_api.h
@@ -36,13 +36,11 @@ private: api::tabs::Tab CreateTabModel(const sessions::TabRestoreService::Tab& tab, - int session_id, - int selected_index); + bool active); std::unique_ptr<api::windows::Window> CreateWindowModel( - const sessions::TabRestoreService::Window& window, - int session_id); + const sessions::TabRestoreService::Window& window); std::unique_ptr<api::sessions::Session> CreateSessionModel( - const sessions::TabRestoreService::Entry* entry); + const sessions::TabRestoreService::Entry& entry); }; class SessionsGetDevicesFunction : public ChromeSyncExtensionFunction { @@ -55,7 +53,7 @@ api::tabs::Tab CreateTabModel(const std::string& session_tag, const sessions::SessionTab& tab, int tab_index, - int selected_index); + bool active); std::unique_ptr<api::windows::Window> CreateWindowModel( const sessions::SessionWindow& window, const std::string& session_tag);
diff --git a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc index 8adeb96f..2d44b432 100644 --- a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc +++ b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
@@ -27,12 +27,14 @@ #include "content/public/browser/browser_url_handler.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" +#include "content/public/browser/resource_dispatcher_host.h" #include "content/public/browser/site_instance.h" #include "content/public/browser/vpn_service_proxy.h" #include "content/public/browser/web_contents.h" #include "content/public/common/content_switches.h" #include "extensions/browser/api/web_request/web_request_api.h" #include "extensions/browser/api/web_request/web_request_api_helpers.h" +#include "extensions/browser/bad_message.h" #include "extensions/browser/extension_host.h" #include "extensions/browser/extension_message_filter.h" #include "extensions/browser/extension_registry.h" @@ -125,6 +127,79 @@ return PRIV_EXTENSION; } +// Determines whether the extension |origin| passed in can be committed by +// the process identified by |child_id| and returns true or false +// accordingly. Please refer to the implementation for more information. +bool IsIllegalOrigin(content::ResourceContext* resource_context, + int child_id, + const GURL& origin) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + // Consider non-extension URLs safe; they will be checked elsewhere. + if (!origin.SchemeIs(kExtensionScheme)) + return false; + + // If there is no extension installed for the URL, it couldn't have + // committed. + // (If the extension was recently uninstalled, the tab would have closed.) + ProfileIOData* io_data = ProfileIOData::FromResourceContext(resource_context); + InfoMap* extension_info_map = io_data->GetExtensionInfoMap(); + const Extension* extension = + extension_info_map->extensions().GetExtensionOrAppByURL(origin); + if (!extension) + return true; + + // Check for platform app origins. These can only be committed by the app + // itself, or by one if its guests if there are accessible_resources. + const ProcessMap& process_map = extension_info_map->process_map(); + if (extension->is_platform_app() && + !process_map.Contains(extension->id(), child_id)) { + // This is a platform app origin not in the app's own process. If there + // are + // no accessible resources, this is illegal. + if (!extension->GetManifestData(manifest_keys::kWebviewAccessibleResources)) + return true; + + // If there are accessible resources, the origin is only legal if the + // given + // process is a guest of the app. + std::string owner_extension_id; + int owner_process_id; + WebViewRendererState::GetInstance()->GetOwnerInfo( + child_id, &owner_process_id, &owner_extension_id); + const Extension* owner_extension = + extension_info_map->extensions().GetByID(owner_extension_id); + return !owner_extension || owner_extension != extension; + } + + // With only the origin and not the full URL, we don't have enough + // information + // to validate hosted apps or web_accessible_resources in normal extensions. + // Assume they're legal. + return false; +} + +// This callback is registered on the ResourceDispatcherHost for the chrome +// extension Origin scheme. We determine whether the extension origin is +// valid. Please see the IsIllegalOrigin() function. +void OnHttpHeaderReceived(const std::string& header, + const std::string& value, + int child_id, + content::ResourceContext* resource_context, + content::OnHeaderProcessedCallback callback) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + GURL origin(value); + DCHECK(origin.SchemeIs(extensions::kExtensionScheme)); + + if (IsIllegalOrigin(resource_context, child_id, origin)) { + // TODO(ananta): Find a way to specify the right error code here. + callback.Run(false, 0); + } else { + callback.Run(true, 0); + } +} + } // namespace ChromeContentBrowserClientExtensionsPart:: @@ -272,52 +347,6 @@ return true; } -bool ChromeContentBrowserClientExtensionsPart::IsIllegalOrigin( - content::ResourceContext* resource_context, - int child_process_id, - const GURL& origin) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - - // Consider non-extension URLs safe; they will be checked elsewhere. - if (!origin.SchemeIs(kExtensionScheme)) - return false; - - // If there is no extension installed for the URL, it couldn't have committed. - // (If the extension was recently uninstalled, the tab would have closed.) - ProfileIOData* io_data = ProfileIOData::FromResourceContext(resource_context); - InfoMap* extension_info_map = io_data->GetExtensionInfoMap(); - const Extension* extension = - extension_info_map->extensions().GetExtensionOrAppByURL(origin); - if (!extension) - return true; - - // Check for platform app origins. These can only be committed by the app - // itself, or by one if its guests if there are accessible_resources. - const ProcessMap& process_map = extension_info_map->process_map(); - if (extension->is_platform_app() && - !process_map.Contains(extension->id(), child_process_id)) { - // This is a platform app origin not in the app's own process. If there are - // no accessible resources, this is illegal. - if (!extension->GetManifestData(manifest_keys::kWebviewAccessibleResources)) - return true; - - // If there are accessible resources, the origin is only legal if the given - // process is a guest of the app. - std::string owner_extension_id; - int owner_process_id; - WebViewRendererState::GetInstance()->GetOwnerInfo( - child_process_id, &owner_process_id, &owner_extension_id); - const Extension* owner_extension = - extension_info_map->extensions().GetByID(owner_extension_id); - return !owner_extension || owner_extension != extension; - } - - // With only the origin and not the full URL, we don't have enough information - // to validate hosted apps or web_accessible_resources in normal extensions. - // Assume they're legal. - return false; -} - // static bool ChromeContentBrowserClientExtensionsPart::IsSuitableHost( Profile* profile, @@ -662,4 +691,9 @@ } } +void ChromeContentBrowserClientExtensionsPart::ResourceDispatcherHostCreated() { + content::ResourceDispatcherHost::Get()->RegisterInterceptor( + "Origin", kExtensionScheme, base::Bind(&OnHttpHeaderReceived)); +} + } // namespace extensions
diff --git a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.h b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.h index 8982d527..a8e10f3 100644 --- a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.h +++ b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.h
@@ -34,9 +34,6 @@ const GURL& effective_site_url); static bool CanCommitURL(content::RenderProcessHost* process_host, const GURL& url); - static bool IsIllegalOrigin(content::ResourceContext* resource_context, - int child_process_id, - const GURL& origin); static bool IsSuitableHost(Profile* profile, content::RenderProcessHost* process_host, const GURL& site_url); @@ -91,6 +88,7 @@ base::CommandLine* command_line, content::RenderProcessHost* process, Profile* profile) override; + void ResourceDispatcherHostCreated() override; DISALLOW_COPY_AND_ASSIGN(ChromeContentBrowserClientExtensionsPart); };
diff --git a/chrome/browser/extensions/component_loader.cc b/chrome/browser/extensions/component_loader.cc index a85f217c..c6289573 100644 --- a/chrome/browser/extensions/component_loader.cc +++ b/chrome/browser/extensions/component_loader.cc
@@ -56,6 +56,7 @@ #endif #if defined(OS_CHROMEOS) +#include "chrome/browser/chromeos/accessibility/accessibility_manager.h" #include "chromeos/chromeos_switches.h" #include "content/public/browser/site_instance.h" #include "content/public/browser/storage_partition.h" @@ -376,8 +377,30 @@ } #if defined(OS_CHROMEOS) +void ComponentLoader::AddChromeVoxExtension( + const base::Closure& done_cb) { + base::FilePath resources_path; + CHECK(PathService::Get(chrome::DIR_RESOURCES, &resources_path)); + + base::FilePath chromevox_path = + resources_path.Append(extension_misc::kChromeVoxExtensionPath); + + const base::FilePath::CharType* manifest_filename = + IsNormalSession() ? extensions::kManifestFilename + : extension_misc::kGuestManifestFilename; + AddWithManifestFile( + manifest_filename, + chromevox_path, + extension_misc::kChromeVoxExtensionId, + done_cb); +} + void ComponentLoader::AddChromeOsSpeechSynthesisExtension() { - AddComponentFromDir( + const base::FilePath::CharType* manifest_filename = + IsNormalSession() ? extensions::kManifestFilename + : extension_misc::kGuestManifestFilename; + AddWithManifestFile( + manifest_filename, base::FilePath(extension_misc::kSpeechSynthesisExtensionPath), extension_misc::kSpeechSynthesisExtensionId, base::Bind(&ComponentLoader::EnableFileSystemInGuestMode, @@ -602,6 +625,12 @@ Add(IDR_ARC_SUPPORT_MANIFEST, base::FilePath(FILE_PATH_LITERAL("chromeos/arc_support"))); } + + // Load ChromeVox extension now if spoken feedback is enabled. + if (chromeos::AccessibilityManager::Get() && + chromeos::AccessibilityManager::Get()->IsSpokenFeedbackEnabled()) { + AddChromeVoxExtension(base::Closure()); + } #endif // defined(OS_CHROMEOS) #if defined(GOOGLE_CHROME_BUILD) @@ -660,26 +689,24 @@ } #if defined(OS_CHROMEOS) -void ComponentLoader::AddComponentFromDir( +void ComponentLoader::AddWithManifestFile( + const base::FilePath::CharType* manifest_filename, const base::FilePath& root_directory, const char* extension_id, const base::Closure& done_cb) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - const base::FilePath::CharType* manifest_filename = - IsNormalSession() ? extensions::kManifestFilename - : extension_misc::kGuestManifestFilename; BrowserThread::PostTaskAndReplyWithResult( BrowserThread::FILE, FROM_HERE, base::Bind(&LoadManifestOnFileThread, root_directory, manifest_filename), - base::Bind(&ComponentLoader::FinishAddComponentFromDir, + base::Bind(&ComponentLoader::FinishAddWithManifestFile, weak_factory_.GetWeakPtr(), root_directory, extension_id, done_cb)); } -void ComponentLoader::FinishAddComponentFromDir( +void ComponentLoader::FinishAddWithManifestFile( const base::FilePath& root_directory, const char* extension_id, const base::Closure& done_cb,
diff --git a/chrome/browser/extensions/component_loader.h b/chrome/browser/extensions/component_loader.h index d71d360..c9d8f654 100644 --- a/chrome/browser/extensions/component_loader.h +++ b/chrome/browser/extensions/component_loader.h
@@ -99,15 +99,10 @@ void Reload(const std::string& extension_id); #if defined(OS_CHROMEOS) - // Add a component extension from a specific directory. Assumes that the - // extension uses a different manifest file when this is a guest session. - // Calls |done_cb| on success, unless the component loader is - // shut down during loading. - void AddComponentFromDir( - const base::FilePath& root_directory, - const char* extension_id, - const base::Closure& done_cb); - + // Calls |done_cb|, if not a null callback, on success. + // NOTE: |done_cb| is not called if the component loader is shut down + // during loading. + void AddChromeVoxExtension(const base::Closure& done_cb); void AddChromeOsSpeechSynthesisExtension(); #endif @@ -180,10 +175,18 @@ void EnableFileSystemInGuestMode(const std::string& id); #if defined(OS_CHROMEOS) - // Used as a reply callback by |AddComponentFromDir|. + // Adds an extension where the manifest file is stored on the file system. + // |manifest_filename| can be relative to the |root_directory|. + void AddWithManifestFile( + const base::FilePath::CharType* manifest_filename, + const base::FilePath& root_directory, + const char* extension_id, + const base::Closure& done_cb); + + // Used as a reply callback by |AddWithManifestFile|. // Called with a |root_directory| and parsed |manifest| and invokes // |done_cb| after adding the extension. - void FinishAddComponentFromDir( + void FinishAddWithManifestFile( const base::FilePath& root_directory, const char* extension_id, const base::Closure& done_cb,
diff --git a/chrome/browser/external_protocol/external_protocol_handler.cc b/chrome/browser/external_protocol/external_protocol_handler.cc index 719a7dc1..540ffba 100644 --- a/chrome/browser/external_protocol/external_protocol_handler.cc +++ b/chrome/browser/external_protocol/external_protocol_handler.cc
@@ -165,9 +165,6 @@ "mailto", "news", "snews", -#if defined(OS_WIN) - "ms-windows-store", -#endif }; bool should_block;
diff --git a/chrome/browser/feedback/OWNERS b/chrome/browser/feedback/OWNERS index e6612b93..2213bbd 100644 --- a/chrome/browser/feedback/OWNERS +++ b/chrome/browser/feedback/OWNERS
@@ -1,2 +1,3 @@ +afakhry@chromium.org rkc@chromium.org zork@chromium.org
diff --git a/chrome/browser/feedback/show_feedback_page.cc b/chrome/browser/feedback/show_feedback_page.cc index 4fc2449..0c04809 100644 --- a/chrome/browser/feedback/show_feedback_page.cc +++ b/chrome/browser/feedback/show_feedback_page.cc
@@ -14,6 +14,8 @@ #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/browser/ui/webui/md_feedback/md_feedback_dialog_controller.h" +#include "chrome/common/chrome_switches.h" #include "components/signin/core/account_id/account_id.h" #include "content/public/browser/web_contents.h" #include "url/gurl.h" @@ -78,6 +80,11 @@ : profile; #endif + if (::switches::MdFeedbackEnabled()) { + MdFeedbackDialogController::GetInstance()->Show(profile); + return; + } + extensions::FeedbackPrivateAPI* api = extensions::FeedbackPrivateAPI::GetFactoryInstance()->Get(profile);
diff --git a/chrome/browser/io_thread_unittest.cc b/chrome/browser/io_thread_unittest.cc index 3b7c8972..f7899766 100644 --- a/chrome/browser/io_thread_unittest.cc +++ b/chrome/browser/io_thread_unittest.cc
@@ -66,14 +66,14 @@ // protected functions in a test (the code would need to explicitly contain // the name of the actual test class). void CheckCnameLookup(bool expected) { - auto http_auth_preferences = + auto* http_auth_preferences = IOThreadPeer::GetAuthPreferences(io_thread_.get()); ASSERT_NE(nullptr, http_auth_preferences); EXPECT_EQ(expected, http_auth_preferences->NegotiateDisableCnameLookup()); } void CheckNegotiateEnablePort(bool expected) { - auto http_auth_preferences = + auto* http_auth_preferences = IOThreadPeer::GetAuthPreferences(io_thread_.get()); ASSERT_NE(nullptr, http_auth_preferences); EXPECT_EQ(expected, http_auth_preferences->NegotiateEnablePort()); @@ -81,7 +81,7 @@ #if defined(OS_ANDROID) void CheckAuthAndroidNegoitateAccountType(std::string expected) { - auto http_auth_preferences = + auto* http_auth_preferences = IOThreadPeer::GetAuthPreferences(io_thread_.get()); ASSERT_NE(nullptr, http_auth_preferences); EXPECT_EQ(expected, @@ -90,13 +90,13 @@ #endif void CheckCanUseDefaultCredentials(bool expected, const GURL& url) { - auto http_auth_preferences = + auto* http_auth_preferences = IOThreadPeer::GetAuthPreferences(io_thread_.get()); EXPECT_EQ(expected, http_auth_preferences->CanUseDefaultCredentials(url)); } void CheckCanDelegate(bool expected, const GURL& url) { - auto http_auth_preferences = + auto* http_auth_preferences = IOThreadPeer::GetAuthPreferences(io_thread_.get()); EXPECT_EQ(expected, http_auth_preferences->CanDelegate(url)); }
diff --git a/chrome/browser/memory/tab_manager.cc b/chrome/browser/memory/tab_manager.cc index 2969476..a99e6ab 100644 --- a/chrome/browser/memory/tab_manager.cc +++ b/chrome/browser/memory/tab_manager.cc
@@ -271,6 +271,62 @@ return GetWebContentsData(contents)->IsDiscarded(); } +bool TabManager::CanDiscardTab(int64_t target_web_contents_id) const { + TabStripModel* model; + int idx = FindTabStripModelById(target_web_contents_id, &model); + + if (idx == -1) + return false; + + WebContents* web_contents = model->GetWebContentsAt(idx); + + // Do not discard tabs that don't have a valid URL (most probably they have + // just been opened and dicarding them would lose the URL). + // TODO(georgesak): Look into a workaround to be able to kill the tab without + // losing the pending navigation. + if (!web_contents->GetLastCommittedURL().is_valid() || + web_contents->GetLastCommittedURL().is_empty()) { + return false; + } + + // Do not discard tabs in which the user has entered text in a form, lest that + // state gets lost. + if (web_contents->GetPageImportanceSignals().had_form_interaction) + return false; + + // Do not discard tabs that are playing either playing audio or accessing the + // microphone or camera as it's too distruptive to the user experience. Note + // that tabs that have recently stopped playing audio by at least + // |kAudioProtectionTimeSeconds| seconds are protected as well. + if (IsMediaTab(web_contents)) + return false; + + // Do not discard PDFs as they might contain entry that is not saved and they + // don't remember their scrolling positions. See crbug.com/547286 and + // crbug.com/65244. + // TODO(georgesak): Remove this workaround when the bugs are fixed. + if (web_contents->GetContentsMimeType() == "application/pdf") + return false; + + // Do not discard a previously discarded tab if that's the desired behavior. + if (discard_once_ && GetWebContentsData(web_contents)->DiscardCount() > 0) + return false; + + // Do not discard a recently used tab. + if (minimum_protection_time_.InSeconds() > 0) { + auto delta = + NowTicks() - GetWebContentsData(web_contents)->LastInactiveTime(); + if (delta < minimum_protection_time_) + return false; + } + + // Do not discard a tab that was explicitly disallowed to. + if (!IsTabAutoDiscardable(web_contents)) + return false; + + return true; +} + void TabManager::DiscardTab() { #if defined(OS_CHROMEOS) // Call Chrome OS specific low memory handling process. @@ -316,47 +372,115 @@ test_tick_clock_ = test_tick_clock; } -void TabManager::TabChangedAt(content::WebContents* contents, - int index, - TabChangeType change_type) { - if (change_type != TabChangeType::ALL) - return; - auto* data = GetWebContentsData(contents); - bool old_state = data->IsRecentlyAudible(); - bool current_state = contents->WasRecentlyAudible(); - if (old_state != current_state) { - data->SetRecentlyAudible(current_state); - data->SetLastAudioChangeTime(NowTicks()); +// Things to collect on the browser thread (because TabStripModel isn't thread +// safe): +// 1) whether or not a tab is pinned +// 2) last time a tab was selected +// 3) is the tab currently selected +TabStatsList TabManager::GetUnsortedTabStats() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + TabStatsList stats_list; + stats_list.reserve(32); // 99% of users have < 30 tabs open. + + // TODO(chrisha): Move this code to a TabStripModel enumeration delegate! + if (!test_tab_strip_models_.empty()) { + for (size_t i = 0; i < test_tab_strip_models_.size(); ++i) { + AddTabStats(test_tab_strip_models_[i].first, // tab_strip_model + test_tab_strip_models_[i].second, // is_app + i == 0, // is_active + &stats_list); + } + } else { + // The code here can only be tested under a full browser test. + AddTabStats(&stats_list); } + + return stats_list; } -void TabManager::ActiveTabChanged(content::WebContents* old_contents, - content::WebContents* new_contents, - int index, - int reason) { - GetWebContentsData(new_contents)->SetDiscardState(false); - // If |old_contents| is set, that tab has switched from being active to - // inactive, so record the time of that transition. - if (old_contents) - GetWebContentsData(old_contents)->SetLastInactiveTime(NowTicks()); +void TabManager::AddObserver(TabManagerObserver* observer) { + observers_.AddObserver(observer); } -void TabManager::TabInsertedAt(content::WebContents* contents, - int index, - bool foreground) { - // Only interested in background tabs, as foreground tabs get taken care of by - // ActiveTabChanged. - if (foreground) - return; +void TabManager::RemoveObserver(TabManagerObserver* observer) { + observers_.RemoveObserver(observer); +} - // A new background tab is similar to having a tab switch from being active to - // inactive. - GetWebContentsData(contents)->SetLastInactiveTime(NowTicks()); +void TabManager::set_minimum_protection_time_for_tests( + base::TimeDelta minimum_protection_time) { + minimum_protection_time_ = minimum_protection_time; +} + +bool TabManager::IsTabAutoDiscardable(content::WebContents* contents) const { + return GetWebContentsData(contents)->IsAutoDiscardable(); +} + +void TabManager::SetTabAutoDiscardableState(content::WebContents* contents, + bool state) { + GetWebContentsData(contents)->SetAutoDiscardableState(state); +} + +// static +bool TabManager::CompareTabStats(const TabStats& first, + const TabStats& second) { + // Being currently selected is most important to protect. + if (first.is_selected != second.is_selected) + return first.is_selected; + + // Non auto-discardable tabs are more important to protect. + if (first.is_auto_discardable != second.is_auto_discardable) + return !first.is_auto_discardable; + + // Protect tabs with pending form entries. + if (first.has_form_entry != second.has_form_entry) + return first.has_form_entry; + + // Protect streaming audio and video conferencing tabs as these are similar to + // active tabs. + if (first.is_media != second.is_media) + return first.is_media; + + // Tab with internal web UI like NTP or Settings are good choices to discard, + // so protect non-Web UI and let the other conditionals finish the sort. + if (first.is_internal_page != second.is_internal_page) + return !first.is_internal_page; + + // Being pinned is important to protect. + if (first.is_pinned != second.is_pinned) + return first.is_pinned; + + // Being an app is important too, as it's the only visible surface in the + // window and should not be discarded. + if (first.is_app != second.is_app) + return first.is_app; + + // TODO(jamescook): Incorporate sudden_termination_allowed into the sort + // order. This is currently not done because pages with unload handlers set + // sudden_termination_allowed false, and that covers too many common pages + // with ad networks and statistics scripts. Ideally check for beforeUnload + // handlers, which are likely to present a dialog asking if the user wants to + // discard state. crbug.com/123049. + + // Being more recently active is more important. + return first.last_active > second.last_active; } /////////////////////////////////////////////////////////////////////////////// // TabManager, private: +void TabManager::OnDiscardedStateChange(content::WebContents* contents, + bool is_discarded) { + FOR_EACH_OBSERVER(TabManagerObserver, observers_, + OnDiscardedStateChange(contents, is_discarded)); +} + +void TabManager::OnAutoDiscardableStateChange(content::WebContents* contents, + bool is_auto_discardable) { + FOR_EACH_OBSERVER( + TabManagerObserver, observers_, + OnAutoDiscardableStateChange(contents, is_auto_discardable)); +} + // static void TabManager::PurgeMemoryAndDiscardTab() { if (g_browser_process && g_browser_process->GetTabManager()) { @@ -488,8 +612,7 @@ if (!contents->IsCrashed()) { TabStats stats; stats.is_app = is_app; - stats.is_internal_page = - IsInternalPage(contents->GetLastCommittedURL()); + stats.is_internal_page = IsInternalPage(contents->GetLastCommittedURL()); stats.is_media = IsMediaTab(contents); stats.is_pinned = model->IsTabPinned(i); stats.is_selected = active_model && model->IsTabSelected(i); @@ -575,62 +698,6 @@ } } -bool TabManager::CanDiscardTab(int64_t target_web_contents_id) const { - TabStripModel* model; - int idx = FindTabStripModelById(target_web_contents_id, &model); - - if (idx == -1) - return false; - - WebContents* web_contents = model->GetWebContentsAt(idx); - - // Do not discard tabs that don't have a valid URL (most probably they have - // just been opened and dicarding them would lose the URL). - // TODO(georgesak): Look into a workaround to be able to kill the tab without - // losing the pending navigation. - if (!web_contents->GetLastCommittedURL().is_valid() || - web_contents->GetLastCommittedURL().is_empty()) { - return false; - } - - // Do not discard tabs in which the user has entered text in a form, lest that - // state gets lost. - if (web_contents->GetPageImportanceSignals().had_form_interaction) - return false; - - // Do not discard tabs that are playing either playing audio or accessing the - // microphone or camera as it's too distruptive to the user experience. Note - // that tabs that have recently stopped playing audio by at least - // |kAudioProtectionTimeSeconds| seconds are protected as well. - if (IsMediaTab(web_contents)) - return false; - - // Do not discard PDFs as they might contain entry that is not saved and they - // don't remember their scrolling positions. See crbug.com/547286 and - // crbug.com/65244. - // TODO(georgesak): Remove this workaround when the bugs are fixed. - if (web_contents->GetContentsMimeType() == "application/pdf") - return false; - - // Do not discard a previously discarded tab if that's the desired behavior. - if (discard_once_ && GetWebContentsData(web_contents)->DiscardCount() > 0) - return false; - - // Do not discard a recently used tab. - if (minimum_protection_time_.InSeconds() > 0) { - auto delta = - NowTicks() - GetWebContentsData(web_contents)->LastInactiveTime(); - if (delta < minimum_protection_time_) - return false; - } - - // Do not discard a tab that was explicitly disallowed to. - if (!IsTabAutoDiscardable(web_contents)) - return false; - - return true; -} - WebContents* TabManager::DiscardWebContentsAt(int index, TabStripModel* model) { // Can't discard active index. if (model->active_index() == index) @@ -709,6 +776,44 @@ #endif } +void TabManager::TabChangedAt(content::WebContents* contents, + int index, + TabChangeType change_type) { + if (change_type != TabChangeType::ALL) + return; + auto* data = GetWebContentsData(contents); + bool old_state = data->IsRecentlyAudible(); + bool current_state = contents->WasRecentlyAudible(); + if (old_state != current_state) { + data->SetRecentlyAudible(current_state); + data->SetLastAudioChangeTime(NowTicks()); + } +} + +void TabManager::ActiveTabChanged(content::WebContents* old_contents, + content::WebContents* new_contents, + int index, + int reason) { + GetWebContentsData(new_contents)->SetDiscardState(false); + // If |old_contents| is set, that tab has switched from being active to + // inactive, so record the time of that transition. + if (old_contents) + GetWebContentsData(old_contents)->SetLastInactiveTime(NowTicks()); +} + +void TabManager::TabInsertedAt(content::WebContents* contents, + int index, + bool foreground) { + // Only interested in background tabs, as foreground tabs get taken care of by + // ActiveTabChanged. + if (foreground) + return; + + // A new background tab is similar to having a tab switch from being active to + // inactive. + GetWebContentsData(contents)->SetLastInactiveTime(NowTicks()); +} + bool TabManager::IsMediaTab(WebContents* contents) const { if (contents->WasRecentlyAudible()) return true; @@ -733,51 +838,6 @@ return web_contents_data; } -// static -bool TabManager::CompareTabStats(const TabStats& first, - const TabStats& second) { - // Being currently selected is most important to protect. - if (first.is_selected != second.is_selected) - return first.is_selected; - - // Non auto-discardable tabs are more important to protect. - if (first.is_auto_discardable != second.is_auto_discardable) - return !first.is_auto_discardable; - - // Protect tabs with pending form entries. - if (first.has_form_entry != second.has_form_entry) - return first.has_form_entry; - - // Protect streaming audio and video conferencing tabs as these are similar to - // active tabs. - if (first.is_media != second.is_media) - return first.is_media; - - // Tab with internal web UI like NTP or Settings are good choices to discard, - // so protect non-Web UI and let the other conditionals finish the sort. - if (first.is_internal_page != second.is_internal_page) - return !first.is_internal_page; - - // Being pinned is important to protect. - if (first.is_pinned != second.is_pinned) - return first.is_pinned; - - // Being an app is important too, as it's the only visible surface in the - // window and should not be discarded. - if (first.is_app != second.is_app) - return first.is_app; - - // TODO(jamescook): Incorporate sudden_termination_allowed into the sort - // order. This is currently not done because pages with unload handlers set - // sudden_termination_allowed false, and that covers too many common pages - // with ad networks and statistics scripts. Ideally check for beforeUnload - // handlers, which are likely to present a dialog asking if the user wants to - // discard state. crbug.com/123049. - - // Being more recently active is more important. - return first.last_active > second.last_active; -} - TimeTicks TabManager::NowTicks() const { if (!test_tick_clock_) return TimeTicks::Now(); @@ -884,65 +944,4 @@ #endif } -// Things to collect on the browser thread (because TabStripModel isn't thread -// safe): -// 1) whether or not a tab is pinned -// 2) last time a tab was selected -// 3) is the tab currently selected -TabStatsList TabManager::GetUnsortedTabStats() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - TabStatsList stats_list; - stats_list.reserve(32); // 99% of users have < 30 tabs open. - - // TODO(chrisha): Move this code to a TabStripModel enumeration delegate! - if (!test_tab_strip_models_.empty()) { - for (size_t i = 0; i < test_tab_strip_models_.size(); ++i) { - AddTabStats(test_tab_strip_models_[i].first, // tab_strip_model - test_tab_strip_models_[i].second, // is_app - i == 0, // is_active - &stats_list); - } - } else { - // The code here can only be tested under a full browser test. - AddTabStats(&stats_list); - } - - return stats_list; -} - -void TabManager::AddObserver(TabManagerObserver* observer) { - observers_.AddObserver(observer); -} - -void TabManager::RemoveObserver(TabManagerObserver* observer) { - observers_.RemoveObserver(observer); -} - -void TabManager::OnDiscardedStateChange(content::WebContents* contents, - bool is_discarded) { - FOR_EACH_OBSERVER(TabManagerObserver, observers_, - OnDiscardedStateChange(contents, is_discarded)); -} - -void TabManager::set_minimum_protection_time_for_tests( - base::TimeDelta minimum_protection_time) { - minimum_protection_time_ = minimum_protection_time; -} - -void TabManager::OnAutoDiscardableStateChange(content::WebContents* contents, - bool is_auto_discardable) { - FOR_EACH_OBSERVER( - TabManagerObserver, observers_, - OnAutoDiscardableStateChange(contents, is_auto_discardable)); -} - -bool TabManager::IsTabAutoDiscardable(content::WebContents* contents) const { - return GetWebContentsData(contents)->IsAutoDiscardable(); -} - -void TabManager::SetTabAutoDiscardableState(content::WebContents* contents, - bool state) { - GetWebContentsData(contents)->SetAutoDiscardableState(state); -} - } // namespace memory
diff --git a/chrome/browser/metrics/metrics_service_browsertest.cc b/chrome/browser/metrics/metrics_service_browsertest.cc index 740f6ba7..9f329da 100644 --- a/chrome/browser/metrics/metrics_service_browsertest.cc +++ b/chrome/browser/metrics/metrics_service_browsertest.cc
@@ -60,7 +60,14 @@ } }; -IN_PROC_BROWSER_TEST_F(MetricsServiceBrowserTest, CloseRenderersNormally) { +// Flaky failing DCHECK on Windows, see crbug.com/636052 +#if defined(OS_WIN) +#define MAYBE_CloseRenderersNormally DISABLED_CloseRenderersNormally +#else +#define MAYBE_CloseRenderersNormally CloseRenderersNormally +#endif +IN_PROC_BROWSER_TEST_F(MetricsServiceBrowserTest, + MAYBE_CloseRenderersNormally) { OpenTabs(); // Verify that the expected stability metrics were recorded.
diff --git a/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc b/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc index 942343b..9d30964 100644 --- a/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc +++ b/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
@@ -66,6 +66,17 @@ using suggestions::SuggestionsService; using suggestions::SuggestionsServiceFactory; +namespace { + +// Clear the tasks that can be scheduled by running services. +void ClearScheduledTasks() { +#if defined(OS_ANDROID) + NTPSnippetsLauncher::Get()->Unschedule(); +#endif // OS_ANDROID +} + +} // namespace + // static ContentSuggestionsServiceFactory* ContentSuggestionsServiceFactory::GetInstance() { @@ -106,13 +117,17 @@ ? State::ENABLED : State::DISABLED; ContentSuggestionsService* service = new ContentSuggestionsService(state); - if (state == State::DISABLED) + if (state == State::DISABLED) { + // Since we won't initialise the services, they won't get a chance to + // unschedule their tasks. We do it explicitly here instead. + ClearScheduledTasks(); return service; + } #if defined(OS_ANDROID) // Create the OfflinePageSuggestionsProvider. if (base::FeatureList::IsEnabled( - chrome::android::kNTPOfflinePageSuggestionsFeature)) { + ntp_snippets::kOfflinePageSuggestionsFeature)) { OfflinePageModel* offline_page_model = OfflinePageModelFactory::GetForBrowserContext(profile); @@ -135,44 +150,48 @@ service->RegisterProvider(std::move(bookmark_suggestions_provider)); } - // Create the NTPSnippetsService (articles provider). - SigninManagerBase* signin_manager = - SigninManagerFactory::GetForProfile(profile); - OAuth2TokenService* token_service = - ProfileOAuth2TokenServiceFactory::GetForProfile(profile); - scoped_refptr<net::URLRequestContextGetter> request_context = - content::BrowserContext::GetDefaultStoragePartition(context) - ->GetURLRequestContext(); - SuggestionsService* suggestions_service = - SuggestionsServiceFactory::GetForProfile(profile); - NTPSnippetsScheduler* scheduler = nullptr; + if (base::FeatureList::IsEnabled(ntp_snippets::kArticleSuggestionsFeature)) { + // Create the NTPSnippetsService (articles provider). + SigninManagerBase* signin_manager = + SigninManagerFactory::GetForProfile(profile); + OAuth2TokenService* token_service = + ProfileOAuth2TokenServiceFactory::GetForProfile(profile); + scoped_refptr<net::URLRequestContextGetter> request_context = + content::BrowserContext::GetDefaultStoragePartition(context) + ->GetURLRequestContext(); + SuggestionsService* suggestions_service = + SuggestionsServiceFactory::GetForProfile(profile); + NTPSnippetsScheduler* scheduler = nullptr; #if defined(OS_ANDROID) - scheduler = NTPSnippetsLauncher::Get(); + scheduler = NTPSnippetsLauncher::Get(); #endif // OS_ANDROID - base::FilePath database_dir( - profile->GetPath().Append(ntp_snippets::kDatabaseFolder)); - scoped_refptr<base::SequencedTaskRunner> task_runner = - BrowserThread::GetBlockingPool() - ->GetSequencedTaskRunnerWithShutdownBehavior( - base::SequencedWorkerPool::GetSequenceToken(), - base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN); - std::unique_ptr<NTPSnippetsService> ntp_snippets_service = - base::MakeUnique<NTPSnippetsService>( - service, service->category_factory(), profile->GetPrefs(), - suggestions_service, g_browser_process->GetApplicationLocale(), - scheduler, base::MakeUnique<NTPSnippetsFetcher>( - signin_manager, token_service, request_context, - profile->GetPrefs(), - base::Bind(&safe_json::SafeJsonParser::Parse), - chrome::GetChannel() == version_info::Channel::STABLE), - base::MakeUnique<ImageFetcherImpl>( - base::MakeUnique<ImageDecoderImpl>(), request_context.get()), - base::MakeUnique<ImageDecoderImpl>(), - base::MakeUnique<NTPSnippetsDatabase>(database_dir, task_runner), - base::MakeUnique<NTPSnippetsStatusService>(signin_manager, - profile->GetPrefs())); - service->set_ntp_snippets_service(ntp_snippets_service.get()); - service->RegisterProvider(std::move(ntp_snippets_service)); + base::FilePath database_dir( + profile->GetPath().Append(ntp_snippets::kDatabaseFolder)); + scoped_refptr<base::SequencedTaskRunner> task_runner = + BrowserThread::GetBlockingPool() + ->GetSequencedTaskRunnerWithShutdownBehavior( + base::SequencedWorkerPool::GetSequenceToken(), + base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN); + bool is_stable_channel = + chrome::GetChannel() == version_info::Channel::STABLE; + std::unique_ptr<NTPSnippetsService> ntp_snippets_service = + base::MakeUnique<NTPSnippetsService>( + service, service->category_factory(), profile->GetPrefs(), + suggestions_service, g_browser_process->GetApplicationLocale(), + scheduler, base::MakeUnique<NTPSnippetsFetcher>( + signin_manager, token_service, request_context, + profile->GetPrefs(), + base::Bind(&safe_json::SafeJsonParser::Parse), + is_stable_channel), + base::MakeUnique<ImageFetcherImpl>( + base::MakeUnique<ImageDecoderImpl>(), request_context.get()), + base::MakeUnique<ImageDecoderImpl>(), + base::MakeUnique<NTPSnippetsDatabase>(database_dir, task_runner), + base::MakeUnique<NTPSnippetsStatusService>(signin_manager, + profile->GetPrefs())); + service->set_ntp_snippets_service(ntp_snippets_service.get()); + service->RegisterProvider(std::move(ntp_snippets_service)); + } return service; }
diff --git a/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc b/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc index f34a995..30106cd9 100644 --- a/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc +++ b/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc
@@ -259,6 +259,8 @@ abort_type_(ABORT_NONE), started_in_foreground_(in_foreground), page_transition_(navigation_handle->GetPageTransition()), + num_cache_requests_(0), + num_network_requests_(0), aborted_chain_size_(aborted_chain_size), aborted_chain_size_same_url_(aborted_chain_size_same_url), embedder_interface_(embedder_interface) { @@ -478,6 +480,14 @@ return false; } +void PageLoadTracker::OnLoadedSubresource(bool was_cached) { + if (was_cached) { + ++num_cache_requests_; + } else { + ++num_network_requests_; + } +} + void PageLoadTracker::StopTracking() { did_stop_tracking_ = true; } @@ -545,7 +555,7 @@ return PageLoadExtraInfo( first_background_time, first_foreground_time, started_in_foreground_, commit_time_.is_null() ? GURL() : url_, time_to_commit, abort_type_, - time_to_abort, metadata_); + time_to_abort, num_cache_requests_, num_network_requests_, metadata_); } void PageLoadTracker::NotifyAbort(UserAbortType abort_type, @@ -732,6 +742,22 @@ navigation_handle, chain_size, chain_size_same_url)))); } +void MetricsWebContentsObserver::OnRequestComplete( + content::ResourceType resource_type, + bool was_cached, + int net_error) { + // For simplicity, only count subresources. Navigations are hard to attribute + // here because we won't have a committed load by the time data streams in + // from the IO thread. + if (resource_type == content::RESOURCE_TYPE_MAIN_FRAME && + net_error != net::OK) { + return; + } + if (!committed_load_) + return; + committed_load_->OnLoadedSubresource(was_cached); +} + const PageLoadExtraInfo MetricsWebContentsObserver::GetPageLoadExtraInfoForCommittedLoad() { DCHECK(committed_load_);
diff --git a/chrome/browser/page_load_metrics/metrics_web_contents_observer.h b/chrome/browser/page_load_metrics/metrics_web_contents_observer.h index 89c92b8a..f610a277 100644 --- a/chrome/browser/page_load_metrics/metrics_web_contents_observer.h +++ b/chrome/browser/page_load_metrics/metrics_web_contents_observer.h
@@ -17,6 +17,7 @@ #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_user_data.h" +#include "content/public/common/resource_type.h" #include "net/base/net_errors.h" #include "third_party/WebKit/public/web/WebInputEvent.h" @@ -156,6 +157,8 @@ bool UpdateTiming(const PageLoadTiming& timing, const PageLoadMetadata& metadata); + void OnLoadedSubresource(bool was_cached); + // Signals that we should stop tracking metrics for the associated page load. // We may stop tracking a page load if it doesn't meet the criteria for // tracking metrics in DidFinishNavigation. @@ -263,6 +266,12 @@ ui::PageTransition page_transition_; + // Note: these are only approximations, based on WebContents attribution from + // ResourceRequestInfo objects while this is the currently committed load in + // the WebContents. + int num_cache_requests_; + int num_network_requests_; + // This is a subtle member. If a provisional load A gets aborted by // provisional load B, which gets aborted by C that eventually commits, then // there exists an abort chain of length 2, starting at A's navigation_start. @@ -318,6 +327,11 @@ // This method is forwarded from the MetricsNavigationThrottle. void WillStartNavigationRequest(content::NavigationHandle* navigation_handle); + // A resource request completed on the IO thread. + void OnRequestComplete(content::ResourceType resource_type, + bool was_cached, + int net_error); + // Flush any buffered metrics, as part of the metrics subsystem persisting // metrics as the application goes into the background. The application may be // killed at any time after this method is invoked without further
diff --git a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc index cc5c8d9..7915a4d 100644 --- a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc
@@ -168,6 +168,13 @@ const char kHistogramForegroundToFirstPaint[] = "PageLoad.PaintTiming.ForegroundToFirstPaint"; +const char kHistogramCacheRequestPercentParseStop[] = + "PageLoad.Experimental.Cache.RequestPercent.ParseStop"; +const char kHistogramCacheTotalRequestsParseStop[] = + "PageLoad.Experimental.Cache.TotalRequests.ParseStop"; +const char kHistogramTotalRequestsParseStop[] = + "PageLoad.Experimental.TotalRequests.ParseStop"; + const char kRapporMetricsNameCoarseTiming[] = "PageLoad.CoarseTiming.NavigationToFirstContentfulPaint"; @@ -389,6 +396,18 @@ internal::kHistogramParseBlockedOnScriptLoadDocumentWrite, timing.parse_blocked_on_script_load_from_document_write_duration .value()); + + int total_requests = info.num_cache_requests + info.num_network_requests; + if (total_requests) { + UMA_HISTOGRAM_PERCENTAGE( + internal::kHistogramCacheRequestPercentParseStop, + (100 * info.num_cache_requests) / total_requests); + UMA_HISTOGRAM_COUNTS(internal::kHistogramCacheTotalRequestsParseStop, + info.num_cache_requests); + UMA_HISTOGRAM_COUNTS(internal::kHistogramTotalRequestsParseStop, + info.num_cache_requests + info.num_network_requests); + } + } else { PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramParseDuration, parse_duration);
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/page_load_metrics_observer.cc index 56df768..2fa1895 100644 --- a/chrome/browser/page_load_metrics/page_load_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/page_load_metrics_observer.cc
@@ -14,6 +14,8 @@ const base::Optional<base::TimeDelta>& time_to_commit, UserAbortType abort_type, const base::Optional<base::TimeDelta>& time_to_abort, + int num_cache_requests, + int num_network_requests, const PageLoadMetadata& metadata) : first_background_time(first_background_time), first_foreground_time(first_foreground_time), @@ -22,6 +24,8 @@ time_to_commit(time_to_commit), abort_type(abort_type), time_to_abort(time_to_abort), + num_cache_requests(num_cache_requests), + num_network_requests(num_network_requests), metadata(metadata) {} PageLoadExtraInfo::PageLoadExtraInfo(const PageLoadExtraInfo& other) = default;
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_observer.h b/chrome/browser/page_load_metrics/page_load_metrics_observer.h index 52e28264..af8d1971 100644 --- a/chrome/browser/page_load_metrics/page_load_metrics_observer.h +++ b/chrome/browser/page_load_metrics/page_load_metrics_observer.h
@@ -69,6 +69,8 @@ const base::Optional<base::TimeDelta>& time_to_commit, UserAbortType abort_type, const base::Optional<base::TimeDelta>& time_to_abort, + int num_cache_requests, + int num_network_requests, const PageLoadMetadata& metadata); PageLoadExtraInfo(const PageLoadExtraInfo& other); @@ -97,6 +99,12 @@ const base::Optional<base::TimeDelta> time_to_abort; + // Note: these are only approximations, based on WebContents attribution from + // ResourceRequestInfo objects while this is the currently committed load in + // the WebContents. + int num_cache_requests; + int num_network_requests; + // Extra information supplied to the page load metrics system from the // renderer. const PageLoadMetadata metadata;
diff --git a/chrome/browser/permissions/permission_context_base.cc b/chrome/browser/permissions/permission_context_base.cc index 8ce7f18..c89c601 100644 --- a/chrome/browser/permissions/permission_context_base.cc +++ b/chrome/browser/permissions/permission_context_base.cc
@@ -7,10 +7,12 @@ #include <stddef.h> #include <utility> +#include "base/callback.h" #include "base/logging.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" +#include "chrome/browser/permissions/permission_decision_auto_blocker.h" #include "chrome/browser/permissions/permission_request.h" #include "chrome/browser/permissions/permission_request_id.h" #include "chrome/browser/permissions/permission_uma_util.h" @@ -25,6 +27,7 @@ #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" #include "content/public/common/origin_util.h" +#include "url/gurl.h" #if defined(OS_ANDROID) #include "chrome/browser/permissions/permission_queue_controller.h" @@ -45,6 +48,7 @@ const content::PermissionType permission_type, const ContentSettingsType content_settings_type) : profile_(profile), + decision_auto_blocker_(new PermissionDecisionAutoBlocker(profile)), permission_type_(permission_type), content_settings_type_(content_settings_type), weak_factory_(this) { @@ -233,6 +237,15 @@ } #endif + // Check if we should convert a dismiss decision into a block decision. This + // is gated on enabling the kBlockPromptsIfDismissedOften feature. + if (!persist && + decision_auto_blocker_->ShouldChangeDismissalToBlock(requesting_origin, + permission_type_)) { + persist = true; + content_setting = CONTENT_SETTING_BLOCK; + } + NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, persist, content_setting); }
diff --git a/chrome/browser/permissions/permission_context_base.h b/chrome/browser/permissions/permission_context_base.h index 2ab7b7bb..f591746 100644 --- a/chrome/browser/permissions/permission_context_base.h +++ b/chrome/browser/permissions/permission_context_base.h
@@ -7,9 +7,8 @@ #include <memory> -#include "base/callback.h" +#include "base/callback_forward.h" #include "base/containers/scoped_ptr_hash_map.h" -#include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "build/build_config.h" #include "chrome/browser/permissions/permission_request.h" @@ -17,11 +16,12 @@ #include "components/content_settings/core/common/content_settings_types.h" #include "components/keyed_service/core/keyed_service.h" #include "content/public/browser/permission_type.h" -#include "url/gurl.h" #if defined(OS_ANDROID) class PermissionQueueController; #endif +class GURL; +class PermissionDecisionAutoBlocker; class PermissionRequestID; class Profile; @@ -157,10 +157,13 @@ } private: + friend class PermissionContextBaseTests; + // Called when a request is no longer used so it can be cleaned up. void CleanUpRequest(const PermissionRequestID& id); Profile* profile_; + std::unique_ptr<PermissionDecisionAutoBlocker> decision_auto_blocker_; const content::PermissionType permission_type_; const ContentSettingsType content_settings_type_; #if defined(OS_ANDROID)
diff --git a/chrome/browser/permissions/permission_context_base_unittest.cc b/chrome/browser/permissions/permission_context_base_unittest.cc index fb5b4c89..2225cad 100644 --- a/chrome/browser/permissions/permission_context_base_unittest.cc +++ b/chrome/browser/permissions/permission_context_base_unittest.cc
@@ -8,15 +8,19 @@ #include "base/bind.h" #include "base/command_line.h" +#include "base/feature_list.h" #include "base/macros.h" #include "base/metrics/field_trial.h" +#include "base/test/histogram_tester.h" #include "base/test/mock_entropy_provider.h" #include "build/build_config.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/infobars/infobar_service.h" +#include "chrome/browser/permissions/permission_decision_auto_blocker.h" #include "chrome/browser/permissions/permission_queue_controller.h" #include "chrome/browser/permissions/permission_request_id.h" #include "chrome/browser/permissions/permission_util.h" +#include "chrome/common/chrome_features.h" #include "chrome/common/chrome_switches.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "chrome/test/base/testing_profile.h" @@ -41,6 +45,8 @@ const char* kPermissionsKillSwitchBlockedValue = PermissionContextBase::kPermissionsKillSwitchBlockedValue; const char kPermissionsKillSwitchTestGroup[] = "TestGroup"; +const char* kPromptGroupName = kPermissionsKillSwitchTestGroup; +const char kPromptTrialName[] = "PermissionPromptsUX"; class TestPermissionContext : public PermissionContextBase { public: @@ -48,9 +54,7 @@ const content::PermissionType permission_type, const ContentSettingsType content_settings_type) : PermissionContextBase(profile, permission_type, content_settings_type), - tab_context_updated_(false), - field_trial_list_( - new base::FieldTrialList(new base::MockEntropyProvider)) {} + tab_context_updated_(false) {} ~TestPermissionContext() override {} @@ -70,15 +74,6 @@ decisions_.push_back(content_setting); } - void ResetFieldTrialList() { - // Destroy the existing FieldTrialList before creating a new one to avoid - // a DCHECK. - field_trial_list_.reset(); - field_trial_list_.reset(new base::FieldTrialList( - new base::MockEntropyProvider)); - variations::testing::ClearAllVariationParams(); - } - ContentSetting GetContentSettingFromMap(const GURL& url_a, const GURL& url_b) { return HostContentSettingsMapFactory::GetForProfile(profile()) @@ -100,6 +95,28 @@ private: std::vector<ContentSetting> decisions_; bool tab_context_updated_; +}; + +class TestKillSwitchPermissionContext : public TestPermissionContext { + public: + TestKillSwitchPermissionContext( + Profile* profile, + const content::PermissionType permission_type, + const ContentSettingsType content_settings_type) + : TestPermissionContext(profile, permission_type, content_settings_type), + field_trial_list_( + new base::FieldTrialList(new base::MockEntropyProvider)) {} + + void ResetFieldTrialList() { + // Destroy the existing FieldTrialList before creating a new one to avoid + // a DCHECK. + field_trial_list_.reset(); + field_trial_list_.reset(new base::FieldTrialList( + new base::MockEntropyProvider)); + variations::testing::ClearAllVariationParams(); + } + + private: std::unique_ptr<base::FieldTrialList> field_trial_list_; }; @@ -190,6 +207,172 @@ permission_context.GetContentSettingFromMap(url, url)); } + void DismissMultipleTimesAndExpectBlock( + const GURL& url, + content::PermissionType permission_type, + ContentSettingsType content_settings_type, + uint32_t iterations) { + base::HistogramTester histograms; + + // Dismiss |iterations| times. The final dismiss should change the decision + // from dismiss to block, and hence change the persisted content setting. + for (uint32_t i = 0; i < iterations; ++i) { + TestPermissionContext permission_context( + profile(), permission_type, content_settings_type); + ContentSetting expected = + (i < (iterations - 1)) ? CONTENT_SETTING_ASK : CONTENT_SETTING_BLOCK; + + const PermissionRequestID id( + web_contents()->GetRenderProcessHost()->GetID(), + web_contents()->GetMainFrame()->GetRoutingID(), i); + permission_context.RequestPermission( + web_contents(), id, url, true /* user_gesture */, + base::Bind(&TestPermissionContext::TrackPermissionDecision, + base::Unretained(&permission_context))); + + RespondToPermission(&permission_context, id, url, CONTENT_SETTING_ASK); + histograms.ExpectTotalCount( + "Permissions.Prompt.DismissCount." + + PermissionUtil::GetPermissionString(permission_type), + i + 1); + + EXPECT_EQ(1u, permission_context.decisions().size()); + EXPECT_EQ(expected, permission_context.decisions()[0]); + EXPECT_TRUE(permission_context.tab_context_updated()); + EXPECT_EQ(expected, + permission_context.GetContentSettingFromMap(url, url)); + } + + // Ensure that we finish in the block state. + TestPermissionContext permission_context( + profile(), permission_type, content_settings_type); + EXPECT_EQ(CONTENT_SETTING_BLOCK, + permission_context.GetContentSettingFromMap(url, url)); + } + + void TestBlockOnSeveralDismissals_TestContent() { + GURL url("https://www.google.com"); + NavigateAndCommit(url); + base::HistogramTester histograms; + + // First, ensure that > 3 dismissals behaves correctly. + for (uint32_t i = 0; i < 4; ++i) { + TestPermissionContext permission_context( + profile(), content::PermissionType::GEOLOCATION, + CONTENT_SETTINGS_TYPE_GEOLOCATION); + + const PermissionRequestID id( + web_contents()->GetRenderProcessHost()->GetID(), + web_contents()->GetMainFrame()->GetRoutingID(), i); + permission_context.RequestPermission( + web_contents(), id, url, true /* user_gesture */, + base::Bind(&TestPermissionContext::TrackPermissionDecision, + base::Unretained(&permission_context))); + + RespondToPermission(&permission_context, id, url, CONTENT_SETTING_ASK); + histograms.ExpectTotalCount("Permissions.Prompt.DismissCount.Geolocation", + i + 1); + EXPECT_EQ(1u, permission_context.decisions().size()); + EXPECT_EQ(CONTENT_SETTING_ASK, permission_context.decisions()[0]); + EXPECT_TRUE(permission_context.tab_context_updated()); + EXPECT_EQ(CONTENT_SETTING_ASK, + permission_context.GetContentSettingFromMap(url, url)); + } + + // Flush the dismissal counts. Enable the block on too many dismissals + // feature, which is disabled by default. + HostContentSettingsMapFactory::GetForProfile(profile()) + ->ClearSettingsForOneType( + CONTENT_SETTINGS_TYPE_PROMPT_NO_DECISION_COUNT); + + // Set up the custom parameter. + base::FieldTrialList field_trials_(nullptr); + base::FieldTrial* trial = base::FieldTrialList::CreateFieldTrial( + kPromptTrialName, kPromptGroupName); + base::FeatureList::ClearInstanceForTesting(); + std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList); + feature_list->RegisterFieldTrialOverride( + features::kBlockPromptsIfDismissedOften.name, + base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial); + base::FeatureList::SetInstance(std::move(feature_list)); + EXPECT_EQ(base::FeatureList::GetFieldTrial( + features::kBlockPromptsIfDismissedOften), + trial); + + EXPECT_TRUE( + base::FeatureList::IsEnabled(features::kBlockPromptsIfDismissedOften)); + + // Sanity check independence per permission type by checking two of them. + DismissMultipleTimesAndExpectBlock(url, + content::PermissionType::GEOLOCATION, + CONTENT_SETTINGS_TYPE_GEOLOCATION, 3); + DismissMultipleTimesAndExpectBlock(url, + content::PermissionType::NOTIFICATIONS, + CONTENT_SETTINGS_TYPE_NOTIFICATIONS, 3); + base::FeatureList::ClearInstanceForTesting(); + } + + void TestVariationBlockOnSeveralDismissals_TestContent() { + GURL url("https://www.google.com"); + NavigateAndCommit(url); + + // Set up the custom parameter and custom value. + base::FieldTrialList field_trials_(nullptr); + base::FieldTrial* trial = base::FieldTrialList::CreateFieldTrial( + kPromptTrialName, kPromptGroupName); + std::map<std::string, std::string> params; + params[PermissionDecisionAutoBlocker::kPromptDismissCountKey] = "5"; + ASSERT_TRUE(variations::AssociateVariationParams( + kPromptTrialName, kPromptGroupName, params)); + + base::FeatureList::ClearInstanceForTesting(); + std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList); + feature_list->RegisterFieldTrialOverride( + features::kBlockPromptsIfDismissedOften.name, + base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial); + base::FeatureList::SetInstance(std::move(feature_list)); + EXPECT_EQ(base::FeatureList::GetFieldTrial( + features::kBlockPromptsIfDismissedOften), + trial); + + std::map<std::string, std::string> actualParams; + EXPECT_TRUE(variations::GetVariationParamsByFeature( + features::kBlockPromptsIfDismissedOften, &actualParams)); + EXPECT_EQ(params, actualParams); + + for (uint32_t i = 0; i < 5; ++i) { + TestPermissionContext permission_context( + profile(), content::PermissionType::MIDI_SYSEX, + CONTENT_SETTINGS_TYPE_MIDI_SYSEX); + + ContentSetting expected = + (i < 4) ? CONTENT_SETTING_ASK : CONTENT_SETTING_BLOCK; + const PermissionRequestID id( + web_contents()->GetRenderProcessHost()->GetID(), + web_contents()->GetMainFrame()->GetRoutingID(), i); + permission_context.RequestPermission( + web_contents(), id, url, true /* user_gesture */, + base::Bind(&TestPermissionContext::TrackPermissionDecision, + base::Unretained(&permission_context))); + + RespondToPermission(&permission_context, id, url, CONTENT_SETTING_ASK); + EXPECT_EQ(1u, permission_context.decisions().size()); + EXPECT_EQ(expected, permission_context.decisions()[0]); + EXPECT_TRUE(permission_context.tab_context_updated()); + EXPECT_EQ(expected, + permission_context.GetContentSettingFromMap(url, url)); + } + + // Ensure that we finish in the block state. + TestPermissionContext permission_context( + profile(), content::PermissionType::MIDI_SYSEX, + CONTENT_SETTINGS_TYPE_MIDI_SYSEX); + EXPECT_EQ(CONTENT_SETTING_BLOCK, + permission_context.GetContentSettingFromMap(url, url)); + base::FeatureList::ClearInstanceForTesting(); + variations::testing::ClearAllVariationParams(); + } + void TestRequestPermissionInvalidUrl( content::PermissionType permission_type, ContentSettingsType content_settings_type) { @@ -254,8 +437,8 @@ void TestGlobalPermissionsKillSwitch( content::PermissionType permission_type, ContentSettingsType content_settings_type) { - TestPermissionContext permission_context(profile(), permission_type, - content_settings_type); + TestKillSwitchPermissionContext permission_context( + profile(), permission_type, content_settings_type); permission_context.ResetFieldTrialList(); EXPECT_FALSE(permission_context.IsPermissionKillSwitchOn()); @@ -333,6 +516,18 @@ TestAskAndDismiss_TestContent(); } +// Simulates clicking Dismiss (X) in the infobar/bubble with the block on too +// many dismissals feature active. The permission should be blocked after +// several dismissals. +TEST_F(PermissionContextBaseTests, TestDismissUntilBlocked) { + TestBlockOnSeveralDismissals_TestContent(); +} + +// Test setting a custom number of dismissals before block via variations. +TEST_F(PermissionContextBaseTests, TestDismissVariations) { + TestVariationBlockOnSeveralDismissals_TestContent(); +} + // Simulates non-valid requesting URL. // The permission should be denied but not saved for future use. TEST_F(PermissionContextBaseTests, TestNonValidRequestingUrl) {
diff --git a/chrome/browser/permissions/permission_decision_auto_blocker.cc b/chrome/browser/permissions/permission_decision_auto_blocker.cc new file mode 100644 index 0000000..12e7170 --- /dev/null +++ b/chrome/browser/permissions/permission_decision_auto_blocker.cc
@@ -0,0 +1,168 @@ +// 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 "chrome/browser/permissions/permission_decision_auto_blocker.h" + +#include <memory> + +#include "base/feature_list.h" +#include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "base/strings/string_number_conversions.h" +#include "base/values.h" +#include "chrome/browser/content_settings/host_content_settings_map_factory.h" +#include "chrome/browser/permissions/permission_uma_util.h" +#include "chrome/browser/permissions/permission_util.h" +#include "chrome/common/chrome_features.h" +#include "components/content_settings/core/browser/host_content_settings_map.h" +#include "components/variations/variations_associated_data.h" +#include "content/public/browser/permission_type.h" +#include "url/gurl.h" + +namespace { + +// The default number of times that users may explicitly dismiss a permission +// prompt from an origin before it is automatically blocked. +const int kPromptDismissalsBeforeBlock = 3; + +std::unique_ptr<base::DictionaryValue> GetOriginDict( + HostContentSettingsMap* settings, + const GURL& origin_url) { + std::unique_ptr<base::DictionaryValue> dict = + base::DictionaryValue::From(settings->GetWebsiteSetting( + origin_url, origin_url, + CONTENT_SETTINGS_TYPE_PROMPT_NO_DECISION_COUNT, std::string(), + nullptr)); + if (!dict) + return base::WrapUnique(new base::DictionaryValue()); + + return dict; +} + +base::DictionaryValue* GetOrCreatePermissionDict( + base::DictionaryValue* origin_dict, + const std::string& permission) { + base::DictionaryValue* permission_dict = nullptr; + if (!origin_dict->GetDictionaryWithoutPathExpansion(permission, + &permission_dict)) { + permission_dict = new base::DictionaryValue(); + origin_dict->SetWithoutPathExpansion(permission, + base::WrapUnique(permission_dict)); + } + + return permission_dict; +} + +} // namespace + +// static +const char PermissionDecisionAutoBlocker::kPromptDismissCountKey[] = + "dismiss_count"; + +// static +const char PermissionDecisionAutoBlocker::kPromptIgnoreCountKey[] = + "ignore_count"; + +// static +void PermissionDecisionAutoBlocker::RemoveCountsByUrl( + Profile* profile, + base::Callback<bool(const GURL& url)> filter) { + HostContentSettingsMap* map = + HostContentSettingsMapFactory::GetForProfile(profile); + + std::unique_ptr<ContentSettingsForOneType> settings( + new ContentSettingsForOneType); + map->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_PROMPT_NO_DECISION_COUNT, + std::string(), settings.get()); + + for (const auto& site : *settings) { + GURL origin(site.primary_pattern.ToString()); + + if (origin.is_valid() && filter.Run(origin)) { + map->SetWebsiteSettingDefaultScope( + origin, GURL(), CONTENT_SETTINGS_TYPE_PROMPT_NO_DECISION_COUNT, + std::string(), nullptr); + } + } +} + +PermissionDecisionAutoBlocker::PermissionDecisionAutoBlocker(Profile* profile) + : profile_(profile), + prompt_dismissals_before_block_(kPromptDismissalsBeforeBlock) { + UpdateFromVariations(); +} + +int PermissionDecisionAutoBlocker::RecordIgnore( + const GURL& url, + content::PermissionType permission) { + int current_ignore_count = + RecordActionInWebsiteSettings(url, permission, kPromptIgnoreCountKey); + + PermissionUmaUtil::PermissionPromptIgnored(permission, current_ignore_count); + + return current_ignore_count; +} + +bool PermissionDecisionAutoBlocker::ShouldChangeDismissalToBlock( + const GURL& url, + content::PermissionType permission) { + int current_dismissal_count = + RecordActionInWebsiteSettings(url, permission, kPromptDismissCountKey); + + PermissionUmaUtil::PermissionPromptDismissed(permission, + current_dismissal_count); + + if (!base::FeatureList::IsEnabled(features::kBlockPromptsIfDismissedOften)) + return false; + + return current_dismissal_count >= prompt_dismissals_before_block_; +} + +int PermissionDecisionAutoBlocker::GetActionCountForTest( + const GURL& url, + content::PermissionType permission, + const char* key) { + HostContentSettingsMap* map = + HostContentSettingsMapFactory::GetForProfile(profile_); + std::unique_ptr<base::DictionaryValue> dict = GetOriginDict(map, url); + + base::DictionaryValue* permission_dict = GetOrCreatePermissionDict( + dict.get(), PermissionUtil::GetPermissionString(permission)); + + int current_count = 0; + permission_dict->GetInteger(key, ¤t_count); + return current_count; +} + +int PermissionDecisionAutoBlocker::RecordActionInWebsiteSettings( + const GURL& url, + content::PermissionType permission, + const char* key) { + HostContentSettingsMap* map = + HostContentSettingsMapFactory::GetForProfile(profile_); + std::unique_ptr<base::DictionaryValue> dict = GetOriginDict(map, url); + + base::DictionaryValue* permission_dict = GetOrCreatePermissionDict( + dict.get(), PermissionUtil::GetPermissionString(permission)); + + int current_count = 0; + permission_dict->GetInteger(key, ¤t_count); + permission_dict->SetInteger(key, ++current_count); + + map->SetWebsiteSettingDefaultScope( + url, GURL(), CONTENT_SETTINGS_TYPE_PROMPT_NO_DECISION_COUNT, + std::string(), std::move(dict)); + + return current_count; +} + +void PermissionDecisionAutoBlocker::UpdateFromVariations() { + int prompt_dismissals = -1; + std::string value = variations::GetVariationParamValueByFeature( + features::kBlockPromptsIfDismissedOften, kPromptDismissCountKey); + + // If converting the value fails, stick with the default value. + if (base::StringToInt(value, &prompt_dismissals) && prompt_dismissals > 0) + prompt_dismissals_before_block_ = prompt_dismissals; +}
diff --git a/chrome/browser/permissions/permission_decision_auto_blocker.h b/chrome/browser/permissions/permission_decision_auto_blocker.h new file mode 100644 index 0000000..997ac06 --- /dev/null +++ b/chrome/browser/permissions/permission_decision_auto_blocker.h
@@ -0,0 +1,61 @@ +// 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 CHROME_BROWSER_PERMISSIONS_PERMISSION_DECISION_AUTO_BLOCKER_H_ +#define CHROME_BROWSER_PERMISSIONS_PERMISSION_DECISION_AUTO_BLOCKER_H_ + +#include "base/callback_forward.h" +#include "base/macros.h" +#include "content/public/browser/permission_type.h" +#include "url/gurl.h" + +class GURL; +class Profile; + +class PermissionDecisionAutoBlocker { + public: + // Removes any recorded counts for urls which match |filter| under |profile|. + static void RemoveCountsByUrl(Profile* profile, + base::Callback<bool(const GURL& url)> filter); + + explicit PermissionDecisionAutoBlocker(Profile* profile); + + // Records that an ignore of a prompt for |permission| was made. + int RecordIgnore(const GURL& url, content::PermissionType permission); + + // Records that a dismissal of a prompt for |permission| was made, and returns + // true if this dismissal should be considered a block. False otherwise. + bool ShouldChangeDismissalToBlock(const GURL& url, + content::PermissionType permission); + + private: + friend class PermissionContextBaseTests; + friend class PermissionDecisionAutoBlockerUnitTest; + friend class RemovePermissionPromptCountsTest; + + // Keys used for storing count data in a website setting. + static const char kPromptDismissCountKey[]; + static const char kPromptIgnoreCountKey[]; + + // Returns the current number of actions recorded under |key| for |permission| + // type at |url|. + int GetActionCountForTest(const GURL& url, + content::PermissionType permission, + const char* key); + + // Records that the user performed an action for a prompt of type |permission| + // on |url| to a website setting keyed by |key|. Returns the total number of + // |key| actions which have been performed for |url|. + int RecordActionInWebsiteSettings(const GURL& url, + content::PermissionType permission, + const char* key); + + // Updates |prompt_dismissals_before_block_|. + void UpdateFromVariations(); + + Profile *profile_; + int prompt_dismissals_before_block_; +}; + +#endif // CHROME_BROWSER_PERMISSIONS_PERMISSION_DECISION_AUTO_BLOCKER_H_
diff --git a/chrome/browser/permissions/permission_decision_auto_blocker_unittest.cc b/chrome/browser/permissions/permission_decision_auto_blocker_unittest.cc new file mode 100644 index 0000000..9ab44cd --- /dev/null +++ b/chrome/browser/permissions/permission_decision_auto_blocker_unittest.cc
@@ -0,0 +1,104 @@ +// 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 "chrome/browser/permissions/permission_decision_auto_blocker.h" + +#include "base/bind.h" +#include "chrome/test/base/chrome_render_view_host_test_harness.h" +#include "chrome/test/base/testing_profile.h" +#include "content/public/browser/permission_type.h" + +namespace { + +bool FilterGoogle(const GURL& url) { + return url == GURL("https://www.google.com"); +} + +bool FilterAll(const GURL& url) { + return true; +} + +} // namespace + +class PermissionDecisionAutoBlockerUnitTest + : public ChromeRenderViewHostTestHarness { + protected: + int GetDismissalCount(const GURL& url, + content::PermissionType permission) { + return PermissionDecisionAutoBlocker(profile()).GetActionCountForTest( + url, permission, PermissionDecisionAutoBlocker::kPromptDismissCountKey); + } + + int GetIgnoreCount(const GURL& url, content::PermissionType permission) { + return PermissionDecisionAutoBlocker(profile()).GetActionCountForTest( + url, permission, PermissionDecisionAutoBlocker::kPromptIgnoreCountKey); + } + + int RecordDismiss(const GURL& url, content::PermissionType permission) { + PermissionDecisionAutoBlocker blocker(profile()); + blocker.ShouldChangeDismissalToBlock(url, permission); + return blocker.GetActionCountForTest( + url, permission, PermissionDecisionAutoBlocker::kPromptDismissCountKey); + } + + int RecordIgnore(const GURL& url, content::PermissionType permission) { + return PermissionDecisionAutoBlocker(profile()).RecordIgnore(url, + permission); + } +}; + +TEST_F(PermissionDecisionAutoBlockerUnitTest, RemoveCountsByUrl) { + GURL url1("https://www.google.com"); + GURL url2("https://www.example.com"); + + // Record some dismissals. + EXPECT_EQ(1, RecordDismiss(url1, content::PermissionType::GEOLOCATION)); + EXPECT_EQ(2, RecordDismiss(url1, content::PermissionType::GEOLOCATION)); + EXPECT_EQ(3, RecordDismiss(url1, content::PermissionType::GEOLOCATION)); + + EXPECT_EQ(1, RecordDismiss(url2, content::PermissionType::GEOLOCATION)); + EXPECT_EQ(1, RecordDismiss(url1, content::PermissionType::NOTIFICATIONS)); + + // Record some ignores. + EXPECT_EQ(1, RecordIgnore(url1, content::PermissionType::MIDI_SYSEX)); + EXPECT_EQ(1, RecordIgnore(url1, content::PermissionType::DURABLE_STORAGE)); + EXPECT_EQ(1, RecordIgnore(url2, content::PermissionType::GEOLOCATION)); + EXPECT_EQ(2, RecordIgnore(url2, content::PermissionType::GEOLOCATION)); + + PermissionDecisionAutoBlocker::RemoveCountsByUrl(profile(), + base::Bind(&FilterGoogle)); + + // Expect that url1's actions are gone, but url2's remain. + EXPECT_EQ(0, GetDismissalCount(url1, content::PermissionType::GEOLOCATION)); + EXPECT_EQ(0, GetDismissalCount(url1, content::PermissionType::NOTIFICATIONS)); + EXPECT_EQ(0, GetIgnoreCount(url1, content::PermissionType::MIDI_SYSEX)); + EXPECT_EQ(0, GetIgnoreCount(url1, content::PermissionType::DURABLE_STORAGE)); + + EXPECT_EQ(1, GetDismissalCount(url2, content::PermissionType::GEOLOCATION)); + EXPECT_EQ(2, GetIgnoreCount(url2, content::PermissionType::GEOLOCATION)); + + // Add some more actions. + EXPECT_EQ(1, RecordDismiss(url1, content::PermissionType::GEOLOCATION)); + EXPECT_EQ(1, RecordDismiss(url1, content::PermissionType::NOTIFICATIONS)); + EXPECT_EQ(2, RecordDismiss(url2, content::PermissionType::GEOLOCATION)); + + EXPECT_EQ(1, RecordIgnore(url1, content::PermissionType::GEOLOCATION)); + EXPECT_EQ(1, RecordIgnore(url1, content::PermissionType::NOTIFICATIONS)); + EXPECT_EQ(1, RecordIgnore(url1, content::PermissionType::DURABLE_STORAGE)); + EXPECT_EQ(1, RecordIgnore(url2, content::PermissionType::MIDI_SYSEX)); + + // Remove everything and expect that it's all gone. + PermissionDecisionAutoBlocker::RemoveCountsByUrl(profile(), + base::Bind(&FilterAll)); + + EXPECT_EQ(0, GetDismissalCount(url1, content::PermissionType::GEOLOCATION)); + EXPECT_EQ(0, GetDismissalCount(url1, content::PermissionType::NOTIFICATIONS)); + EXPECT_EQ(0, GetDismissalCount(url2, content::PermissionType::GEOLOCATION)); + + EXPECT_EQ(0, GetIgnoreCount(url1, content::PermissionType::GEOLOCATION)); + EXPECT_EQ(0, GetIgnoreCount(url1, content::PermissionType::NOTIFICATIONS)); + EXPECT_EQ(0, GetIgnoreCount(url2, content::PermissionType::GEOLOCATION)); + EXPECT_EQ(0, GetIgnoreCount(url2, content::PermissionType::DURABLE_STORAGE)); + EXPECT_EQ(0, GetIgnoreCount(url2, content::PermissionType::MIDI_SYSEX)); +}
diff --git a/chrome/browser/permissions/permission_infobar_delegate.cc b/chrome/browser/permissions/permission_infobar_delegate.cc index 0bd2469..46282a3 100644 --- a/chrome/browser/permissions/permission_infobar_delegate.cc +++ b/chrome/browser/permissions/permission_infobar_delegate.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/permissions/permission_infobar_delegate.h" +#include "chrome/browser/permissions/permission_decision_auto_blocker.h" #include "chrome/browser/permissions/permission_request.h" #include "chrome/browser/permissions/permission_uma_util.h" #include "chrome/grit/generated_resources.h" @@ -13,6 +14,9 @@ PermissionInfobarDelegate::~PermissionInfobarDelegate() { if (!action_taken_) { + PermissionDecisionAutoBlocker(profile_).RecordIgnore(requesting_origin_, + permission_type_); + PermissionUmaUtil::PermissionIgnored( permission_type_, user_gesture_ ? PermissionRequestGestureType::GESTURE
diff --git a/chrome/browser/permissions/permission_request_impl.cc b/chrome/browser/permissions/permission_request_impl.cc index 4faf00eb..feb02d3a 100644 --- a/chrome/browser/permissions/permission_request_impl.cc +++ b/chrome/browser/permissions/permission_request_impl.cc
@@ -5,7 +5,7 @@ #include "chrome/browser/permissions/permission_request_impl.h" #include "build/build_config.h" -#include "chrome/browser/permissions/permission_context_base.h" +#include "chrome/browser/permissions/permission_decision_auto_blocker.h" #include "chrome/browser/permissions/permission_uma_util.h" #include "chrome/grit/generated_resources.h" #include "components/url_formatter/elide_url.h" @@ -33,6 +33,9 @@ PermissionRequestImpl::~PermissionRequestImpl() { DCHECK(is_finished_); if (!action_taken_) { + PermissionDecisionAutoBlocker(profile_).RecordIgnore(request_origin_, + permission_type_); + PermissionUmaUtil::PermissionIgnored(permission_type_, GetGestureType(), request_origin_, profile_); }
diff --git a/chrome/browser/permissions/permission_request_impl.h b/chrome/browser/permissions/permission_request_impl.h index 333f04ef..05fd3a88 100644 --- a/chrome/browser/permissions/permission_request_impl.h +++ b/chrome/browser/permissions/permission_request_impl.h
@@ -13,7 +13,6 @@ #include "content/public/browser/permission_type.h" class GURL; -class PermissionContextBase; class Profile; // Default implementation of PermissionRequest, it is assumed that the
diff --git a/chrome/browser/permissions/permission_uma_util.cc b/chrome/browser/permissions/permission_uma_util.cc index ee699857..6554732 100644 --- a/chrome/browser/permissions/permission_uma_util.cc +++ b/chrome/browser/permissions/permission_uma_util.cc
@@ -85,8 +85,7 @@ break; } - std::string permission_str = - PermissionUtil::GetPermissionString(permission); + std::string permission_str = PermissionUtil::GetPermissionString(permission); if (permission_str.empty()) return ""; return base::StringPrintf("ContentSettings.PermissionActions_%s.%s.Url", @@ -102,8 +101,7 @@ if (permission == PermissionType::GEOLOCATION) { // TODO(dominickn): remove this deprecated metric - crbug.com/605836. rappor::SampleDomainAndRegistryFromGURL( - rappor_service, - "ContentSettings.PermissionRequested.Geolocation.Url", + rappor_service, "ContentSettings.PermissionRequested.Geolocation.Url", requesting_origin); rappor_service->RecordSample( "ContentSettings.PermissionRequested.Geolocation.Url2", @@ -123,8 +121,7 @@ permission == PermissionType::MIDI_SYSEX) { // TODO(dominickn): remove this deprecated metric - crbug.com/605836. rappor::SampleDomainAndRegistryFromGURL( - rappor_service, - "ContentSettings.PermissionRequested.Midi.Url", + rappor_service, "ContentSettings.PermissionRequested.Midi.Url", requesting_origin); rappor_service->RecordSample( "ContentSettings.PermissionRequested.Midi.Url2", @@ -356,6 +353,100 @@ requests[0]->GetGestureType(), requests[0]->GetPermissionRequestType()); } +void PermissionUmaUtil::PermissionPromptDismissed( + content::PermissionType permission, + int count) { + switch (permission) { + case PermissionType::GEOLOCATION: + UMA_HISTOGRAM_COUNTS_100("Permissions.Prompt.DismissCount.Geolocation", + count); + break; + case PermissionType::NOTIFICATIONS: + UMA_HISTOGRAM_COUNTS_100("Permissions.Prompt.DismissCount.Notifications", + count); + break; + case PermissionType::MIDI_SYSEX: + UMA_HISTOGRAM_COUNTS_100("Permissions.Prompt.DismissCount.MidiSysEx", + count); + break; + case PermissionType::PUSH_MESSAGING: + UMA_HISTOGRAM_COUNTS_100("Permissions.Prompt.DismissCount.PushMessaging", + count); + break; + case PermissionType::PROTECTED_MEDIA_IDENTIFIER: + UMA_HISTOGRAM_COUNTS_100("Permissions.Prompt.DismissCount.ProtectedMedia", + count); + break; + case PermissionType::DURABLE_STORAGE: + UMA_HISTOGRAM_COUNTS_100("Permissions.Prompt.DismissCount.DurableStorage", + count); + break; + case PermissionType::AUDIO_CAPTURE: + UMA_HISTOGRAM_COUNTS_100("Permissions.Prompt.DismissCount.AudioCapture", + count); + break; + case PermissionType::VIDEO_CAPTURE: + UMA_HISTOGRAM_COUNTS_100("Permissions.Prompt.DismissCount.VideoCapture", + count); + break; + // The user is not prompted for these permissions, thus there is no dismiss + // recorded for them. + case PermissionType::MIDI: + case PermissionType::BACKGROUND_SYNC: + case PermissionType::NUM: + NOTREACHED() << "PERMISSION " + << PermissionUtil::GetPermissionString(permission) + << " not accounted for"; + } +} + +void PermissionUmaUtil::PermissionPromptIgnored( + content::PermissionType permission, + int count) { + switch (permission) { + case PermissionType::GEOLOCATION: + UMA_HISTOGRAM_COUNTS_100("Permissions.Prompt.IgnoreCount.Geolocation", + count); + break; + case PermissionType::NOTIFICATIONS: + UMA_HISTOGRAM_COUNTS_100("Permissions.Prompt.IgnoreCount.Notifications", + count); + break; + case PermissionType::MIDI_SYSEX: + UMA_HISTOGRAM_COUNTS_100("Permissions.Prompt.IgnoreCount.MidiSysEx", + count); + break; + case PermissionType::PUSH_MESSAGING: + UMA_HISTOGRAM_COUNTS_100("Permissions.Prompt.IgnoreCount.PushMessaging", + count); + break; + case PermissionType::PROTECTED_MEDIA_IDENTIFIER: + UMA_HISTOGRAM_COUNTS_100("Permissions.Prompt.IgnoreCount.ProtectedMedia", + count); + break; + case PermissionType::DURABLE_STORAGE: + UMA_HISTOGRAM_COUNTS_100("Permissions.Prompt.IgnoreCount.DurableStorage", + count); + break; + case PermissionType::AUDIO_CAPTURE: + UMA_HISTOGRAM_COUNTS_100("Permissions.Prompt.IgnoreCount.AudioCapture", + count); + break; + case PermissionType::VIDEO_CAPTURE: + UMA_HISTOGRAM_COUNTS_100("Permissions.Prompt.IgnoreCount.VideoCapture", + count); + break; + // The user is not prompted for these permissions, thus there is no + // ignore recorded for them. + case PermissionType::MIDI: + case PermissionType::BACKGROUND_SYNC: + case PermissionType::NUM: + NOTREACHED() << "PERMISSION " + << PermissionUtil::GetPermissionString(permission) + << " not accounted for"; + } +} + bool PermissionUmaUtil::IsOptedIntoPermissionActionReporting(Profile* profile) { if (!base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnablePermissionActionReporting))
diff --git a/chrome/browser/permissions/permission_uma_util.h b/chrome/browser/permissions/permission_uma_util.h index 4ce425c7..ed0149a 100644 --- a/chrome/browser/permissions/permission_uma_util.h +++ b/chrome/browser/permissions/permission_uma_util.h
@@ -114,6 +114,16 @@ static void PermissionPromptDenied( const std::vector<PermissionRequest*>& requests); + // Records |count| total dismissal actions for a prompt of type |permission| + // for a single origin. + static void PermissionPromptDismissed(content::PermissionType permission, + int count); + + // Records |count| total ignore actions for a prompt of type |permission| for + // a single origin. + static void PermissionPromptIgnored(content::PermissionType permission, + int count); + private: friend class PermissionUmaUtilTest;
diff --git a/chrome/browser/predictors/resource_prefetch_predictor.cc b/chrome/browser/predictors/resource_prefetch_predictor.cc index 497a3596..bed0510 100644 --- a/chrome/browser/predictors/resource_prefetch_predictor.cc +++ b/chrome/browser/predictors/resource_prefetch_predictor.cc
@@ -63,7 +63,7 @@ RESOURCE_STATUS_UNSUPPORTED_RESOURCE_TYPE = 4, RESOURCE_STATUS_NOT_GET = 8, RESOURCE_STATUS_URL_TOO_LONG = 16, - RESOURCE_STATUS_NOT_CACHEABLE = 32, + RESOURCE_STATUS_NO_STORE = 32, RESOURCE_STATUS_HEADERS_MISSING = 64, RESOURCE_STATUS_MAX = 128, }; @@ -280,12 +280,8 @@ if (!response->response_info().headers.get()) resource_status |= RESOURCE_STATUS_HEADERS_MISSING; - if (!IsCacheable(response)) - resource_status |= RESOURCE_STATUS_NOT_CACHEABLE; - - UMA_HISTOGRAM_ENUMERATION("ResourcePrefetchPredictor.ResourceStatus", - resource_status, - RESOURCE_STATUS_MAX); + if (IsNoStore(response)) + resource_status |= RESOURCE_STATUS_NO_STORE; return resource_status == 0; } @@ -312,20 +308,14 @@ } // static -bool ResourcePrefetchPredictor::IsCacheable(const net::URLRequest* response) { +bool ResourcePrefetchPredictor::IsNoStore(const net::URLRequest* response) { if (response->was_cached()) - return true; + return false; - // For non cached responses, we will ensure that the freshness lifetime is - // some sane value. const net::HttpResponseInfo& response_info = response->response_info(); if (!response_info.headers.get()) return false; - base::Time response_time(response_info.response_time); - response_time += base::TimeDelta::FromSeconds(1); - base::TimeDelta freshness = - response_info.headers->GetFreshnessLifetimes(response_time).freshness; - return freshness > base::TimeDelta(); + return response_info.headers->HasHeaderValue("cache-control", "no-store"); } // static
diff --git a/chrome/browser/predictors/resource_prefetch_predictor.h b/chrome/browser/predictors/resource_prefetch_predictor.h index 15768ecf..252da51e 100644 --- a/chrome/browser/predictors/resource_prefetch_predictor.h +++ b/chrome/browser/predictors/resource_prefetch_predictor.h
@@ -66,8 +66,6 @@ // * ResourcePrefetcher - Lives entirely on the IO thread, owned by the // ResourcePrefetcherManager, and issues net::URLRequest to fetch resources. // -// TODO(shishir): Do speculative prefetching for https resources and/or https -// main frame urls. // TODO(zhenw): Currently only main frame requests/redirects/responses are // recorded. Consider recording sub-frame responses independently or together // with main frame. @@ -187,8 +185,8 @@ static bool IsHandledResourceType(content::ResourceType resource_type, const std::string& mime_type); - // Returns true if the request (should have a response in it) is cacheable. - static bool IsCacheable(const net::URLRequest* request); + // Returns true if the request (should have a response in it) is "no-store". + static bool IsNoStore(const net::URLRequest* request); // KeyedService methods override. void Shutdown() override;
diff --git a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.mm b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.mm index b949da4..2fabbf19 100644 --- a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.mm +++ b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.mm
@@ -82,14 +82,6 @@ [historySwiper_ touchesEndedWithEvent:event]; } -- (BOOL)canRubberbandLeft:(NSView*)view { - return [historySwiper_ canRubberbandLeft:view]; -} - -- (BOOL)canRubberbandRight:(NSView*)view { - return [historySwiper_ canRubberbandRight:view]; -} - // HistorySwiperDelegate methods - (BOOL)shouldAllowHistorySwiping {
diff --git a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper.h b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper.h index 56313254..97c888fc 100644 --- a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper.h +++ b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper.h
@@ -198,12 +198,6 @@ - (void)beginGestureWithEvent:(NSEvent*)event; - (void)endGestureWithEvent:(NSEvent*)event; -// These methods control whether a given view is allowed to rubberband in the -// given direction. This is inversely related to whether the view is allowed to -// 2-finger history swipe in the given direction. -- (BOOL)canRubberbandLeft:(NSView*)view; -- (BOOL)canRubberbandRight:(NSView*)view; - // Designated initializer. - (id)initWithDelegate:(id<HistorySwiperDelegate>)delegate;
diff --git a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper.mm b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper.mm index 3ec51eb..ba51708 100644 --- a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper.mm +++ b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper.mm
@@ -142,46 +142,6 @@ } } -- (BOOL)canRubberbandLeft:(NSView*)view { - Browser* browser = chrome::FindBrowserWithWindow([view window]); - // If history swiping isn't possible, allow rubberbanding. - if (!browser) - return true; - - // TODO(erikchen): Update this comment after determining whether this - // NULL-check fixes the crash. - // This NULL check likely prevents a crash. http://crbug.com/418761 - if (!browser->tab_strip_model()->GetActiveWebContents()) - return true; - - if (!chrome::CanGoBack(browser)) - return true; - // History swiping is possible. By default, disallow rubberbanding. If the - // user has both started, and then cancelled history swiping for this - // gesture, allow rubberbanding. - return receivingTouches_ && recognitionState_ == history_swiper::kCancelled; -} - -- (BOOL)canRubberbandRight:(NSView*)view { - Browser* browser = chrome::FindBrowserWithWindow([view window]); - // If history swiping isn't possible, allow rubberbanding. - if (!browser) - return true; - - // TODO(erikchen): Update this comment after determining whether this - // NULL-check fixes the crash. - // This NULL check likely prevents a crash. http://crbug.com/418761 - if (!browser->tab_strip_model()->GetActiveWebContents()) - return true; - - if (!chrome::CanGoForward(browser)) - return true; - // History swiping is possible. By default, disallow rubberbanding. If the - // user has both started, and then cancelled history swiping for this - // gesture, allow rubberbanding. - return receivingTouches_ && recognitionState_ == history_swiper::kCancelled; -} - - (void)beginGestureWithEvent:(NSEvent*)event { inGesture_ = YES;
diff --git a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc index 11bc778..53d4e66 100644 --- a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc +++ b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc
@@ -23,6 +23,7 @@ #include "chrome/browser/download/download_resource_throttle.h" #include "chrome/browser/mod_pagespeed/mod_pagespeed_metrics.h" #include "chrome/browser/net/resource_prefetch_predictor_observer.h" +#include "chrome/browser/page_load_metrics/metrics_web_contents_observer.h" #include "chrome/browser/plugins/plugin_prefs.h" #include "chrome/browser/prerender/prerender_manager.h" #include "chrome/browser/prerender/prerender_manager_factory.h" @@ -160,11 +161,9 @@ return prerender::PrerenderManagerFactory::GetForProfile(profile); } -void UpdatePrerenderNetworkBytesCallback( - const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter, - int64_t bytes) { +void UpdatePrerenderNetworkBytesCallback(content::WebContents* web_contents, + int64_t bytes) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - content::WebContents* web_contents = web_contents_getter.Run(); // PrerenderContents::FromWebContents handles the NULL case. prerender::PrerenderContents* prerender_contents = prerender::PrerenderContents::FromWebContents(web_contents); @@ -281,17 +280,13 @@ } #endif // !defined(DISABLE_NACL) -// This function is called in RequestComplete to log metrics about main frame -// resources. -void LogMainFrameMetricsOnUIThread( - const GURL& url, - int net_error, - base::TimeDelta request_loading_time, - const content::ResourceRequestInfo::WebContentsGetter& - web_contents_getter) { - content::WebContents* web_contents = web_contents_getter.Run(); - if (!web_contents) - return; +// This function is called in NotifyUIThreadOfRequestComplete to log metrics +// about main frame resources. +void LogMainFrameMetricsOnUIThread(const GURL& url, + int net_error, + base::TimeDelta request_loading_time, + content::WebContents* web_contents) { + DCHECK(web_contents); Profile* profile = Profile::FromBrowserContext(web_contents->GetBrowserContext()); @@ -343,6 +338,32 @@ } } +void NotifyUIThreadOfRequestComplete( + const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter, + const GURL& url, + content::ResourceType resource_type, + bool was_cached, + int net_error, + int64_t total_received_bytes, + base::TimeDelta request_loading_time) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + content::WebContents* web_contents = web_contents_getter.Run(); + if (!web_contents) + return; + if (resource_type == content::RESOURCE_TYPE_MAIN_FRAME) { + LogMainFrameMetricsOnUIThread(url, net_error, request_loading_time, + web_contents); + } + if (!was_cached) + UpdatePrerenderNetworkBytesCallback(web_contents, total_received_bytes); + page_load_metrics::MetricsWebContentsObserver* metrics_observer = + page_load_metrics::MetricsWebContentsObserver::FromWebContents( + web_contents); + if (metrics_observer) { + metrics_observer->OnRequestComplete(resource_type, was_cached, net_error); + } +} + } // namespace ChromeResourceDispatcherHostDelegate::ChromeResourceDispatcherHostDelegate() @@ -790,25 +811,18 @@ // Notification that a request has completed. void ChromeResourceDispatcherHostDelegate::RequestComplete( net::URLRequest* url_request) { - // Jump on the UI thread and inform the prerender about the bytes. + if (!url_request) + return; const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(url_request); - if (url_request && !url_request->was_cached()) { - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - base::Bind(&UpdatePrerenderNetworkBytesCallback, - info->GetWebContentsGetterForRequest(), - url_request->GetTotalReceivedBytes())); - } - - if (url_request && - info->GetResourceType() == content::RESOURCE_TYPE_MAIN_FRAME) { - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&LogMainFrameMetricsOnUIThread, url_request->url(), - url_request->status().error(), - base::TimeTicks::Now() - url_request->creation_time(), - info->GetWebContentsGetterForRequest())); - } + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&NotifyUIThreadOfRequestComplete, + info->GetWebContentsGetterForRequest(), url_request->url(), + info->GetResourceType(), url_request->was_cached(), + url_request->status().error(), + url_request->GetTotalReceivedBytes(), + base::TimeTicks::Now() - url_request->creation_time())); } bool ChromeResourceDispatcherHostDelegate::ShouldEnableLoFiMode(
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 dfebfa9..15a8ae0 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
@@ -236,16 +236,15 @@ DISALLOW_COPY_AND_ASSIGN(ViewCompositionRangeChangedObserver); }; -// This class observes the |expected_view| for a change in the text selection -// that has a selection length of |expected_length|. +// This class observes the |expected_view| for a change in the text selection. class ViewTextSelectionObserver : public TextInputManagerObserverBase { public: ViewTextSelectionObserver(content::WebContents* web_contents, content::RenderWidgetHostView* expected_view, - size_t expected_selection_length) + size_t expected_length) : TextInputManagerObserverBase(web_contents), expected_view_(expected_view), - expected_selection_length_(expected_selection_length) { + expected_length_(expected_length) { tester()->SetOnTextSelectionChangedCallback(base::Bind( &ViewTextSelectionObserver::VerifyChange, base::Unretained(this))); } @@ -253,15 +252,15 @@ private: void VerifyChange() { if (expected_view_ == tester()->GetUpdatedView()) { - size_t selection_length; - if (tester()->GetCurrentTextSelectionLength(&selection_length) && - expected_selection_length_ == selection_length) + size_t length; + EXPECT_TRUE(tester()->GetCurrentTextSelectionLength(&length)); + if (length == expected_length_) OnSuccess(); } } const content::RenderWidgetHostView* const expected_view_; - const size_t expected_selection_length_; + const size_t expected_length_; DISALLOW_COPY_AND_ASSIGN(ViewTextSelectionObserver); }; @@ -647,37 +646,56 @@ // This test creates a page with multiple child frames and adds an <input> to // each frame. Then, sequentially, each <input> is focused by sending a tab key. -// After focusing each input, the whole text is automatically selected and a -// ViewHostMsg_SelectionChanged IPC sent back to the browser. This test verifies -// that the browser tracks the text selection from all frames. +// After focusing each input, a sequence of key presses (character 'E') are sent +// to the focused widget and then the whole text is selected using Ctrl+A. The +// test then verifies that the selection length equals the length of the +// sequence of 'E's. IN_PROC_BROWSER_TEST_F(SitePerProcessTextInputManagerTest, TrackTextSelectionForAllFrames) { - // TODO(ekaramad): Since IME related methods in WebFrameWidgetImpl are not - // implemented yet, this test does not work on child frames. Add child frames - // to this test when IME methods in WebFramgeWidgetImpl are implemented - // (https://crbug.com/626746). - CreateIframePage("a()"); - std::vector<content::RenderFrameHost*> frames{GetFrame(IndexVector{})}; + CreateIframePage("a(b,c(a,b),d)"); + std::vector<content::RenderFrameHost*> frames{ + GetFrame(IndexVector{}), GetFrame(IndexVector{0}), + GetFrame(IndexVector{1}), GetFrame(IndexVector{1, 0}), + GetFrame(IndexVector{1, 1}), GetFrame(IndexVector{2})}; + std::vector<std::string> values{"main", "b", "c", "ca", "cb", "d"}; std::vector<content::RenderWidgetHostView*> views; - for (auto frame : frames) + for (auto* frame : frames) views.push_back(frame->GetView()); - std::vector<std::string> input_text{"abc"}; for (size_t i = 0; i < frames.size(); ++i) - AddInputFieldToFrame(frames[i], "text", input_text[i], false); + AddInputFieldToFrame(frames[i], "text", values[i], true); content::WebContents* web_contents = active_contents(); - auto send_tab_and_wait_for_selection_change = [&web_contents]( - content::RenderFrameHost* frame, size_t expected_length) { - ViewTextSelectionObserver text_selection_observer( - web_contents, frame->GetView(), expected_length); + auto send_tab_and_wait_for_value = [&web_contents](const std::string& value) { + TextInputManagerValueObserver observer(web_contents, value); SimulateKeyPress(web_contents, ui::DomKey::TAB, ui::DomCode::TAB, ui::VKEY_TAB, false, false, false, false); - text_selection_observer.Wait(); + observer.Wait(); }; - for (size_t i = 0; i < frames.size(); ++i) - send_tab_and_wait_for_selection_change(frames[i], input_text[i].size()); + auto send_keys_select_all_wait_for_selection_change = [&web_contents]( + content::RenderWidgetHostView* view, size_t count) { + ViewTextSelectionObserver observer(web_contents, view, count); + for (size_t i = 0; i < count; ++i) { + SimulateKeyPress(web_contents, ui::DomKey::FromCharacter('E'), + ui::DomCode::US_E, ui::VKEY_E, false, false, false, + false); + } + // Send Ctrl+A to select the whole text. + SimulateKeyPress(web_contents, ui::DomKey::FromCharacter('a'), + ui::DomCode::US_A, ui::VKEY_A, true, false, false, false); + observer.Wait(); + }; + + size_t count = 2; + for (size_t i = 0; i < views.size(); ++i) { + // First focus the <input>. + send_tab_and_wait_for_value(values[i]); + + // Send a sequence of |count| 'E' keys and wait until the view receives a + // selection change update for a text of the corresponding size, |count|. + send_keys_select_all_wait_for_selection_change(views[i], count++); + } } // The following test verifies that when the active widget changes value, it is
diff --git a/chrome/browser/resources/chromeos/arc_support/playstore.js b/chrome/browser/resources/chromeos/arc_support/playstore.js index 16a6a9bf..2eda8be 100644 --- a/chrome/browser/resources/chromeos/arc_support/playstore.js +++ b/chrome/browser/resources/chromeos/arc_support/playstore.js
@@ -16,33 +16,73 @@ var selectLangZoneTerms = doc.getElementById('play-footer'). getElementsByTagName('select')[0]; - if (window.location.href == 'https://play.google.com/about/play-terms.html') { - var matchByLangZone = '/intl/' + navigator.language + '_' + - document.countryCode + '/about/play-terms.html'; - for (var i = selectLangZoneTerms.options.length - 1; i >= 0; --i) { - var option = selectLangZoneTerms.options[i]; - if (option.value == matchByLangZone) { - window.location.href = option.value; - return; + var initialLoad = window.location.href == + 'https://play.google.com/about/play-terms.html'; + var langSegments = navigator.language.split('-'); + if (initialLoad) { + var applyTermsForLangAndZone = function(termsLang) { + var matchByLangZone = '/intl/' + termsLang + '_' + + document.countryCode + '/about/play-terms.html'; + for (var i = selectLangZoneTerms.options.length - 1; i >= 0; --i) { + var option = selectLangZoneTerms.options[i]; + if (option.value == matchByLangZone) { + window.location.href = option.value; + return true; + } } + return false; + }; + + // Try two versions of the language, full and short (if it exists, for + // example en-GB -> en). Note, terms may contain entries for both types, for + // example: en_ie, es-419_ar, es_as, pt-PT_pt. + if (applyTermsForLangAndZone(navigator.language)) { + return; + } + if (langSegments.length == 2 && + applyTermsForLangAndZone(langSegments[0])) { + return; } } var matchByLang = '/intl/' + navigator.language + '_'; + var matchByLangShort = null; + if (langSegments.length == 2) { + matchByLangShort = '/intl/' + langSegments[0] + '_'; + } + var matchByZone = '_' + document.countryCode + '/about/play-terms.html'; var matchByDefault = '/intl/en/about/play-terms.html'; + // We are allowed to display terms by default only in language that matches + // current UI language. In other cases we have to switch to default version. + var langMatch = false; + var defaultExist = false; + for (var i = selectLangZoneTerms.options.length - 1; i >= 0; --i) { var option = selectLangZoneTerms.options[i]; - if (selectLangZoneTerms.selectedIndex != i && - !option.value.startsWith(matchByLang) && + if (selectLangZoneTerms.selectedIndex == i) { + langMatch = option.value.startsWith(matchByLang) || + (matchByLangShort && option.value.startsWith(matchByLangShort)); + continue; + } + if (option.value == matchByDefault) { + defaultExist = true; + continue; + } + if (!option.value.startsWith(matchByLang) && !option.value.endsWith(matchByZone) && - option.value != matchByDefault && option.text != 'English') { + !(matchByLangShort && option.value.startsWith(matchByLangShort)) && + option.text != 'English') { selectLangZoneTerms.removeChild(option); } } - // Show content once we reached target url. - document.body.hidden = false; + if (initialLoad && !langMatch && defaultExist) { + window.location.href = matchByDefault; + } else { + // Show content once we reached target url. + document.body.hidden = false; + } } /**
diff --git a/chrome/browser/resources/chromeos/chromevox/chromevox/background/keymaps/next_keymap.json b/chrome/browser/resources/chromeos/chromevox/chromevox/background/keymaps/next_keymap.json index 525ccfc..5116134 100644 --- a/chrome/browser/resources/chromeos/chromevox/chromevox/background/keymaps/next_keymap.json +++ b/chrome/browser/resources/chromeos/chromevox/chromevox/background/keymaps/next_keymap.json
@@ -364,6 +364,25 @@ } }, { + "command": "nextLandmark", + "sequence": { + "cvoxModifier": true, + "keys": { + "keyCode": [186] + } + } + }, + { + "command": "previousLandmark", + "sequence": { + "cvoxModifier": true, + "keys": { + "keyCode": [186], + "shiftKey": [true] + } + } + }, + { "command": "jumpToBottom", "sequence": { "cvoxModifier": true, @@ -488,7 +507,8 @@ "sequence": { "cvoxModifier": true, "keys": { - "keyCode": [219] + "keyCode": [219], + "shiftKey": [true] } } }, @@ -497,7 +517,7 @@ "sequence": { "cvoxModifier": true, "keys": { - "keyCode": [221] + "keyCode": [219] } } }, @@ -506,7 +526,8 @@ "sequence": { "cvoxModifier": true, "keys": { - "keyCode": [186] + "keyCode": [221], + "shiftKey": [true] } } }, @@ -515,7 +536,7 @@ "sequence": { "cvoxModifier": true, "keys": { - "keyCode": [222] + "keyCode": [221] } } },
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js index 30e5445..55e00dc 100644 --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
@@ -143,8 +143,6 @@ chrome.accessibilityPrivate.onAccessibilityGesture.addListener( this.onAccessibilityGesture_); - - Notifications.onStartup(); }; /** @@ -236,6 +234,7 @@ onModeChanged_: function(newMode, oldMode) { this.keyboardHandler_.onModeChanged(newMode, oldMode); CommandHandler.onModeChanged(newMode, oldMode); + Notifications.onModeChange(newMode, oldMode); if (newMode == ChromeVoxMode.CLASSIC) chrome.accessibilityPrivate.setFocusRing([]);
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js index 8bc806a..4bf88834 100644 --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js
@@ -373,6 +373,16 @@ pred = AutomationPredicate.visitedLink; predErrorMsg = 'no_previous_visited_link'; break; + case 'nextLandmark': + dir = Dir.FORWARD; + pred = AutomationPredicate.landmark; + predErrorMsg = 'no_next_landmark'; + break; + case 'previousLandmark': + dir = Dir.BACKWARD; + pred = AutomationPredicate.landmark; + predErrorMsg = 'no_previous_landmark'; + break; case 'right': case 'nextObject': current = current.move(cursors.Unit.NODE, Dir.FORWARD);
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/notifications.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/notifications.js index cc6e387..791e411 100644 --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/notifications.js +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/notifications.js
@@ -71,30 +71,23 @@ Notifications.currentUpdate; /** - * Runs notifications that should be shown for startup. - */ -Notifications.onStartup = function() { - // Only run on background page. - if (document.location.href.indexOf('background.html') == -1) - return; - - Notifications.reset(); - Notifications.currentUpdate = new UpdateNotification(); - Notifications.currentUpdate.show(); -}; - -/** * Runs notifications that should be shown for mode changes. + * @param {ChromeVoxMode} newMode + * @param {?ChromeVoxMode} oldMode Can be null at startup when no range was + * previously set. */ -Notifications.onModeChange = function() { +Notifications.onModeChange = function(newMode, oldMode) { // Only run on background page. if (document.location.href.indexOf('background.html') == -1) return; - if (ChromeVoxState.instance.mode !== ChromeVoxMode.FORCE_NEXT) + if (newMode !== ChromeVoxMode.FORCE_NEXT) return; - Notifications.reset(); + // Reset the notifications only when mode changes after startup. This prevents + // us from making notification announcements every time on startup. + if (oldMode) + Notifications.reset(); Notifications.currentUpdate = new UpdateNotification(); Notifications.currentUpdate.show(); };
diff --git a/chrome/browser/resources/feedback/manifest.json b/chrome/browser/resources/feedback/manifest.json index bfc3f60..5a6139db 100644 --- a/chrome/browser/resources/feedback/manifest.json +++ b/chrome/browser/resources/feedback/manifest.json
@@ -18,7 +18,7 @@ "background": { "scripts": ["js/event_handler.js"] }, - "content_security_policy": "default-src 'none'; script-src 'self' blob: filesystem: chrome://resources; style-src 'unsafe-inline' blob: file: filesystem: data: *; img-src * blob: file: filesystem: data:; media-src 'self' blob: filesystem:" + "content_security_policy": "default-src 'none'; script-src 'self' blob: filesystem: chrome://resources; style-src 'unsafe-inline' blob: chrome: file: filesystem: data: *; img-src * blob: file: filesystem: data:; media-src 'self' blob: filesystem:" }, "display_in_launcher": false, "display_in_new_tab_page": false
diff --git a/chrome/browser/resources/md_extensions/extensions.html b/chrome/browser/resources/md_extensions/extensions.html index 153b60f..bd137138 100644 --- a/chrome/browser/resources/md_extensions/extensions.html +++ b/chrome/browser/resources/md_extensions/extensions.html
@@ -1,8 +1,8 @@ <!doctype html> -<html i18n-values="dir:textdirection;lang:language"> +<html dir="$i18n{textdirection}" lang="$i18n{language}"> <head> <meta charset="utf8"> - <title i18n-content="title"></title> + <title>$i18n{title}</title> <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://extensions/manager.html"> <style> @@ -20,7 +20,6 @@ <body> <extensions-manager></extensions-manager> <link rel="import" href="chrome://resources/html/load_time_data.html"> - <link rel="import" href="chrome://resources/html/i18n_template.html"> <link rel="import" href="chrome://extensions/strings.html"> <link rel="import" href="chrome://extensions/service.html"> <script src="chrome://extensions/extensions.js"></script>
diff --git a/chrome/browser/resources/md_extensions/manager.html b/chrome/browser/resources/md_extensions/manager.html index 238a78d..0f35b0b0 100644 --- a/chrome/browser/resources/md_extensions/manager.html +++ b/chrome/browser/resources/md_extensions/manager.html
@@ -19,8 +19,8 @@ <extensions-drop-overlay></extensions-drop-overlay> <paper-header-panel id="panel"> <div class="paper-header"> - <h1 i18n-content="toolbarTitle"></h1> - <cr-search-field i18n-values="label:search" + <h1>$i18n{toolbarTitle}</h1> + <cr-search-field label="$i18n{search}" on-search-changed="onFilterChanged_"></cr-search-field> </div> <extensions-sidebar in-dev-mode="[[inDevMode]]">
diff --git a/chrome/browser/resources/md_extensions/sidebar.html b/chrome/browser/resources/md_extensions/sidebar.html index e1b73db..c3aeed3 100644 --- a/chrome/browser/resources/md_extensions/sidebar.html +++ b/chrome/browser/resources/md_extensions/sidebar.html
@@ -13,12 +13,12 @@ <paper-item class="section-menu-item" id="sections-extensions" on-tap="onExtensionsTap_"> <iron-icon icon="extension"></iron-icon> - <span i18n-content="sidebarExtensions"></span> + <span>$i18n{sidebarExtensions}</span> </paper-item> <paper-item class="section-menu-item" id="sections-apps" on-tap="onAppsTap_"> <iron-icon icon="apps"></iron-icon> - <span i18n-content="sidebarApps"></span> + <span>$i18n{sidebarApps}</span> </paper-item> </paper-menu> <a class="section-item" id="more-extensions" target="_blank"
diff --git a/chrome/browser/resources/md_history/app.js b/chrome/browser/resources/md_history/app.js index 05de235..c9a41b99 100644 --- a/chrome/browser/resources/md_history/app.js +++ b/chrome/browser/resources/md_history/app.js
@@ -200,8 +200,14 @@ * @param {boolean} isTabSyncEnabled Is tab sync enabled for this profile? */ setForeignSessions: function(sessionList, isTabSyncEnabled) { - if (!isTabSyncEnabled) + if (!isTabSyncEnabled) { + var syncedDeviceManagerElem = + /** @type {HistorySyncedDeviceManagerElement} */this + .$$('history-synced-device-manager'); + if (syncedDeviceManagerElem) + syncedDeviceManagerElem.tabSyncDisabled(); return; + } this.set('queryResult_.sessionList', sessionList); },
diff --git a/chrome/browser/resources/md_history/history_item.html b/chrome/browser/resources/md_history/history_item.html index 28de141..37f5168 100644 --- a/chrome/browser/resources/md_history/history_item.html +++ b/chrome/browser/resources/md_history/history_item.html
@@ -140,7 +140,8 @@ <span id="time-accessed">[[item.readableTimestamp]]</span> <div class="website-icon" id="icon"></div> <div id="title-and-domain"> - <a href="[[item.url]]" id="title" class="website-title"> + <a href="[[item.url]]" id="title" class="website-title" + title="[[cropItemTitle_(item.title)]]"> <history-searched-label title="[[cropItemTitle_(item.title)]]" search-term="[[searchTerm]]"></history-searched-label> </a>
diff --git a/chrome/browser/resources/md_history/synced_device_manager.js b/chrome/browser/resources/md_history/synced_device_manager.js index 030d1ca..d329273b 100644 --- a/chrome/browser/resources/md_history/synced_device_manager.js +++ b/chrome/browser/resources/md_history/synced_device_manager.js
@@ -207,6 +207,14 @@ }, /** + * End fetching synced tabs when sync is disabled. + */ + tabSyncDisabled: function() { + this.fetchingSyncedTabs_ = false; + this.clearDisplayedSyncedDevices_(); + }, + + /** * Get called when user's sign in state changes, this will affect UI of synced * tabs page. Sign in promo gets displayed when user is signed out, and * different messages are shown when there are no synced tabs.
diff --git a/chrome/browser/resources/md_user_manager/control_bar.html b/chrome/browser/resources/md_user_manager/control_bar.html index f21f602f..8c3319f 100644 --- a/chrome/browser/resources/md_user_manager/control_bar.html +++ b/chrome/browser/resources/md_user_manager/control_bar.html
@@ -25,9 +25,9 @@ <div id="logo" class="product-logo" alt=""></div> <paper-button id="launchGuest" class="action secondary" on-tap="onLaunchGuestTap_" - i18n-content="browseAsGuest" hidden="[[!showGuest]]"></paper-button> + hidden="[[!showGuest]]">$i18n{browseAsGuest}</paper-button> <paper-button id="addUser" class="action secondary" on-tap="onAddUserTap_" - i18n-content="addUser" hidden="[[!showAddPerson]]"></paper-button> + hidden="[[!showAddPerson]]">$i18n{addUser}</paper-button> </div> </template> <script src="control_bar.js"></script>
diff --git a/chrome/browser/resources/md_user_manager/create_profile.html b/chrome/browser/resources/md_user_manager/create_profile.html index b483d019..695fc6e7 100644 --- a/chrome/browser/resources/md_user_manager/create_profile.html +++ b/chrome/browser/resources/md_user_manager/create_profile.html
@@ -31,6 +31,7 @@ visibility 0s linear 400ms; align-items: center; background-color: var(--paper-red-50); + box-shadow: 0 1px 2px 0 rgba(0, 0, 0, .12); color: var(--google-red-700); display: flex; height: 40px;
diff --git a/chrome/browser/resources/md_user_manager/create_profile.js b/chrome/browser/resources/md_user_manager/create_profile.js index 6b2ea41..d997d9e 100644 --- a/chrome/browser/resources/md_user_manager/create_profile.js +++ b/chrome/browser/resources/md_user_manager/create_profile.js
@@ -266,15 +266,20 @@ }, /** - * Displays the import supervised user popup. + * Displays the import supervised user popup or an error message if there are + * no existing supervised users. * @param {!Array<!SupervisedUser>} supervisedUsers The list of existing * supervised users. * @private */ showImportSupervisedUserPopup_: function(supervisedUsers) { this.loadingSupervisedUsers_ = false; - this.$.importUserPopup.show(this.signedInUser_(this.signedInUserIndex_), - supervisedUsers); + if (supervisedUsers.length > 0) { + this.$.importUserPopup.show(this.signedInUser_(this.signedInUserIndex_), + supervisedUsers); + } else { + this.handleMessage_(this.i18n('noSupervisedUserImportText')); + } }, /**
diff --git a/chrome/browser/resources/md_user_manager/import_supervised_user.html b/chrome/browser/resources/md_user_manager/import_supervised_user.html index 116f7aedc..84131ec 100644 --- a/chrome/browser/resources/md_user_manager/import_supervised_user.html +++ b/chrome/browser/resources/md_user_manager/import_supervised_user.html
@@ -42,10 +42,6 @@ --paper-item-focused-before: { background: none; }; - --paper-item-selected: { - background: rgba(0, 0, 0, .04); - font-weight: normal; - }; } paper-listbox paper-item .profile-img { @@ -67,7 +63,7 @@ <user-manager-dialog id="dialog"> <div class="title">$i18n{supervisedUserImportTitle}</div> <div class="body"> - <div id="message">[[getMessage_(supervisedUsers_)]]</div> + <div id="message">$i18n{supervisedUserImportText}</div> <paper-listbox class="no-padding" selected="{{supervisedUserIndex_}}"> <template is="dom-repeat" items="[[supervisedUsers_]]"> <paper-item disabled="[[item.onCurrentDevice]]">
diff --git a/chrome/browser/resources/md_user_manager/import_supervised_user.js b/chrome/browser/resources/md_user_manager/import_supervised_user.js index f35c55e..c572419 100644 --- a/chrome/browser/resources/md_user_manager/import_supervised_user.js +++ b/chrome/browser/resources/md_user_manager/import_supervised_user.js
@@ -75,18 +75,6 @@ }, /** - * Computed binding that returns the appropriate import message depending on - * whether or not there are any supervised users to import. - * @param {!Array<!SupervisedUser>} supervisedUsers - * @private - * @return {string} - */ - getMessage_: function(supervisedUsers) { - return supervisedUsers.length > 0 ? this.i18n('supervisedUserImportText') : - this.i18n('noSupervisedUserImportText'); - }, - - /** * param {number} supervisedUserIndex Index of the selected supervised user. * @private * @return {boolean} Whether the 'Import' button should be disabled.
diff --git a/chrome/browser/resources/md_user_manager/supervised_user_learn_more.html b/chrome/browser/resources/md_user_manager/supervised_user_learn_more.html index fc10361..eebb7b1e 100644 --- a/chrome/browser/resources/md_user_manager/supervised_user_learn_more.html +++ b/chrome/browser/resources/md_user_manager/supervised_user_learn_more.html
@@ -51,9 +51,7 @@ <span id="title">$i18n{supervisedUserLearnMoreTitle}</span> <iron-icon icon="user-manager:supervisor-account"></iron-icon> </div> - <div class="content-area" - i18n-values=".innerHTML:supervisedUserLearnMoreText"> - </div> + <div class="content-area">$i18nRaw{supervisedUserLearnMoreText}</div> <div id="actions"> <paper-button id="done" class="action primary" on-tap="onDoneTap_"> $i18n{supervisedUserLearnMoreDone}
diff --git a/chrome/browser/resources/md_user_manager/user_manager.html b/chrome/browser/resources/md_user_manager/user_manager.html index 54b93880..7b726c8 100644 --- a/chrome/browser/resources/md_user_manager/user_manager.html +++ b/chrome/browser/resources/md_user_manager/user_manager.html
@@ -320,7 +320,6 @@ <error-dialog></error-dialog> <include src="../../../../ui/login/account_picker/user_pod_template.html"> </user-manager-pages> - <link rel="import" href="chrome://resources/html/i18n_template.html"> <script src="user_manager.js"></script> </body> </html>
diff --git a/chrome/browser/resources/options/browser_options.html b/chrome/browser/resources/options/browser_options.html index b4a7400..fcfbb64 100644 --- a/chrome/browser/resources/options/browser_options.html +++ b/chrome/browser/resources/options/browser_options.html
@@ -896,6 +896,8 @@ <div id="accessibility-settings" hidden> <button id="accessibility-settings-button" i18n-content="accessibilitySettings"></button> + <button id="talkback-settings-button" + i18n-content="accessibilityTalkBackSettings"></button> </div> </div> </div>
diff --git a/chrome/browser/resources/options/browser_options.js b/chrome/browser/resources/options/browser_options.js index 7d7200c..87fe6704 100644 --- a/chrome/browser/resources/options/browser_options.js +++ b/chrome/browser/resources/options/browser_options.js
@@ -726,13 +726,13 @@ // Accessibility section (CrOS only). if (cr.isChromeOS) { - var updateAccessibilitySettingsButton = function() { + var updateAccessibilitySettingsSection = function() { $('accessibility-settings').hidden = !($('accessibility-spoken-feedback-check').checked); }; Preferences.getInstance().addEventListener( 'settings.accessibility', - updateAccessibilitySettingsButton); + updateAccessibilitySettingsSection); $('accessibility-learn-more').onclick = function(unused_event) { chrome.send('coreOptionsUserMetricsAction', ['Options_AccessibilityLearnMore']); @@ -740,9 +740,12 @@ $('accessibility-settings-button').onclick = function(unused_event) { window.open(loadTimeData.getString('accessibilitySettingsURL')); }; + $('talkback-settings-button').onclick = function(unused_event) { + chrome.send('showAccessibilityTalkBackSettings'); + }; $('accessibility-spoken-feedback-check').onchange = - updateAccessibilitySettingsButton; - updateAccessibilitySettingsButton(); + updateAccessibilitySettingsSection; + updateAccessibilitySettingsSection(); var updateScreenMagnifierCenterFocus = function() { $('accessibility-screen-magnifier-center-focus-check').disabled = @@ -834,11 +837,18 @@ $('android-apps-settings-label').innerHTML = loadTimeData.getString('androidAppsSettingsLabel'); Preferences.getInstance().addEventListener('arc.enabled', function(e) { - var settings = $('android-apps-settings'); // Only change settings visibility on committed settings changes. - if (!settings || e.value.uncommitted) + if (e.value.uncommitted) return; - settings.hidden = !e.value.value; + + var isArcEnabled = !e.value.value; + var androidAppSettings = $('android-apps-settings'); + if (androidAppSettings != null) + androidAppSettings.hidden = isArcEnabled; + + var talkbackSettingsButton = $('talkback-settings-button'); + if (talkbackSettingsButton != null) + talkbackSettingsButton.hidden = isArcEnabled; }); $('android-apps-settings-link').addEventListener('click', function(e) {
diff --git a/chrome/browser/resources/settings/appearance_page/appearance_page.html b/chrome/browser/resources/settings/appearance_page/appearance_page.html index 63755ee..8303b98 100644 --- a/chrome/browser/resources/settings/appearance_page/appearance_page.html +++ b/chrome/browser/resources/settings/appearance_page/appearance_page.html
@@ -60,7 +60,7 @@ </div> </template> </div> - <div class="settings-box two-line" + <div class="settings-box" hidden="[[!pageVisibility.homeButton]]"> <settings-checkbox class="start" label="$i18n{showHomeButton}" sub-label="[[getShowHomeSubLabel_(prefs.homepage_is_newtabpage.value, prefs.homepage.value)]]"
diff --git a/chrome/browser/resources/settings/controls/settings_checkbox.html b/chrome/browser/resources/settings/controls/settings_checkbox.html index fb33783..bd8a2548 100644 --- a/chrome/browser/resources/settings/controls/settings_checkbox.html +++ b/chrome/browser/resources/settings/controls/settings_checkbox.html
@@ -10,9 +10,14 @@ <link rel="import" type="css" href="chrome://resources/cr_elements/shared.css"> <template> <style include="settings-shared"> - :host { + #outerRow { align-items: center; display: flex; + min-height: var(--settings-row-two-line-min-height); + width: 100%; + } + + #outerRow[noSubLabel] { min-height: var(--settings-row-min-height); } @@ -20,6 +25,10 @@ @apply(--settings-secondary); } + paper-checkbox:not([disabled]) { + width: 100%; + } + paper-checkbox:not([checked]) .secondary { @apply(--settings-secondary-unchecked); } @@ -30,7 +39,7 @@ </style> <cr-events id="events"></cr-events> - <div class="layout horizontal center"> + <div id="outerRow" noSubLabel$="[[!subLabel]]"> <paper-checkbox id="checkbox" checked="{{checked}}" disabled="[[checkboxDisabled_(disabled, pref)]]"> <div>[[label]]</div>
diff --git a/chrome/browser/resources/settings/device_page/device_page.js b/chrome/browser/resources/settings/device_page/device_page.js index 9e4efee..c029783 100644 --- a/chrome/browser/resources/settings/device_page/device_page.js +++ b/chrome/browser/resources/settings/device_page/device_page.js
@@ -135,7 +135,7 @@ checkPointerSubpage_: function() { if (!this.hasMouse_ && !this.hasTouchpad_ && settings.getCurrentRoute() == settings.Route.POINTERS) { - this.$.pages.fire('subpage-back'); + settings.navigateTo(settings.Route.DEVICE); } }, });
diff --git a/chrome/browser/resources/settings/device_page/keyboard.html b/chrome/browser/resources/settings/device_page/keyboard.html index dfc71bd..8f2f5e0f 100644 --- a/chrome/browser/resources/settings/device_page/keyboard.html +++ b/chrome/browser/resources/settings/device_page/keyboard.html
@@ -51,7 +51,7 @@ </settings-dropdown-menu> </div> </template> - <div class="settings-box two-line"> + <div class="settings-box"> <settings-checkbox pref="{{prefs.settings.language.send_function_keys}}" label="$i18n{keyboardSendFunctionKeys}"
diff --git a/chrome/browser/resources/settings/internet_page/compiled_resources2.gyp b/chrome/browser/resources/settings/internet_page/compiled_resources2.gyp index e9d59db..8ab3604 100644 --- a/chrome/browser/resources/settings/internet_page/compiled_resources2.gyp +++ b/chrome/browser/resources/settings/internet_page/compiled_resources2.gyp
@@ -18,6 +18,7 @@ { 'target_name': 'internet_detail_page', 'dependencies': [ + '../compiled_resources2.gyp:route', '<(DEPTH)/ui/webui/resources/cr_elements/network/compiled_resources2.gyp:cr_onc_types', '<(DEPTH)/ui/webui/resources/cr_elements/policy/compiled_resources2.gyp:cr_policy_network_behavior', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
diff --git a/chrome/browser/resources/settings/internet_page/internet_detail_page.html b/chrome/browser/resources/settings/internet_page/internet_detail_page.html index 114d7de..f676347 100644 --- a/chrome/browser/resources/settings/internet_page/internet_detail_page.html +++ b/chrome/browser/resources/settings/internet_page/internet_detail_page.html
@@ -10,6 +10,7 @@ <link rel="import" href="chrome://resources/cr_elements/network/cr_onc_types.html"> <link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_behavior.html"> <link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_indicator.html"> +<link rel="import" href="/route.html"> <link rel="import" href="internet_shared_css.html"> <link rel="import" href="network_apnlist.html"> <link rel="import" href="network_ip_config.html"> @@ -203,7 +204,7 @@ <!-- Proxy --> <div hidden$="[[!isRememberedOrConnected_(networkProperties)]]"> - <div class="subtitle">Proxy</div> + <div class="subtitle">Proxy</div> <network-proxy editable on-proxy-change="onProxyChange_" network-properties="[[networkProperties]]"> </network-proxy>
diff --git a/chrome/browser/resources/settings/internet_page/internet_detail_page.js b/chrome/browser/resources/settings/internet_page/internet_detail_page.js index 598a02a..b8dbbd4b 100644 --- a/chrome/browser/resources/settings/internet_page/internet_detail_page.js +++ b/chrome/browser/resources/settings/internet_page/internet_detail_page.js
@@ -127,11 +127,9 @@ /** @private */ close_: function() { - // Delay sending subpage-back until the next render frame to allow other - // subpages to load first. - setTimeout(function() { - this.fire('subpage-back'); - }.bind(this)); + // Delay navigating until the next render frame to allow other subpages to + // load first. + setTimeout(function() { settings.navigateTo(settings.Route.INTERNET) }); }, /** @private */
diff --git a/chrome/browser/resources/settings/people_page/compiled_resources2.gyp b/chrome/browser/resources/settings/people_page/compiled_resources2.gyp index 3b5f215..3f68188 100644 --- a/chrome/browser/resources/settings/people_page/compiled_resources2.gyp +++ b/chrome/browser/resources/settings/people_page/compiled_resources2.gyp
@@ -66,15 +66,25 @@ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], }, { + 'target_name': 'password_prompt_dialog', + 'dependencies': [ + '../compiled_resources2.gyp:route', + '<(EXTERNS_GYP):quick_unlock_private', + ], + 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], + }, + { 'target_name': 'people_page', 'dependencies': [ '../compiled_resources2.gyp:route', '../settings_page/compiled_resources2.gyp:settings_animated_pages', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert', + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:web_ui_listener_behavior', 'easy_unlock_browser_proxy', 'easy_unlock_turn_off_dialog', + 'lock_state_behavior', 'profile_info_browser_proxy', 'sync_browser_proxy', ], @@ -88,7 +98,7 @@ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], }, { - 'target_name': 'quick_unlock_authenticate', + 'target_name': 'lock_state_behavior', 'dependencies': [ '../compiled_resources2.gyp:route', '<(EXTERNS_GYP):quick_unlock_private', @@ -96,30 +106,21 @@ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], }, { - 'target_name': 'quick_unlock_choose_method', + 'target_name': 'lock_screen', 'dependencies': [ '../compiled_resources2.gyp:route', - '../prefs/compiled_resources2.gyp:prefs_types', - '../prefs/compiled_resources2.gyp:prefs_behavior', - 'quick_unlock_password_detect_behavior', - '<(EXTERNS_GYP):quick_unlock_private', - ], - 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], - }, - { - 'target_name': 'quick_unlock_password_detect_behavior', - 'dependencies': [ - '../compiled_resources2.gyp:route', - ], - 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], - }, - { - 'target_name': 'quick_unlock_setup_pin', - 'dependencies': [ - '../compiled_resources2.gyp:route', - 'quick_unlock_password_detect_behavior', + 'lock_state_behavior', + 'password_prompt_dialog', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior', - '<(EXTERNS_GYP):quick_unlock_private', + ], + 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], + }, + { + 'target_name': 'setup_pin_dialog', + 'dependencies': [ + '../compiled_resources2.gyp:route', + 'password_prompt_dialog', + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior', ], 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], },
diff --git a/chrome/browser/resources/settings/people_page/lock_screen.html b/chrome/browser/resources/settings/people_page/lock_screen.html new file mode 100644 index 0000000..6318855 --- /dev/null +++ b/chrome/browser/resources/settings/people_page/lock_screen.html
@@ -0,0 +1,59 @@ +<link rel="import" href="chrome://resources/html/i18n_behavior.html"> +<link rel="import" href="chrome://resources/html/polymer.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> +<link rel="import" href="/people_page/lock_state_behavior.html"> +<link rel="import" href="/people_page/password_prompt_dialog.html"> +<link rel="import" href="/people_page/setup_pin_dialog.html"> +<link rel="import" href="/prefs/prefs_behavior.html"> +<link rel="import" href="/route.html"> +<link rel="import" href="/settings_shared_css.html"> + +<dom-module id="settings-lock-screen"> + <template> + <style include="settings-shared"></style> + <style> + .radio-indent { + margin-left: 28px; + } + + paper-button { + text-transform: none; + } + </style> + + <div> + <div class="list-frame"> + <paper-radio-group selected="{{selectedUnlockType}}"> + <paper-radio-button name="password"> + $i18n{lockScreenPasswordOnly} + </paper-radio-button> + <paper-radio-button name="pin+password"> + $i18n{lockScreenPinOrPassword} + </paper-radio-button> + <div class="settings-box continuation radio-indent" + hidden$="[[!showConfigurePinButton_(selectedUnlockType)]]"> + <paper-button is="action-link" on-tap="onConfigurePin_"> + [[getSetupPinText_(hasPin)]] + </paper-button> + </div> + </paper-radio-group> + </div> + + <div class="settings-box single-column"> + <settings-checkbox pref="{{prefs.settings.enable_screen_lock}}" + label="$i18n{enableScreenlock}"> + </settings-checkbox> + </div> + + <settings-password-prompt-dialog id="passwordPrompt" + on-close="onPasswordClosed_" + set-modes="{{setModes_}}"> + </settings-password-prompt-dialog> + <settings-setup-pin-dialog id="setupPin" on-done="onPinSetupDone_" + set-modes="[[setModes_]]"> + </settings-setup-pin-dialog> + </div> + </template> + + <script src="lock_screen.js"></script> +</dom-module>
diff --git a/chrome/browser/resources/settings/people_page/lock_screen.js b/chrome/browser/resources/settings/people_page/lock_screen.js new file mode 100644 index 0000000..f296363b --- /dev/null +++ b/chrome/browser/resources/settings/people_page/lock_screen.js
@@ -0,0 +1,125 @@ +// 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. + +/** + * @fileoverview + * 'settings-lock-screen' allows the user to change how they unlock their + * device. + * + * Example: + * + * <settings-lock-screen + * prefs="{{prefs}}"> + * </settings-lock-screen> + */ + +Polymer({ + is: 'settings-lock-screen', + + behaviors: [I18nBehavior, LockStateBehavior, settings.RouteObserverBehavior], + + properties: { + /** Preferences state. */ + prefs: { + type: Object + }, + + /** + * setModes_ is a partially applied function that stores the previously + * entered password. It's defined only when the user has already entered a + * valid password. + * + * @type {Object|undefined} + * @private + */ + setModes_: { + type: Object, + observer: 'onSetModesChanged_' + }, + }, + + /** selectedUnlockType is defined in LockStateBehavior. */ + observers: ['selectedUnlockTypeChanged_(selectedUnlockType)'], + + /** @override */ + attached: function() { + // currentRouteChanged is not called during the initial navigation. If the + // user navigates directly to the lockScreen page, we still want to show the + // password prompt page. + this.currentRouteChanged(); + }, + + /** + * Overridden from settings.RouteObserverBehavior. + * @protected + */ + currentRouteChanged: function() { + if (settings.getCurrentRoute() == settings.Route.LOCK_SCREEN && + !this.setModes_) { + this.$.passwordPrompt.open(); + } else { + // If the user navigated away from the lock screen settings page they will + // have to re-enter their password. + this.setModes_ = undefined; + } + }, + + /** + * Called when the unlock type has changed. + * @param {!string} selected The current unlock type. + * @private + */ + selectedUnlockTypeChanged_: function(selected) { + if (selected == LockScreenUnlockType.VALUE_PENDING) + return; + + if (selected != LockScreenUnlockType.PIN_PASSWORD && this.setModes_) { + this.setModes_.call(null, [], [], function(didSet) { + assert(didSet, 'Failed to clear quick unlock modes'); + }); + } + }, + + /** @private */ + onSetModesChanged_: function() { + if (settings.getCurrentRoute() == settings.Route.LOCK_SCREEN && + !this.setModes_) { + this.$.setupPin.close(); + this.$.passwordPrompt.open(); + } + }, + + /** @private */ + onPasswordClosed_: function() { + if (!this.setModes_) + settings.navigateTo(settings.Route.PEOPLE); + }, + + /** @private */ + onPinSetupDone_: function() { + this.$.setupPin.close(); + }, + + /** + * Returns true if the setup pin section should be shown. + * @param {!string} selectedUnlockType The current unlock type. Used to let + * Polymer know about the dependency. + * @private + */ + showConfigurePinButton_: function(selectedUnlockType) { + return selectedUnlockType === LockScreenUnlockType.PIN_PASSWORD; + }, + + /** @private */ + getSetupPinText_: function() { + if (this.hasPin) + return this.i18n('lockScreenChangePinButton'); + return this.i18n('lockScreenSetupPinButton'); + }, + + /** @private */ + onConfigurePin_: function() { + this.$.setupPin.open(); + }, +});
diff --git a/chrome/browser/resources/settings/people_page/lock_state_behavior.html b/chrome/browser/resources/settings/people_page/lock_state_behavior.html new file mode 100644 index 0000000..508b4344 --- /dev/null +++ b/chrome/browser/resources/settings/people_page/lock_state_behavior.html
@@ -0,0 +1,2 @@ +<link rel="import" href="chrome://resources/html/polymer.html"> +<script src="lock_state_behavior.js"></script>
diff --git a/chrome/browser/resources/settings/people_page/lock_state_behavior.js b/chrome/browser/resources/settings/people_page/lock_state_behavior.js new file mode 100644 index 0000000..e96c2af3 --- /dev/null +++ b/chrome/browser/resources/settings/people_page/lock_state_behavior.js
@@ -0,0 +1,76 @@ +// 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. + +/** + * @fileoverview + * Contains utilities that help identify the current way that the lock screen + * will be displayed. + */ + +/** @enum {string} */ +var LockScreenUnlockType = { + VALUE_PENDING: 'value_pending', + PASSWORD: 'password', + PIN_PASSWORD: 'pin+password' +}; + +/** @polymerBehavior */ +var LockStateBehavior = { + properties: { + /** + * The currently selected unlock type. + * @type {!LockScreenUnlockType} + */ + selectedUnlockType: { + type: String, + notify: true, + value: LockScreenUnlockType.VALUE_PENDING + }, + + /** + * True/false if there is a PIN set; undefined if the computation is still + * pending. This is a separate value from selectedUnlockType because the UI + * can change the selectedUnlockType before setting up a PIN. + * @type {boolean|undefined} + */ + hasPin: { + type: Boolean, + notify: true + } + }, + + /** @override */ + attached: function() { + this.boundOnActiveModesChanged_ = this.updateUnlockType_.bind(this); + chrome.quickUnlockPrivate.onActiveModesChanged.addListener( + this.boundOnActiveModesChanged_); + + this.updateUnlockType_(); + }, + + /** @override */ + detached: function() { + chrome.quickUnlockPrivate.onActiveModesChanged.removeListener( + this.boundOnActiveModesChanged_); + }, + + /** + * Updates the selected unlock type radio group. This function will get called + * after preferences are initialized, after the quick unlock mode has been + * changed, and after the lockscreen preference has changed. + * + * @private + */ + updateUnlockType_: function() { + chrome.quickUnlockPrivate.getActiveModes(function(modes) { + if (modes.includes(chrome.quickUnlockPrivate.QuickUnlockMode.PIN)) { + this.hasPin = true; + this.selectedUnlockType = LockScreenUnlockType.PIN_PASSWORD; + } else { + this.hasPin = false; + this.selectedUnlockType = LockScreenUnlockType.PASSWORD; + } + }.bind(this)); + }, +};
diff --git a/chrome/browser/resources/settings/people_page/password_prompt_dialog.html b/chrome/browser/resources/settings/people_page/password_prompt_dialog.html new file mode 100644 index 0000000..8221eff3 --- /dev/null +++ b/chrome/browser/resources/settings/people_page/password_prompt_dialog.html
@@ -0,0 +1,51 @@ +<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html"> +<link rel="import" href="chrome://resources/html/polymer.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html"> +<link rel="import" href="/settings_shared_css.html"> +<link rel="import" href="/settings_shared_css.html"> + +<dom-module id="settings-password-prompt-dialog"> + <template> + <style include="settings-shared"> + #passwordInput { + display: inline-block; + } + + .settings-box { + padding: 0; + } + </style> + + <dialog is="cr-dialog" id="dialog"> + <div class="title">$i18n{passwordPromptTitle}</div> + <div class="body"> + + <div class="settings-box first">$i18n{passwordPromptEnterPassword}</div> + + <paper-input id="passwordInput" type="password" autofocus + label="$i18n{passwordPromptPasswordLabel}" + no-label-float + value="{{password_}}" + on-change="checkPassword_" + invalid$="[[passwordInvalid_]]" + error-message="$i18n{passwordPromptInvalidPassword}" + aria-disabled="false"> + </paper-input> + + <div class="button-strip"> + <paper-button class="cancel-button" on-tap="cancel"> + $i18n{cancel} + </paper-button> + + <paper-button class="action-button" on-tap="checkPassword_" + disabled$="[[!enableConfirm_(password_, + passwordInvalid_)]]"> + $i18n{confirm} + </paper-button> + </div> + </div> + </dialog> + </template> + <script src="password_prompt_dialog.js"></script> +</dom-module>
diff --git a/chrome/browser/resources/settings/people_page/password_prompt_dialog.js b/chrome/browser/resources/settings/people_page/password_prompt_dialog.js new file mode 100644 index 0000000..944be30 --- /dev/null +++ b/chrome/browser/resources/settings/people_page/password_prompt_dialog.js
@@ -0,0 +1,171 @@ +// 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. + +/** + * @fileoverview + * + * 'settings-password-prompt-dialog' shows a dialog which asks for the user to + * enter their password. It validates the password is correct. Once the user has + * entered their account password, the page fires an 'authenticated' event and + * updates the setModes binding. + * + * The setModes binding is a wrapper around chrome.quickUnlockPrivate.setModes + * which has a prebound account password. The account password by itself is not + * available for other elements to access. + * + * Example: + * + * <settings-password-prompt-dialog + * id="passwordPrompt" + * set-modes="[[setModes]]"> + * </settings-password-prompt-dialog> + * + * this.$.passwordPrompt.open() + */ + +(function() { +'use strict'; + +/** @const */ var PASSWORD_ACTIVE_DURATION_MS = 10 * 60 * 1000; // Ten minutes. + +/** + * Helper method that checks if |password| is valid. + * @param {string} password + * @param {function(boolean):void} onCheck + */ +function checkAccountPassword_(password, onCheck) { + // We check the account password by trying to update the active set of quick + // unlock modes without changing any credentials. + chrome.quickUnlockPrivate.getActiveModes(function(modes) { + var credentials = + /** @type {!Array<string>} */ (Array(modes.length).fill('')); + chrome.quickUnlockPrivate.setModes(password, modes, credentials, onCheck); + }); +} + +Polymer({ + is: 'settings-password-prompt-dialog', + + properties: { + /** + * A wrapper around chrome.quickUnlockPrivate.setModes with the account + * password already supplied. If this is null, the authentication screen + * needs to be redisplayed. This property will be cleared after + * PASSWORD_ACTIVE_DURATION_MS milliseconds. + */ + setModes: { + type: Object, + notify: true + }, + + /** + * The actual value of the password field. This is cleared whenever the + * authentication screen is not displayed so that the user's password is not + * easily available to an attacker. The actual password is stored as an + * captured closure variable inside of setModes. + * @private + */ + password_: { + type: String, + observer: 'onPasswordChanged_' + }, + + /** + * Helper property which marks password as valid/invalid. + * @private + */ + passwordInvalid_: Boolean + }, + + /** + * Open up the dialog. This will wait until the dialog has loaded before + * opening it. + */ + open: function() { + // Wait until the dialog is attached to the DOM before trying to open it. + var dialog = /** @type {{isConnected: boolean}} */ (this.$.dialog); + if (!dialog.isConnected) { + setTimeout(this.open.bind(this)); + return; + } + + this.$.dialog.showModal(); + }, + + /** Close the dialog. */ + close: function() { + if (this.$.dialog.open) + this.$.dialog.close(); + + this.password_ = ''; + }, + + /** Cancel the password prompt. */ + cancel: function() { + if (this.$.dialog.open) + this.$.dialog.cancel(); + + // We bind setModes_ in an on-change event, so when the user hits cancel + // after they enter their valid password we may have authenticated them. + this.setModes_ = undefined; + }, + + /** + * Run the account password check. + * @private + */ + checkPassword_: function() { + clearTimeout(this.clearAccountPasswordTimeout_); + + // The user might have started entering a password and then deleted it all. + // Do not submit/show an error in this case. + if (!this.password_) { + this.passwordInvalid_ = false; + return; + } + + function onPasswordChecked(valid) { + // The password might have been cleared during the duration of the + // getActiveModes call. + this.passwordInvalid_ = !valid && !!this.password_; + + if (valid) { + // Create the |this.setModes| closure and automatically clear it after + // |PASSWORD_ACTIVE_DURATION_MS|. + var password = this.password_; + this.password_ = ''; + + this.setModes = function(modes, credentials, onComplete) { + chrome.quickUnlockPrivate.setModes( + password, modes, credentials, onComplete); + }; + + function clearSetModes() { + // Reset the password so that any cached references to this.setModes + // will fail. + password = ''; + this.setModes = null; + } + + this.clearAccountPasswordTimeout_ = setTimeout( + clearSetModes.bind(this), PASSWORD_ACTIVE_DURATION_MS); + this.close(); + } + } + + checkAccountPassword_(this.password_, onPasswordChecked.bind(this)); + }, + + /** @private */ + onPasswordChanged_: function() { + this.passwordInvalid_ = false; + }, + + /** @private */ + enableConfirm_: function() { + return !!this.password_ && !this.passwordInvalid_; + } +}); + +})();
diff --git a/chrome/browser/resources/settings/people_page/people_page.html b/chrome/browser/resources/settings/people_page/people_page.html index ac843ff..13b2f0a1 100644 --- a/chrome/browser/resources/settings/people_page/people_page.html +++ b/chrome/browser/resources/settings/people_page/people_page.html
@@ -1,4 +1,5 @@ <link rel="import" href="chrome://resources/cr_elements/icons.html"> +<link rel="import" href="chrome://resources/html/i18n_behavior.html"> <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html"> <link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animatable.html"> @@ -18,9 +19,8 @@ <link rel="import" href="/people_page/change_picture.html"> <link rel="import" href="/people_page/easy_unlock_browser_proxy.html"> <link rel="import" href="/people_page/easy_unlock_turn_off_dialog.html"> -<link rel="import" href="/people_page/quick_unlock_authenticate.html"> -<link rel="import" href="/people_page/quick_unlock_choose_method.html"> -<link rel="import" href="/people_page/quick_unlock_setup_pin.html"> +<link rel="import" href="/people_page/lock_screen.html"> +<link rel="import" href="/people_page/lock_state_behavior.html"> <link rel="import" href="/people_page/users_page.html"> </if> <if expr="not chromeos"> @@ -160,19 +160,24 @@ </div> <if expr="chromeos"> - <div class="settings-box single-column"> - <settings-checkbox pref="{{prefs.settings.enable_screen_lock}}" - label="$i18n{enableScreenlock}"> - </settings-checkbox> - </div> + <template is="dom-if" if="[[!quickUnlockEnabled_]]"> + <div class="settings-box single-column"> + <settings-checkbox pref="{{prefs.settings.enable_screen_lock}}" + label="$i18n{enableScreenlock}"> + </settings-checkbox> + </div> + </template> - <!-- TODO(jdufault): Disable navigating to /quickUnlock/* if pin is - disabled. --> - <template is="dom-if" if=[[quickUnlockEnabled_]]> - <div class="settings-box"> - <paper-button on-tap="onQuickUnlockTap_" class="primary-button"> - $i18n{quickUnlockTitle} - </paper-button> + <template is="dom-if" if="[[quickUnlockEnabled_]]"> + <div class="settings-box two-line" actionable + on-tap="onConfigureLockTap_"> + <div class="middle"> + <div>$i18n{lockScreenTitle}</div> + <div class="secondary"> + [[getPasswordState_(hasPin, + prefs.settings.enable_screen_lock.value)]] + </div> + </div> </div> </template> @@ -234,34 +239,24 @@ </div> </template> </neon-animatable> - <template is="dom-if" name="sync"> - <settings-subpage - associated-control="[[$$('#customize-sync')]]" - page-title="$i18n{syncPageTitle}"> - <settings-sync-page></settings-sync-page> - </settings-subpage> + <template is="dom-if" if="[[isAdvancedSyncSettingsVisible_(syncStatus)]]"> + <template is="dom-if" name="sync"> + <settings-subpage + associated-control="[[$$('#customize-sync')]]" + page-title="$i18n{syncPageTitle}"> + <settings-sync-page></settings-sync-page> + </settings-subpage> + </template> </template> <if expr="chromeos"> - <template is="dom-if" name="quick-unlock-authenticate" no-search> - <settings-subpage page-title="$i18n{quickUnlockTitle}"> - <settings-quick-unlock-authenticate - set-modes="{{quickUnlockSetModes}}" - profile-name="[[profileName_]]"> - </settings-quick-unlock-authenticate> - </settings-subpage> - </template> - <template is="dom-if" name="quick-unlock-choose-method" no-search> - <settings-subpage page-title="$i18n{quickUnlockTitle}"> - <settings-quick-unlock-choose-method - set-modes="[[quickUnlockSetModes]]" prefs="{{prefs}}"> - </settings-quick-unlock-choose-method> - </settings-subpage> - </template> - <template is="dom-if" name="quick-unlock-setup-pin" no-search> - <settings-subpage page-title="$i18n{quickUnlockTitle}"> - <settings-quick-unlock-setup-pin set-modes="[[quickUnlockSetModes]]"> - </settings-quick-unlock-setup-pin> - </settings-subpage> + <template is="dom-if" if="[[quickUnlockEnabled_]]"> + <template is="dom-if" name="lockScreen"> + <settings-subpage page-title="$i18n{lockScreenTitle}"> + <settings-lock-screen + prefs="{{prefs}}"> + </settings-lock-screen> + </settings-subpage> + </template> </template> <template is="dom-if" name="users"> <settings-subpage
diff --git a/chrome/browser/resources/settings/people_page/people_page.js b/chrome/browser/resources/settings/people_page/people_page.js index cc6dcc1..da7961a35 100644 --- a/chrome/browser/resources/settings/people_page/people_page.js +++ b/chrome/browser/resources/settings/people_page/people_page.js
@@ -10,7 +10,11 @@ is: 'settings-people-page', behaviors: [ + I18nBehavior, WebUIListenerBehavior, +<if expr="chromeos"> + LockStateBehavior, +</if> ], properties: { @@ -135,6 +139,17 @@ </if> }, +<if expr="chromeos"> + /** @private */ + getPasswordState_: function(hasPin, enableScreenLock) { + if (!enableScreenLock) + return this.i18n('lockScreenNone'); + if (hasPin) + return this.i18n('lockScreenPinOrPassword'); + return this.i18n('lockScreenPasswordOnly'); + }, +</if> + /** * Handler for when the profile's icon and name is updated. * @private @@ -232,8 +247,8 @@ <if expr="chromeos"> /** @private */ - onQuickUnlockTap_: function() { - settings.navigateTo(settings.Route.QUICK_UNLOCK_AUTHENTICATE); + onConfigureLockTap_: function() { + settings.navigateTo(settings.Route.LOCK_SCREEN); }, /** @private */
diff --git a/chrome/browser/resources/settings/people_page/quick_unlock_authenticate.html b/chrome/browser/resources/settings/people_page/quick_unlock_authenticate.html deleted file mode 100644 index 96524ac..0000000 --- a/chrome/browser/resources/settings/people_page/quick_unlock_authenticate.html +++ /dev/null
@@ -1,54 +0,0 @@ -<link rel="import" href="chrome://resources/html/polymer.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html"> -<link rel="import" href="/route.html"> -<link rel="import" href="/settings_page/settings_section.html"> -<link rel="import" href="/settings_shared_css.html"> - -<dom-module id="settings-quick-unlock-authenticate"> - <template> - <style include="settings-shared"></style> - <style> - #profile-name { - margin-right: 16px; - } - - #password-input { - display: inline-block; - } - - .secondary-action { - /* Increase the length of the vertical line, since it has no actual - content to be sized to. */ - padding: 10px 0 10px 0; - } - </style> - - <div> - <div class="settings-box">$i18n{quickUnlockConfirmLogin}</div> - - <div class="settings-box block first"> - <span id="profile-name"> - [[profileName]] - </span> - - <!-- The secondary-action would normally be on the paper-input element, - but that makes the secondary-action have a long top-section because - the paper-input has an floating text element appear above it which is - invisible when there is no content inside the input. --> - <span class="secondary-action"></span> - - <paper-input id="password-input" type="password" - label="$i18n{quickUnlockPasswordLabel}" - value="{{password_}}" - invalid$="[[passwordInvalid_]]" - on-change="checkPasswordNow_" - on-input="startDelayedPasswordCheck_" - error-message="$i18n{quickUnlockInvalidPassword}" - aria-disabled="false"> - </paper-input> - </div> - </div> - </template> - - <script src="quick_unlock_authenticate.js"></script> -</dom-module>
diff --git a/chrome/browser/resources/settings/people_page/quick_unlock_authenticate.js b/chrome/browser/resources/settings/people_page/quick_unlock_authenticate.js deleted file mode 100644 index 8fed447..0000000 --- a/chrome/browser/resources/settings/people_page/quick_unlock_authenticate.js +++ /dev/null
@@ -1,155 +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. - -/** - * @fileoverview - * - * 'settings-quick-unlock-authenticate' shows a password input prompt to the - * user. It validates the password is correct. Once the user has entered their - * account password, the page navigates to the quick unlock setup methods page. - * - * This element provides a wrapper around chrome.quickUnlockPrivate.setModes - * which has a prebound account password (the |set-modes| property). The account - * password by itself is not available for other elements to access. - * - * Example: - * - * <settings-quick-unlock-authenticate - * set-modes="[[setModes]]" - * profile-name="[[profileName_]]"> - * </settings-quick-unlock-authenticate> - */ - -(function() { -'use strict'; - -/** @const */ var PASSWORD_ACTIVE_DURATION_MS = 10 * 60 * 1000; // Ten minutes. -/** @const */ var AUTOSUBMIT_DELAY_MS = 500; // .5 seconds - -/** - * Helper method that checks if |password| is valid. - * @param {string} password - * @param {function(boolean):void} onCheck - */ -function checkAccountPassword_(password, onCheck) { - // We check the account password by trying to update the active set of quick - // unlock modes without changing any credentials. - chrome.quickUnlockPrivate.getActiveModes(function(modes) { - var credentials = - /** @type {!Array<string>} */ (Array(modes.length).fill('')); - chrome.quickUnlockPrivate.setModes(password, modes, credentials, onCheck); - }); -} - -Polymer({ - is: 'settings-quick-unlock-authenticate', - - behavior: [settings.RouteObserverBehavior], - - properties: { - /** - * A wrapper around chrome.quickUnlockPrivate.setModes with the account - * password already supplied. If this is null, the authentication screen - * needs to be redisplayed. This property will be cleared after - * PASSWORD_ACTIVE_DURATION_MS milliseconds. - */ - setModes: { - type: Object, - notify: true - }, - - /** - * Name of the profile. - */ - profileName: String, - - /** - * The actual value of the password field. This is cleared whenever the - * authentication screen is not displayed so that the user's password is not - * easily available to an attacker. The actual password is stored as an - * captured closure variable inside of setModes. - * @private - */ - password_: String, - - /** - * Helper property which marks password as valid/invalid. - * @private - */ - passwordInvalid_: Boolean - }, - - /** @protected */ - currentRouteChanged: function() { - // Clear local state if this screen is not active so if this screen shows - // up again the user will get a fresh UI. - if (settings.getCurrentRoute() == settings.Route.QUICK_UNLOCK_AUTHENTICATE) - return; - - this.password_ = ''; - this.passwordInvalid_ = false; - }, - - /** - * Start or restart a timer to check the account password and move past the - * authentication screen. - * @private - */ - startDelayedPasswordCheck_: function() { - clearTimeout(this.delayedPasswordCheckTimeout_); - this.delayedPasswordCheckTimeout_ = - setTimeout(this.checkPasswordNow_.bind(this), AUTOSUBMIT_DELAY_MS); - }, - - /** - * Run the account password check right now. This will cancel any delayed - * check. - * @private - */ - checkPasswordNow_: function() { - clearTimeout(this.delayedPasswordCheckTimeout_); - clearTimeout(this.clearAccountPasswordTimeout_); - - // The user might have started entering a password and then deleted it all. - // Do not submit/show an error in this case. - if (!this.password_) { - this.passwordInvalid_ = false; - return; - } - - function onPasswordChecked(valid) { - // The password might have been cleared during the duration of the - // getActiveModes call. - this.passwordInvalid_ = !valid && !!this.password_; - - if (valid) { - // Create the |this.setModes| closure and automatically clear it after - // |PASSWORD_ACTIVE_DURATION_MS|. - var password = this.password_; - this.password_ = ''; - - this.setModes = function(modes, credentials, onComplete) { - chrome.quickUnlockPrivate.setModes( - password, modes, credentials, onComplete); - }; - - function clearSetModes() { - // Reset the password so that any cached references to this.setModes - // will fail. - password = ''; - this.setModes = null; - } - - this.clearAccountPasswordTimeout_ = setTimeout( - clearSetModes.bind(this), PASSWORD_ACTIVE_DURATION_MS); - - settings.navigateTo(settings.Route.QUICK_UNLOCK_CHOOSE_METHOD); - } - } - - checkAccountPassword_(this.password_, onPasswordChecked.bind(this)); - } -}); - -})();
diff --git a/chrome/browser/resources/settings/people_page/quick_unlock_choose_method.html b/chrome/browser/resources/settings/people_page/quick_unlock_choose_method.html deleted file mode 100644 index e159fb5..0000000 --- a/chrome/browser/resources/settings/people_page/quick_unlock_choose_method.html +++ /dev/null
@@ -1,63 +0,0 @@ -<link rel="import" href="chrome://resources/html/polymer.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html"> -<link rel="import" href="/people_page/pin_keyboard.html"> -<link rel="import" href="/people_page/quick_unlock_password_detect_behavior.html"> -<link rel="import" href="/prefs/prefs_behavior.html"> -<link rel="import" href="/route.html"> -<link rel="import" href="/settings_page/settings_section.html"> -<link rel="import" href="/settings_shared_css.html"> - - -<dom-module id="settings-quick-unlock-choose-method"> - <template> - <style include="settings-shared"></style> - <style> - #warning-message { - color: var(--paper-grey-500); - font-style: italic; - } - - .align-end { - justify-content: flex-end; - } - </style> - - <div> - <div class="settings-box"> - $i18n{quickUnlockChooseUnlockMethod} - </div> - - <div class="list-frame"> - <paper-radio-group selected="{{selectedUnlockType_}}"> - <paper-radio-button name="password"> - $i18n{quickUnlockUnlockMethodPassword} - </paper-radio-button> - <paper-radio-button name="pin+password"> - $i18n{quickUnlockUnlockMethodPinAndPassword} - </paper-radio-button> - <paper-radio-button name="none"> - $i18n{quickUnlockUnlockMethodNone} - </paper-radio-button> - </paper-radio-group> - </div> - - <div class="step" hidden$="[[!showSetupPin_(selectedUnlockType_)]]"> - <div class="settings-box continuation"> - <!-- TODO(jdufault): i18n once this string is finalized. --> - <span id="warning-message"> - Warning about how PIN is weaker than a password. - </span> - </div> - - <div class="align-end settings-box"> - <paper-button class="action-button" on-tap="onConfigurePin_"> - $i18n{quickUnlockConfigurePinButton} - </paper-button> - </div> - </div> - </div> - </template> - - <script src="quick_unlock_choose_method.js"></script> -</dom-module>
diff --git a/chrome/browser/resources/settings/people_page/quick_unlock_password_detect_behavior.html b/chrome/browser/resources/settings/people_page/quick_unlock_password_detect_behavior.html deleted file mode 100644 index 1479ade..0000000 --- a/chrome/browser/resources/settings/people_page/quick_unlock_password_detect_behavior.html +++ /dev/null
@@ -1,3 +0,0 @@ -<link rel="import" href="chrome://resources/html/polymer.html"> -<link rel="import" href="/route.html"> -<script src="/people_page/quick_unlock_password_detect_behavior.js"></script>
diff --git a/chrome/browser/resources/settings/people_page/quick_unlock_password_detect_behavior.js b/chrome/browser/resources/settings/people_page/quick_unlock_password_detect_behavior.js deleted file mode 100644 index 24e98d44..0000000 --- a/chrome/browser/resources/settings/people_page/quick_unlock_password_detect_behavior.js +++ /dev/null
@@ -1,25 +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. - -/** - * @fileoverview - * Contains utilities for verifying the user has entered an account password. - */ - -/** @polymerBehavior */ -var QuickUnlockPasswordDetectBehavior = { - properties: { - setModes: Object - }, - - /** - * Verifies that there is an account password available for the - * chrome.quickUnlockPrivate.setModes call. If there is no password, this will - * redirect to the authenticate screen. - */ - askForPasswordIfUnset: function() { - if (!this.setModes) - settings.navigateTo(settings.Route.QUICK_UNLOCK_AUTHENTICATE); - } -};
diff --git a/chrome/browser/resources/settings/people_page/quick_unlock_setup_pin.html b/chrome/browser/resources/settings/people_page/quick_unlock_setup_pin.html deleted file mode 100644 index efd310f..0000000 --- a/chrome/browser/resources/settings/people_page/quick_unlock_setup_pin.html +++ /dev/null
@@ -1,78 +0,0 @@ -<link rel="import" href="chrome://resources/html/polymer.html"> -<link rel="import" href="chrome://resources/html/i18n_behavior.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> -<link rel="import" href="/people_page/pin_keyboard.html"> -<link rel="import" href="/people_page/quick_unlock_password_detect_behavior.html"> -<link rel="import" href="/route.html"> -<link rel="import" href="/settings_page/settings_section.html"> -<link rel="import" href="/settings_shared_css.html"> - -<dom-module id="settings-quick-unlock-setup-pin"> - <template> - <style include="settings-shared"></style> - <style> - iron-icon { - -webkit-margin-end: var(--iron-icon-spacing); - } - - .warning { - color: var(--paper-grey-500); - } - - .warning > iron-icon { - --iron-icon-fill-color: var(--paper-grey-500); - } - - .error { - color: var(--paper-red-500); - } - - .error > iron-icon { - --iron-icon-fill-color: var(--paper-red-500); - } - - .align-center { - justify-content: center; - } - - .align-end { - justify-content: flex-end; - } - </style> - - <div> - <!-- Title; only shown if warning/error is hidden. --> - <div class="settings-box" hidden$="[[hasProblem_(problemMessage_)]]"> - <span>[[getTitleMessage_(isConfirmStep_)]]</span> - </div> - - <!-- Warning/error; only shown if title is hidden. --> - <div class$="[[problemClass_]] settings-box" - hidden$="[[!hasProblem_(problemMessage_)]]"> - <iron-icon icon="icons:warning"></iron-icon> - <span>[[problemMessage_]]</span> - </div> - - <!-- Pin keyboard --> - <div class="align-center settings-box continuation"> - <pin-keyboard on-pin-change="onPinChange_" on-submit="onPinSubmit_" - value="{{pinKeyboardValue_}}"></pin-keyboard> - </div> - - <div class="align-end settings-box"> - <paper-button class="cancel-button" on-tap="resetState_" - hidden$="[[!isConfirmStep_]]"> - $i18n{quickUnlockConfigurePinBackButton} - </paper-button> - - <paper-button class="action-button" on-tap="onPinSubmit_" - disabled$="[[!enableSubmit_]]"> - <span>[[getContinueMessage_(isConfirmStep_)]]</span> - </paper-button> - </div> - - </div> - </template> - - <script src="quick_unlock_setup_pin.js"></script> -</dom-module>
diff --git a/chrome/browser/resources/settings/people_page/quick_unlock_setup_pin.js b/chrome/browser/resources/settings/people_page/quick_unlock_setup_pin.js deleted file mode 100644 index e74ab32..0000000 --- a/chrome/browser/resources/settings/people_page/quick_unlock_setup_pin.js +++ /dev/null
@@ -1,291 +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. - -/** - * @fileoverview - * 'settings-quick-unlock-setup-pin' is the settings page for choosing a PIN. - * - * Example: - * - * <settings-quick-unlock-setup-pin set-modes="[[quickUnlockSetModes]]"> - * </settings-quick-unlock-setup-pin> - */ - -(function() { -'use strict'; - -/** - * Metainformation about a problem message to pass to showProblem. |class| is - * the css class to show the problem message with. |messageId| is the i18n - * string id to use. - * @const - */ -var ProblemInfo = { - TOO_SHORT: { - messageId: 'quickUnlockConfigurePinChoosePinTooShort', - class: 'error' - }, - WEAK: { - messageId: 'quickUnlockConfigurePinChoosePinWeakPinWarning', - class: 'warning' - }, - MISMATCHED: { - messageId: 'quickUnlockConfigurePinMismatchedPins', - class: 'error' - } -}; - -/** - * A list of the top-10 most commmonly used PINs. This list is taken from - * www.datagenetics.com/blog/september32012/. - * @const - */ -var WEAK_PINS = [ - '1234', '1111', '0000', '1212', '7777', '1004', '2000', '4444', '2222', - '6969' -]; - -Polymer({ - is: 'settings-quick-unlock-setup-pin', - - behaviors: [ - I18nBehavior, - QuickUnlockPasswordDetectBehavior, - settings.RouteObserverBehavior - ], - - properties: { - /** - * The current PIN keyboard value. - * @private - */ - pinKeyboardValue_: String, - - /** - * Stores the initial PIN value so it can be confirmed. - * @private - */ - initialPin_: String, - - /** - * The actual problem message to display. - * @private - */ - problemMessage_: String, - - /** - * The type of problem class to show (warning or error). - */ - problemClass_: String, - - /** - * Should the step-specific submit button be displayed? - * @private - */ - enableSubmit_: Boolean, - - /** - * The current step/subpage we are on. - * @private - */ - isConfirmStep_: { - type: Boolean, - value: false - }, - }, - - observers: ['onSetModesChanged_(setModes)'], - - /** @override */ - attached: function() { - this.resetState_(); - - if (settings.getCurrentRoute() == settings.Route.QUICK_UNLOCK_SETUP_PIN) - this.askForPasswordIfUnset(); - }, - - /** @protected */ - currentRouteChanged: function() { - if (settings.getCurrentRoute() == settings.Route.QUICK_UNLOCK_SETUP_PIN) { - this.askForPasswordIfUnset(); - } else { - // If the user hits the back button, they can leave the element - // half-completed; therefore, reset state if the element is not active. - this.resetState_(); - } - }, - - /** @private */ - onSetModesChanged_: function() { - if (settings.getCurrentRoute() == settings.Route.QUICK_UNLOCK_SETUP_PIN) - this.askForPasswordIfUnset(); - }, - - /** - * Resets the element to the initial state. - * @private - */ - resetState_: function() { - this.initialPin_ = ''; - this.pinKeyboardValue_ = ''; - this.enableSubmit_ = false; - this.isConfirmStep_ = false; - this.onPinChange_(); - }, - - /** - * Returns true if the given PIN is likely easy to guess. - * @private - * @param {string} pin - * @return {boolean} - */ - isPinWeak_: function(pin) { - // Warn if it's a top-10 pin. - if (WEAK_PINS.includes(pin)) - return true; - - // Warn if the PIN is consecutive digits. - var delta = 0; - for (var i = 1; i < pin.length; ++i) { - var prev = Number(pin[i - 1]); - var num = Number(pin[i]); - if (Number.isNaN(prev) || Number.isNaN(num)) - return false; - delta = Math.max(delta, Math.abs(num - prev)); - } - - return delta <= 1; - }, - - /** - * Returns true if the given PIN matches PIN requirements, such as minimum - * length. - * @private - * @param {string|undefined} pin - * @return {boolean} - */ - isPinLongEnough_: function(pin) { - return !!pin && pin.length >= 4; - }, - - /** - * Returns true if the PIN is ready to be changed to a new value. - * @private - * @return {boolean} - */ - canSubmit_: function() { - return this.isPinLongEnough_(this.pinKeyboardValue_) && - this.initialPin_ == this.pinKeyboardValue_; - }, - - /** - * Notify the user about a problem. - * @private - * @param {!{messageId: string, class: string}} problemInfo - */ - showProblem_: function(problemInfo) { - this.problemMessage_ = this.i18n(problemInfo.messageId); - this.problemClass_ = problemInfo.class; - this.updateStyles(); - }, - - /** @private */ - hideProblem_: function() { - this.problemMessage_ = ''; - this.problemClass_ = ''; - }, - - /** @private */ - onPinChange_: function() { - if (!this.isConfirmStep_) { - var isPinLongEnough = this.isPinLongEnough_(this.pinKeyboardValue_); - var isWeak = isPinLongEnough && this.isPinWeak_(this.pinKeyboardValue_); - - if (!isPinLongEnough && this.pinKeyboardValue_) - this.showProblem_(ProblemInfo.TOO_SHORT); - else if (isWeak) - this.showProblem_(ProblemInfo.WEAK); - else - this.hideProblem_(); - - this.enableSubmit_ = isPinLongEnough; - - } else { - var canSubmit = this.canSubmit_(); - - if (!canSubmit && this.pinKeyboardValue_) - this.showProblem_(ProblemInfo.MISMATCHED); - else - this.hideProblem_(); - - this.enableSubmit_ = canSubmit; - } - }, - - /** @private */ - onPinSubmit_: function() { - if (!this.isConfirmStep_) { - if (this.isPinLongEnough_(this.pinKeyboardValue_)) { - this.initialPin_ = this.pinKeyboardValue_; - this.pinKeyboardValue_ = ''; - this.isConfirmStep_ = true; - this.onPinChange_(); - } - } else { - // onPinSubmit_ gets called if the user hits enter on the PIN keyboard. - // The PIN is not guaranteed to be valid in that case. - if (!this.canSubmit_()) - return; - - function onSetModesCompleted(didSet) { - if (!didSet) { - console.error('Failed to update pin'); - return; - } - - this.resetState_(); - settings.navigateTo(settings.Route.QUICK_UNLOCK_CHOOSE_METHOD); - } - - this.setModes.call( - null, - [chrome.quickUnlockPrivate.QuickUnlockMode.PIN], - [this.pinKeyboardValue_], - onSetModesCompleted.bind(this)); - } - }, - - /** - * @private - * @param {string} problemMessage - * @return {boolean} - */ - hasProblem_: function(problemMessage) { - return !!problemMessage; - }, - - /** - * @private - * @param {boolean} isConfirmStep - * @return {string} - */ - getTitleMessage_: function(isConfirmStep) { - if (!isConfirmStep) - return this.i18n('quickUnlockConfigurePinChoosePinTitle'); - return this.i18n('quickUnlockConfigurePinConfirmPinTitle'); - }, - - /** - * @private - * @param {boolean} isConfirmStep - * @return {string} - */ - getContinueMessage_: function(isConfirmStep) { - if (!isConfirmStep) - return this.i18n('quickUnlockConfigurePinContinueButton'); - return this.i18n('save'); - }, -}); - -})();
diff --git a/chrome/browser/resources/settings/people_page/setup_pin_dialog.html b/chrome/browser/resources/settings/people_page/setup_pin_dialog.html new file mode 100644 index 0000000..0c6ab82 --- /dev/null +++ b/chrome/browser/resources/settings/people_page/setup_pin_dialog.html
@@ -0,0 +1,68 @@ +<link rel="import" href="chrome://resources/html/polymer.html"> +<link rel="import" href="chrome://resources/html/i18n_behavior.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> +<link rel="import" href="/people_page/pin_keyboard.html"> +<link rel="import" href="/settings_shared_css.html"> + +<dom-module id="settings-setup-pin-dialog"> + <template> + <style include="settings-shared"></style> + <style> + iron-icon { + -webkit-margin-end: var(--iron-icon-spacing); + } + + .warning { + color: var(--paper-grey-500); + } + + .warning > iron-icon { + --iron-icon-fill-color: var(--paper-grey-500); + } + + .error { + color: var(--paper-red-500); + } + + .error > iron-icon { + --iron-icon-fill-color: var(--paper-red-500); + } + + .align-center { + justify-content: center; + } + </style> + + <dialog is="cr-dialog" id="dialog" on-close="close"> + <div class="title">[[getTitleMessage_(isConfirmStep_)]]</div> + <div class="body"> + <!-- Warning/error; only shown if title is hidden. --> + <div class$="[[problemClass_]] settings-box first" + hidden$="[[!hasProblem_(problemMessage_)]]"> + <iron-icon icon="icons:warning"></iron-icon> + <span>[[problemMessage_]]</span> + </div> + + <!-- Pin keyboard --> + <div class="align-center settings-box continuation"> + <pin-keyboard id="pinKeyboard" on-pin-change="onPinChange_" + on-submit="onPinSubmit_" value="{{pinKeyboardValue_}}"> + </pin-keyboard> + </div> + + <div class="button-strip"> + <paper-button class="cancel-button" on-tap="onCancelTap_"> + $i18n{cancel} + </paper-button> + + <paper-button class="action-button" on-tap="onPinSubmit_" + disabled$="[[!enableSubmit_]]"> + <span>[[getContinueMessage_(isConfirmStep_)]]</span> + </paper-button> + </div> + </div> + </dialog> + </template> + + <script src="setup_pin_dialog.js"></script> +</dom-module>
diff --git a/chrome/browser/resources/settings/people_page/setup_pin_dialog.js b/chrome/browser/resources/settings/people_page/setup_pin_dialog.js new file mode 100644 index 0000000..a3985a55 --- /dev/null +++ b/chrome/browser/resources/settings/people_page/setup_pin_dialog.js
@@ -0,0 +1,260 @@ +// 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. + +/** + * @fileoverview + * 'settings-setup-pin-dialog' is the settings page for choosing a PIN. + * + * Example: + * + * <settings-setup-pin-dialog set-modes="[[quickUnlockSetModes]]"> + * </settings-setup-pin-dialog> + */ + +(function() { +'use strict'; + +/** + * A list of the top-10 most commmonly used PINs. This list is taken from + * www.datagenetics.com/blog/september32012/. + * @const + */ +var WEAK_PINS = [ + '1234', '1111', '0000', '1212', '7777', '1004', '2000', '4444', '2222', + '6969' +]; + +Polymer({ + is: 'settings-setup-pin-dialog', + + behaviors: [I18nBehavior], + + properties: { + /** + * The current PIN keyboard value. + * @private + */ + pinKeyboardValue_: String, + + /** + * Stores the initial PIN value so it can be confirmed. + * @private + */ + initialPin_: String, + + /** + * The actual problem message to display. + * @private + */ + problemMessage_: String, + + /** + * The type of problem class to show (warning or error). + */ + problemClass_: String, + + /** + * Should the step-specific submit button be displayed? + * @private + */ + enableSubmit_: Boolean, + + /** + * The current step/subpage we are on. + * @private + */ + isConfirmStep_: { + type: Boolean, + value: false + }, + }, + + /** @override */ + attached: function() { + this.resetState_(); + }, + + open: function() { + this.$.dialog.showModal(); + this.$.pinKeyboard.focus(); + }, + + close: function() { + if (this.$.dialog.open) + this.$.dialog.close(); + + this.resetState_(); + }, + + /** + * Resets the element to the initial state. + * @private + */ + resetState_: function() { + this.initialPin_ = ''; + this.pinKeyboardValue_ = ''; + this.enableSubmit_ = false; + this.isConfirmStep_ = false; + this.onPinChange_(); + }, + + /** @private */ + onCancelTap_: function() { + this.resetState_(); + this.$.dialog.cancel(); + }, + + /** + * Returns true if the given PIN is likely easy to guess. + * @private + * @param {string} pin + * @return {boolean} + */ + isPinWeak_: function(pin) { + // Warn if it's a top-10 pin. + if (WEAK_PINS.includes(pin)) + return true; + + // Warn if the PIN is consecutive digits. + var delta = 0; + for (var i = 1; i < pin.length; ++i) { + var prev = Number(pin[i - 1]); + var num = Number(pin[i]); + if (Number.isNaN(prev) || Number.isNaN(num)) + return false; + delta = Math.max(delta, Math.abs(num - prev)); + } + + return delta <= 1; + }, + + /** + * Returns true if the given PIN matches PIN requirements, such as minimum + * length. + * @private + * @param {string|undefined} pin + * @return {boolean} + */ + isPinLongEnough_: function(pin) { + return !!pin && pin.length >= 4; + }, + + /** + * Returns true if the PIN is ready to be changed to a new value. + * @private + * @return {boolean} + */ + canSubmit_: function() { + return this.isPinLongEnough_(this.pinKeyboardValue_) && + this.initialPin_ == this.pinKeyboardValue_; + }, + + /** + * Notify the user about a problem. + * @private + * @param {string} messageId + * @param {string} problemClass + */ + showProblem_: function(messageId, problemClass) { + this.problemMessage_ = this.i18n(messageId); + this.problemClass_ = problemClass; + this.updateStyles(); + }, + + /** @private */ + hideProblem_: function() { + this.problemMessage_ = ''; + this.problemClass_ = ''; + }, + + /** @private */ + onPinChange_: function() { + if (!this.isConfirmStep_) { + var isPinLongEnough = this.isPinLongEnough_(this.pinKeyboardValue_); + var isWeak = isPinLongEnough && this.isPinWeak_(this.pinKeyboardValue_); + + if (!isPinLongEnough && this.pinKeyboardValue_) + this.showProblem_('configurePinTooShort', 'error'); + else if (isWeak) + this.showProblem_('configurePinWeakPin', 'warning'); + else + this.hideProblem_(); + + this.enableSubmit_ = isPinLongEnough; + + } else { + var canSubmit = this.canSubmit_(); + + if (!canSubmit && this.pinKeyboardValue_) + this.showProblem_('configurePinMismatched', 'error'); + else + this.hideProblem_(); + + this.enableSubmit_ = canSubmit; + } + }, + + /** @private */ + onPinSubmit_: function() { + if (!this.isConfirmStep_) { + if (this.isPinLongEnough_(this.pinKeyboardValue_)) { + this.initialPin_ = this.pinKeyboardValue_; + this.pinKeyboardValue_ = ''; + this.isConfirmStep_ = true; + this.onPinChange_(); + } + } else { + // onPinSubmit_ gets called if the user hits enter on the PIN keyboard. + // The PIN is not guaranteed to be valid in that case. + if (!this.canSubmit_()) + return; + + function onSetModesCompleted(didSet) { + if (!didSet) { + console.error('Failed to update pin'); + return; + } + + this.resetState_(); + this.fire('done'); + } + + this.setModes.call( + null, + [chrome.quickUnlockPrivate.QuickUnlockMode.PIN], + [this.pinKeyboardValue_], + onSetModesCompleted.bind(this)); + } + }, + + /** + * @private + * @param {string} problemMessage + * @return {boolean} + */ + hasProblem_: function(problemMessage) { + return !!problemMessage; + }, + + /** + * @private + * @param {boolean} isConfirmStep + * @return {string} + */ + getTitleMessage_: function(isConfirmStep) { + return this.i18n(isConfirmStep ? 'configurePinConfirmPinTitle' : + 'configurePinChoosePinTitle'); + }, + + /** + * @private + * @param {boolean} isConfirmStep + * @return {string} + */ + getContinueMessage_: function(isConfirmStep) { + return this.i18n(isConfirmStep ? 'confirm' : 'configurePinContinueButton'); + }, +}); + +})();
diff --git a/chrome/browser/resources/settings/route.js b/chrome/browser/resources/settings/route.js index 096b3c13..981c574e 100644 --- a/chrome/browser/resources/settings/route.js +++ b/chrome/browser/resources/settings/route.js
@@ -121,16 +121,9 @@ </if> <if expr="chromeos"> r.CHANGE_PICTURE = r.PEOPLE.createChild('/changePicture', 'changePicture'); - r.QUICK_UNLOCK_AUTHENTICATE = - r.PEOPLE.createChild('/quickUnlock/authenticate', - 'quick-unlock-authenticate'); - r.QUICK_UNLOCK_CHOOSE_METHOD = - r.PEOPLE.createChild('/quickUnlock/chooseMethod', - 'quick-unlock-choose-method'); - r.QUICK_UNLOCK_SETUP_PIN = - r.QUICK_UNLOCK_CHOOSE_METHOD.createChild('/quickUnlock/setupPin', - 'quick-unlock-setup-pin'); r.ACCOUNTS = r.PEOPLE.createChild('/accounts', 'users'); + r.LOCK_SCREEN = r.PEOPLE.createChild('/lockScreen', 'lockScreen'); + r.SETUP_PIN = r.LOCK_SCREEN.createDialog('/setupPin', 'setupPin'); r.DEVICE = r.BASIC.createSection('/device', 'device'); r.POINTERS = r.DEVICE.createChild('/pointer-overlay', 'pointers'); @@ -365,8 +358,10 @@ url += '?' + queryString; } + // History serializes the state, so we don't push the actual route object. + var previousRoutePath = currentRoute_.path; setCurrentRoute(route, params); - window.history.pushState(undefined, '', url); + window.history.pushState(previousRoutePath, '', url); }; window.addEventListener('popstate', function(event) {
diff --git a/chrome/browser/resources/settings/search_settings.js b/chrome/browser/resources/settings/search_settings.js index 8d65774..50e805e 100644 --- a/chrome/browser/resources/settings/search_settings.js +++ b/chrome/browser/resources/settings/search_settings.js
@@ -13,7 +13,7 @@ var SEARCH_BUBBLE_CSS_CLASS = 'search-bubble'; /** - * A CSS attribute indicating that a node shoud be ignored during searching. + * A CSS attribute indicating that a node should be ignored during searching. * @const {string} */ var SKIP_SEARCH_CSS_ATTRIBUTE = 'no-search'; @@ -102,6 +102,7 @@ } else { var span = document.createElement('span'); span.classList.add(HIT_CSS_CLASS); + span.style.backgroundColor = '#ffeb3b'; // --var(--paper-yellow-500) span.textContent = tokens[i]; wrapper.appendChild(span); } @@ -128,9 +129,16 @@ return; } - if (IGNORED_ELEMENTS.has(node.nodeName) || - (node.hasAttribute && node.hasAttribute(SKIP_SEARCH_CSS_ATTRIBUTE))) { + if (IGNORED_ELEMENTS.has(node.nodeName)) return; + + if (node instanceof HTMLElement) { + var element = /** @type {HTMLElement} */(node); + if (element.hasAttribute(SKIP_SEARCH_CSS_ATTRIBUTE) || + element.hasAttribute('hidden') || + element.style.display == 'none') { + return; + } } if (node.nodeType == Node.TEXT_NODE) { @@ -214,7 +222,7 @@ } } if (parent) - parent.hidden = false; + parent.hiddenBySearch = false; // Need to add the search bubble after the parent SETTINGS-SECTION has // become visible, otherwise |offsetWidth| returns zero. @@ -335,7 +343,7 @@ var sections = Polymer.dom( this.node.root).querySelectorAll('settings-section'); for (var i = 0; i < sections.length; i++) - sections[i].hidden = !visible; + sections[i].hiddenBySearch = !visible; }, };
diff --git a/chrome/browser/resources/settings/settings_page/compiled_resources2.gyp b/chrome/browser/resources/settings/settings_page/compiled_resources2.gyp index 4e42a40..b3767dbb 100644 --- a/chrome/browser/resources/settings/settings_page/compiled_resources2.gyp +++ b/chrome/browser/resources/settings/settings_page/compiled_resources2.gyp
@@ -6,11 +6,10 @@ { 'target_name': 'main_page_behavior', 'dependencies': [ + '../animation/compiled_resources2.gyp:animation', '../compiled_resources2.gyp:route', 'settings_section', - 'transition_behavior', - '<(EXTERNS_GYP):web_animations', - '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util', + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert', ], 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], }, @@ -30,6 +29,7 @@ { 'target_name': 'settings_section', 'dependencies': [ + '../animation/compiled_resources2.gyp:animation', '<(EXTERNS_GYP):web_animations', ], 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], @@ -37,6 +37,7 @@ { 'target_name': 'settings_subpage', 'dependencies': [ + '../compiled_resources2.gyp:route', 'settings_subpage_search', '<(DEPTH)/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/compiled_resources2.gyp:iron-resizable-behavior-extracted', '<(DEPTH)/third_party/polymer/v1_0/components-chromium/neon-animation/compiled_resources2.gyp:neon-animatable-behavior-extracted', @@ -54,13 +55,5 @@ ], 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], }, - { - 'target_name': 'transition_behavior', - 'dependencies': [ - '<(EXTERNS_GYP):settings_private', - '<(EXTERNS_GYP):web_animations', - ], - 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], - }, ], }
diff --git a/chrome/browser/resources/settings/settings_page/main_page_behavior.html b/chrome/browser/resources/settings/settings_page/main_page_behavior.html index 90c04a7..a44ecadb 100644 --- a/chrome/browser/resources/settings/settings_page/main_page_behavior.html +++ b/chrome/browser/resources/settings/settings_page/main_page_behavior.html
@@ -1,4 +1,4 @@ +<link rel="import" href="chrome://resources/html/assert.html"> +<link rel="import" href="/animation/animation.html"> <link rel="import" href="/route.html"> -<link rel="import" href="/settings_page/transition_behavior.html"> - <script src="/settings_page/main_page_behavior.js"></script>
diff --git a/chrome/browser/resources/settings/settings_page/main_page_behavior.js b/chrome/browser/resources/settings/settings_page/main_page_behavior.js index 5e408b2e..b1b31d65 100644 --- a/chrome/browser/resources/settings/settings_page/main_page_behavior.js +++ b/chrome/browser/resources/settings/settings_page/main_page_behavior.js
@@ -42,231 +42,165 @@ * @param {!settings.Route} oldRoute */ currentRouteChanged: function(newRoute, oldRoute) { - var newRouteIsSubpage = newRoute && newRoute.subpage.length; - var oldRouteIsSubpage = oldRoute && oldRoute.subpage.length; + // Allow the page to load before expanding the section. TODO(michaelpg): + // Time this better when refactoring settings-animated-pages. + if (!oldRoute && newRoute.subpage.length) + setTimeout(this.tryTransitionToSection_.bind(this)); + else + this.tryTransitionToSection_(); + }, - if (!oldRoute && newRouteIsSubpage) { - // Allow the page to load before expanding the section. TODO(michaelpg): - // Time this better when refactoring settings-animated-pages. - setTimeout(function() { - var section = this.getSection_(newRoute.section); - if (section) - this.expandSection_(section); - }.bind(this)); + /** + * If possible, transitions to the current route's section (by expanding or + * scrolling to it). If another transition is running, finishes or cancels + * that one, then schedules this function again. This ensures the current + * section is quickly shown, without getting the page into a broken state -- + * if currentRoute changes in between calls, just transition to the new route. + * @private + */ + tryTransitionToSection_: function() { + var currentRoute = settings.getCurrentRoute(); + var currentSection = this.getSection_(currentRoute.section); + + // If an animation is already playing, try finishing or canceling it. + if (this.currentAnimation_) { + this.maybeStopCurrentAnimation_(); + // Either way, this function will be called again once the current + // animation ends. return; } - if (newRouteIsSubpage) { - if (!oldRouteIsSubpage || newRoute.section != oldRoute.section) { - var section = this.getSection_(newRoute.section); - if (section) - this.expandSection_(section); + var promise; + var expandedSection = /** @type {?SettingsSectionElement} */( + this.$$('settings-section.expanded')); + if (expandedSection) { + // If the section shouldn't be expanded, collapse it. + if (!currentRoute.subpage.length || expandedSection != currentSection) { + promise = this.collapseSection_(expandedSection); + // Scroll to the collapsed section. TODO(michaelpg): This can look weird + // because the collapse we just scheduled calculated its end target + // based on the current scroll position. This bug existed before, and is + // fixed in the next patch by making the card position: absolute. + if (currentSection) + this.scrollToSection_(); } - } else { - if (oldRouteIsSubpage) { - var section = this.getSection_(oldRoute.section); - if (section) - this.collapseSection_(section); - } - - // Scrolls to the section if this main page contains the route's section. - if (newRoute && newRoute.section && this.getSection_(newRoute.section)) + } else if (currentSection) { + // Expand the section into a subpage or scroll to it on the main page. + if (currentRoute.subpage.length) + promise = this.expandSection_(currentSection); + else this.scrollToSection_(); } + + // When this animation ends, another may be necessary. Call this function + // again after the promise resolves. + if (promise) + promise.then(this.tryTransitionToSection_.bind(this)); + }, + + /** + * If the current animation is inconsistent with the current route, stops the + * animation by finishing or canceling it so the new route can be animated to. + * @private + */ + maybeStopCurrentAnimation_: function() { + var currentRoute = settings.getCurrentRoute(); + var animatingSection = /** @type {?SettingsSectionElement} */( + this.$$('settings-section.expanding, settings-section.collapsing')); + assert(animatingSection); + + if (animatingSection.classList.contains('expanding')) { + // Cancel the animation to go back to the main page if the animating + // section shouldn't be expanded. + if (animatingSection.section != currentRoute.section || + !currentRoute.subpage.length) { + this.currentAnimation_.cancel(); + } + // Otherwise, let the expand animation continue. + return; + } + + assert(animatingSection.classList.contains('collapsing')); + if (!currentRoute.subpage.length) + return; + + // If the collapsing section actually matches the current route's section, + // we can just cancel the animation to re-expand the section. + if (animatingSection.section == currentRoute.section) { + this.currentAnimation_.cancel(); + return; + } + + // The current route is a subpage, so that section needs to expand. + // Immediately finish the current collapse animation so that can happen. + this.currentAnimation_.finish(); }, /** * Animates the card in |section|, expanding it to fill the page. * @param {!SettingsSectionElement} section + * @return {!Promise} Resolved when the transition is finished or canceled. * @private */ expandSection_: function(section) { - // If another section's card is expanding, cancel that animation first. - var expanding = this.$$('.expanding'); - if (expanding) { - if (expanding == section) - return; + assert(this.scroller); + assert(section.canAnimateExpand()); - if (this.animations['section']) { - // Cancel the animation, then call startExpandSection_. - this.cancelAnimation('section', function() { - this.startExpandSection_(section); - }.bind(this)); - } else { - // The animation must have finished but its promise hasn't resolved yet. - // When it resolves, collapse that section's card before expanding - // this one. - setTimeout(function() { - this.collapseSection_( - /** @type {!SettingsSectionElement} */(expanding)); - this.finishAnimation('section', function() { - this.startExpandSection_(section); - }.bind(this)); - }.bind(this)); - } + // Save the scroller position before freezing it. + this.origScrollTop_ = this.scroller.scrollTop; + this.toggleScrolling_(false); - return; - } - - if (this.$$('.collapsing') && this.animations['section']) { - // Finish the collapse animation before expanding. - this.finishAnimation('section', function() { - this.startExpandSection_(section); - }.bind(this)); - return; - } - - this.startExpandSection_(section); - }, - - /** - * Helper function to set up and start the expand animation. - * @param {!SettingsSectionElement} section - */ - startExpandSection_: function(section) { - if (!section.canAnimateExpand()) - return; - - // Freeze the scroller and save its position. - this.listScrollTop_ = this.scroller.scrollTop; - - var scrollerWidth = this.scroller.clientWidth; - this.scroller.style.overflow = 'hidden'; - // Adjust width to compensate for scroller. - var scrollbarWidth = this.scroller.clientWidth - scrollerWidth; - this.scroller.style.width = 'calc(100% - ' + scrollbarWidth + 'px)'; - - // Freezes the section's height so its card can be removed from the flow. + // Freeze the section's height so its card can be removed from the flow. section.setFrozen(true); - // Expand the section's card to fill the parent. - var animationPromise = this.playExpandSection_(section); - - animationPromise.then(function() { - this.scroller.scrollTop = 0; - this.toggleOtherSectionsHidden_(section.section, true); - }.bind(this), function() { - // Animation was canceled; restore the section. - section.setFrozen(false); - }.bind(this)).then(function() { - this.scroller.style.overflow = ''; - this.scroller.style.width = ''; - }.bind(this)); - }, - - /** - * Expands the card in |section| to fill the page. - * @param {!SettingsSectionElement} section - * @return {!Promise} - * @private - */ - playExpandSection_: function(section) { - // We must be attached. - assert(this.scroller); - - var promise; - var animationConfig = section.animateExpand(this.scroller); - if (animationConfig) { - promise = this.animateElement('section', animationConfig.card, - animationConfig.keyframes, animationConfig.options); - } else { - promise = Promise.resolve(); - } + this.currentAnimation_ = section.animateExpand(this.scroller); + var promise = this.currentAnimation_ ? + this.currentAnimation_.finished : Promise.resolve(); var finished; - promise.then(function() { + return promise.then(function() { + this.scroller.scrollTop = 0; + this.toggleOtherSectionsHidden_(section.section, true); finished = true; - this.style.margin = 'auto'; }.bind(this), function() { - // The animation was canceled; catch the error and continue. + // The animation was canceled; restore the section. + section.setFrozen(false); finished = false; }).then(function() { section.cleanUpAnimateExpand(finished); - }); - - return promise; + this.toggleScrolling_(true); + this.currentAnimation_ = null; + }.bind(this)); }, /** * Animates the card in |section|, collapsing it back into its section. * @param {!SettingsSectionElement} section + * @return {!Promise} Resolved when the transition is finished or canceled. * @private */ collapseSection_: function(section) { - // If the section's card is still expanding, cancel the expand animation. - if (section.classList.contains('expanding')) { - if (this.animations['section']) { - this.cancelAnimation('section'); - } else { - // The animation must have finished but its promise hasn't finished - // resolving; try again asynchronously. - this.async(function() { - this.collapseSection_(section); - }); - } - return; - } - - if (!section.canAnimateCollapse()) - return; + assert(this.scroller); + assert(section.canAnimateCollapse()); this.toggleOtherSectionsHidden_(section.section, false); + this.toggleScrolling_(false); - var scrollerWidth = this.scroller.clientWidth; - this.scroller.style.overflow = 'hidden'; - // Adjust width to compensate for scroller. - var scrollbarWidth = this.scroller.clientWidth - scrollerWidth; - this.scroller.style.width = 'calc(100% - ' + scrollbarWidth + 'px)'; + this.currentAnimation_ = + section.animateCollapse(this.scroller, this.origScrollTop_); + var promise = this.currentAnimation_ ? + this.currentAnimation_.finished : Promise.resolve(); - this.playCollapseSection_(section).then(function() { - section.setFrozen(false); - this.scroller.style.overflow = ''; - this.scroller.style.width = ''; - section.classList.remove('collapsing'); - }.bind(this)); - }, - - /** - * Collapses the card in |section| back to its normal position. - * @param {!SettingsSectionElement} section - * @return {!Promise} - * @private - */ - playCollapseSection_: function(section) { - // We must be attached. - assert(this.scroller); - - this.style.margin = ''; - - var promise; - var animationConfig = - section.animateCollapse(this.scroller, this.listScrollTop_); - if (animationConfig) { - promise = this.animateElement('section', animationConfig.card, - animationConfig.keyframes, animationConfig.options); - } else { - promise = Promise.resolve(); - } - - promise.then(function() { + return promise.then(function() { section.cleanUpAnimateCollapse(true); }, function() { section.cleanUpAnimateCollapse(false); - }); - return promise; - }, - - /** @private */ - scrollToSection_: function() { - doWhenReady( - function() { - return this.scrollHeight > 0; - }.bind(this), - function() { - // If the current section changes while we are waiting for the page to - // be ready, scroll to the newest requested section. - this.getSection_(settings.getCurrentRoute().section).scrollIntoView(); - }.bind(this)); + }).then(function() { + section.setFrozen(false); + section.classList.remove('collapsing'); + this.toggleScrolling_(true); + this.currentAnimation_ = null; + }.bind(this)); }, /** @@ -282,6 +216,21 @@ section.hidden = hidden && (section.section != sectionName); }, + /** @private */ + scrollToSection_: function() { + doWhenReady( + function() { + return this.scrollHeight > 0; + }.bind(this), + function() { + // If the current section changes while we are waiting for the page to + // be ready, scroll to the newest requested section. + var section = this.getSection_(settings.getCurrentRoute().section); + if (section) + section.scrollIntoView(); + }.bind(this)); + }, + /** * Helper function to get a section from the local DOM. * @param {string} section Section name of the element to get. @@ -289,14 +238,34 @@ * @private */ getSection_: function(section) { + if (!section) + return null; return /** @type {?SettingsSectionElement} */( this.$$('[section=' + section + ']')); }, + + /** + * Enables or disables user scrolling, via overscroll: hidden. Room for the + * hidden scrollbar is added to prevent the page width from changing back and + * forth. + * @param {boolean} enabled + * @private + */ + toggleScrolling_: function(enabled) { + if (enabled) { + this.scroller.style.overflow = ''; + this.scroller.style.width = ''; + } else { + var scrollerWidth = this.scroller.clientWidth; + this.scroller.style.overflow = 'hidden'; + var scrollbarWidth = this.scroller.clientWidth - scrollerWidth; + this.scroller.style.width = 'calc(100% - ' + scrollbarWidth + 'px)'; + } + } }; /** @polymerBehavior */ var MainPageBehavior = [ settings.RouteObserverBehavior, - TransitionBehavior, MainPageBehaviorImpl, ];
diff --git a/chrome/browser/resources/settings/settings_page/settings_animated_pages.js b/chrome/browser/resources/settings/settings_page/settings_animated_pages.js index 937584b..5b979920 100644 --- a/chrome/browser/resources/settings/settings_page/settings_animated_pages.js +++ b/chrome/browser/resources/settings/settings_page/settings_animated_pages.js
@@ -36,12 +36,6 @@ // Observe the light DOM so we know when it's ready. this.lightDomObserver_ = Polymer.dom(this).observeNodes( this.lightDomChanged_.bind(this)); - - this.addEventListener('subpage-back', function() { - var parent = settings.getCurrentRoute().parent; - assert(parent); - settings.navigateTo(parent); - }.bind(this)); }, /**
diff --git a/chrome/browser/resources/settings/settings_page/settings_section.html b/chrome/browser/resources/settings/settings_page/settings_section.html index d475b15..87db96da 100644 --- a/chrome/browser/resources/settings/settings_page/settings_section.html +++ b/chrome/browser/resources/settings/settings_page/settings_section.html
@@ -1,6 +1,7 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animation-runner-behavior.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/shadow.html"> +<link rel="import" href="/animation/animation.html"> <dom-module id="settings-section"> <template> @@ -41,6 +42,10 @@ :host(.expanded.frozen) #card { position: relative; } + + :host([hidden-by-search]) { + display: none; + } </style> <div id="header"> <div class="title">{{pageTitle}}</div>
diff --git a/chrome/browser/resources/settings/settings_page/settings_section.js b/chrome/browser/resources/settings/settings_page/settings_section.js index de1e420..e0e3afd1 100644 --- a/chrome/browser/resources/settings/settings_page/settings_section.js +++ b/chrome/browser/resources/settings/settings_page/settings_section.js
@@ -33,6 +33,16 @@ /** Title for the section header. */ pageTitle: String, + + /** + * A CSS attribute used for temporarily hiding a SETTINGS-SECTION for the + * purposes of searching. + */ + hiddenBySearch: { + type: Boolean, + value: false, + reflectToAttribute: true, + }, }, /** @@ -95,7 +105,7 @@ * class while the animation plays. * * @param {!HTMLElement} container The scrolling container to fill. - * @return {?SettingsSectionElement.AnimationConfig} + * @return {?settings.animation.Animation} Animation played, if any. */ animateExpand: function(container) { var card = this.$.card; @@ -126,7 +136,7 @@ duration: EXPAND_DURATION }); // TODO(michaelpg): Change elevation of sections. - return {card: card, keyframes: keyframes, options: options}; + return new settings.animation.Animation(card, keyframes, options); }, /** @@ -157,7 +167,7 @@ * @param {!HTMLElement} container The scrolling container the card fills. * @param {number} prevScrollTop scrollTop of the container before this * section expanded. - * @return {?SettingsSectionElement.AnimationConfig} + * @return {?settings.animation.Animation} Animation played, if any. */ animateCollapse: function(container, prevScrollTop) { this.$.header.hidden = false; @@ -209,7 +219,7 @@ card.style.width = cardWidthStart + 'px'; - return {card: card, keyframes: keyframes, options: options}; + return new settings.animation.Animation(card, keyframes, options); }, /** @@ -221,13 +231,3 @@ this.$.card.style.width = ''; }, }); - -/** - * Information needed by TransitionBehavior to schedule animations. - * @typedef {{ - * card: !HTMLElement, - * keyframes: !Array<!Object>, - * options: !KeyframeEffectOptions - * }} - */ -SettingsSectionElement.AnimationConfig;
diff --git a/chrome/browser/resources/settings/settings_page/settings_subpage.html b/chrome/browser/resources/settings/settings_page/settings_subpage.html index 3f7a80c2..a869431c 100644 --- a/chrome/browser/resources/settings/settings_page/settings_subpage.html +++ b/chrome/browser/resources/settings/settings_page/settings_subpage.html
@@ -3,6 +3,7 @@ <link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animatable-behavior.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html"> <link rel="import" href="/icons.html"> +<link rel="import" href="/route.html"> <link rel="import" href="/settings_page/settings_subpage_search.html"> <link rel="import" href="/settings_shared_css.html">
diff --git a/chrome/browser/resources/settings/settings_page/settings_subpage.js b/chrome/browser/resources/settings/settings_page/settings_subpage.js index abb43dc..e7b171a1 100644 --- a/chrome/browser/resources/settings/settings_page/settings_subpage.js +++ b/chrome/browser/resources/settings/settings_page/settings_subpage.js
@@ -5,8 +5,7 @@ /** * @fileoverview * 'settings-subpage' shows a subpage beneath a subheader. The header contains - * the subpage title and a back icon. The back icon fires an event which - * is caught by settings-animated-pages, so it requires no separate handling. + * the subpage title and a back icon. */ Polymer({ @@ -44,8 +43,15 @@ /** @private */ onTapBack_: function() { - // Event is caught by settings-animated-pages. - this.fire('subpage-back'); + var previousRoute = + window.history.state && + assert(settings.getRouteForPath( + /** @type {string} */ (window.history.state))); + + if (previousRoute && previousRoute.contains(settings.getCurrentRoute())) + window.history.back(); + else + settings.navigateTo(assert(settings.getCurrentRoute().parent)); }, /** @private */
diff --git a/chrome/browser/resources/settings/settings_page/transition_behavior.html b/chrome/browser/resources/settings/settings_page/transition_behavior.html deleted file mode 100644 index 34251dcf..0000000 --- a/chrome/browser/resources/settings/settings_page/transition_behavior.html +++ /dev/null
@@ -1,2 +0,0 @@ -<link rel="import" href="chrome://resources/html/polymer.html"> -<script src="/settings_page/transition_behavior.js"></script>
diff --git a/chrome/browser/resources/settings/settings_page/transition_behavior.js b/chrome/browser/resources/settings/settings_page/transition_behavior.js deleted file mode 100644 index 0aecfb39..0000000 --- a/chrome/browser/resources/settings/settings_page/transition_behavior.js +++ /dev/null
@@ -1,86 +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. - -/** - * Adds convenience functions to control native Web Animations. The - * implementation details may change as Chrome support evolves. - * @polymerBehavior - */ -var TransitionBehavior = { - ready: function() { - /** - * @type {!Object<!Animation>} - * Map of running animations by animation name. Animation names are - * arbitrary but used to prevent multiple animations of the same type (e.g., - * expand/collapse section) from running simultaneously. - */ - this.animations = {}; - - /** - * @private {!Object<!Promise>} - * Map of Promises for each running animation. Key names and existence - * should correspond with |animations|. - */ - this.promises_ = {}; - }, - - /** - * Calls el.animate(keyframes, opt_options). Returns a Promise which is - * resolved when the transition ends, or rejected when the transition is - * canceled. If an animation with the same name is in progress, that - * animation is finished immediately before creating the new animation. - * @param {string} name Name of the animation, used to finish this animation - * when playing the same type of animation again. - * @param {!HTMLElement} el The element to animate. - * @param {!Array|!Object} keyframes Keyframes, as in Element.animate. - * @param {number|!KeyframeEffectOptions=} opt_options Options, as in - * Element.animate. - * @return {!Promise} A promise which is resolved when the animation finishes - * or rejected if the animation is canceled. - */ - animateElement: function(name, el, keyframes, opt_options) { - if (this.animations[name]) - this.animations[name].finish(); - - var animation = el.animate(keyframes, opt_options); - this.animations[name] = animation; - - this.promises_[name] = new Promise(function(resolve, reject) { - animation.addEventListener('finish', function() { - this.animations[name] = undefined; - resolve(); - }.bind(this)); - - animation.addEventListener('cancel', function() { - this.animations[name] = undefined; - reject(); - }.bind(this)); - }.bind(this)); - return this.promises_[name]; - }, - - /** - * Finishes the ongoing named animation, waits for the animation's Promise - * to be resolved, then calls the callback. - * @param {string} name Name of the animation passed to animateElement. - * @param {function()=} opt_callback Called once the animation finishes. - */ - finishAnimation: function(name, opt_callback) { - if (opt_callback) - this.promises_[name].then(opt_callback); - this.animations[name].finish(); - }, - - /** - * Cancels the ongoing named animation, waits for the animation's Promise - * to be rejected, then calls the callback. - * @param {string} name Name of the animation passed to animateElement. - * @param {function()=} opt_callback Called once the animation cancels. - */ - cancelAnimation: function(name, opt_callback) { - if (opt_callback) - this.promises_[name].catch(opt_callback); - this.animations[name].cancel(); - }, -};
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd index 372c49e9..36279116 100644 --- a/chrome/browser/resources/settings/settings_resources.grd +++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -232,12 +232,6 @@ <structure name="IDR_SETTINGS_SETTINGS_SHARED_CSS_HTML" file="settings_shared_css.html" type="chrome_html" /> - <structure name="IDR_SETTINGS_TRANSITION_BEHAVIOR_HTML" - file="settings_page/transition_behavior.html" - type="chrome_html" /> - <structure name="IDR_SETTINGS_TRANSITION_BEHAVIOR_JS" - file="settings_page/transition_behavior.js" - type="chrome_html" /> <structure name="IDR_SETTINGS_CR_SETTINGS_UI_HTML" file="settings_ui/settings_ui.html" type="chrome_html" /> @@ -1039,40 +1033,40 @@ type="chrome_html" flattenhtml="true" allowexternalscript="true" /> - <structure name="IDR_SETTINGS_PIN_KEYBOARD_HTML" + <structure name="IDR_SETTINGS_PEOPLE_PASSWORD_PROMPT_DIALOG_JS" + file="people_page/password_prompt_dialog.js" + type="chrome_html" /> + <structure name="IDR_SETTINGS_PEOPLE_PASSWORD_PROMPT_DIALOG_HTML" + file="people_page/password_prompt_dialog.html" + type="chrome_html" + flattenhtml="true" + allowexternalscript="true" /> + <structure name="IDR_SETTINGS_PEOPLE_PIN_KEYBOARD_HTML" file="people_page/pin_keyboard.html" type="chrome_html" flattenhtml="true" allowexternalscript="true"/> - <structure name="IDR_SETTINGS_QUICK_UNLOCK_AUTHENTICATE_JS" - file="people_page/quick_unlock_authenticate.js" + <structure name="IDR_SETTINGS_PEOPLE_LOCK_SCREEN_JS" + file="people_page/lock_screen.js" type="chrome_html" /> - <structure name="IDR_SETTINGS_QUICK_UNLOCK_AUTHENTICATE_HTML" - file="people_page/quick_unlock_authenticate.html" + <structure name="IDR_SETTINGS_PEOPLE_LOCK_SCREEN_HTML" + file="people_page/lock_screen.html" type="chrome_html" flattenhtml="true" allowexternalscript="true" /> - <structure name="IDR_SETTINGS_QUICK_UNLOCK_CHOOSE_METHOD_JS" - file="people_page/quick_unlock_choose_method.js" + <structure name="IDR_SETTINGS_PEOPLE_LOCK_STATE_BEHAVIOR_JS" + file="people_page/lock_state_behavior.js" type="chrome_html" /> - <structure name="IDR_SETTINGS_QUICK_UNLOCK_CHOOSE_METHOD_HTML" - file="people_page/quick_unlock_choose_method.html" + <structure name="IDR_SETTINGS_PEOPLE_LOCK_STATE_BEHAVIOR_HTML" + file="people_page/lock_state_behavior.html" type="chrome_html" flattenhtml="true" allowexternalscript="true" /> - <structure name="IDR_SETTINGS_QUICK_UNLOCK_SETUP_PIN_JS" - file="people_page/quick_unlock_setup_pin.js" + <structure name="IDR_SETTINGS_PEOPLE_SETUP_PIN_DIALOG_JS" + file="people_page/setup_pin_dialog.js" type="chrome_html" /> - <structure name="IDR_SETTINGS_QUICK_UNLOCK_SETUP_PIN_HTML" - file="people_page/quick_unlock_setup_pin.html" - type="chrome_html" - flattenhtml="true" - allowexternalscript="true" /> - <structure name="IDR_SETTINGS_QUICK_UNLOCK_PASSWORD_DETECT_BEHAVIOR_JS" - file="people_page/quick_unlock_password_detect_behavior.js" - type="chrome_html" /> - <structure name="IDR_SETTINGS_QUICK_UNLOCK_PASSWORD_DETECT_BEHAVIOR_HTML" - file="people_page/quick_unlock_password_detect_behavior.html" + <structure name="IDR_SETTINGS_PEOPLE_SETUP_PIN_DIALOG_HTML" + file="people_page/setup_pin_dialog.html" type="chrome_html" flattenhtml="true" allowexternalscript="true" />
diff --git a/chrome/browser/resources/settings/settings_shared_css.html b/chrome/browser/resources/settings/settings_shared_css.html index 2ffad3d..0fe267a 100644 --- a/chrome/browser/resources/settings/settings_shared_css.html +++ b/chrome/browser/resources/settings/settings_shared_css.html
@@ -268,7 +268,7 @@ /* A row with two lines of text. Often the lower line will be .secondary. */ .settings-box.two-line { - min-height: 56px; + min-height: var(--settings-row-two-line-min-height); } /* @@ -369,10 +369,6 @@ top: 10px; width: 10px; } - - .search-highlight-hit { - background-color: var(--paper-yellow-500); - } </style> </template> </dom-module>
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.html b/chrome/browser/resources/settings/settings_ui/settings_ui.html index bd61243..227ad2b 100644 --- a/chrome/browser/resources/settings/settings_ui/settings_ui.html +++ b/chrome/browser/resources/settings/settings_ui/settings_ui.html
@@ -14,33 +14,6 @@ <dom-module id="settings-ui"> <template> <style include="settings-shared"> - /* TODO(dbeam): remove appeal before launch. */ - #appeal { - align-items: center; - background: rgb(123, 170, 247); - display: flex; - } - - #request { - flex: 1; - font-size: .8125rem; - font-weight: bold; - padding: 8px 24px; - } - - #request h1 { - font-size: 1rem; - margin: 0; - } - - #request a { - color: rgb(100, 100, 255); - } - - #close { - padding: 20px; - } - :host { @apply(--layout-fit); --paper-header-panel-waterfall-container: { @@ -110,11 +83,8 @@ overflow: auto; } </style> - <!-- TODO(dpapad): Remove "coming soon" string once crbug.com/608535 fully - addressed --> - <cr-toolbar page-name="$i18n{settings}" - clear-label="$i18n{clearSearch}" search-prompt="$i18n{searchPrompt} - (coming soon!)" on-cr-menu-tap="onMenuButtonTap_" + <cr-toolbar page-name="$i18n{settings}" clear-label="$i18n{clearSearch}" + search-prompt="$i18n{searchPrompt}" on-cr-menu-tap="onMenuButtonTap_" spinner-active="[[toolbarSpinnerActive_]]"> </cr-toolbar> <app-drawer swipe-open> @@ -130,18 +100,6 @@ page-visibility="[[pageVisibility_]]"> </settings-main> </paper-header-panel> - - <!-- TODO(dbeam): remove before launch. --> - <div id="appeal" hidden="[[appealClosed_]]"> - <span id="request"> - <h1>Please read: A personal appeal from the Chrome settings team.</h1> - <a href="[[appealBugUrl_]]">Please file bugs</a> - before you - <a href="chrome://settings-frame">go back to the old settings</a>. - </span> - <span id="close" tabindex=0 on-tap="onCloseAppealTap_">✕</span> - </div> - </template> <script src="settings_ui.js"></script> </dom-module>
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.js b/chrome/browser/resources/settings/settings_ui/settings_ui.js index 5216127..c082ebd 100644 --- a/chrome/browser/resources/settings/settings_ui/settings_ui.js +++ b/chrome/browser/resources/settings/settings_ui/settings_ui.js
@@ -25,36 +25,6 @@ type: Object, }, - /** @private */ - appealClosed_: { - type: Boolean, - value: function() { - return !!(window.sessionStorage.appealClosed_ || - window.localStorage.appealClosed_); - }, - }, - - /** @private */ - appealBugUrl_: { - type: String, - value: function() { - var url = - 'https://bugs.chromium.org/p/chromium/issues/entry?' + - 'labels=Proj-MaterialDesign-WebUI,Pri-2,Type-Bug&' + - 'components=UI%3ESettings&description='; - var description = - 'What steps will reproduce the problem?\n' + - '(1) \n(2) \n(3) \n\nWhat is the expected result?\n\n\n' + - 'What happens instead?\n\n\nPlease provide any additional ' + - 'information below. Attach a screenshot if possible.\n\n'; - var version = navigator.userAgent.match(/Chrom(?:e|ium)\/([\d.]+)/); - if (version) - description += 'Version: ' + version[1]; - url += encodeURIComponent(description); - return url; - }, - }, - /** @private {boolean} */ toolbarSpinnerActive_: { type: Boolean, @@ -121,11 +91,6 @@ } }, - /** @private */ - onCloseAppealTap_: function() { - window.sessionStorage.appealClosed_ = this.appealClosed_ = true; - }, - /** * @param {Event} event * @private
diff --git a/chrome/browser/resources/settings/settings_vars_css.html b/chrome/browser/resources/settings/settings_vars_css.html index d98644d..5621d02 100644 --- a/chrome/browser/resources/settings/settings_vars_css.html +++ b/chrome/browser/resources/settings/settings_vars_css.html
@@ -42,6 +42,7 @@ --settings-page-vertical-margin: 21px; --settings-row-min-height: 44px; + --settings-row-two-line-min-height: 56px; --settings-separator-line: var(--cr-separator-line); --settings-title-bar-background-color: var(--google-blue-700);
diff --git a/chrome/browser/resources/settings/site_settings/add_site_dialog.js b/chrome/browser/resources/settings/site_settings/add_site_dialog.js index 29e5216..c149df5 100644 --- a/chrome/browser/resources/settings/site_settings/add_site_dialog.js +++ b/chrome/browser/resources/settings/site_settings/add_site_dialog.js
@@ -61,7 +61,7 @@ return; // Can happen when Enter is pressed. var pattern = this.addPatternWildcard_(this.site_); this.setCategoryPermissionForOrigin( - pattern, '', this.category, this.allowException ? + pattern, pattern, this.category, this.allowException ? settings.PermissionValues.ALLOW : settings.PermissionValues.BLOCK); this.$.dialog.close(); },
diff --git a/chrome/browser/resources/settings/site_settings/all_sites.html b/chrome/browser/resources/settings/site_settings/all_sites.html index afae857..3e8415d 100644 --- a/chrome/browser/resources/settings/site_settings/all_sites.html +++ b/chrome/browser/resources/settings/site_settings/all_sites.html
@@ -11,9 +11,9 @@ display: block; } </style> - <settings-site-list id="siteList" all-sites + <site-list id="siteList" all-sites category="all-sites" selected-site="{{selectedSite}}"> - </settings-site-list> + </site-list> </template> <script src="all_sites.js"></script> </dom-module>
diff --git a/chrome/browser/resources/settings/site_settings/compiled_resources2.gyp b/chrome/browser/resources/settings/site_settings/compiled_resources2.gyp index a248a29..2a45b8b 100644 --- a/chrome/browser/resources/settings/site_settings/compiled_resources2.gyp +++ b/chrome/browser/resources/settings/site_settings/compiled_resources2.gyp
@@ -71,6 +71,7 @@ { 'target_name': 'site_details', 'dependencies': [ + '../compiled_resources2.gyp:route', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
diff --git a/chrome/browser/resources/settings/site_settings/site_details.html b/chrome/browser/resources/settings/site_settings/site_details.html index 22d9184..cdfbf581 100644 --- a/chrome/browser/resources/settings/site_settings/site_details.html +++ b/chrome/browser/resources/settings/site_settings/site_details.html
@@ -3,6 +3,7 @@ <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html"> <link rel="import" href="/icons.html"> +<link rel="import" href="/route.html"> <link rel="import" href="/settings_shared_css.html"> <link rel="import" href="/site_settings/constants.html"> <link rel="import" href="/site_settings/site_details_permission.html">
diff --git a/chrome/browser/resources/settings/site_settings/site_details.js b/chrome/browser/resources/settings/site_settings/site_details.js index 980dc6e..0e659b2 100644 --- a/chrome/browser/resources/settings/site_settings/site_details.js +++ b/chrome/browser/resources/settings/site_settings/site_details.js
@@ -89,7 +89,7 @@ */ navigateBackIfNoData_: function() { if (this.storedData_ == '' && !this.permissionShowing_()) - this.fire('subpage-back'); + settings.navigateTo(settings.Route.SITE_SETTINGS_ALL); }, /**
diff --git a/chrome/browser/resources/settings/site_settings/site_list.html b/chrome/browser/resources/settings/site_settings/site_list.html index 9a2e67e..063a03ab 100644 --- a/chrome/browser/resources/settings/site_settings/site_list.html +++ b/chrome/browser/resources/settings/site_settings/site_list.html
@@ -16,7 +16,7 @@ <link rel="import" href="/site_settings/site_settings_behavior.html"> <link rel="import" href="/site_settings/site_settings_prefs_browser_proxy.html"> -<dom-module id="settings-site-list"> +<dom-module id="site-list"> <template> <style include="settings-shared"> paper-menu-button {
diff --git a/chrome/browser/resources/settings/site_settings/site_list.js b/chrome/browser/resources/settings/site_settings/site_list.js index 83383b9..7650672 100644 --- a/chrome/browser/resources/settings/site_settings/site_list.js +++ b/chrome/browser/resources/settings/site_settings/site_list.js
@@ -4,12 +4,12 @@ /** * @fileoverview - * 'settings-site-list' shows a list of Allowed and Blocked sites for a given + * 'site-list' shows a list of Allowed and Blocked sites for a given * category. */ Polymer({ - is: 'settings-site-list', + is: 'site-list', behaviors: [SiteSettingsBehavior, WebUIListenerBehavior],
diff --git a/chrome/browser/resources/settings/site_settings/site_settings_category.html b/chrome/browser/resources/settings/site_settings/site_settings_category.html index d7457b6..252cc93 100644 --- a/chrome/browser/resources/settings/site_settings/site_settings_category.html +++ b/chrome/browser/resources/settings/site_settings/site_settings_category.html
@@ -25,11 +25,11 @@ -webkit-margin-start: -11px; } - settings-site-list { + site-list { border-bottom: 1px solid var(--paper-grey-300); } - settings-site-list:last-of-type { + site-list:last-of-type { border-bottom: none; } @@ -49,24 +49,24 @@ <content select=".cookie-controls"></content> - <settings-site-list + <site-list category="[[category]]" category-subtype="[[PermissionValues.BLOCK]]" category-enabled="[[categoryEnabled]]" selected-site="{{selectedSite}}"> - </settings-site-list> - <settings-site-list + </site-list> + <site-list category="[[category]]" category-subtype="[[PermissionValues.ALLOW]]" category-enabled="[[categoryEnabled]]" selected-site="{{selectedSite}}"> - </settings-site-list> - <settings-site-list + </site-list> + <site-list category="[[category]]" category-subtype="[[PermissionValues.SESSION_ONLY]]" category-enabled="[[categoryEnabled]]" selected-site="{{selectedSite}}"> - </settings-site-list> + </site-list> <div class="settings-box"> <content select=".site-data"></content>
diff --git a/chrome/browser/resources/snippets_internals.html b/chrome/browser/resources/snippets_internals.html index 81ad55b..f80dbe3 100644 --- a/chrome/browser/resources/snippets_internals.html +++ b/chrome/browser/resources/snippets_internals.html
@@ -40,52 +40,7 @@ </div> <div id="snippets"> - <h2>Snippets directly from NTPSnippetsService - <span class="detail">(click for details)</span> - </h2> - <table class="section-details"> - <tr jsselect="list" style="display:none"> - <td class="title-link"> - <span class="snippet-title" jsvalues="hidden-id:id"> - <span jscontent="title"></span>>></span> - <div jsvalues="id:id" class="snippet-detail hidden"> - <table> - <tr> - <td>ID - <td jscontent="snippetId"> - <tr> - <td>Validity - <td class="expiry"> - <span class="date" jscontent="published"></span> – - <span class="date" jscontent="expires"></span> - <tr> - <td>Site title - <td jscontent="siteTitle"> - <tr> - <td>Text - <td jscontent="snippet"> - <tr> - <td>URL - <td><a class="url" jsvalues="href:url" jscontent="url"></a> - <tr> - <td>Favicon - <td><a class="url" jsvalues="href:faviconUrl" - jscontent="faviconUrl"></a> - <tr> - <td>Salient image - <td><a class="url" jsvalues="href:salientImageUrl" - jscontent="salientImageUrl"></a> - <tr> - <td>Score - <td jscontent="score"> - </table> - </div> - </table> - <div class="detail" id="snippets-empty"></div> - <div class="forms"> - <input id="submit-clear" type="submit" value="Clear the list"> - <input id="submit-dump" type="submit" value="Dump the list"> - </div> + <h2>NTPSnippetsService</h2> <div class="forms"> <input id="submit-download" type="submit" value="Add snippets"> <span id="hosts-restrict">from hosts <span class="detail">(specify at @@ -96,56 +51,16 @@ <span id="hosts-status" class="detail"></span> </div> </div> - + <div id="last-json" class="hidden"> - <h2>Last JSON</h2> + <h2>Last JSON from Server</h2> <a id="last-json-button">Show the last JSON >></a> <div id="last-json-container" class="hidden"> <div id="last-json-text"></div> <input id="last-json-dump" type="submit" value="Dump the last JSON"> </div> </div> - - <div id="dismissed-snippets"> - <h2>Dismissed snippets <span class="detail">(click for details)</span></h2> - <table class="section-details"> - <tr jsselect="list" style="display:none"> - <td class="title-link"> - <span class="dismissed-snippet-title" jsvalues="hidden-id:id"> - <span jscontent="title"></span> >></span> - <div jsvalues="id:id" class="snippet-detail hidden"> - <table> - <tr> - <td>Validity - <td class="expiry"> - <span class="date" jscontent="published"></span> – - <span class="date" jscontent="expires"></span> - <tr> - <td>Site title - <td jscontent="siteTitle"> - <tr> - <td>Text - <td jscontent="snippet"> - <tr> - <td>URL - <td><a class="url" jsvalues="href:url" jscontent="url"></a> - <tr> - <td>Favicon - <td><a class="url" jsvalues="href:faviconUrl" - jscontent="faviconUrl"></a> - <tr> - <td>Salient image - <td><a class="url" jsvalues="href:salientImageUrl" - jscontent="salientImageUrl"></a> - </table> - </div> - </table> - <div class="detail" id="dismissed-snippets-empty"></div> - <div class="forms"> - <input id="dismissed-snippets-clear" type="submit" value="Clear list"> - </div> - </div> - + <div id="hosts"> <h2>Suggestion hosts</h2> <table class="section-details"> @@ -154,10 +69,11 @@ </table> <div class="detail" id="hosts-empty"></div> </div> - + <div id="content-suggestions"> <h2>Content suggestions by category <span class="detail">(click for details)</span> + <input id="submit-dump" type="submit" value="Dump the list"> </h2> <div jsselect="list" style="display:none"> <h3> @@ -165,12 +81,22 @@ <span class="detail"> (<span jscontent="status"></span>) </span> + + <input jsvalues="category-id:categoryId" type="submit" + class="submit-clear-cached-suggestions" + value="Clear cached suggestions"> + <input jsvalues="hidden-id:dismissedContainerId" type="submit" + class="hidden-toggler" + value="Show dismissed suggestions"> + <input jsvalues="category-id:categoryId" type="submit" + class="submit-clear-dismissed-suggestions" + value="Clear dismissed suggestions"> </h3> - + <table class="section-details"> <tr jsselect="suggestions" style="display:none"> <td class="title-link"> - <span class="content-suggestion-title" + <span class="hidden-toggler content-suggestion-title" jsvalues="hidden-id:id"> <span jscontent="title"></span>>> </span> @@ -185,7 +111,46 @@ <tr> <td>AMP URL <td> - <a class="amp-url" jsvalues="href:ampUrl" + <a class="amp-url" jsvalues="href:ampUrl" + jscontent="ampUrl"></a> + <tr> + <td>Snippet text + <td jscontent="snippetText"> + <tr> + <td>Publish date + <td class="expiry"> + <span class="date" jscontent="publishDate"></span> + <tr> + <td>Publisher name + <td jscontent="publisherName"> + </table> + </div> + </table> + + <table jsvalues="id:dismissedContainerId" + class="section-details hidden"> + <thead> + <tr> + <th style="text-align:left">Dismissed suggestions + </thead> + <tr jsselect="dismissedSuggestions" style="display:none"> + <td class="title-link"> + <span class="hidden-toggler content-suggestion-title" + jsvalues="hidden-id:id"> + <span jscontent="title"></span> (dismissed)>> + </span> + <div jsvalues="id:id" class="content-suggestion-detail hidden"> + <table> + <tr> + <td>ID + <td jscontent="suggestionId"> + <tr> + <td>URL + <td><a class="url" jsvalues="href:url" jscontent="url"></a> + <tr> + <td>AMP URL + <td> + <a class="amp-url" jsvalues="href:ampUrl" jscontent="ampUrl"></a> <tr> <td>Snippet text @@ -202,11 +167,5 @@ </table> </div> <div class="detail" id="content-suggestions-empty"></div> - <div class="forms"> - <input id="submit-clear-cached-suggestions" type="submit" - value="Clear cached suggestions"> - <input id="submit-clear-dismissed-suggestions" type="submit" - value="Clear dismissed suggestions"> - </div> </div> </div>
diff --git a/chrome/browser/resources/snippets_internals.js b/chrome/browser/resources/snippets_internals.js index 79c9ad14..673c697f 100644 --- a/chrome/browser/resources/snippets_internals.js +++ b/chrome/browser/resources/snippets_internals.js
@@ -5,8 +5,8 @@ cr.define('chrome.SnippetsInternals', function() { 'use strict'; - // Stores the list of snippets we received in receiveSnippets. - var lastSnippets = []; + // Stores the list of suggestions we received in receiveContentSuggestions. + var lastSuggestions = []; function initialize() { $('submit-download').addEventListener('click', function(event) { @@ -14,13 +14,8 @@ event.preventDefault(); }); - $('submit-clear').addEventListener('click', function(event) { - chrome.send('clear'); - event.preventDefault(); - }); - $('submit-dump').addEventListener('click', function(event) { - downloadJson(JSON.stringify(lastSnippets)); + downloadJson(JSON.stringify(lastSuggestions)); event.preventDefault(); }); @@ -33,23 +28,6 @@ event.preventDefault(); }); - $('dismissed-snippets-clear').addEventListener('click', function(event) { - chrome.send('clearDismissed'); - event.preventDefault(); - }); - - $('submit-clear-cached-suggestions') - .addEventListener('click', function(event) { - chrome.send('clearCachedSuggestions'); - event.preventDefault(); - }); - - $('submit-clear-dismissed-suggestions') - .addEventListener('click', function(event) { - chrome.send('clearDismissedSuggestions'); - event.preventDefault(); - }); - window.addEventListener('focus', refreshContent); window.setInterval(refreshContent, 1000); @@ -74,19 +52,34 @@ function(host) { return host.url;}).join(' '); } - function receiveSnippets(snippets) { - lastSnippets = snippets; - displayList(snippets, 'snippets', 'snippet-title'); - } - - function receiveDismissedSnippets(dismissedSnippets) { - displayList(dismissedSnippets, 'dismissed-snippets', - 'dismissed-snippet-title'); - } - function receiveContentSuggestions(categoriesList) { + lastSuggestions = categoriesList; displayList(categoriesList, 'content-suggestions', - 'content-suggestion-title'); + 'hidden-toggler'); + + var clearCachedButtons = + document.getElementsByClassName('submit-clear-cached-suggestions'); + for (var button of clearCachedButtons) { + button.addEventListener('click', onClearCachedButtonClicked); + } + + var clearDismissedButtons = + document.getElementsByClassName('submit-clear-dismissed-suggestions'); + for (var button of clearDismissedButtons) { + button.addEventListener('click', onClearDismissedButtonClicked); + } + } + + function onClearCachedButtonClicked(event) { + event.preventDefault(); + var id = parseInt(event.currentTarget.getAttribute('category-id'), 10); + chrome.send('clearCachedSuggestions', [id]); + } + + function onClearDismissedButtonClicked(event) { + event.preventDefault(); + var id = parseInt(event.currentTarget.getAttribute('category-id'), 10); + chrome.send('clearDismissedSuggestions', [id]); } function receiveJson(json) { @@ -120,7 +113,7 @@ $(id).classList.toggle('hidden'); } - function displayList(object, domId, titleClass) { + function displayList(object, domId, toggleClass) { jstProcess(new JsEvalContext(object), $(domId)); var text; @@ -137,7 +130,7 @@ if ($(domId + '-empty')) $(domId + '-empty').textContent = text; if ($(domId + '-clear')) $(domId + '-clear').style.display = display; - var links = document.getElementsByClassName(titleClass); + var links = document.getElementsByClassName(toggleClass); for (var link of links) { link.addEventListener('click', toggleHidden); } @@ -149,8 +142,6 @@ setHostRestricted: setHostRestricted, receiveProperty: receiveProperty, receiveHosts: receiveHosts, - receiveSnippets: receiveSnippets, - receiveDismissedSnippets: receiveDismissedSnippets, receiveContentSuggestions: receiveContentSuggestions, receiveJson: receiveJson, };
diff --git a/chrome/browser/resources/usb_internals/usb_internals.css b/chrome/browser/resources/usb_internals/usb_internals.css new file mode 100644 index 0000000..c11885b6 --- /dev/null +++ b/chrome/browser/resources/usb_internals/usb_internals.css
@@ -0,0 +1,33 @@ +/* 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. + */ + +table.styled-table { + border-collapse: collapse; +} + +table.styled-table, +.styled-table th, +.styled-table td { + border: 1px solid #777; + padding-left: 4px; + padding-right: 4px; +} + +.styled-table th { + text-align: left; +} + +.page-section { + border: 1px solid #777; + padding: 4px; +} + +.action-success { + color: green; +} + +.action-failure { + color: red; +}
diff --git a/chrome/browser/resources/usb_internals/usb_internals.html b/chrome/browser/resources/usb_internals/usb_internals.html new file mode 100644 index 0000000..504b78d --- /dev/null +++ b/chrome/browser/resources/usb_internals/usb_internals.html
@@ -0,0 +1,58 @@ +<!doctype html> +<html> +<head> + <meta charset="utf-8"> + <title>USB Internals</title> + <link rel="stylesheet" href="chrome://resources/css/text_defaults.css"> + <link rel="stylesheet" href="usb_internals.css"> + <script src="chrome://resources/js/cr.js"></script> + <script src="chrome://resources/js/util.js"></script> + <script src="usb_internals.js"></script> +</head> +<body> + <p> + <table class="styled-table"> + <thead> + <tr> + <th>Name</th> + <th>Serial number</th> + <th>Landing page</th> + <th>Allowed origin</th> + <th> + </tr> + </thead> + <tbody id="test-device-list"> + </tbody> + </table> + </p> + + <div class="page-section"> + <strong>Add a test device:</strong> + <form id="add-test-device-form" action=""> + <p> + <label> + Name: <input id="test-device-name" type="text" size="40"> + </label> + </p> + <p> + <label> + Serial number: <input id="test-device-serial" type="text" size="40"> + </label> + </p> + <p> + <label> + Landing page: + <input id="test-device-landing-page" type="text" size="40"> + </label> + </p> + <p> + <label> + Allowed origin: + <input id="test-device-allowed-origin" type="text" size="40"> + </label> + </p> + <button type="submit">Add</button> <span id="add-test-device-result"></span> + </form> + </div> +</body> +</html>
diff --git a/chrome/browser/resources/usb_internals/usb_internals.js b/chrome/browser/resources/usb_internals/usb_internals.js new file mode 100644 index 0000000..7784ec02 --- /dev/null +++ b/chrome/browser/resources/usb_internals/usb_internals.js
@@ -0,0 +1,97 @@ +// 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. + +/** + * Javascript for usb_internals.html, served from chrome://usb-internals/. + */ + +(function() { + // Connection to the UsbInternalsPageHandler instance running in the browser + // process. + let pageHandler = null; + + function refreshDeviceList() { + pageHandler.getTestDevices().then(function(response) { + let tableBody = $('test-device-list'); + tableBody.innerHTML = ''; + for (let device of response.devices) { + let row = document.createElement('tr'); + let name = document.createElement('td'); + let serialNumber = document.createElement('td'); + let landingPage = document.createElement('td'); + let allowedOrigin = document.createElement('td'); + let remove = document.createElement('td'); + let removeButton = document.createElement('button'); + name.textContent = device.name; + serialNumber.textContent = device.serial_number; + landingPage.textContent = device.landing_page.url; + allowedOrigin.textContent = device.allowed_origin.scheme + '://' + + device.allowed_origin.host + ':' + device.allowed_origin.port; + removeButton.addEventListener('click', function() { + pageHandler.removeDeviceForTesting(device.guid) + .then(refreshDeviceList); + }); + removeButton.textContent = 'Remove'; + row.appendChild(name); + row.appendChild(serialNumber); + row.appendChild(landingPage); + row.appendChild(allowedOrigin); + remove.appendChild(removeButton); + row.appendChild(remove); + tableBody.appendChild(row); + } + }); + } + + function addTestDevice(event) { + pageHandler.addDeviceForTesting( + $('test-device-name').value, + $('test-device-serial').value, + $('test-device-landing-page').value, + $('test-device-allowed-origin').value).then(function(response) { + if (response.success) + refreshDeviceList(); + $('add-test-device-result').textContent = response.message; + $('add-test-device-result').className = + response.success ? 'action-success' : 'action-failure'; + }); + event.preventDefault(); + } + + /** + * Helper to convert callback-based define() API to a promise-based API. + * @param {!Array<string>} moduleNames + * @return {!Promise} + */ + function importModules(moduleNames) { + return new Promise(function(resolve, reject) { + define(moduleNames, function(var_args) { + resolve(Array.prototype.slice.call(arguments, 0)); + }); + }); + } + + function initializeProxies() { + return importModules([ + 'mojo/public/js/connection', + 'chrome/browser/ui/webui/usb_internals/usb_internals.mojom', + 'content/public/renderer/frame_interfaces', + ]).then(function(modules) { + let connection = modules[0]; + let mojom = modules[1]; + let frameInterfaces = modules[2]; + + pageHandler = connection.bindHandleToProxy( + frameInterfaces.getInterface(mojom.UsbInternalsPageHandler.name), + mojom.UsbInternalsPageHandler); + }); + } + + document.addEventListener('DOMContentLoaded', function() { + initializeProxies().then(function() { + $('add-test-device-form').addEventListener('submit', addTestDevice); + refreshDeviceList(); + }); + }); +})();
diff --git a/chrome/browser/safe_browsing/incident_reporting/verifier_test/verifier_test_dll.cc b/chrome/browser/safe_browsing/incident_reporting/verifier_test/verifier_test_dll.cc index 0c6f075..092c226 100644 --- a/chrome/browser/safe_browsing/incident_reporting/verifier_test/verifier_test_dll.cc +++ b/chrome/browser/safe_browsing/incident_reporting/verifier_test/verifier_test_dll.cc
@@ -9,12 +9,16 @@ namespace { void (*g_somestate)(int) = nullptr; -int g_somevalue = 0; +volatile int g_somevalue = 0; } // namespace extern "C" void DummyExport(int foo) { + // The test will patch the code of this function. Do a volatile store to a + // global variable to defeat LLVM's dead store elimination and the linker's + // ICF. Otherwise the code patch affects code run during DLL unloading. + // http://crbug.com/636157 g_somevalue = foo; }
diff --git a/chrome/browser/search/hotword_service.cc b/chrome/browser/search/hotword_service.cc index f5579e1..34b6fe4 100644 --- a/chrome/browser/search/hotword_service.cc +++ b/chrome/browser/search/hotword_service.cc
@@ -175,7 +175,7 @@ void RecordHotwordEnabledMetric(HotwordService *service, Profile* profile) { HotwordEnabled enabled_state = DISABLED; - auto prefs = profile->GetPrefs(); + auto* prefs = profile->GetPrefs(); if (!prefs->HasPrefPath(prefs::kHotwordSearchEnabled) && !prefs->HasPrefPath(prefs::kHotwordAlwaysOnSearchEnabled)) { enabled_state = UNSET;
diff --git a/chrome/browser/sessions/persistent_tab_restore_service_browsertest.cc b/chrome/browser/sessions/persistent_tab_restore_service_browsertest.cc index a196c7b4..5c76b355 100644 --- a/chrome/browser/sessions/persistent_tab_restore_service_browsertest.cc +++ b/chrome/browser/sessions/persistent_tab_restore_service_browsertest.cc
@@ -38,12 +38,11 @@ // One entry should be created. ASSERT_EQ(1U, trs->entries().size()); const sessions::TabRestoreService::Entry* restored_entry = - trs->entries().front(); + trs->entries().front().get(); // It should be a window with an app. ASSERT_EQ(sessions::TabRestoreService::WINDOW, restored_entry->type); - const Window* restored_window = - static_cast<const Window*>(restored_entry); + const Window* restored_window = static_cast<const Window*>(restored_entry); EXPECT_EQ(app_name, restored_window->app_name); }
diff --git a/chrome/browser/sessions/persistent_tab_restore_service_unittest.cc b/chrome/browser/sessions/persistent_tab_restore_service_unittest.cc index 2e0825b4..59c4148 100644 --- a/chrome/browser/sessions/persistent_tab_restore_service_unittest.cc +++ b/chrome/browser/sessions/persistent_tab_restore_service_unittest.cc
@@ -226,7 +226,7 @@ ASSERT_EQ(1U, service_->entries().size()); // Make sure the entry matches. - sessions::TabRestoreService::Entry* entry = service_->entries().front(); + sessions::TabRestoreService::Entry* entry = service_->entries().front().get(); ASSERT_EQ(sessions::TabRestoreService::TAB, entry->type); Tab* tab = static_cast<Tab*>(entry); EXPECT_FALSE(tab->pinned); @@ -250,7 +250,7 @@ ASSERT_EQ(2U, service_->entries().size()); // Make sure the entry matches. - entry = service_->entries().front(); + entry = service_->entries().front().get(); ASSERT_EQ(sessions::TabRestoreService::TAB, entry->type); tab = static_cast<Tab*>(entry); EXPECT_FALSE(tab->pinned); @@ -286,7 +286,7 @@ // And verify the entry. sessions::PersistentTabRestoreService::Entry* entry = - service_->entries().front(); + service_->entries().front().get(); ASSERT_EQ(sessions::TabRestoreService::TAB, entry->type); Tab* tab = static_cast<Tab*>(entry); EXPECT_FALSE(tab->pinned); @@ -311,7 +311,7 @@ // We have to explicitly mark the tab as pinned as there is no browser for // these tests. - sessions::TabRestoreService::Entry* entry = service_->entries().front(); + sessions::TabRestoreService::Entry* entry = service_->entries().front().get(); ASSERT_EQ(sessions::TabRestoreService::TAB, entry->type); Tab* tab = static_cast<Tab*>(entry); tab->pinned = true; @@ -325,7 +325,7 @@ ASSERT_EQ(1U, service_->entries().size()); // And verify the entry. - entry = service_->entries().front(); + entry = service_->entries().front().get(); ASSERT_EQ(sessions::TabRestoreService::TAB, entry->type); tab = static_cast<Tab*>(entry); EXPECT_TRUE(tab->pinned); @@ -355,7 +355,7 @@ ASSERT_EQ(1U, service_->entries().size()); const sessions::TabRestoreService::Entry* restored_entry = - service_->entries().front(); + service_->entries().front().get(); ASSERT_EQ(sessions::TabRestoreService::TAB, restored_entry->type); const Tab* restored_tab = @@ -402,17 +402,18 @@ // Make sure we get back one entry with one tab whose url is url1. ASSERT_EQ(1U, service_->entries().size()); - sessions::TabRestoreService::Entry* entry2 = service_->entries().front(); + sessions::TabRestoreService::Entry* entry2 = + service_->entries().front().get(); ASSERT_EQ(sessions::TabRestoreService::WINDOW, entry2->type); sessions::TabRestoreService::Window* window = static_cast<sessions::TabRestoreService::Window*>(entry2); ASSERT_EQ(1U, window->tabs.size()); EXPECT_EQ(0, window->timestamp.ToInternalValue()); EXPECT_EQ(0, window->selected_tab_index); - ASSERT_EQ(1U, window->tabs[0].navigations.size()); - EXPECT_EQ(0, window->tabs[0].current_navigation_index); - EXPECT_EQ(0, window->tabs[0].timestamp.ToInternalValue()); - EXPECT_TRUE(url1_ == window->tabs[0].navigations[0].virtual_url()); + ASSERT_EQ(1U, window->tabs[0]->navigations.size()); + EXPECT_EQ(0, window->tabs[0]->current_navigation_index); + EXPECT_EQ(0, window->tabs[0]->timestamp.ToInternalValue()); + EXPECT_TRUE(url1_ == window->tabs[0]->navigations[0].virtual_url()); } // Makes sure we don't attempt to load previous sessions after a restore. @@ -461,20 +462,20 @@ // the tab restore service. The previous session entry should be first. ASSERT_EQ(2U, service_->entries().size()); // The first entry should come from the session service. - sessions::TabRestoreService::Entry* entry = service_->entries().front(); + sessions::TabRestoreService::Entry* entry = service_->entries().front().get(); ASSERT_EQ(sessions::TabRestoreService::WINDOW, entry->type); sessions::TabRestoreService::Window* window = static_cast<sessions::TabRestoreService::Window*>(entry); ASSERT_EQ(1U, window->tabs.size()); EXPECT_EQ(0, window->selected_tab_index); EXPECT_EQ(0, window->timestamp.ToInternalValue()); - ASSERT_EQ(1U, window->tabs[0].navigations.size()); - EXPECT_EQ(0, window->tabs[0].current_navigation_index); - EXPECT_EQ(0, window->tabs[0].timestamp.ToInternalValue()); - EXPECT_TRUE(url1_ == window->tabs[0].navigations[0].virtual_url()); + ASSERT_EQ(1U, window->tabs[0]->navigations.size()); + EXPECT_EQ(0, window->tabs[0]->current_navigation_index); + EXPECT_EQ(0, window->tabs[0]->timestamp.ToInternalValue()); + EXPECT_TRUE(url1_ == window->tabs[0]->navigations[0].virtual_url()); // Then the closed tab. - entry = *(++service_->entries().begin()); + entry = (++service_->entries().begin())->get(); ASSERT_EQ(sessions::TabRestoreService::TAB, entry->type); Tab* tab = static_cast<Tab*>(entry); ASSERT_FALSE(tab->pinned); @@ -504,19 +505,19 @@ // the tab restore service. The previous session entry should be first. ASSERT_EQ(2U, service_->entries().size()); // The first entry should come from the session service. - sessions::TabRestoreService::Entry* entry = service_->entries().front(); + sessions::TabRestoreService::Entry* entry = service_->entries().front().get(); ASSERT_EQ(sessions::TabRestoreService::WINDOW, entry->type); sessions::TabRestoreService::Window* window = static_cast<sessions::TabRestoreService::Window*>(entry); ASSERT_EQ(1U, window->tabs.size()); EXPECT_EQ(0, window->selected_tab_index); - EXPECT_TRUE(window->tabs[0].pinned); - ASSERT_EQ(1U, window->tabs[0].navigations.size()); - EXPECT_EQ(0, window->tabs[0].current_navigation_index); - EXPECT_TRUE(url1_ == window->tabs[0].navigations[0].virtual_url()); + EXPECT_TRUE(window->tabs[0]->pinned); + ASSERT_EQ(1U, window->tabs[0]->navigations.size()); + EXPECT_EQ(0, window->tabs[0]->current_navigation_index); + EXPECT_TRUE(url1_ == window->tabs[0]->navigations[0].virtual_url()); // Then the closed tab. - entry = *(++service_->entries().begin()); + entry = (++service_->entries().begin())->get(); ASSERT_EQ(sessions::TabRestoreService::TAB, entry->type); Tab* tab = static_cast<Tab*>(entry); ASSERT_FALSE(tab->pinned); @@ -549,17 +550,17 @@ ASSERT_EQ(kMaxEntries, service_->entries().size()); // The first entry should come from the session service. - sessions::TabRestoreService::Entry* entry = service_->entries().front(); + sessions::TabRestoreService::Entry* entry = service_->entries().front().get(); ASSERT_EQ(sessions::TabRestoreService::WINDOW, entry->type); sessions::TabRestoreService::Window* window = static_cast<sessions::TabRestoreService::Window*>(entry); ASSERT_EQ(1U, window->tabs.size()); EXPECT_EQ(0, window->selected_tab_index); EXPECT_EQ(0, window->timestamp.ToInternalValue()); - ASSERT_EQ(1U, window->tabs[0].navigations.size()); - EXPECT_EQ(0, window->tabs[0].current_navigation_index); - EXPECT_EQ(0, window->tabs[0].timestamp.ToInternalValue()); - EXPECT_TRUE(url1_ == window->tabs[0].navigations[0].virtual_url()); + ASSERT_EQ(1U, window->tabs[0]->navigations.size()); + EXPECT_EQ(0, window->tabs[0]->current_navigation_index); + EXPECT_EQ(0, window->tabs[0]->timestamp.ToInternalValue()); + EXPECT_TRUE(url1_ == window->tabs[0]->navigations[0].virtual_url()); } // Makes sure we restore timestamps correctly. @@ -578,7 +579,8 @@ std::vector<SerializedNavigationEntry> old_navigations; { // |entry|/|tab| doesn't survive after RecreateService(). - sessions::TabRestoreService::Entry* entry = service_->entries().front(); + sessions::TabRestoreService::Entry* entry = + service_->entries().front().get(); ASSERT_EQ(sessions::TabRestoreService::TAB, entry->type); Tab* tab = static_cast<Tab*>(entry); tab->timestamp = tab_timestamp; @@ -600,7 +602,7 @@ // And verify the entry. sessions::TabRestoreService::Entry* restored_entry = - service_->entries().front(); + service_->entries().front().get(); ASSERT_EQ(sessions::TabRestoreService::TAB, restored_entry->type); Tab* restored_tab = static_cast<Tab*>(restored_entry); @@ -627,7 +629,8 @@ std::vector<sessions::SerializedNavigationEntry> old_navigations; { // |entry|/|tab| doesn't survive after RecreateService(). - sessions::TabRestoreService::Entry* entry = service_->entries().front(); + sessions::TabRestoreService::Entry* entry = + service_->entries().front().get(); ASSERT_EQ(sessions::TabRestoreService::TAB, entry->type); Tab* tab = static_cast<Tab*>(entry); old_navigations = tab->navigations; @@ -648,7 +651,7 @@ // And verify the entry. sessions::TabRestoreService::Entry* restored_entry = - service_->entries().front(); + service_->entries().front().get(); ASSERT_EQ(sessions::TabRestoreService::TAB, restored_entry->type); Tab* restored_tab = static_cast<Tab*>(restored_entry); @@ -669,11 +672,11 @@ base::StringPrintf("http://%d", static_cast<int>(i)), base::SizeTToString(i)); - Tab* tab = new Tab(); + auto tab = base::MakeUnique<Tab>(); tab->navigations.push_back(navigation); tab->current_navigation_index = 0; - mutable_entries()->push_back(tab); + mutable_entries()->push_back(std::move(tab)); } // Only keep kMaxEntries around. @@ -689,61 +692,62 @@ SerializedNavigationEntry navigation = SerializedNavigationEntryTestHelper::CreateNavigation(kRecentUrl, "Most recent"); - Tab* tab = new Tab(); + auto tab = base::MakeUnique<Tab>(); tab->navigations.push_back(navigation); tab->current_navigation_index = 0; - mutable_entries()->push_front(tab); + mutable_entries()->push_front(std::move(tab)); EXPECT_EQ(max_entries + 1, service_->entries().size()); PruneEntries(); EXPECT_EQ(max_entries, service_->entries().size()); - EXPECT_EQ(GURL(kRecentUrl), - static_cast<Tab*>(service_->entries().front())-> - navigations[0].virtual_url()); + EXPECT_EQ(GURL(kRecentUrl), static_cast<Tab&>(*service_->entries().front()) + .navigations[0] + .virtual_url()); // Ignore NTPs. navigation = SerializedNavigationEntryTestHelper::CreateNavigation( chrome::kChromeUINewTabURL, "New tab"); - tab = new Tab(); + tab = base::MakeUnique<Tab>(); tab->navigations.push_back(navigation); tab->current_navigation_index = 0; - mutable_entries()->push_front(tab); + mutable_entries()->push_front(std::move(tab)); EXPECT_EQ(max_entries + 1, service_->entries().size()); PruneEntries(); EXPECT_EQ(max_entries, service_->entries().size()); - EXPECT_EQ(GURL(kRecentUrl), - static_cast<Tab*>(service_->entries().front())-> - navigations[0].virtual_url()); + EXPECT_EQ(GURL(kRecentUrl), static_cast<Tab&>(*service_->entries().front()) + .navigations[0] + .virtual_url()); // Don't prune pinned NTPs. - tab = new Tab(); + tab = base::MakeUnique<Tab>(); tab->pinned = true; tab->current_navigation_index = 0; tab->navigations.push_back(navigation); - mutable_entries()->push_front(tab); + mutable_entries()->push_front(std::move(tab)); EXPECT_EQ(max_entries + 1, service_->entries().size()); PruneEntries(); EXPECT_EQ(max_entries, service_->entries().size()); EXPECT_EQ(GURL(chrome::kChromeUINewTabURL), - static_cast<Tab*>(service_->entries().front())-> - navigations[0].virtual_url()); + static_cast<Tab*>(service_->entries().front().get()) + ->navigations[0] + .virtual_url()); // Don't prune NTPs that have multiple navigations. // (Erase the last NTP first.) - delete service_->entries().front(); mutable_entries()->erase(mutable_entries()->begin()); - tab = new Tab(); + tab = base::MakeUnique<Tab>(); tab->current_navigation_index = 1; tab->navigations.push_back(navigation); tab->navigations.push_back(navigation); - mutable_entries()->push_front(tab); + mutable_entries()->push_front(std::move(tab)); EXPECT_EQ(max_entries, service_->entries().size()); PruneEntries(); EXPECT_EQ(max_entries, service_->entries().size()); EXPECT_EQ(GURL(chrome::kChromeUINewTabURL), - static_cast<Tab*>(service_->entries().front())-> - navigations[1].virtual_url()); + static_cast<Tab*>(service_->entries().front().get()) + ->navigations[1] + .virtual_url()); } // Regression test for crbug.com/106082
diff --git a/chrome/browser/sessions/session_restore_browsertest.cc b/chrome/browser/sessions/session_restore_browsertest.cc index 919e283..60b2220 100644 --- a/chrome/browser/sessions/session_restore_browsertest.cc +++ b/chrome/browser/sessions/session_restore_browsertest.cc
@@ -543,16 +543,16 @@ ASSERT_EQ(1U, service->entries().size()); ASSERT_EQ(sessions::TabRestoreService::WINDOW, service->entries().front()->type); - const sessions::TabRestoreService::Window* window = - static_cast<sessions::TabRestoreService::Window*>( - service->entries().front()); + auto* window = static_cast<sessions::TabRestoreService::Window*>( + service->entries().front().get()); EXPECT_EQ(3U, window->tabs.size()); // Find the SessionID for entry2. Since the session service was destroyed, // there is no guarantee that the SessionID for the tab has remained the same. base::Time timestamp; int http_status_code = 0; - for (const sessions::TabRestoreService::Tab& tab : window->tabs) { + for (const auto& tab_ptr : window->tabs) { + const sessions::TabRestoreService::Tab& tab = *tab_ptr; // If this tab held url2, then restore this single tab. if (tab.navigations[0].virtual_url() == url2) { timestamp = tab.navigations[0].timestamp(); @@ -575,7 +575,7 @@ ASSERT_EQ(sessions::TabRestoreService::WINDOW, service->entries().front()->type); window = static_cast<sessions::TabRestoreService::Window*>( - service->entries().front()); + service->entries().front().get()); EXPECT_EQ(2U, window->tabs.size()); // Make sure that the restored tab was restored with the correct @@ -615,9 +615,8 @@ // Expect the window to be converted to a tab by the TRS. EXPECT_EQ(1U, service->entries().size()); ASSERT_EQ(sessions::TabRestoreService::TAB, service->entries().front()->type); - const sessions::TabRestoreService::Tab* tab = - static_cast<sessions::TabRestoreService::Tab*>( - service->entries().front()); + auto* tab = static_cast<const sessions::TabRestoreService::Tab*>( + service->entries().front().get()); // Restore the tab. std::vector<sessions::LiveTab*> content =
diff --git a/chrome/browser/sessions/tab_restore_browsertest.cc b/chrome/browser/sessions/tab_restore_browsertest.cc index f5f0b5e..a5b85a4 100644 --- a/chrome/browser/sessions/tab_restore_browsertest.cc +++ b/chrome/browser/sessions/tab_restore_browsertest.cc
@@ -441,19 +441,20 @@ TabRestoreServiceFactory::GetForProfile(browser->profile()); const sessions::TabRestoreService::Entries& entries = service->entries(); EXPECT_EQ(1u, entries.size()); - sessions::TabRestoreService::Entry* entry = entries.front(); + sessions::TabRestoreService::Entry* entry = entries.front().get(); ASSERT_EQ(sessions::TabRestoreService::WINDOW, entry->type); sessions::TabRestoreService::Window* entry_win = static_cast<sessions::TabRestoreService::Window*>(entry); - std::vector<sessions::TabRestoreService::Tab>& tabs = entry_win->tabs; + auto& tabs = entry_win->tabs; EXPECT_EQ(3u, tabs.size()); // Find the Tab to restore. - sessions::TabRestoreService::Tab tab_to_restore; + SessionID::id_type tab_id_to_restore = 0; bool found_tab_to_restore = false; - for (const auto& tab : tabs) { + for (const auto& tab_ptr : tabs) { + auto& tab = *tab_ptr; if (tab.navigations[tab.current_navigation_index].virtual_url() == url1_) { - tab_to_restore = tab; + tab_id_to_restore = tab.id; found_tab_to_restore = true; break; } @@ -468,7 +469,7 @@ content::WindowedNotificationObserver tab_loaded_observer( content::NOTIFICATION_LOAD_STOP, content::NotificationService::AllSources()); - service->RestoreEntryById(browser->live_tab_context(), tab_to_restore.id, + service->RestoreEntryById(browser->live_tab_context(), tab_id_to_restore, NEW_FOREGROUND_TAB); tab_added_observer.Wait(); tab_loaded_observer.Wait();
diff --git a/chrome/browser/ssl/chrome_security_state_model_client.cc b/chrome/browser/ssl/chrome_security_state_model_client.cc index 3e1834b..0988c8ac 100644 --- a/chrome/browser/ssl/chrome_security_state_model_client.cc +++ b/chrome/browser/ssl/chrome_security_state_model_client.cc
@@ -231,7 +231,7 @@ return; } - state->initialized = true; + state->connection_info_initialized = true; state->url = entry->GetURL(); const content::SSLStatus& ssl = entry->GetSSL(); state->initial_security_level =
diff --git a/chrome/browser/subresource_filter/chrome_subresource_filter_client.cc b/chrome/browser/subresource_filter/chrome_subresource_filter_client.cc new file mode 100644 index 0000000..10ad9e1 --- /dev/null +++ b/chrome/browser/subresource_filter/chrome_subresource_filter_client.cc
@@ -0,0 +1,22 @@ +// 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 "chrome/browser/subresource_filter/chrome_subresource_filter_client.h" + +#include "chrome/browser/content_settings/tab_specific_content_settings.h" + +ChromeSubresourceFilterClient::ChromeSubresourceFilterClient( + content::WebContents* web_contents) + : web_contents_(web_contents) { + DCHECK(web_contents); +} + +ChromeSubresourceFilterClient::~ChromeSubresourceFilterClient() {} + +void ChromeSubresourceFilterClient::ToggleNotificationVisibility( + bool visibility) { + TabSpecificContentSettings* content_settings = + TabSpecificContentSettings::FromWebContents(web_contents_); + content_settings->SetSubresourceBlocked(visibility); +}
diff --git a/chrome/browser/subresource_filter/chrome_subresource_filter_client.h b/chrome/browser/subresource_filter/chrome_subresource_filter_client.h new file mode 100644 index 0000000..42d932e --- /dev/null +++ b/chrome/browser/subresource_filter/chrome_subresource_filter_client.h
@@ -0,0 +1,31 @@ +// 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 CHROME_BROWSER_SUBRESOURCE_FILTER_CHROME_SUBRESOURCE_FILTER_CLIENT_H_ +#define CHROME_BROWSER_SUBRESOURCE_FILTER_CHROME_SUBRESOURCE_FILTER_CLIENT_H_ + +#include "base/macros.h" +#include "components/subresource_filter/core/browser/subresource_filter_client.h" + +namespace content { +class WebContents; +} // namespace content + +// Chrome implementation of SubresourceFilterClient. +class ChromeSubresourceFilterClient + : public subresource_filter::SubresourceFilterClient { + public: + explicit ChromeSubresourceFilterClient(content::WebContents* web_contents); + ~ChromeSubresourceFilterClient() override; + + // SubresourceFilterClient: + void ToggleNotificationVisibility(bool visibility) override; + + private: + content::WebContents* web_contents_; + + DISALLOW_COPY_AND_ASSIGN(ChromeSubresourceFilterClient); +}; + +#endif // CHROME_BROWSER_SUBRESOURCE_FILTER_CHROME_SUBRESOURCE_FILTER_CLIENT_H_
diff --git a/chrome/browser/translate/chrome_translate_client.cc b/chrome/browser/translate/chrome_translate_client.cc index 6bf702d..24b1aeb7 100644 --- a/chrome/browser/translate/chrome_translate_client.cc +++ b/chrome/browser/translate/chrome_translate_client.cc
@@ -25,7 +25,6 @@ #include "chrome/common/chrome_paths.h" #include "chrome/common/pref_names.h" #include "components/prefs/pref_service.h" -#include "components/translate/content/common/translate_messages.h" #include "components/translate/core/browser/language_state.h" #include "components/translate/core/browser/page_translated_details.h" #include "components/translate/core/browser/translate_accept_languages.h" @@ -138,6 +137,27 @@ translate::TranslateManager::GetTargetLanguage(translate_prefs.get()); } +// static +void ChromeTranslateClient::BindContentTranslateDriver( + content::RenderFrameHost* render_frame_host, + translate::mojom::ContentTranslateDriverRequest request) { + content::WebContents* web_contents = + content::WebContents::FromRenderFrameHost(render_frame_host); + if (!web_contents) + return; + + ChromeTranslateClient* instance = + ChromeTranslateClient::FromWebContents(web_contents); + // We try to bind to the driver, but if driver is not ready for now or totally + // not available for this render frame host, the request will be just dropped. + // This would cause the message pipe to be closed, which will raise a + // connection error on the peer side. + if (!instance) + return; + + instance->translate_driver().BindRequest(std::move(request)); +} + translate::TranslateManager* ChromeTranslateClient::GetTranslateManager() { return translate_manager_.get(); }
diff --git a/chrome/browser/translate/chrome_translate_client.h b/chrome/browser/translate/chrome_translate_client.h index d216295..cf4a356 100644 --- a/chrome/browser/translate/chrome_translate_client.h +++ b/chrome/browser/translate/chrome_translate_client.h
@@ -71,6 +71,10 @@ std::string* source, std::string* target); + static void BindContentTranslateDriver( + content::RenderFrameHost* render_frame_host, + translate::mojom::ContentTranslateDriverRequest request); + // Gets the associated TranslateManager. translate::TranslateManager* GetTranslateManager();
diff --git a/chrome/browser/translate/translate_manager_render_view_host_unittest.cc b/chrome/browser/translate/translate_manager_render_view_host_unittest.cc index db00e35..1541186 100644 --- a/chrome/browser/translate/translate_manager_render_view_host_unittest.cc +++ b/chrome/browser/translate/translate_manager_render_view_host_unittest.cc
@@ -36,7 +36,7 @@ #include "components/prefs/pref_change_registrar.h" #include "components/prefs/pref_service.h" #include "components/translate/content/browser/content_translate_driver.h" -#include "components/translate/content/common/translate_messages.h" +#include "components/translate/content/common/translate.mojom.h" #include "components/translate/core/browser/translate_accept_languages.h" #include "components/translate/core/browser/translate_download_manager.h" #include "components/translate/core/browser/translate_language_list.h" @@ -52,8 +52,8 @@ #include "content/public/browser/notification_registrar.h" #include "content/public/browser/web_contents.h" #include "content/public/common/url_constants.h" -#include "content/public/test/mock_render_process_host.h" #include "content/public/test/test_renderer_host.h" +#include "mojo/public/cpp/bindings/binding.h" #include "net/base/net_errors.h" #include "net/url_request/test_url_fetcher_factory.h" #include "net/url_request/url_fetcher_delegate.h" @@ -115,6 +115,62 @@ DISALLOW_COPY_AND_ASSIGN(MockTranslateBubbleFactory); }; +class FakePageImpl : public translate::mojom::Page { + public: + FakePageImpl() + : called_translate_(false), + called_revert_translation_(false), + binding_(this) {} + ~FakePageImpl() override {} + + translate::mojom::PagePtr BindToNewPagePtr() { + binding_.Close(); + translate_callback_pending_.Reset(); + return binding_.CreateInterfacePtrAndBind(); + } + + // translate::mojom::Page implementation. + void Translate(const std::string& translate_script, + const std::string& source_lang, + const std::string& target_lang, + const TranslateCallback& callback) override { + // Ensure pending callback gets called. + if (translate_callback_pending_) { + translate_callback_pending_.Run(true, "", "", + translate::TranslateErrors::NONE); + translate_callback_pending_.Reset(); + } + + called_translate_ = true; + source_lang_ = source_lang; + target_lang_ = target_lang; + + translate_callback_pending_ = callback; + } + + void RevertTranslation() override { called_revert_translation_ = true; } + + void PageTranslated(bool cancelled, + const std::string& source_lang, + const std::string& target_lang, + translate::TranslateErrors::Type error) { + translate_callback_pending_.Run(cancelled, source_lang, target_lang, error); + translate_callback_pending_.Reset(); + } + + bool called_translate_; + base::Optional<std::string> source_lang_; + base::Optional<std::string> target_lang_; + bool called_revert_translation_; + + private: + TranslateCallback translate_callback_pending_; + + mojo::Binding<translate::mojom::Page> binding_; + + DISALLOW_COPY_AND_ASSIGN(FakePageImpl); +}; + } // namespace // An observer that keeps track of whether a navigation entry was committed. @@ -238,42 +294,57 @@ bool page_translatable) { translate::LanguageDetectionDetails details; details.adopted_language = lang; - main_rfh()->OnMessageReceived( - ChromeFrameHostMsg_TranslateLanguageDetermined(0, details, - page_translatable)); + ChromeTranslateClient::FromWebContents(web_contents()) + ->translate_driver() + .RegisterPage(fake_page_.BindToNewPagePtr(), details, + page_translatable); } - void SimulateOnPageTranslated(int routing_id, - const std::string& source_lang, + void SimulateOnPageTranslated(const std::string& source_lang, const std::string& target_lang, translate::TranslateErrors::Type error) { - main_rfh()->OnMessageReceived(ChromeFrameHostMsg_PageTranslated( - routing_id, source_lang, target_lang, error)); + // Ensure fake_page_ Translate() call gets dispatched. + base::RunLoop().RunUntilIdle(); + + fake_page_.PageTranslated(false, source_lang, target_lang, error); + + // Ensure fake_page_ Translate() response callback gets dispatched. + base::RunLoop().RunUntilIdle(); } void SimulateOnPageTranslated(const std::string& source_lang, const std::string& target_lang) { - SimulateOnPageTranslated( - 0, source_lang, target_lang, translate::TranslateErrors::NONE); + SimulateOnPageTranslated(source_lang, target_lang, + translate::TranslateErrors::NONE); } bool GetTranslateMessage(std::string* original_lang, std::string* target_lang) { - const IPC::Message* message = process()->sink().GetFirstMessageMatching( - ChromeFrameMsg_TranslatePage::ID); - if (!message) + base::RunLoop().RunUntilIdle(); + + if (!fake_page_.called_translate_) return false; - std::tuple<int, std::string, std::string, std::string> translate_param; - ChromeFrameMsg_TranslatePage::Read(message, &translate_param); - // Ignore get<0>(translate_param) which is the page seq no. - // Ignore get<1>(translate_param) which is the script injected in the page. + EXPECT_TRUE(fake_page_.source_lang_); + EXPECT_TRUE(fake_page_.target_lang_); + if (original_lang) - *original_lang = std::get<2>(translate_param); + *original_lang = *fake_page_.source_lang_; if (target_lang) - *target_lang = std::get<3>(translate_param); + *target_lang = *fake_page_.target_lang_; + + // Reset + fake_page_.called_translate_ = false; + fake_page_.source_lang_ = base::nullopt; + fake_page_.target_lang_ = base::nullopt; + return true; } + bool IsTranslationReverted() { + base::RunLoop().RunUntilIdle(); + return fake_page_.called_revert_translation_; + } + InfoBarService* infobar_service() { return InfoBarService::FromWebContents(web_contents()); } @@ -404,8 +475,6 @@ } virtual void TearDown() { - process()->sink().ClearMessages(); - notification_registrar_.Remove( this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED, @@ -492,6 +561,8 @@ std::set<infobars::InfoBarDelegate*> removed_infobars_; std::unique_ptr<MockTranslateBubbleFactory> bubble_factory_; + FakePageImpl fake_page_; + DISALLOW_COPY_AND_ASSIGN(TranslateManagerRenderViewHostTest); }; @@ -621,7 +692,6 @@ infobar->translate_step()); // Simulate clicking translate. - process()->sink().ClearMessages(); infobar->Translate(); // The "Translating..." infobar should be showing. @@ -649,7 +719,6 @@ infobar->translate_step()); // Simulate changing the original language and translating. - process()->sink().ClearMessages(); std::string new_original_lang = infobar->language_code_at(0); infobar->UpdateOriginalLanguage(new_original_lang); infobar->Translate(); @@ -662,7 +731,6 @@ ASSERT_TRUE(infobar != NULL); // Simulate changing the target language and translating. - process()->sink().ClearMessages(); std::string new_target_lang = infobar->language_code_at(1); infobar->UpdateTargetLanguage(new_target_lang); infobar->Translate(); @@ -704,7 +772,6 @@ infobar->translate_step()); // Simulate clicking translate. - process()->sink().ClearMessages(); infobar->Translate(); SimulateTranslateScriptURLFetch(false); @@ -766,8 +833,8 @@ menu.reset(CreateContextMenu()); menu->Init(); menu->ExecuteCommand(IDC_CONTENT_CONTEXT_TRANSLATE, 0); - SimulateOnPageTranslated( - 1, "en", "en", translate::TranslateErrors::IDENTICAL_LANGUAGES); + SimulateOnPageTranslated("en", "en", + translate::TranslateErrors::IDENTICAL_LANGUAGES); infobar = GetTranslateInfoBar(); ASSERT_TRUE(infobar != NULL); EXPECT_EQ(translate::TRANSLATE_STEP_TRANSLATE_ERROR, @@ -781,8 +848,8 @@ menu.reset(CreateContextMenu()); menu->Init(); menu->ExecuteCommand(IDC_CONTENT_CONTEXT_TRANSLATE, 0); - SimulateOnPageTranslated( - 2, std::string(), "en", translate::TranslateErrors::UNKNOWN_LANGUAGE); + SimulateOnPageTranslated(std::string(), "en", + translate::TranslateErrors::UNKNOWN_LANGUAGE); infobar = GetTranslateInfoBar(); ASSERT_TRUE(infobar != NULL); EXPECT_EQ(translate::TRANSLATE_STEP_TRANSLATE_ERROR, @@ -843,7 +910,6 @@ SimulateOnPageTranslated("fr", "en"); // Now navigate to a new page in the same language. - process()->sink().ClearMessages(); SimulateNavigation(GURL("http://news.google.fr"), "fr", true); // This should have automatically triggered a translation. @@ -853,7 +919,6 @@ EXPECT_EQ("en", target_lang); // Now navigate to a page in a different language. - process()->sink().ClearMessages(); SimulateNavigation(GURL("http://news.google.es"), "es", true); // This should not have triggered a translate. @@ -1097,7 +1162,6 @@ EnableBubbleTest(); SimulateNavigation(GURL("http://mail.google.fr"), "fr", true); - process()->sink().ClearMessages(); SimulateTranslatePress(); SimulateTranslateScriptURLFetch(true); // Simulate the render notifying the translation has been done, but it @@ -1118,11 +1182,8 @@ // Pressing the button on that infobar should revert to the original // language. - process()->sink().ClearMessages(); infobar->MessageInfoBarButtonPressed(); - const IPC::Message* message = process()->sink().GetFirstMessageMatching( - ChromeFrameMsg_RevertTranslation::ID); - EXPECT_TRUE(message != NULL); + EXPECT_TRUE(IsTranslationReverted()); // And it should have removed the infobar. EXPECT_TRUE(GetTranslateInfoBar() == NULL); } @@ -1373,7 +1434,6 @@ EXPECT_TRUE(GetTranslateMessage(&original_lang, &target_lang)); EXPECT_EQ("fr", original_lang); EXPECT_EQ("en", target_lang); - process()->sink().ClearMessages(); // Try another language, it should not be autotranslated. SimulateNavigation(GURL("http://www.google.es"), "es", true); @@ -1450,7 +1510,6 @@ EXPECT_TRUE(GetTranslateMessage(&original_lang, &target_lang)); EXPECT_EQ("fr", original_lang); EXPECT_EQ("en", target_lang); - process()->sink().ClearMessages(); // This should also have reverted the blacklisting of this site and language. EXPECT_FALSE(translate_prefs->IsBlockedLanguage("fr")); @@ -1473,7 +1532,6 @@ ASSERT_TRUE(infobar != NULL); infobar->Translate(); EXPECT_TRUE(GetTranslateMessage(&original_lang, &target_lang)); - process()->sink().ClearMessages(); menu.reset(CreateContextMenu()); menu->Init(); EXPECT_TRUE(menu->IsCommandIdEnabled(IDC_CONTENT_CONTEXT_TRANSLATE)); @@ -1488,7 +1546,6 @@ ASSERT_TRUE(infobar != NULL); infobar->Translate(); EXPECT_TRUE(GetTranslateMessage(&original_lang, &target_lang)); - process()->sink().ClearMessages(); menu.reset(CreateContextMenu()); menu->Init(); EXPECT_TRUE(menu->IsCommandIdEnabled(IDC_CONTENT_CONTEXT_TRANSLATE)); @@ -1548,7 +1605,6 @@ if (i < 7) { EXPECT_FALSE(infobar->ShouldShowAlwaysTranslateShortcut()); infobar->Translate(); - process()->sink().ClearMessages(); } else { EXPECT_TRUE(infobar->ShouldShowAlwaysTranslateShortcut()); } @@ -1564,7 +1620,6 @@ // That should have triggered a page translate. std::string original_lang, target_lang; EXPECT_TRUE(GetTranslateMessage(&original_lang, &target_lang)); - process()->sink().ClearMessages(); // Now test that declining the translation causes a "never translate" button // to be shown (in non incognito mode only). @@ -1591,7 +1646,6 @@ EXPECT_TRUE(translate_prefs->IsBlockedLanguage("de")); // No translation should have occured and the infobar should be gone. EXPECT_FALSE(GetTranslateMessage(&original_lang, &target_lang)); - process()->sink().ClearMessages(); ASSERT_TRUE(GetTranslateInfoBar() == NULL); } @@ -1625,9 +1679,10 @@ SimulateNavigation(GURL("http://www.google.fr"), "fr", true); translate::TranslateInfoBarDelegate* infobar = GetTranslateInfoBar(); ASSERT_TRUE(infobar != NULL); - process()->sink().ClearMessages(); infobar->Translate(); SimulateTranslateScriptURLFetch(true); + // The translate request should have been sent. + EXPECT_TRUE(GetTranslateMessage(NULL, NULL)); SimulateOnPageTranslated("fr", "en"); // A task should have been posted to clear the script, run it. @@ -1637,12 +1692,10 @@ SimulateNavigation(GURL("http://www.google.es"), "es", true); infobar = GetTranslateInfoBar(); ASSERT_TRUE(infobar != NULL); - process()->sink().ClearMessages(); infobar->Translate(); // If we don't simulate the URL fetch, the TranslateManager should be waiting // for the script and no message should have been sent to the renderer. - EXPECT_TRUE(process()->sink().GetFirstMessageMatching( - ChromeFrameMsg_TranslatePage::ID) == NULL); + EXPECT_FALSE(GetTranslateMessage(NULL, NULL)); // Now simulate the URL fetch. SimulateTranslateScriptURLFetch(true); // Now the message should have been sent. @@ -1679,7 +1732,6 @@ bubble->GetViewState()); // Simulate clicking translate. - process()->sink().ClearMessages(); bubble->Translate(); // Check the bubble shows "Translating...". @@ -1722,7 +1774,6 @@ bubble->GetViewState()); // Simulate clicking translate. - process()->sink().ClearMessages(); bubble->Translate(); SimulateTranslateScriptURLFetch(false);
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 5313eaa..8df4dffb 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -7,6 +7,7 @@ import("//build/config/ui.gni") import("//build/split_static_library.gni") import("//chrome/common/features.gni") +import("//media/media_options.gni") gypi_values = exec_script("//build/gypi_to_gn.py", [ rebase_path("../../chrome_browser_ui.gypi") ], @@ -148,6 +149,10 @@ deps += [ "//extensions/browser" ] } + if (is_chromeos && use_cras) { + defines += [ "USE_CRAS" ] + } + if (!is_ios) { sources += rebase_path(gypi_values.chrome_browser_ui_non_ios_sources, ".", @@ -161,6 +166,7 @@ "//chrome/browser/ui/webui/engagement:mojo_bindings", "//chrome/browser/ui/webui/omnibox:mojo_bindings", "//chrome/browser/ui/webui/plugins:mojo_bindings", + "//chrome/browser/ui/webui/usb_internals:mojo_bindings", "//chrome/common/net", "//chrome/installer/util:with_no_strings", "//components/autofill/content/browser:risk_proto", @@ -274,7 +280,7 @@ "//ash", "//ash:ash_with_content", "//ash/common/strings", - "//ash/sysui/public/interfaces", + "//ash/public/interfaces", "//components/user_manager", "//mash/shelf/public/interfaces", "//ui/app_list/presenter",
diff --git a/chrome/browser/ui/android/bluetooth_chooser_android.cc b/chrome/browser/ui/android/bluetooth_chooser_android.cc index a74e7088..164963c 100644 --- a/chrome/browser/ui/android/bluetooth_chooser_android.cc +++ b/chrome/browser/ui/android/bluetooth_chooser_android.cc
@@ -92,14 +92,19 @@ AttachCurrentThread(), java_dialog_.obj(), java_state); } -void BluetoothChooserAndroid::AddDevice(const std::string& device_id, - const base::string16& device_name) { +void BluetoothChooserAndroid::AddOrUpdateDevice( + const std::string& device_id, + bool should_update_name, + const base::string16& device_name, + bool is_gatt_connected, + bool is_paired, + const int8_t* rssi) { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef<jstring> java_device_id = ConvertUTF8ToJavaString(env, device_id); ScopedJavaLocalRef<jstring> java_device_name = ConvertUTF16ToJavaString(env, device_name); - Java_BluetoothChooserDialog_addDevice( + Java_BluetoothChooserDialog_addOrUpdateDevice( env, java_dialog_.obj(), java_device_id.obj(), java_device_name.obj()); }
diff --git a/chrome/browser/ui/android/bluetooth_chooser_android.h b/chrome/browser/ui/android/bluetooth_chooser_android.h index 0af0b1a..13ab583a 100644 --- a/chrome/browser/ui/android/bluetooth_chooser_android.h +++ b/chrome/browser/ui/android/bluetooth_chooser_android.h
@@ -26,8 +26,12 @@ bool CanAskForScanningPermission() override; void SetAdapterPresence(AdapterPresence presence) override; void ShowDiscoveryState(DiscoveryState state) override; - void AddDevice(const std::string& device_id, - const base::string16& device_name) override; + void AddOrUpdateDevice(const std::string& device_id, + bool should_update_name, + const base::string16& device_name, + bool is_gatt_connected, + bool is_paired, + const int8_t* rssi) override; void RemoveDevice(const std::string& device_id) override; // Report the dialog's result.
diff --git a/chrome/browser/ui/android/infobars/autofill_credit_card_filling_infobar.cc b/chrome/browser/ui/android/infobars/autofill_credit_card_filling_infobar.cc index 47c5b27..91215046 100644 --- a/chrome/browser/ui/android/infobars/autofill_credit_card_filling_infobar.cc +++ b/chrome/browser/ui/android/infobars/autofill_credit_card_filling_infobar.cc
@@ -17,6 +17,8 @@ #include "ui/gfx/image/image.h" #include "url/gurl.h" +using base::android::ScopedJavaLocalRef; + AutofillCreditCardFillingInfoBar::AutofillCreditCardFillingInfoBar( std::unique_ptr<autofill::AutofillCreditCardFillingInfoBarDelegateMobile> delegate)
diff --git a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc index 7f26aeb..493e19ab 100644 --- a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc +++ b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
@@ -39,6 +39,7 @@ const char kLastBackupAndroidId[] = "last_backup_android_id"; const char kLastBackupTime[] = "last_backup_time"; const char kLastLaunchTime[] = "lastlaunchtime"; +const char kLaunchable[] = "launchable"; const char kShouldSync[] = "should_sync"; const char kSystem[] = "system"; const char kOrientationLock[] = "orientation_lock"; @@ -59,7 +60,7 @@ base::DictionaryValue* Get() override { base::DictionaryValue* dict = DictionaryPrefUpdate::Get(); base::DictionaryValue* dict_item = nullptr; - if (!dict->GetDictionary(id_, &dict_item)) { + if (!dict->GetDictionaryWithoutPathExpansion(id_, &dict_item)) { dict_item = new base::DictionaryValue(); dict->SetWithoutPathExpansion(id_, dict_item); } @@ -189,7 +190,8 @@ DCHECK(IsArcEnabled()); DictionaryPrefUpdate update(prefs, prefs::kArcPackages); base::DictionaryValue* packages = update.Get(); - const bool removed = packages->Remove(package_name, nullptr); + const bool removed = packages->RemoveWithoutPathExpansion(package_name, + nullptr); DCHECK(removed); } @@ -455,6 +457,7 @@ bool sticky = false; bool notifications_enabled = true; bool shortcut = false; + bool launchable = true; int orientation_lock_value = 0; app->GetString(kName, &name); app->GetString(kPackageName, &package_name); @@ -464,6 +467,7 @@ app->GetBoolean(kSticky, &sticky); app->GetBoolean(kNotificationsEnabled, ¬ifications_enabled); app->GetBoolean(kShortcut, &shortcut); + app->GetBoolean(kLaunchable, &launchable); app->GetInteger(kOrientationLock, &orientation_lock_value); DCHECK(!name.empty()); @@ -477,17 +481,18 @@ } bool deferred; - if (SetNotificationsEnabledDeferred(prefs_).Get(app_id, &deferred)) { + if (SetNotificationsEnabledDeferred(prefs_).Get(app_id, &deferred)) notifications_enabled = deferred; - } + arc::mojom::OrientationLock orientation_lock = static_cast<arc::mojom::OrientationLock>(orientation_lock_value); return base::MakeUnique<AppInfo>( name, package_name, activity, intent_uri, icon_resource_id, last_launch_time, sticky, notifications_enabled, - ready_apps_.count(app_id) > 0, arc::ShouldShowInLauncher(app_id), - shortcut, orientation_lock); + ready_apps_.count(app_id) > 0, + launchable && arc::ShouldShowInLauncher(app_id), shortcut, launchable, + orientation_lock); } bool ArcAppListPrefs::IsRegistered(const std::string& app_id) const { @@ -496,7 +501,7 @@ const base::DictionaryValue* app = nullptr; const base::DictionaryValue* apps = prefs_->GetDictionary(prefs::kArcApps); - return apps && apps->GetDictionary(app_id, &app); + return apps && apps->GetDictionaryWithoutPathExpansion(app_id, &app); } bool ArcAppListPrefs::IsShortcut(const std::string& app_id) const { @@ -522,7 +527,7 @@ } void ArcAppListPrefs::DisableAllApps() { - std::set<std::string> old_ready_apps; + std::unordered_set<std::string> old_ready_apps; old_ready_apps.swap(ready_apps_); for (auto& app_id : old_ready_apps) { FOR_EACH_OBSERVER(Observer, observer_list_, @@ -588,6 +593,20 @@ } } +void ArcAppListPrefs::MayAddNonLaunchableApp(const std::string& name, + const std::string& package_name, + const std::string& activity) { + DCHECK(IsArcEnabled()); + if (IsRegistered(GetAppId(package_name, activity))) + return; + + AddAppAndShortcut(name, package_name, activity, + std::string() /* intent_uri */, + std::string() /* icon_resource_id */, false /* sticky */, + false /* notifications_enabled */, false /* shortcut */, + false /* launchable */, arc::mojom::OrientationLock::NONE); +} + void ArcAppListPrefs::AddAppAndShortcut( const std::string& name, const std::string& package_name, @@ -597,13 +616,15 @@ const bool sticky, const bool notifications_enabled, const bool shortcut, + const bool launchable, const arc::mojom::OrientationLock orientation_lock) { std::string app_id = shortcut ? GetAppId(package_name, intent_uri) : GetAppId(package_name, activity); - bool was_registered = IsRegistered(app_id); - + const bool was_registered = IsRegistered(app_id); if (was_registered) { std::unique_ptr<ArcAppListPrefs::AppInfo> app_old_info = GetApp(app_id); + DCHECK(app_old_info); + DCHECK(launchable); if (name != app_old_info->name) { FOR_EACH_OBSERVER(Observer, observer_list_, OnAppNameUpdated(app_id, name)); @@ -620,20 +641,24 @@ app_dict->SetBoolean(kSticky, sticky); app_dict->SetBoolean(kNotificationsEnabled, notifications_enabled); app_dict->SetBoolean(kShortcut, shortcut); + app_dict->SetBoolean(kLaunchable, launchable); app_dict->SetInteger(kOrientationLock, static_cast<int>(orientation_lock)); // From now, app is available. - if (!ready_apps_.count(app_id)) + const bool was_disabled = ready_apps_.count(app_id) == 0; + if (was_disabled) ready_apps_.insert(app_id); if (was_registered) { - FOR_EACH_OBSERVER(Observer, observer_list_, - OnAppReadyChanged(app_id, true)); + if (was_disabled) { + FOR_EACH_OBSERVER(Observer, observer_list_, + OnAppReadyChanged(app_id, true)); + } } else { AppInfo app_info(name, package_name, activity, intent_uri, icon_resource_id, base::Time(), sticky, notifications_enabled, true, - arc::ShouldShowInLauncher(app_id), shortcut, - orientation_lock); + launchable && arc::ShouldShowInLauncher(app_id), shortcut, + launchable, orientation_lock); FOR_EACH_OBSERVER(Observer, observer_list_, OnAppRegistered(app_id, app_info)); @@ -693,7 +718,7 @@ std::string() /* intent_uri */, std::string() /* icon_resource_id */, app->sticky, app->notifications_enabled, false /* shortcut */, - app->orientation_lock); + true /* launchable */, app->orientation_lock); } // Detect removed ARC apps after current refresh. @@ -722,18 +747,41 @@ OnTaskOrientationLockRequested(task_id, orientation_lock)); } -void ArcAppListPrefs::OnAppAdded(arc::mojom::AppInfoPtr app) { - if ((app->name.get().empty() || app->package_name.get().empty() || - app->activity.get().empty())) { +void ArcAppListPrefs::AddApp(const arc::mojom::AppInfo& app_info) { + if ((app_info.name.get().empty() || app_info.package_name.get().empty() || + app_info.activity.get().empty())) { VLOG(2) << "App Name, package name, and activity cannot be empty."; return; } - AddAppAndShortcut(app->name, app->package_name, app->activity, + AddAppAndShortcut(app_info.name, app_info.package_name, app_info.activity, std::string() /* intent_uri */, - std::string() /* icon_resource_id */, app->sticky, - app->notifications_enabled, false /* shortcut */, - app->orientation_lock); + std::string() /* icon_resource_id */, app_info.sticky, + app_info.notifications_enabled, false /* shortcut */, + true /* launchable */, app_info.orientation_lock); +} + +void ArcAppListPrefs::OnAppAddedDeprecated(arc::mojom::AppInfoPtr app) { + AddApp(*app); +} + +void ArcAppListPrefs::OnPackageAppListRefreshed( + const mojo::String& package_name, + mojo::Array<arc::mojom::AppInfoPtr> apps) { + if (package_name.get().empty()) { + VLOG(2) << "Package name cannot be empty."; + return; + } + + std::unordered_set<std::string> apps_to_remove = + GetAppsForPackage(package_name); + for (const auto& app : apps) { + apps_to_remove.erase(GetAppId(app->package_name, app->activity)); + AddApp(*app); + } + + for (const auto& app_id : apps_to_remove) + RemoveApp(app_id); } void ArcAppListPrefs::OnInstallShortcut(arc::mojom::ShortcutInfoPtr shortcut) { @@ -746,12 +794,13 @@ std::string() /* activity */, shortcut->intent_uri, shortcut->icon_resource_id, false /* sticky */, false /* notifications_enabled */, true /* shortcut */, - arc::mojom::OrientationLock::NONE); + true /* launchable */, arc::mojom::OrientationLock::NONE); } -void ArcAppListPrefs::OnPackageRemoved(const mojo::String& package_name) { +std::unordered_set<std::string> ArcAppListPrefs::GetAppsForPackage( + const std::string& package_name) const { + std::unordered_set<std::string> app_set; const base::DictionaryValue* apps = prefs_->GetDictionary(prefs::kArcApps); - std::vector<std::string> apps_to_remove; for (base::DictionaryValue::Iterator app_it(*apps); !app_it.IsAtEnd(); app_it.Advance()) { const base::Value* value = &app_it.value(); @@ -770,10 +819,16 @@ if (package_name != app_package) continue; - apps_to_remove.push_back(app_it.key()); + app_set.insert(app_it.key()); } - for (auto& app_id : apps_to_remove) + return app_set; +} + +void ArcAppListPrefs::OnPackageRemoved(const mojo::String& package_name) { + const std::unordered_set<std::string> apps_to_remove = + GetAppsForPackage(package_name); + for (const auto& app_id : apps_to_remove) RemoveApp(app_id); RemovePackageFromPrefs(prefs_, package_name); @@ -814,7 +869,9 @@ void ArcAppListPrefs::OnTaskCreated(int32_t task_id, const mojo::String& package_name, - const mojo::String& activity) { + const mojo::String& activity, + const mojo::String& name) { + MayAddNonLaunchableApp(name, package_name, activity); FOR_EACH_OBSERVER(Observer, observer_list_, OnTaskCreated(task_id, package_name, activity)); } @@ -933,6 +990,7 @@ bool ready, bool showInLauncher, bool shortcut, + bool launchable, arc::mojom::OrientationLock orientation_lock) : name(name), package_name(package_name), @@ -945,6 +1003,7 @@ ready(ready), showInLauncher(showInLauncher), shortcut(shortcut), + launchable(launchable), orientation_lock(orientation_lock) {} // Need to add explicit destructor for chromium style checker error:
diff --git a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.h b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.h index e1ce1d8..33486fd 100644 --- a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.h +++ b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.h
@@ -9,8 +9,8 @@ #include <map> #include <memory> -#include <set> #include <string> +#include <unordered_set> #include <vector> #include "base/files/file_path.h" @@ -63,6 +63,7 @@ bool ready, bool showInLauncher, bool shortcut, + bool launchable, arc::mojom::OrientationLock orientation_lock); ~AppInfo(); @@ -77,6 +78,7 @@ bool ready; bool showInLauncher; bool shortcut; + bool launchable; arc::mojom::OrientationLock orientation_lock; }; @@ -228,7 +230,10 @@ // arc::mojom::AppHost: void OnAppListRefreshed(mojo::Array<arc::mojom::AppInfoPtr> apps) override; - void OnAppAdded(arc::mojom::AppInfoPtr app) override; + void OnAppAddedDeprecated(arc::mojom::AppInfoPtr app) override; + void OnPackageAppListRefreshed( + const mojo::String& package_name, + mojo::Array<arc::mojom::AppInfoPtr> apps) override; void OnInstallShortcut(arc::mojom::ShortcutInfoPtr app) override; void OnPackageRemoved(const mojo::String& package_name) override; void OnAppIcon(const mojo::String& package_name, @@ -240,7 +245,8 @@ mojo::Array<uint8_t> icon_png_data); void OnTaskCreated(int32_t task_id, const mojo::String& package_name, - const mojo::String& activity) override; + const mojo::String& activity, + const mojo::String& name) override; void OnTaskDestroyed(int32_t task_id) override; void OnTaskSetActive(int32_t task_id) override; void OnNotificationsEnabledChanged(const mojo::String& package_name, @@ -253,6 +259,7 @@ int32_t task_id, const arc::mojom::OrientationLock orientation_lock) override; + void AddApp(const arc::mojom::AppInfo& app_info); void AddAppAndShortcut(const std::string& name, const std::string& package_name, const std::string& activity, @@ -261,6 +268,7 @@ const bool sticky, const bool notifications_enabled, const bool shortcut, + const bool launchable, arc::mojom::OrientationLock orientation_lock); void DisableAllApps(); void RemoveAllApps(); @@ -278,6 +286,14 @@ void OnIconInstalled(const std::string& app_id, ui::ScaleFactor scale_factor, bool install_succeed); + std::unordered_set<std::string> GetAppsForPackage( + const std::string& package_name) const; + + // This checks if app is not registered yet and in this case creates + // non-launchable app entry. + void MayAddNonLaunchableApp(const std::string& name, + const std::string& package_name, + const std::string& activity); Profile* const profile_; @@ -292,7 +308,7 @@ // stored. base::FilePath base_path_; // Contains set of ARC apps that are currently ready. - std::set<std::string> ready_apps_; + std::unordered_set<std::string> ready_apps_; // Keeps deferred icon load requests. Each app may contain several requests // for different scale factor. Scale factor is defined by specific bit // position.
diff --git a/chrome/browser/ui/app_list/arc/arc_app_test.cc b/chrome/browser/ui/app_list/arc/arc_app_test.cc index 01aad31..a1387bac 100644 --- a/chrome/browser/ui/app_list/arc/arc_app_test.cc +++ b/chrome/browser/ui/app_list/arc/arc_app_test.cc
@@ -19,9 +19,9 @@ namespace { -constexpr char kPackageName1[] = "fakepackagename1"; -constexpr char kPackageName2[] = "fakepackagename2"; -constexpr char kPackageName3[] = "fakepackagename3"; +constexpr char kPackageName1[] = "fake.package.name1"; +constexpr char kPackageName2[] = "fake.package.name2"; +constexpr char kPackageName3[] = "fake.package.name3"; } // static
diff --git a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc index 4ef89ee..4468326 100644 --- a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc +++ b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
@@ -38,7 +38,7 @@ namespace { -constexpr char kTestPackageName[] = "fakepackagename2"; +constexpr char kTestPackageName[] = "fake.package.name2"; class FakeAppIconLoaderDelegate : public AppIconLoaderDelegate { public: @@ -911,3 +911,59 @@ ASSERT_EQ(2u, app_instance()->launch_requests().size()); EXPECT_TRUE(app_instance()->launch_requests()[1]->IsForApp(app2)); } + +// Validates an app that have no launchable flag. +TEST_F(ArcAppModelBuilderTest, NonLaunchableApp) { + ArcAppListPrefs* prefs = ArcAppListPrefs::Get(profile_.get()); + ASSERT_NE(nullptr, prefs); + + ValidateHaveApps(std::vector<arc::mojom::AppInfo>()); + app_instance()->RefreshAppList(); + // Send all except first. + std::vector<arc::mojom::AppInfo> apps(fake_apps().begin() + 1, + fake_apps().end()); + app_instance()->SendRefreshAppList(apps); + ValidateHaveApps(apps); + + const std::string app_id = ArcAppTest::GetAppId(fake_apps()[0]); + + EXPECT_FALSE(prefs->IsRegistered(app_id)); + EXPECT_FALSE(FindArcItem(app_id)); + app_instance()->SendTaskCreated(0, fake_apps()[0]); + // App should not appear now in the model but should be registered. + EXPECT_FALSE(FindArcItem(app_id)); + EXPECT_TRUE(prefs->IsRegistered(app_id)); +} + +TEST_F(ArcAppModelBuilderTest, ArcAppsOnPackageUpdated) { + ArcAppListPrefs* prefs = ArcAppListPrefs::Get(profile_.get()); + ASSERT_NE(nullptr, prefs); + + std::vector<arc::mojom::AppInfo> apps = fake_apps(); + ASSERT_GE(3u, apps.size()); + apps[0].package_name = apps[2].package_name; + apps[1].package_name = apps[2].package_name; + // Second app should be preserved after update. + std::vector<arc::mojom::AppInfo> apps1(apps.begin(), apps.begin() + 2); + std::vector<arc::mojom::AppInfo> apps2(apps.begin() + 1, apps.begin() + 3); + + app_instance()->RefreshAppList(); + app_instance()->SendRefreshAppList(apps1); + ValidateHaveApps(apps1); + + const std::string app_id = ArcAppTest::GetAppId(apps[1]); + const base::Time now_time = base::Time::Now(); + prefs->SetLastLaunchTime(app_id, now_time); + std::unique_ptr<ArcAppListPrefs::AppInfo> app_info_before = + prefs->GetApp(app_id); + ASSERT_TRUE(app_info_before); + EXPECT_EQ(now_time, app_info_before->last_launch_time); + + app_instance()->SendPackageAppListRefreshed(apps[0].package_name, apps2); + ValidateHaveApps(apps2); + + std::unique_ptr<ArcAppListPrefs::AppInfo> app_info_after = + prefs->GetApp(app_id); + ASSERT_TRUE(app_info_after); + EXPECT_EQ(now_time, app_info_after->last_launch_time); +}
diff --git a/chrome/browser/ui/app_list/arc/arc_app_utils.cc b/chrome/browser/ui/app_list/arc/arc_app_utils.cc index 651bbb8..94e69c1 100644 --- a/chrome/browser/ui/app_list/arc/arc_app_utils.cc +++ b/chrome/browser/ui/app_list/arc/arc_app_utils.cc
@@ -30,6 +30,7 @@ // Minimum required versions. constexpr int kMinVersion = 0; constexpr int kCanHandleResolutionMinVersion = 1; +constexpr int kSendBroadcastMinVersion = 1; constexpr int kUninstallPackageMinVersion = 2; constexpr int kShowPackageInfoMinVersion = 5; constexpr int kRemoveIconMinVersion = 9; @@ -182,6 +183,11 @@ return false; } + if (!app_info->launchable) { + VLOG(2) << "Cannot launch non-launchable app: " << app_id << "."; + return false; + } + arc::mojom::AppInstance* app_instance = GetAppInstance(kMinVersion, kLaunchAppStr); if (!app_instance) @@ -227,6 +233,31 @@ ->LaunchAndRelease(); } +void ShowTalkBackSettings() { + arc::ArcBridgeService* bridge_service = arc::ArcBridgeService::Get(); + if (!bridge_service) { + VLOG(2) << "ARC bridge is not ready"; + return; + } + + arc::mojom::IntentHelperInstance *intent_helper_instance = + bridge_service->intent_helper()->instance(); + if (!intent_helper_instance) { + VLOG(2) << "ARC intent helper instance is not ready"; + return; + } + if (bridge_service->intent_helper()->version() < kSendBroadcastMinVersion) { + VLOG(2) << "ARC intent helper instance is too old"; + return; + } + + intent_helper_instance->SendBroadcast( + "org.chromium.arc.intent_helper.SHOW_TALKBACK_SETTINGS", + "org.chromium.arc.intent_helper", + "org.chromium.arc.intent_helper.SettingsReceiver", + "{}"); +} + bool CanHandleResolution(content::BrowserContext* context, const std::string& app_id, const gfx::Rect& rect,
diff --git a/chrome/browser/ui/app_list/arc/arc_app_utils.h b/chrome/browser/ui/app_list/arc/arc_app_utils.h index 2a8fbe3..f5d6aecf 100644 --- a/chrome/browser/ui/app_list/arc/arc_app_utils.h +++ b/chrome/browser/ui/app_list/arc/arc_app_utils.h
@@ -42,6 +42,9 @@ const std::string& app_id, const gfx::Rect& target_rect); +// Open TalkBack settings window. +void ShowTalkBackSettings(); + // Tests if the application can use the given target resolution. // The callback will receive the information once known. // A false will get returned if the result cannot be determined in which case
diff --git a/chrome/browser/ui/ash/DEPS b/chrome/browser/ui/ash/DEPS index de7ea75..c23e2da 100644 --- a/chrome/browser/ui/ash/DEPS +++ b/chrome/browser/ui/ash/DEPS
@@ -1,5 +1,5 @@ include_rules = [ - "+ash/sysui/public/interfaces", + "+ash/public/interfaces", "+components/arc", "+components/drive", "+components/user_manager",
diff --git a/chrome/browser/ui/ash/chrome_screenshot_grabber.cc b/chrome/browser/ui/ash/chrome_screenshot_grabber.cc index ee6152e..13c60cd 100644 --- a/chrome/browser/ui/ash/chrome_screenshot_grabber.cc +++ b/chrome/browser/ui/ash/chrome_screenshot_grabber.cc
@@ -20,6 +20,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/drive/file_system_util.h" #include "chrome/browser/chromeos/file_manager/open_util.h" +#include "chrome/browser/chromeos/note_taking_app_utils.h" #include "chrome/browser/download/download_prefs.h" #include "chrome/browser/notifications/notification_ui_manager.h" #include "chrome/browser/notifications/notifier_state_tracker.h" @@ -56,7 +57,7 @@ std::string encoded; base::Base64Encode(png_data->data(), &encoded); - // Only cares about HTML because ChromeOS doesn't need other formats. + // Only care about HTML because Chrome OS doesn't need other formats. // TODO(dcheng): Why don't we take advantage of the ability to write bitmaps // to the clipboard here? { @@ -116,21 +117,32 @@ platform_util::ShowItemInFolder(profile_, screenshot_path_); } void ButtonClick(int button_index) override { - DCHECK(success_ && button_index == 0); + DCHECK(success_); - // To avoid keeping the screenshot image on memory, it will re-read the - // screenshot file and copy it to the clipboard. - if (drive::util::IsUnderDriveMountPoint(screenshot_path_)) { - drive::FileSystemInterface* file_system = - drive::util::GetFileSystemByProfile(profile_); - file_system->GetFile(drive::util::ExtractDrivePath(screenshot_path_), - base::Bind(&ReadFileAndCopyToClipboardDrive)); - return; + switch (button_index) { + case BUTTON_COPY_TO_CLIPBOARD: { + // To avoid keeping the screenshot image in memory, re-read the + // screenshot file and copy it to the clipboard. + if (drive::util::IsUnderDriveMountPoint(screenshot_path_)) { + drive::FileSystemInterface* file_system = + drive::util::GetFileSystemByProfile(profile_); + file_system->GetFile(drive::util::ExtractDrivePath(screenshot_path_), + base::Bind(&ReadFileAndCopyToClipboardDrive)); + return; + } + content::BrowserThread::GetBlockingPool()->PostTask( + FROM_HERE, + base::Bind(&ReadFileAndCopyToClipboardLocal, screenshot_path_)); + break; + } + case BUTTON_ANNOTATE: { + if (chromeos::IsNoteTakingAppAvailable(profile_)) + chromeos::LaunchNoteTakingAppForNewNote(profile_, screenshot_path_); + break; + } + default: + NOTREACHED() << "Unhandled button index " << button_index; } - - content::BrowserThread::GetBlockingPool()->PostTask( - FROM_HERE, - base::Bind(&ReadFileAndCopyToClipboardLocal, screenshot_path_)); } bool HasClickedListener() override { return success_; } std::string id() const override { return std::string(kNotificationId); } @@ -138,6 +150,11 @@ private: ~ScreenshotGrabberNotificationDelegate() override {} + enum ButtonIndex { + BUTTON_COPY_TO_CLIPBOARD = 0, + BUTTON_ANNOTATE, + }; + const bool success_; Profile* profile_; const base::FilePath screenshot_path_; @@ -404,16 +421,30 @@ // a fresh notification pop-up. g_browser_process->notification_ui_manager()->CancelById( notification_id, NotificationUIManager::GetProfileID(GetProfile())); - bool success = + + const bool success = (screenshot_result == ui::ScreenshotGrabberObserver::SCREENSHOT_SUCCESS); + message_center::RichNotificationData optional_field; if (success) { - message_center::ButtonInfo button_info(l10n_util::GetStringUTF16( + // The order in which these buttons are added must be reflected by + // ScreenshotGrabberNotificationDelegate::ButtonIndex. + message_center::ButtonInfo copy_button(l10n_util::GetStringUTF16( IDS_MESSAGE_CENTER_NOTIFICATION_BUTTON_COPY_SCREENSHOT_TO_CLIPBOARD)); - button_info.icon = ui::ResourceBundle::GetSharedInstance().GetImageNamed( + copy_button.icon = ui::ResourceBundle::GetSharedInstance().GetImageNamed( IDR_NOTIFICATION_SCREENSHOT_COPY_TO_CLIPBOARD); - optional_field.buttons.push_back(button_info); + optional_field.buttons.push_back(copy_button); + + if (chromeos::IsNoteTakingAppAvailable(GetProfile())) { + message_center::ButtonInfo annotate_button(l10n_util::GetStringUTF16( + IDS_MESSAGE_CENTER_NOTIFICATION_BUTTON_ANNOTATE_SCREENSHOT)); + annotate_button.icon = + ui::ResourceBundle::GetSharedInstance().GetImageNamed( + IDR_NOTIFICATION_SCREENSHOT_ANNOTATE); + optional_field.buttons.push_back(annotate_button); + } } + return new Notification( message_center::NOTIFICATION_TYPE_SIMPLE, l10n_util::GetStringUTF16(
diff --git a/chrome/browser/ui/ash/chrome_wallpaper_manager.cc b/chrome/browser/ui/ash/chrome_wallpaper_manager.cc index e03640b..da105fd 100644 --- a/chrome/browser/ui/ash/chrome_wallpaper_manager.cc +++ b/chrome/browser/ui/ash/chrome_wallpaper_manager.cc
@@ -11,7 +11,7 @@ ChromeWallpaperManager::~ChromeWallpaperManager() {} void ChromeWallpaperManager::ProcessRequest( - ash::sysui::mojom::WallpaperManagerRequest request) { + ash::mojom::WallpaperManagerRequest request) { bindings_.AddBinding(this, std::move(request)); }
diff --git a/chrome/browser/ui/ash/chrome_wallpaper_manager.h b/chrome/browser/ui/ash/chrome_wallpaper_manager.h index 6876606..ae7078c 100644 --- a/chrome/browser/ui/ash/chrome_wallpaper_manager.h +++ b/chrome/browser/ui/ash/chrome_wallpaper_manager.h
@@ -5,22 +5,22 @@ #ifndef CHROME_BROWSER_UI_ASH_CHROME_WALLPAPER_MANAGER_H_ #define CHROME_BROWSER_UI_ASH_CHROME_WALLPAPER_MANAGER_H_ -#include "ash/sysui/public/interfaces/wallpaper.mojom.h" +#include "ash/public/interfaces/wallpaper.mojom.h" #include "mojo/public/cpp/bindings/binding_set.h" -// ChromeWallpaperManager exposes chrome wallpaper functionality to ash_sysui. -class ChromeWallpaperManager : public ash::sysui::mojom::WallpaperManager { +// ChromeWallpaperManager exposes chrome wallpaper functionality to mash. +class ChromeWallpaperManager : public ash::mojom::WallpaperManager { public: ChromeWallpaperManager(); ~ChromeWallpaperManager() override; - void ProcessRequest(ash::sysui::mojom::WallpaperManagerRequest request); + void ProcessRequest(ash::mojom::WallpaperManagerRequest request); private: - // ash::sysui::mojom::WallpaperManager: + // ash::mojom::WallpaperManager: void Open() override; - mojo::BindingSet<ash::sysui::mojom::WallpaperManager> bindings_; + mojo::BindingSet<ash::mojom::WallpaperManager> bindings_; DISALLOW_COPY_AND_ASSIGN(ChromeWallpaperManager); };
diff --git a/chrome/browser/ui/ash/launcher/arc_app_launcher_browsertest.cc b/chrome/browser/ui/ash/launcher/arc_app_launcher_browsertest.cc index 6dcb9d9..d72acaf 100644 --- a/chrome/browser/ui/ash/launcher/arc_app_launcher_browsertest.cc +++ b/chrome/browser/ui/ash/launcher/arc_app_launcher_browsertest.cc
@@ -41,14 +41,41 @@ namespace { const char kTestAppName[] = "Test Arc App"; +const char kTestAppName2[] = "Test Arc App 2"; const char kTestAppPackage[] = "test.arc.app.package"; const char kTestAppActivity[] = "test.arc.app.package.activity"; +const char kTestAppActivity2[] = "test.arc.app.package.activity2"; constexpr int kAppAnimatedThresholdMs = 100; -std::string GetTestAppId() { +std::string GetTestApp1Id() { return ArcAppListPrefs::GetAppId(kTestAppPackage, kTestAppActivity); } +std::string GetTestApp2Id() { + return ArcAppListPrefs::GetAppId(kTestAppPackage, kTestAppActivity2); +} + +mojo::Array<arc::mojom::AppInfoPtr> GetTestAppsList(bool multi_app) { + std::vector<arc::mojom::AppInfo> apps; + + arc::mojom::AppInfo app; + app.name = kTestAppName; + app.package_name = kTestAppPackage; + app.activity = kTestAppActivity; + app.sticky = false; + apps.push_back(app); + + if (multi_app) { + app.name = kTestAppName2; + app.package_name = kTestAppPackage; + app.activity = kTestAppActivity2; + app.sticky = false; + apps.push_back(app); + } + + return mojo::Array<arc::mojom::AppInfoPtr>::From(apps); +} + ChromeLauncherController* chrome_controller() { return ChromeLauncherController::instance(); } @@ -93,9 +120,7 @@ } // namespace -class ArcAppLauncherBrowserTest - : public ExtensionBrowserTest, - public testing::WithParamInterface<TestParameter> { +class ArcAppLauncherBrowserTest : public ExtensionBrowserTest { public: ArcAppLauncherBrowserTest() {} ~ArcAppLauncherBrowserTest() override {} @@ -114,26 +139,38 @@ void SetUpOnMainThread() override { arc::ArcAuthService::Get()->EnableArc(); } - void InstallTestApp() { - std::vector<arc::mojom::AppInfo> apps; - - arc::mojom::AppInfo app; - app.name = kTestAppName; - app.package_name = kTestAppPackage; - app.activity = kTestAppActivity; - app.sticky = false; - apps.push_back(app); - - app_host()->OnAppListRefreshed( - mojo::Array<arc::mojom::AppInfoPtr>::From(apps)); + void InstallTestApps(bool multi_app) { + app_host()->OnAppListRefreshed(GetTestAppsList(multi_app)); std::unique_ptr<ArcAppListPrefs::AppInfo> app_info = - app_prefs()->GetApp(GetTestAppId()); + app_prefs()->GetApp(GetTestApp1Id()); ASSERT_TRUE(app_info); EXPECT_TRUE(app_info->ready); + if (multi_app) { + std::unique_ptr<ArcAppListPrefs::AppInfo> app_info2 = + app_prefs()->GetApp(GetTestApp2Id()); + ASSERT_TRUE(app_info2); + EXPECT_TRUE(app_info2->ready); + } + + arc::mojom::ArcPackageInfo package_info; + package_info.package_name = kTestAppPackage; + package_info.package_version = 1; + package_info.last_backup_android_id = 1; + package_info.last_backup_time = 1; + package_info.sync = false; + app_host()->OnPackageAdded(arc::mojom::ArcPackageInfo::From(package_info)); + base::RunLoop().RunUntilIdle(); } + void SendPackageUpdated(bool multi_app) { + app_host()->OnPackageAppListRefreshed(kTestAppPackage, + GetTestAppsList(multi_app)); + } + + void SendPackageRemoved() { app_host()->OnPackageRemoved(kTestAppPackage); } + void StartInstance() { auth_service()->OnPrimaryUserProfilePrepared(profile()); app_instance_observer()->OnInstanceReady(); @@ -159,20 +196,32 @@ arc::ArcAuthService* auth_service() { return arc::ArcAuthService::Get(); } + private: + DISALLOW_COPY_AND_ASSIGN(ArcAppLauncherBrowserTest); +}; + +class ArcAppDeferredLauncherBrowserTest + : public ArcAppLauncherBrowserTest, + public testing::WithParamInterface<TestParameter> { + public: + ArcAppDeferredLauncherBrowserTest() {} + ~ArcAppDeferredLauncherBrowserTest() override {} + + protected: bool is_pinned() const { return std::tr1::get<1>(GetParam()); } TestAction test_action() const { return std::tr1::get<0>(GetParam()); } private: - DISALLOW_COPY_AND_ASSIGN(ArcAppLauncherBrowserTest); + DISALLOW_COPY_AND_ASSIGN(ArcAppDeferredLauncherBrowserTest); }; // This tests simulates normal workflow for starting Arc app in deferred mode. -IN_PROC_BROWSER_TEST_P(ArcAppLauncherBrowserTest, StartAppDeferred) { +IN_PROC_BROWSER_TEST_P(ArcAppDeferredLauncherBrowserTest, StartAppDeferred) { // Install app to remember existing apps. - InstallTestApp(); + InstallTestApps(false); - const std::string app_id = GetTestAppId(); + const std::string app_id = GetTestApp1Id(); if (is_pinned()) { shelf_delegate()->PinAppWithID(app_id); EXPECT_TRUE(shelf_delegate()->GetShelfIDForAppID(app_id)); @@ -205,7 +254,7 @@ case TEST_ACTION_START: // Now simulates that Arc is started and app list is refreshed. This // should stop animation and delete icon from the shelf. - InstallTestApp(); + InstallTestApps(false); EXPECT_TRUE(chrome_controller() ->GetArcDeferredLauncher() ->GetActiveTime(app_id) @@ -239,6 +288,38 @@ } } -INSTANTIATE_TEST_CASE_P(ArcAppLauncherBrowserTestInstance, - ArcAppLauncherBrowserTest, +INSTANTIATE_TEST_CASE_P(ArcAppDeferredLauncherBrowserTestInstance, + ArcAppDeferredLauncherBrowserTest, ::testing::ValuesIn(build_test_parameter)); + +// This tests validates pin state on package update and remove. +IN_PROC_BROWSER_TEST_F(ArcAppLauncherBrowserTest, PinOnPackageUpdateAndRemove) { + InstallTestApps(true); + + const std::string app_id1 = GetTestApp1Id(); + const std::string app_id2 = GetTestApp2Id(); + shelf_delegate()->PinAppWithID(app_id1); + shelf_delegate()->PinAppWithID(app_id2); + const ash::ShelfID shelf_id1_before = + shelf_delegate()->GetShelfIDForAppID(app_id1); + EXPECT_TRUE(shelf_id1_before); + EXPECT_TRUE(shelf_delegate()->GetShelfIDForAppID(app_id2)); + + // Package contains only one app. + SendPackageUpdated(false); + // Second pin should gone. + EXPECT_EQ(shelf_id1_before, shelf_delegate()->GetShelfIDForAppID(app_id1)); + EXPECT_FALSE(shelf_delegate()->GetShelfIDForAppID(app_id2)); + + // Package contains two apps. + SendPackageUpdated(true); + // Second pin should not appear. + EXPECT_EQ(shelf_id1_before, shelf_delegate()->GetShelfIDForAppID(app_id1)); + EXPECT_FALSE(shelf_delegate()->GetShelfIDForAppID(app_id2)); + + // Package removed. + SendPackageRemoved(); + // No pin is expected. + EXPECT_FALSE(shelf_delegate()->GetShelfIDForAppID(app_id1)); + EXPECT_FALSE(shelf_delegate()->GetShelfIDForAppID(app_id2)); +}
diff --git a/chrome/browser/ui/ash/launcher/arc_launcher_context_menu.cc b/chrome/browser/ui/ash/launcher/arc_launcher_context_menu.cc index 8081f871..d4ceb30 100644 --- a/chrome/browser/ui/ash/launcher/arc_launcher_context_menu.cc +++ b/chrome/browser/ui/ash/launcher/arc_launcher_context_menu.cc
@@ -5,6 +5,8 @@ #include "chrome/browser/ui/ash/launcher/arc_launcher_context_menu.h" #include "ash/common/shelf/shelf_item_types.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h" #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.h" #include "chrome/grit/generated_resources.h" @@ -19,12 +21,28 @@ ArcLauncherContextMenu::~ArcLauncherContextMenu() {} void ArcLauncherContextMenu::Init() { + const ArcAppListPrefs* arc_list_prefs = + ArcAppListPrefs::Get(controller()->GetProfile()); + DCHECK(arc_list_prefs); + + const std::string app_id = controller()->GetAppIDForShelfID(item().id); + std::unique_ptr<ArcAppListPrefs::AppInfo> app_info = + arc_list_prefs->GetApp(app_id); + if (!app_info) { + NOTREACHED(); + return; + } + const bool app_is_open = controller()->IsOpen(item().id); if (!app_is_open) { + DCHECK(app_info->launchable); AddItemWithStringId(MENU_OPEN_NEW, IDS_APP_CONTEXT_MENU_ACTIVATE_ARC); AddSeparator(ui::NORMAL_SEPARATOR); } - AddPinMenu(); + + if (app_info->launchable) + AddPinMenu(); + if (app_is_open) AddItemWithStringId(MENU_CLOSE, IDS_LAUNCHER_CONTEXT_MENU_CLOSE); AddSeparator(ui::NORMAL_SEPARATOR);
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc index 9fd7fe3..cf06064 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc
@@ -872,7 +872,7 @@ app_info.name, app_info.package_name, app_info.activity, std::string() /* intent_uri */, std::string() /* icon_resource_id */, false /* sticky */, true /* notifications_enabled */, - false /* shortcut */, app_info.orientation_lock); + false /* shortcut */, true /* launchable */, app_info.orientation_lock); const std::string app_id = ArcAppListPrefs::GetAppId(app_info.package_name, app_info.activity); EXPECT_TRUE(prefs->GetApp(app_id)); @@ -882,7 +882,8 @@ void NotifyOnTaskCreated(const arc::mojom::AppInfo& appinfo, int32_t task_id) { ArcAppListPrefs* const prefs = arc_test_.arc_app_list_prefs(); - prefs->OnTaskCreated(task_id, appinfo.package_name, appinfo.activity); + prefs->OnTaskCreated(task_id, appinfo.package_name, appinfo.activity, + appinfo.name); } void NotifyOnTaskOrientationLockRequested(int32_t task_id,
diff --git a/chrome/browser/ui/ash/launcher/chrome_mash_shelf_controller.cc b/chrome/browser/ui/ash/launcher/chrome_mash_shelf_controller.cc index 434a02e..8348f9a 100644 --- a/chrome/browser/ui/ash/launcher/chrome_mash_shelf_controller.cc +++ b/chrome/browser/ui/ash/launcher/chrome_mash_shelf_controller.cc
@@ -72,7 +72,7 @@ void ChromeMashShelfController::Init() { shell::Connector* connector = content::MojoShellConnection::GetForProcess()->GetConnector(); - connector->ConnectToInterface("mojo:ash_sysui", &shelf_controller_); + connector->ConnectToInterface("mojo:ash", &shelf_controller_); // Set shelf alignment and auto-hide behavior from preferences. Profile* profile = ProfileManager::GetActiveUserProfile();
diff --git a/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc b/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc index a2c2258..2a5b03a 100644 --- a/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc +++ b/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc
@@ -157,7 +157,9 @@ // Verifies contextmenu items for Arc app TEST_F(LauncherContextMenuTest, ArcLauncherContextMenuItemCheck) { arc_test().app_instance()->RefreshAppList(); - arc_test().app_instance()->SendRefreshAppList(arc_test().fake_apps()); + arc_test().app_instance()->SendRefreshAppList( + std::vector<arc::mojom::AppInfo>(arc_test().fake_apps().begin(), + arc_test().fake_apps().begin() + 1)); const std::string app_id = ArcAppTest::GetAppId(arc_test().fake_apps()[0]); controller()->PinAppWithID(app_id); @@ -202,4 +204,17 @@ EXPECT_TRUE(menu->IsCommandIdEnabled(LauncherContextMenu::MENU_PIN)); EXPECT_TRUE(IsItemPresentInMenu(menu.get(), LauncherContextMenu::MENU_CLOSE)); EXPECT_TRUE(menu->IsCommandIdEnabled(LauncherContextMenu::MENU_CLOSE)); + + // Arc non-launchable app is running. + const std::string app_id2 = ArcAppTest::GetAppId(arc_test().fake_apps()[1]); + arc_test().app_instance()->SendTaskCreated(2, arc_test().fake_apps()[1]); + item.id = controller()->GetShelfIDForAppID(app_id2); + ASSERT_TRUE(item.id); + menu.reset(new ArcLauncherContextMenu(controller(), &item, wm_shelf)); + + EXPECT_FALSE( + IsItemPresentInMenu(menu.get(), LauncherContextMenu::MENU_OPEN_NEW)); + EXPECT_FALSE(IsItemPresentInMenu(menu.get(), LauncherContextMenu::MENU_PIN)); + EXPECT_TRUE(IsItemPresentInMenu(menu.get(), LauncherContextMenu::MENU_CLOSE)); + EXPECT_TRUE(menu->IsCommandIdEnabled(LauncherContextMenu::MENU_CLOSE)); }
diff --git a/chrome/browser/ui/bluetooth/DEPS b/chrome/browser/ui/bluetooth/DEPS new file mode 100644 index 0000000..fa20d38 --- /dev/null +++ b/chrome/browser/ui/bluetooth/DEPS
@@ -0,0 +1,3 @@ +include_rules = [ + "+content/browser/bluetooth", +]
diff --git a/chrome/browser/ui/bluetooth/bluetooth_chooser_controller.cc b/chrome/browser/ui/bluetooth/bluetooth_chooser_controller.cc index f8c98f61..49dccb9 100644 --- a/chrome/browser/ui/bluetooth/bluetooth_chooser_controller.cc +++ b/chrome/browser/ui/bluetooth/bluetooth_chooser_controller.cc
@@ -13,6 +13,7 @@ #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h" #include "chrome/common/url_constants.h" #include "chrome/grit/generated_resources.h" +#include "content/browser/bluetooth/bluetooth_metrics.h" #include "ui/base/l10n/l10n_util.h" #include "url/gurl.h" @@ -49,22 +50,26 @@ } size_t BluetoothChooserController::NumOptions() const { - return device_names_and_ids_.size(); + return device_ids_.size(); } base::string16 BluetoothChooserController::GetOption(size_t index) const { - DCHECK_LT(index, device_names_and_ids_.size()); - const base::string16& device_name = device_names_and_ids_[index].first; - const auto& it = device_name_map_.find(device_name); + DCHECK_LT(index, device_ids_.size()); + const std::string& device_id = device_ids_[index]; + const auto& device_name_it = device_id_to_name_map_.find(device_id); + DCHECK(device_name_it != device_id_to_name_map_.end()); + const auto& it = device_name_map_.find(device_name_it->second); DCHECK(it != device_name_map_.end()); return it->second == 1 - ? device_name + ? device_name_it->second : l10n_util::GetStringFUTF16( - IDS_DEVICE_CHOOSER_DEVICE_NAME_WITH_ID, device_name, - base::UTF8ToUTF16(device_names_and_ids_[index].second)); + IDS_DEVICE_CHOOSER_DEVICE_NAME_WITH_ID, + device_name_it->second, base::UTF8ToUTF16(device_id)); } void BluetoothChooserController::RefreshOptions() { + if (event_handler_.is_null()) + return; ClearAllDevices(); event_handler_.Run(content::BluetoothChooser::Event::RESCAN, std::string()); } @@ -74,17 +79,27 @@ } void BluetoothChooserController::Select(size_t index) { - DCHECK_LT(index, device_names_and_ids_.size()); + if (event_handler_.is_null()) { + content::RecordRequestDeviceOutcome( + content::UMARequestDeviceOutcome:: + BLUETOOTH_CHOOSER_EVENT_HANDLER_INVALID); + return; + } + DCHECK_LT(index, device_ids_.size()); event_handler_.Run(content::BluetoothChooser::Event::SELECTED, - device_names_and_ids_[index].second); + device_ids_[index]); } void BluetoothChooserController::Cancel() { + if (event_handler_.is_null()) + return; event_handler_.Run(content::BluetoothChooser::Event::CANCELLED, std::string()); } void BluetoothChooserController::Close() { + if (event_handler_.is_null()) + return; event_handler_.Run(content::BluetoothChooser::Event::CANCELLED, std::string()); } @@ -148,31 +163,63 @@ } } -void BluetoothChooserController::AddDevice(const std::string& device_id, - const base::string16& device_name) { - device_names_and_ids_.push_back(std::make_pair(device_name, device_id)); +void BluetoothChooserController::AddOrUpdateDevice( + const std::string& device_id, + bool should_update_name, + const base::string16& device_name, + bool is_gatt_connected, + bool is_paired, + const int8_t* rssi) { + auto result = device_id_to_name_map_.insert({device_id, device_name}); + if (!result.second) { + // TODO(ortuno): Update device's information. + // https://crbug.com/634366 Update name + // http://crbug.com/543466 Update connection and paired status + // http://crbug.com/629689 Update RSSI. + return; + } + + device_ids_.push_back(device_id); ++device_name_map_[device_name]; if (view()) - view()->OnOptionAdded(device_names_and_ids_.size() - 1); + view()->OnOptionAdded(device_ids_.size() - 1); } void BluetoothChooserController::RemoveDevice(const std::string& device_id) { - for (auto it = device_names_and_ids_.begin(); - it != device_names_and_ids_.end(); ++it) { - if (it->second == device_id) { - size_t index = it - device_names_and_ids_.begin(); - DCHECK_GT(device_name_map_[it->first], 0); - if (--device_name_map_[it->first] == 0) - device_name_map_.erase(it->first); - device_names_and_ids_.erase(it); - if (view()) - view()->OnOptionRemoved(index); - return; + const auto& name_it = device_id_to_name_map_.find(device_id); + if (name_it == device_id_to_name_map_.end()) + return; + + size_t index = 0; + for (const auto& saved_device_id : device_ids_) { + if (saved_device_id != device_id) { + ++index; + continue; } + + device_ids_.erase(device_ids_.begin() + index); + + const auto& it = device_name_map_.find(name_it->second); + DCHECK(it != device_name_map_.end()); + DCHECK_GT(it->second, 0); + + if (--(it->second) == 0) + device_name_map_.erase(it); + + device_id_to_name_map_.erase(name_it); + + if (view()) + view()->OnOptionRemoved(index); + return; } } +void BluetoothChooserController::ResetEventHandler() { + event_handler_.Reset(); +} + void BluetoothChooserController::ClearAllDevices() { - device_names_and_ids_.clear(); + device_ids_.clear(); + device_id_to_name_map_.clear(); device_name_map_.clear(); }
diff --git a/chrome/browser/ui/bluetooth/bluetooth_chooser_controller.h b/chrome/browser/ui/bluetooth/bluetooth_chooser_controller.h index 35becbf..2c6b9db3 100644 --- a/chrome/browser/ui/bluetooth/bluetooth_chooser_controller.h +++ b/chrome/browser/ui/bluetooth/bluetooth_chooser_controller.h
@@ -47,23 +47,34 @@ // discovery is happening. void OnDiscoveryStateChanged(content::BluetoothChooser::DiscoveryState state); - // Shows a new device in the chooser. - void AddDevice(const std::string& device_id, - const base::string16& device_name); + // Shows a new device in the chooser or updates its information. + // TODO(ortuno): Update device's name if necessary. + // https://crbug.com/634366 + void AddOrUpdateDevice(const std::string& device_id, + bool should_update_name, + const base::string16& device_name, + bool is_gatt_connected, + bool is_paired, + const int8_t* rssi); // Tells the chooser that a device is no longer available. void RemoveDevice(const std::string& device_id); + // Called when |event_handler_| is no longer valid and should not be used + // any more. + void ResetEventHandler(); + private: // Clears |device_names_and_ids_| and |device_name_map_|. Called when // Bluetooth adapter is turned on or off, or when re-scan happens. void ClearAllDevices(); - // Each pair is a (device name, device id). - std::vector<std::pair<base::string16, std::string>> device_names_and_ids_; - content::BluetoothChooser::EventHandler event_handler_; + std::vector<std::string> device_ids_; + std::unordered_map<std::string, base::string16> device_id_to_name_map_; // Maps from device name to number of devices. std::unordered_map<base::string16, int> device_name_map_; + + content::BluetoothChooser::EventHandler event_handler_; base::string16 no_devices_text_; base::string16 status_text_;
diff --git a/chrome/browser/ui/bluetooth/bluetooth_chooser_desktop.cc b/chrome/browser/ui/bluetooth/bluetooth_chooser_desktop.cc index f24e4a95..bbb907a 100644 --- a/chrome/browser/ui/bluetooth/bluetooth_chooser_desktop.cc +++ b/chrome/browser/ui/bluetooth/bluetooth_chooser_desktop.cc
@@ -13,7 +13,12 @@ DCHECK(bluetooth_chooser_controller_); } -BluetoothChooserDesktop::~BluetoothChooserDesktop() {} +BluetoothChooserDesktop::~BluetoothChooserDesktop() { + // This satisfies the WebContentsDelegate::RunBluetoothChooser() requirement + // that the EventHandler can be destroyed any time after the BluetoothChooser + // instance. + bluetooth_chooser_controller_->ResetEventHandler(); +} void BluetoothChooserDesktop::SetAdapterPresence(AdapterPresence presence) { bluetooth_chooser_controller_->OnAdapterPresenceChanged(presence); @@ -23,9 +28,16 @@ bluetooth_chooser_controller_->OnDiscoveryStateChanged(state); } -void BluetoothChooserDesktop::AddDevice(const std::string& device_id, - const base::string16& device_name) { - bluetooth_chooser_controller_->AddDevice(device_id, device_name); +void BluetoothChooserDesktop::AddOrUpdateDevice( + const std::string& device_id, + bool should_update_name, + const base::string16& device_name, + bool is_gatt_connected, + bool is_paired, + const int8_t* rssi) { + bluetooth_chooser_controller_->AddOrUpdateDevice( + device_id, should_update_name, device_name, is_gatt_connected, is_paired, + rssi); } void BluetoothChooserDesktop::RemoveDevice(const std::string& device_id) {
diff --git a/chrome/browser/ui/bluetooth/bluetooth_chooser_desktop.h b/chrome/browser/ui/bluetooth/bluetooth_chooser_desktop.h index 77c2cd21..a0dc1d94 100644 --- a/chrome/browser/ui/bluetooth/bluetooth_chooser_desktop.h +++ b/chrome/browser/ui/bluetooth/bluetooth_chooser_desktop.h
@@ -22,8 +22,12 @@ // BluetoothChooser: void SetAdapterPresence(AdapterPresence presence) override; void ShowDiscoveryState(DiscoveryState state) override; - void AddDevice(const std::string& device_id, - const base::string16& device_name) override; + void AddOrUpdateDevice(const std::string& device_id, + bool should_update_name, + const base::string16& device_name, + bool is_gatt_connected, + bool is_paired, + const int8_t* rssi) override; void RemoveDevice(const std::string& device_id) override; private:
diff --git a/chrome/browser/ui/bluetooth/chrome_extension_bluetooth_chooser.cc b/chrome/browser/ui/bluetooth/chrome_extension_bluetooth_chooser.cc index f7edd9b8..36ee5f14 100644 --- a/chrome/browser/ui/bluetooth/chrome_extension_bluetooth_chooser.cc +++ b/chrome/browser/ui/bluetooth/chrome_extension_bluetooth_chooser.cc
@@ -33,10 +33,16 @@ bluetooth_chooser_controller_->OnDiscoveryStateChanged(state); } -void ChromeExtensionBluetoothChooser::AddDevice( +void ChromeExtensionBluetoothChooser::AddOrUpdateDevice( const std::string& device_id, - const base::string16& device_name) { - bluetooth_chooser_controller_->AddDevice(device_id, device_name); + bool should_update_name, + const base::string16& device_name, + bool is_gatt_connected, + bool is_paired, + const int8_t* rssi) { + bluetooth_chooser_controller_->AddOrUpdateDevice( + device_id, should_update_name, device_name, is_gatt_connected, is_paired, + rssi); } void ChromeExtensionBluetoothChooser::RemoveDevice(
diff --git a/chrome/browser/ui/bluetooth/chrome_extension_bluetooth_chooser.h b/chrome/browser/ui/bluetooth/chrome_extension_bluetooth_chooser.h index 6e4d1a5..5f9123a 100644 --- a/chrome/browser/ui/bluetooth/chrome_extension_bluetooth_chooser.h +++ b/chrome/browser/ui/bluetooth/chrome_extension_bluetooth_chooser.h
@@ -29,8 +29,12 @@ // content::BluetoothChooser: void SetAdapterPresence(AdapterPresence presence) override; void ShowDiscoveryState(DiscoveryState state) override; - void AddDevice(const std::string& device_id, - const base::string16& device_name) override; + void AddOrUpdateDevice(const std::string& device_id, + bool should_update_name, + const base::string16& device_name, + bool is_gatt_connected, + bool is_paired, + const int8_t* rssi) override; void RemoveDevice(const std::string& device_id) override; private:
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc index b8ac90b..4a25e9dd 100644 --- a/chrome/browser/ui/browser.cc +++ b/chrome/browser/ui/browser.cc
@@ -36,7 +36,6 @@ #include "chrome/browser/background/background_contents_service.h" #include "chrome/browser/background/background_contents_service_factory.h" #include "chrome/browser/banners/app_banner_manager_desktop.h" -#include "chrome/browser/banners/app_banner_manager_emulation.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_shutdown.h" #include "chrome/browser/character_encoding.h" @@ -1349,9 +1348,9 @@ } void Browser::RequestAppBannerFromDevTools(content::WebContents* web_contents) { - banners::AppBannerManagerEmulation::CreateForWebContents(web_contents); - banners::AppBannerManagerEmulation* manager = - banners::AppBannerManagerEmulation::FromWebContents(web_contents); + banners::AppBannerManagerDesktop::CreateForWebContents(web_contents); + banners::AppBannerManagerDesktop* manager = + banners::AppBannerManagerDesktop::FromWebContents(web_contents); manager->RequestAppBanner(web_contents->GetLastCommittedURL(), true); }
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm index 907fb1e5..86a384a 100644 --- a/chrome/browser/ui/cocoa/browser_window_controller.mm +++ b/chrome/browser/ui/cocoa/browser_window_controller.mm
@@ -1713,6 +1713,8 @@ statusBubble_->UpdateSizeAndPosition(); } + [self updatePermissionBubbleAnchor]; + // The FindBar needs to know its own position to properly detect overlaps // with find results. The position changes whenever the window is resized, // and |layoutSubviews| computes the FindBar's position.
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_private.h b/chrome/browser/ui/cocoa/browser_window_controller_private.h index d754669..2bd50d4a 100644 --- a/chrome/browser/ui/cocoa/browser_window_controller_private.h +++ b/chrome/browser/ui/cocoa/browser_window_controller_private.h
@@ -78,6 +78,9 @@ // hidden while a permissions bubble is visible.) - (void)permissionBubbleWindowWillClose:(NSNotification*)notification; +// Updates the anchor position of the permission bubble. +- (void)updatePermissionBubbleAnchor; + // Enter or exit fullscreen without using Cocoa's System Fullscreen API. These // methods are internal implementations of |-setFullscreen:|. - (void)enterImmersiveFullscreen;
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_private.mm b/chrome/browser/ui/cocoa/browser_window_controller_private.mm index 2250576..1eb48d44 100644 --- a/chrome/browser/ui/cocoa/browser_window_controller_private.mm +++ b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
@@ -269,9 +269,7 @@ // Will update the location of the permission bubble when showing/hiding the // top level toolbar in fullscreen. - PermissionRequestManager* manager = [self permissionRequestManager]; - if (manager) - manager->UpdateAnchorPosition(); + [self updatePermissionBubbleAnchor]; browser_->GetBubbleManager()->UpdateAllBubbleAnchors(); } @@ -421,10 +419,7 @@ if (statusBubble_) statusBubble_->SwitchParentWindow(destWindow); - // Updates the bubble position. - PermissionRequestManager* manager = [self permissionRequestManager]; - if (manager) - manager->UpdateAnchorPosition(); + [self updatePermissionBubbleAnchor]; // Move the title over. [destWindow setTitle:[sourceWindow title]]; @@ -462,6 +457,12 @@ delay:YES]; } +- (void)updatePermissionBubbleAnchor { + PermissionRequestManager* manager = [self permissionRequestManager]; + if (manager) + manager->UpdateAnchorPosition(); +} + - (void)configureFullscreenToolbarController { BOOL fullscreenForTab = [self isFullscreenForTabContentOrExtension]; BOOL kioskMode =
diff --git a/chrome/browser/ui/cocoa/history_menu_bridge.mm b/chrome/browser/ui/cocoa/history_menu_bridge.mm index 82ac385..2de3d122 100644 --- a/chrome/browser/ui/cocoa/history_menu_bridge.mm +++ b/chrome/browser/ui/cocoa/history_menu_bridge.mm
@@ -137,16 +137,15 @@ NSInteger index = [menu indexOfItemWithTag:kRecentlyClosedTitle] + 1; NSUInteger added_count = 0; - for (sessions::TabRestoreService::Entries::const_iterator it = - entries.begin(); - it != entries.end() && added_count < kRecentlyClosedCount; ++it) { - sessions::TabRestoreService::Entry* entry = *it; - + for (const auto& entry : entries) { + if (added_count >= kRecentlyClosedCount) + break; // If this is a window, create a submenu for all of its tabs. if (entry->type == sessions::TabRestoreService::WINDOW) { - sessions::TabRestoreService::Window* entry_win = - (sessions::TabRestoreService::Window*)entry; - std::vector<sessions::TabRestoreService::Tab>& tabs = entry_win->tabs; + const auto* entry_win = + static_cast<sessions::TabRestoreService::Window*>(entry.get()); + const std::vector<std::unique_ptr<sessions::TabRestoreService::Tab>>& + tabs = entry_win->tabs; if (tabs.empty()) continue; @@ -178,9 +177,8 @@ // Loop over the window's tabs and add them to the submenu. NSInteger subindex = [[submenu itemArray] count]; - std::vector<sessions::TabRestoreService::Tab>::const_iterator it; - for (it = tabs.begin(); it != tabs.end(); ++it) { - HistoryItem* tab_item = HistoryItemForTab(*it); + for (const auto& tab : tabs) { + HistoryItem* tab_item = HistoryItemForTab(*tab); if (tab_item) { item->tabs.push_back(tab_item); AddItemToMenu(tab_item, submenu.get(), kRecentlyClosed + 1, @@ -203,9 +201,8 @@ ++added_count; } } else if (entry->type == sessions::TabRestoreService::TAB) { - sessions::TabRestoreService::Tab* tab = - static_cast<sessions::TabRestoreService::Tab*>(entry); - HistoryItem* item = HistoryItemForTab(*tab); + const auto& tab = static_cast<sessions::TabRestoreService::Tab&>(*entry); + HistoryItem* item = HistoryItemForTab(tab); if (item) { AddItemToMenu(item, menu, kRecentlyClosed, index++); ++added_count;
diff --git a/chrome/browser/ui/cocoa/history_menu_bridge_unittest.mm b/chrome/browser/ui/cocoa/history_menu_bridge_unittest.mm index ec800d6..634d233 100644 --- a/chrome/browser/ui/cocoa/history_menu_bridge_unittest.mm +++ b/chrome/browser/ui/cocoa/history_menu_bridge_unittest.mm
@@ -98,14 +98,10 @@ } MockTRS::Entries CreateSessionEntries( - std::vector<std::unique_ptr<MockTRS::Entry>>* out, std::initializer_list<MockTRS::Entry*> entries) { MockTRS::Entries ret; - out->reserve(out->size() + entries.size()); - for (auto* entry : entries) { + for (auto* entry : entries) ret.emplace_back(entry); - out->emplace_back(entry); - } return ret; } @@ -127,10 +123,8 @@ auto window = new MockTRS::Window; window->id = id; window->tabs.reserve(tabs.size()); - for (auto* tab : tabs) { - window->tabs.emplace_back(std::move(*tab)); - delete tab; - } + for (auto* tab : tabs) + window->tabs.emplace_back(std::move(tab)); return window; } @@ -241,8 +235,7 @@ // Test that the menu is created for a set of simple tabs. TEST_F(HistoryMenuBridgeTest, RecentlyClosedTabs) { std::unique_ptr<MockTRS> trs(new MockTRS(profile())); - std::vector<std::unique_ptr<MockTRS::Entry>> hold_entries; - auto entries{CreateSessionEntries(&hold_entries, { + auto entries{CreateSessionEntries({ CreateSessionTab(24, "http://google.com", "Google"), CreateSessionTab(42, "http://apple.com", "Apple"), })}; @@ -271,8 +264,7 @@ // Test that the menu is created for a mix of windows and tabs. TEST_F(HistoryMenuBridgeTest, RecentlyClosedTabsAndWindows) { std::unique_ptr<MockTRS> trs(new MockTRS(profile())); - std::vector<std::unique_ptr<MockTRS::Entry>> hold_entries; - auto entries{CreateSessionEntries(&hold_entries, { + auto entries{CreateSessionEntries({ CreateSessionTab(24, "http://google.com", "Google"), CreateSessionWindow(30, { CreateSessionTab(31, "http://foo.com", "foo"),
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h index ebad2c8..6d98c21 100644 --- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h +++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h
@@ -40,7 +40,7 @@ AutocompleteMatch::Type matchType_; - int max_lines_; + int maxLines_; } @property(readonly, retain, nonatomic) NSAttributedString* contents; @@ -53,7 +53,7 @@ @property(readonly, nonatomic) BOOL isContentsRTL; @property(readonly, nonatomic) bool isAnswer; @property(readonly, nonatomic) AutocompleteMatch::Type matchType; -@property(readonly, nonatomic) int max_lines; +@property(readonly, nonatomic) int maxLines; - (instancetype)initWithMatch:(const AutocompleteMatch&)match contentsOffset:(CGFloat)contentsOffset
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm index 5098dc0..4d7bbcc 100644 --- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm +++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm
@@ -420,7 +420,7 @@ @synthesize isContentsRTL = isContentsRTL_; @synthesize isAnswer = isAnswer_; @synthesize matchType = matchType_; -@synthesize max_lines = max_lines_; +@synthesize maxLines = maxLines_; - (instancetype)initWithMatch:(const AutocompleteMatch&)match contentsOffset:(CGFloat)contentsOffset @@ -453,7 +453,7 @@ [CreateAnswerLine(match.answer->first_line(), isDarkTheme) retain]; description_ = [CreateAnswerLine(match.answer->second_line(), isDarkTheme) retain]; - max_lines_ = match.answer->second_line().num_text_lines(); + maxLines_ = match.answer->second_line().num_text_lines(); } else { contents_ = [CreateClassifiedAttributedString( match.contents, ContentTextColor(isDarkTheme), match.contents_class, @@ -463,7 +463,7 @@ match.description, DimTextColor(isDarkTheme), match.description_class, isDarkTheme) retain]; } - max_lines_ = 1; + maxLines_ = 1; } } return self;
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm index d0bc566..dd21664 100644 --- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm +++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm
@@ -33,7 +33,7 @@ answerImage:(NSImage*)answerImage { base::scoped_nsobject<NSMutableArray> array([[NSMutableArray alloc] init]); BOOL isDarkTheme = [tableView hasDarkTheme]; - CGFloat max_match_contents_width = 0.0f; + CGFloat maxMatchContentsWidth = 0.0f; CGFloat contentsOffset = -1.0f; for (const AutocompleteMatch& match : result) { if (match.type == AutocompleteMatchType::SEARCH_SUGGEST_TAIL && @@ -50,12 +50,12 @@ [cellData setIncognitoImage:popupView.ImageForMatch(match)]; [array addObject:cellData]; if (match.type == AutocompleteMatchType::SEARCH_SUGGEST_TAIL) { - max_match_contents_width = - std::max(max_match_contents_width, [cellData getMatchContentsWidth]); + maxMatchContentsWidth = + std::max(maxMatchContentsWidth, [cellData getMatchContentsWidth]); } } - [tableView setMaxMatchContentsWidth:max_match_contents_width]; + [tableView setMaxMatchContentsWidth:maxMatchContentsWidth]; return [self initWithArray:array]; } @@ -120,7 +120,7 @@ NSAttributedString* text = [cellData description]; // Provide no more than 3 lines of space. rowRect.size.height = - std::min(3, [cellData max_lines]) * [text size].height; + std::min(3, [cellData maxLines]) * [text size].height; NSRect textRect = [text boundingRectWithSize:rowRect.size options:NSStringDrawingUsesLineFragmentOrigin |
diff --git a/chrome/browser/ui/cocoa/translate/translate_bubble_controller.h b/chrome/browser/ui/cocoa/translate/translate_bubble_controller.h index ee2ae19..0aeb9631 100644 --- a/chrome/browser/ui/cocoa/translate/translate_bubble_controller.h +++ b/chrome/browser/ui/cocoa/translate/translate_bubble_controller.h
@@ -44,6 +44,9 @@ // This is nil when the current WebContents is in an incognito window. NSButton* alwaysTranslateCheckbox_; + // The 'Try again' button on the error panel. + NSButton* tryAgainButton_; + // The combobox model which is used to deny translation at the view before // translate. std::unique_ptr<TranslateDenialComboboxModel> translateDenialComboboxModel_;
diff --git a/chrome/browser/ui/cocoa/translate/translate_bubble_controller.mm b/chrome/browser/ui/cocoa/translate/translate_bubble_controller.mm index 1a751bb0..cc2b6d2 100644 --- a/chrome/browser/ui/cocoa/translate/translate_bubble_controller.mm +++ b/chrome/browser/ui/cocoa/translate/translate_bubble_controller.mm
@@ -105,6 +105,7 @@ - (void)handleDoneButtonPressed; - (void)handleCancelButtonPressed; - (void)handleShowOriginalButtonPressed; +- (void)handleTryAgainButtonPressed; - (void)handleAdvancedLinkButtonPressed; - (void)handleLanguageSettingsLinkButtonPressed; - (void)handleDenialPopUpButtonNopeSelected; @@ -198,7 +199,8 @@ } - (void)switchToErrorView:(translate::TranslateErrors::Type)errorType { - // FIXME: Implement this. + [self switchView:TranslateBubbleModel::VIEW_STATE_ERROR]; + model_->ShowError(errorType); } - (void)performLayout { @@ -387,7 +389,35 @@ 0); NSView* view = [[NSView alloc] initWithFrame:contentFrame]; - // TODO(hajimehoshi): Implement this. + NSString* message = + l10n_util::GetNSString(IDS_TRANSLATE_BUBBLE_COULD_NOT_TRANSLATE); + NSTextField* textLabel = [self addText:message toView:view]; + message = l10n_util::GetNSStringWithFixup(IDS_TRANSLATE_BUBBLE_ADVANCED); + NSButton* advancedLinkButton = + [self addLinkButtonWithText:message + action:@selector(handleAdvancedLinkButtonPressed) + toView:view]; + NSString* title = + l10n_util::GetNSString(IDS_TRANSLATE_BUBBLE_TRY_AGAIN); + tryAgainButton_ = [self addButton:title + action:@selector(handleTryAgainButtonPressed) + toView:view]; + + // Layout + CGFloat yPos = 0; + + [tryAgainButton_ + setFrameOrigin:NSMakePoint( + kContentWidth - NSWidth([tryAgainButton_ frame]), + yPos)]; + + yPos += NSHeight([tryAgainButton_ frame]) + kUnrelatedControlVerticalSpacing; + + [textLabel setFrameOrigin:NSMakePoint(0, yPos)]; + [advancedLinkButton + setFrameOrigin:NSMakePoint(NSMaxX([textLabel frame]), yPos)]; + + [view setFrameSize:NSMakeSize(kContentWidth, NSMaxY([textLabel frame]))]; return view; } @@ -664,6 +694,11 @@ [self close]; } +- (void)handleTryAgainButtonPressed { + model_->Translate(); + translate::ReportUiAction(translate::TRY_AGAIN_BUTTON_CLICKED); +} + - (void)handleAdvancedLinkButtonPressed { translate::ReportUiAction(translate::ADVANCED_LINK_CLICKED); [self switchView:TranslateBubbleModel::VIEW_STATE_ADVANCED];
diff --git a/chrome/browser/ui/cocoa/translate/translate_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/translate/translate_bubble_controller_unittest.mm index f72588b..4feceb8 100644 --- a/chrome/browser/ui/cocoa/translate/translate_bubble_controller_unittest.mm +++ b/chrome/browser/ui/cocoa/translate/translate_bubble_controller_unittest.mm
@@ -12,6 +12,7 @@ #import "chrome/browser/ui/cocoa/cocoa_profile_test.h" #import "chrome/browser/ui/cocoa/info_bubble_window.h" #include "chrome/browser/ui/cocoa/run_loop_testing.h" +#include "chrome/browser/ui/translate/translate_bubble_model.h" #include "chrome/common/url_constants.h" #include "content/public/browser/site_instance.h" @@ -23,6 +24,18 @@ @end +@implementation TranslateBubbleController (ForTesting) + +- (NSView*)errorView { + NSNumber* key = @(TranslateBubbleModel::VIEW_STATE_ERROR); + return [views_ objectForKey:key]; +} +- (NSButton*)tryAgainButton { + return tryAgainButton_; +} + +@end + class TranslateBubbleControllerTest : public CocoaProfileTest { public: void SetUp() override { @@ -44,6 +57,7 @@ } BrowserWindowController* bwc() { return bwc_; } + TranslateBubbleController* bubble() { return [bwc() translateBubbleController]; } @@ -61,6 +75,14 @@ [window setAllowedAnimations:info_bubble::kAnimateNone]; } + void SwitchToErrorView() { + translate::TranslateStep step = translate::TRANSLATE_STEP_TRANSLATE_ERROR; + [bwc_ + showTranslateBubbleForWebContents:web_contents_ + step:step + errorType:translate::TranslateErrors::NETWORK]; + } + void CloseBubble() { [bubble() close]; chrome::testing::NSRunLoopRunAllPending(); @@ -82,6 +104,30 @@ EXPECT_FALSE(bubble()); } +TEST_F(TranslateBubbleControllerTest, SwitchToErrorView) { + EXPECT_FALSE(bubble()); + ShowBubble(); + const TranslateBubbleModel* model = [bubble() model]; + + EXPECT_TRUE(bubble()); + EXPECT_EQ(TranslateBubbleModel::ViewState::VIEW_STATE_BEFORE_TRANSLATE, + model->GetViewState()); + + SwitchToErrorView(); + + NSView* errorView = [bubble() errorView]; + // We should have 3 subview inside the error view: + // A NSTextField and two NSButton. + EXPECT_EQ(3UL, [[errorView subviews] count]); + + // one of the subview should be "Try again" button. + EXPECT_TRUE([[errorView subviews] containsObject:[bubble() tryAgainButton]]); + EXPECT_EQ(TranslateBubbleModel::ViewState::VIEW_STATE_ERROR, + model->GetViewState()); + EXPECT_TRUE(bubble()); + CloseBubble(); +} + TEST_F(TranslateBubbleControllerTest, CloseRegistersDecline) { const char kDeclineTranslateDismissUI[] = "Translate.DeclineTranslateDismissUI";
diff --git a/chrome/browser/ui/cocoa/website_settings/permission_bubble_controller.mm b/chrome/browser/ui/cocoa/website_settings/permission_bubble_controller.mm index d9908715..3746bf4 100644 --- a/chrome/browser/ui/cocoa/website_settings/permission_bubble_controller.mm +++ b/chrome/browser/ui/cocoa/website_settings/permission_bubble_controller.mm
@@ -300,8 +300,9 @@ } - (void)parentWindowDidResize:(NSNotification*)notification { - DCHECK(bridge_); - [self updateAnchorPosition]; + // Override the base class implementation, which sets the anchor point. But + // it's not necessary since BrowserWindowController will notify the + // PermissionRequestManager to update the anchor position on a resize. } - (void)parentWindowDidMove:(NSNotification*)notification {
diff --git a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc index 1b76e6c8..d141885 100644 --- a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc +++ b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
@@ -36,6 +36,7 @@ #include "components/content_settings/core/common/content_settings.h" #include "components/prefs/pref_service.h" #include "components/rappor/rappor_utils.h" +#include "components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h" #include "components/url_formatter/elide_url.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/render_frame_host.h" @@ -995,6 +996,7 @@ } void ContentSettingMixedScriptBubbleModel::OnCustomLinkClicked() { + DCHECK(rappor_service()); if (!web_contents()) return; @@ -1007,8 +1009,7 @@ content_settings::MIXED_SCRIPT_ACTION_CLICKED_ALLOW); rappor::SampleDomainAndRegistryFromGURL( - g_browser_process->rappor_service(), - "ContentSettings.MixedScript.UserClickedAllow", + rappor_service(), "ContentSettings.MixedScript.UserClickedAllow", web_contents()->GetLastCommittedURL()); } @@ -1190,8 +1191,10 @@ } void ContentSettingSubresourceFilterBubbleModel::OnManageLinkClicked() { - // TODO(melandory): Notify ContentSubresourceFilterDriverFactory page reload - // was requested. + subresource_filter::ContentSubresourceFilterDriverFactory* driver_factory = + subresource_filter::ContentSubresourceFilterDriverFactory:: + FromWebContents(web_contents()); + driver_factory->OnReloadRequested(); } ContentSettingSubresourceFilterBubbleModel* @@ -1333,14 +1336,14 @@ return nullptr; } -ContentSettingBubbleModel::ContentSettingBubbleModel( - Delegate* delegate, - WebContents* web_contents, - Profile* profile) +ContentSettingBubbleModel::ContentSettingBubbleModel(Delegate* delegate, + WebContents* web_contents, + Profile* profile) : web_contents_(web_contents), profile_(profile), delegate_(delegate), - setting_is_managed_(false) { + setting_is_managed_(false), + rappor_service_(g_browser_process->rappor_service()) { registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, content::Source<WebContents>(web_contents)); registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
diff --git a/chrome/browser/ui/content_settings/content_setting_bubble_model.h b/chrome/browser/ui/content_settings/content_setting_bubble_model.h index 897ac77b..1105d57 100644 --- a/chrome/browser/ui/content_settings/content_setting_bubble_model.h +++ b/chrome/browser/ui/content_settings/content_setting_bubble_model.h
@@ -32,6 +32,10 @@ class WebContents; } +namespace rappor { +class RapporService; +} + // The hierarchy of bubble models: // // ContentSettingsBubbleModel - base class @@ -169,6 +173,11 @@ virtual ContentSettingSubresourceFilterBubbleModel* AsSubresourceFilterBubbleModel(); + // Sets the Rappor service used for testing. + void SetRapporServiceForTesting(rappor::RapporService* rappor_service) { + rappor_service_ = rappor_service; + } + protected: ContentSettingBubbleModel( Delegate* delegate, @@ -216,6 +225,7 @@ void set_setting_is_managed(bool managed) { setting_is_managed_ = managed; } + rappor::RapporService* rappor_service() const { return rappor_service_; } private: virtual void SetTitle() = 0; @@ -230,6 +240,8 @@ // A flag that indicates if the content setting managed i.e. can't be // controlled by the user. bool setting_is_managed_; + // The service used to record Rappor metrics. Can be set for testing. + rappor::RapporService* rappor_service_; DISALLOW_COPY_AND_ASSIGN(ContentSettingBubbleModel); };
diff --git a/chrome/browser/ui/content_settings/content_setting_bubble_model_browsertest.cc b/chrome/browser/ui/content_settings/content_setting_bubble_model_browsertest.cc index aa96772b..3669217 100644 --- a/chrome/browser/ui/content_settings/content_setting_bubble_model_browsertest.cc +++ b/chrome/browser/ui/content_settings/content_setting_bubble_model_browsertest.cc
@@ -4,8 +4,11 @@ #include <vector> +#include "base/command_line.h" #include "base/files/file_path.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/histogram_tester.h" +#include "chrome/browser/content_settings/chrome_content_settings_utils.h" #include "chrome/browser/content_settings/tab_specific_content_settings.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_content_setting_bubble_model_delegate.h" @@ -15,8 +18,12 @@ #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" #include "components/content_settings/core/common/content_settings_types.h" +#include "components/rappor/test_rappor_service.h" +#include "content/public/common/content_switches.h" #include "content/public/test/test_navigation_observer.h" +#include "net/dns/mock_host_resolver.h" #include "net/test/embedded_test_server/embedded_test_server.h" +#include "net/test/embedded_test_server/request_handler_util.h" #include "testing/gtest/include/gtest/gtest.h" const base::FilePath::CharType kDocRoot[] = @@ -69,6 +76,75 @@ CONTENT_SETTINGS_TYPE_MIXEDSCRIPT)); } +class ContentSettingsMixedScriptIgnoreCertErrorsTest + : public ContentSettingBubbleModelMixedScriptTest { + protected: + void SetUpCommandLine(base::CommandLine* command_line) override { + command_line->AppendSwitch(switches::kIgnoreCertificateErrors); + } +}; + +// Tests that a MIXEDSCRIPT type ContentSettingBubbleModel records UMA +// and Rappor metrics when the content is allowed to run. +// +// This test fixture sets up the browser to ignore certificate errors, +// so that a non-matching, non-local hostname can be used for the +// test. This is because Rappor treats local hostnames as slightly +// special, so it's a little nicer to test with a non-local hostname. +IN_PROC_BROWSER_TEST_F(ContentSettingsMixedScriptIgnoreCertErrorsTest, + MainFrameMetrics) { + GURL url(https_server_->GetURL("/content_setting_bubble/mixed_script.html")); + + // Rappor treats local hostnames a little bit special (e.g. records + // "127.0.0.1" as "localhost"), so use a non-local hostname for + // convenience. + host_resolver()->AddRule("*", "127.0.0.1"); + GURL::Replacements replace_host; + replace_host.SetHostStr("example.test"); + url = url.ReplaceComponents(replace_host); + + rappor::TestRapporService rappor_service; + EXPECT_EQ(0, rappor_service.GetReportsCount()); + base::HistogramTester histograms; + histograms.ExpectTotalCount("ContentSettings.MixedScript", 0); + + // Load a page with mixed content and do quick verification by looking at + // the title string. + ui_test_utils::NavigateToURL(browser(), url); + + EXPECT_TRUE(GetActiveTabSpecificContentSettings()->IsContentBlocked( + CONTENT_SETTINGS_TYPE_MIXEDSCRIPT)); + + // Emulate link clicking on the mixed script bubble. + std::unique_ptr<ContentSettingBubbleModel> model( + ContentSettingBubbleModel::CreateContentSettingBubbleModel( + browser()->content_setting_bubble_model_delegate(), + browser()->tab_strip_model()->GetActiveWebContents(), + browser()->profile(), CONTENT_SETTINGS_TYPE_MIXEDSCRIPT)); + model->SetRapporServiceForTesting(&rappor_service); + model->OnCustomLinkClicked(); + + // Wait for reload + content::TestNavigationObserver observer( + browser()->tab_strip_model()->GetActiveWebContents()); + observer.Wait(); + + EXPECT_FALSE(GetActiveTabSpecificContentSettings()->IsContentBlocked( + CONTENT_SETTINGS_TYPE_MIXEDSCRIPT)); + + // Check that the UMA and Rappor counts are as expected. + histograms.ExpectBucketCount( + "ContentSettings.MixedScript", + content_settings::MIXED_SCRIPT_ACTION_CLICKED_ALLOW, 1); + EXPECT_EQ(1, rappor_service.GetReportsCount()); + std::string sample; + rappor::RapporType type; + EXPECT_TRUE(rappor_service.GetRecordedSampleForMetric( + "ContentSettings.MixedScript.UserClickedAllow", &sample, &type)); + EXPECT_EQ(url.host(), sample); + EXPECT_EQ(rappor::ETLD_PLUS_ONE_RAPPOR_TYPE, type); +} + // Tests that a MIXEDSCRIPT type ContentSettingBubbleModel does not work // for an iframe (mixed script in iframes is never allowed and the mixed // content shield isn't shown for it).
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc index 3aad1e61..6c5c6dd 100644 --- a/chrome/browser/ui/tab_helpers.cc +++ b/chrome/browser/ui/tab_helpers.cc
@@ -27,6 +27,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/sessions/session_tab_helper.h" #include "chrome/browser/ssl/chrome_security_state_model_client.h" +#include "chrome/browser/subresource_filter/chrome_subresource_filter_client.h" #include "chrome/browser/tab_contents/navigation_metrics_recorder.h" #include "chrome/browser/tracing/navigation_tracing.h" #include "chrome/browser/translate/chrome_translate_client.h" @@ -177,8 +178,10 @@ ChromeSecurityStateModelClient::CreateForWebContents(web_contents); if (SiteEngagementService::IsEnabled()) SiteEngagementService::Helper::CreateForWebContents(web_contents); + std::unique_ptr<ChromeSubresourceFilterClient> subresource_filter_client( + new ChromeSubresourceFilterClient(web_contents)); subresource_filter::ContentSubresourceFilterDriverFactory:: - CreateForWebContents(web_contents); + CreateForWebContents(web_contents, std::move(subresource_filter_client)); // TODO(vabr): Remove TabSpecificContentSettings from here once their function // is taken over by ChromeContentSettingsClient. http://crbug.com/387075 TabSpecificContentSettings::CreateForWebContents(web_contents);
diff --git a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc index c8e5fd2..90b6687 100644 --- a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc +++ b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc
@@ -440,27 +440,28 @@ #endif int added_count = 0; - sessions::TabRestoreService::Entries entries = service->entries(); - for (sessions::TabRestoreService::Entries::const_iterator it = - entries.begin(); - it != entries.end() && added_count < kMaxLocalEntries; ++it) { - sessions::TabRestoreService::Entry* entry = *it; - if (entry->type == sessions::TabRestoreService::TAB) { - sessions::TabRestoreService::Tab* tab = - static_cast<sessions::TabRestoreService::Tab*>(entry); - const sessions::SerializedNavigationEntry& current_navigation = - tab->navigations.at(tab->current_navigation_index); - BuildLocalTabItem( - entry->id, - current_navigation.title(), - current_navigation.virtual_url(), - ++last_local_model_index_); - } else { - DCHECK_EQ(entry->type, sessions::TabRestoreService::WINDOW); - BuildLocalWindowItem( - entry->id, static_cast<sessions::TabRestoreService::Window*>(entry) - ->tabs.size(), - ++last_local_model_index_); + for (const auto& entry : service->entries()) { + if (added_count == kMaxLocalEntries) + break; + switch (entry->type) { + case sessions::TabRestoreService::TAB: { + auto& tab = + static_cast<const sessions::TabRestoreService::Tab&>(*entry); + const sessions::SerializedNavigationEntry& current_navigation = + tab.navigations.at(tab.current_navigation_index); + BuildLocalTabItem(entry->id, current_navigation.title(), + current_navigation.virtual_url(), + ++last_local_model_index_); + break; + } + case sessions::TabRestoreService::WINDOW: { + BuildLocalWindowItem( + entry->id, + static_cast<const sessions::TabRestoreService::Window&>(*entry) + .tabs.size(), + ++last_local_model_index_); + break; + } } ++added_count; }
diff --git a/chrome/browser/ui/views/autofill/card_unmask_prompt_views.cc b/chrome/browser/ui/views/autofill/card_unmask_prompt_views.cc index de2ec39d..737e366 100644 --- a/chrome/browser/ui/views/autofill/card_unmask_prompt_views.cc +++ b/chrome/browser/ui/views/autofill/card_unmask_prompt_views.cc
@@ -507,7 +507,7 @@ void CardUnmaskPromptViews::FadeOutView::PaintChildren( const ui::PaintContext& context) { const bool kLcdTextRequiresOpaqueLayer = true; - ui::CompositingRecorder recorder(context, size(), alpha_, + ui::CompositingRecorder recorder(context, alpha_, kLcdTextRequiresOpaqueLayer); views::View::PaintChildren(context); }
diff --git a/chrome/browser/ui/views/frame/global_menu_bar_x11.cc b/chrome/browser/ui/views/frame/global_menu_bar_x11.cc index 6b9f3be..51eb417 100644 --- a/chrome/browser/ui/views/frame/global_menu_bar_x11.cc +++ b/chrome/browser/ui/views/frame/global_menu_bar_x11.cc
@@ -751,12 +751,12 @@ for (sessions::TabRestoreService::Entries::const_iterator it = entries.begin(); it != entries.end() && added_count < kRecentlyClosedCount; ++it) { - sessions::TabRestoreService::Entry* entry = *it; + sessions::TabRestoreService::Entry* entry = it->get(); if (entry->type == sessions::TabRestoreService::WINDOW) { sessions::TabRestoreService::Window* entry_win = static_cast<sessions::TabRestoreService::Window*>(entry); - std::vector<sessions::TabRestoreService::Tab>& tabs = entry_win->tabs; + auto& tabs = entry_win->tabs; if (tabs.empty()) continue; @@ -792,10 +792,8 @@ // Loop over the window's tabs and add them to the submenu. int subindex = 2; - std::vector<sessions::TabRestoreService::Tab>::const_iterator iter; - for (iter = tabs.begin(); iter != tabs.end(); ++iter) { - sessions::TabRestoreService::Tab tab = *iter; - HistoryItem* tab_item = HistoryItemForTab(tab); + for (const auto& tab : tabs) { + HistoryItem* tab_item = HistoryItemForTab(*tab); item->tabs.push_back(tab_item); AddHistoryItemToMenu(tab_item, parent_item,
diff --git a/chrome/browser/ui/views/media_router/media_router_ui_browsertest.cc b/chrome/browser/ui/views/media_router/media_router_ui_browsertest.cc index 22d59aa..217be79c 100644 --- a/chrome/browser/ui/views/media_router/media_router_ui_browsertest.cc +++ b/chrome/browser/ui/views/media_router/media_router_ui_browsertest.cc
@@ -80,8 +80,8 @@ base::Unretained(this), app_menu_button)); app_menu_button->ShowMenu(false); - EXPECT_FALSE(app_menu_button->IsMenuShowing()); nav_observer.Wait(); + EXPECT_FALSE(app_menu_button->IsMenuShowing()); ASSERT_EQ(chrome::kChromeUIMediaRouterURL, nav_observer.last_navigation_url().spec()); nav_observer.StopWatchingNewWebContents();
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc index 0d3ffbbc..4b854bcf 100644 --- a/chrome/browser/ui/views/tabs/tab.cc +++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -116,6 +116,32 @@ const char kTabCloseButtonName[] = "TabCloseButton"; +// Parameters for PaintTabBackgroundUsingParams(). +struct PaintBackgroundParams { + PaintBackgroundParams(bool is_active, + gfx::ImageSkia* fill_image_ptr, + bool has_custom_image, + gfx::Rect rect, + SkColor stroke_color, + SkColor toolbar_color, + SkColor background_tab_color) + : is_active(is_active), + fill_image(fill_image_ptr ? *fill_image_ptr : gfx::ImageSkia()), + has_custom_image(has_custom_image), + rect(rect), + stroke_color(stroke_color), + toolbar_color(toolbar_color), + background_tab_color(background_tab_color) {} + + const bool is_active; + const gfx::ImageSkia fill_image; + const bool has_custom_image; + const gfx::Rect rect; + const SkColor stroke_color; + const SkColor toolbar_color; + const SkColor background_tab_color; +}; + //////////////////////////////////////////////////////////////////////////////// // ImageCacheEntryMetadata // @@ -124,6 +150,7 @@ ImageCacheEntryMetadata(int resource_id, SkColor fill_color, SkColor stroke_color, + bool use_fill_and_stroke_images, ui::ScaleFactor scale_factor, const gfx::Size& size); @@ -134,18 +161,22 @@ int resource_id; // Only needed by pre-MD SkColor fill_color; // Both colors only needed by MD SkColor stroke_color; + bool use_fill_and_stroke_images; ui::ScaleFactor scale_factor; gfx::Size size; }; -ImageCacheEntryMetadata::ImageCacheEntryMetadata(int resource_id, - SkColor fill_color, - SkColor stroke_color, - ui::ScaleFactor scale_factor, - const gfx::Size& size) +ImageCacheEntryMetadata::ImageCacheEntryMetadata( + int resource_id, + SkColor fill_color, + SkColor stroke_color, + bool use_fill_and_stroke_images, + ui::ScaleFactor scale_factor, + const gfx::Size& size) : resource_id(resource_id), fill_color(fill_color), stroke_color(stroke_color), + use_fill_and_stroke_images(use_fill_and_stroke_images), scale_factor(scale_factor), size(size) { DCHECK_NE(ui::SCALE_FACTOR_NONE, scale_factor); @@ -164,8 +195,9 @@ bool ImageCacheEntryMetadata::operator==( const ImageCacheEntryMetadata& rhs) const { return resource_id == rhs.resource_id && fill_color == rhs.fill_color && - stroke_color == rhs.stroke_color && scale_factor == rhs.scale_factor && - size == rhs.size; + stroke_color == rhs.stroke_color && + use_fill_and_stroke_images == rhs.use_fill_and_stroke_images && + scale_factor == rhs.scale_factor && size == rhs.size; } //////////////////////////////////////////////////////////////////////////////// @@ -174,16 +206,19 @@ // A cached image and the metadata used to generate it. struct ImageCacheEntry { ImageCacheEntry(const ImageCacheEntryMetadata& metadata, - const gfx::ImageSkia& image); + const gfx::ImageSkia& fill_image, + const gfx::ImageSkia& stroke_image); ~ImageCacheEntry(); ImageCacheEntryMetadata metadata; - gfx::ImageSkia image; + gfx::ImageSkia fill_image; + gfx::ImageSkia stroke_image; }; ImageCacheEntry::ImageCacheEntry(const ImageCacheEntryMetadata& metadata, - const gfx::ImageSkia& image) - : metadata(metadata), image(image) {} + const gfx::ImageSkia& fill_image, + const gfx::ImageSkia& stroke_image) + : metadata(metadata), fill_image(fill_image), stroke_image(stroke_image) {} ImageCacheEntry::~ImageCacheEntry() {} @@ -410,10 +445,8 @@ } void PaintTabFill(gfx::Canvas* canvas, - gfx::ImageSkia* fill_image, - int x_offset, - int y_offset, - const gfx::Size& size, + const gfx::ImageSkia& fill_image, + gfx::Rect rect, bool is_active) { const gfx::Insets tab_insets(GetLayoutInsets(TAB)); // If this isn't the foreground tab, don't draw over the toolbar, but do @@ -422,7 +455,7 @@ // Draw left edge. gfx::ImageSkia tab_l = gfx::ImageSkiaOperations::CreateTiledImage( - *fill_image, x_offset, y_offset, g_mask_images.l_width, size.height()); + fill_image, rect.x(), rect.y(), g_mask_images.l_width, rect.height()); gfx::ImageSkia theme_l = gfx::ImageSkiaOperations::CreateMaskedImage( tab_l, *g_mask_images.image_l); canvas->DrawImageInt( @@ -431,22 +464,118 @@ // Draw right edge. gfx::ImageSkia tab_r = gfx::ImageSkiaOperations::CreateTiledImage( - *fill_image, x_offset + size.width() - g_mask_images.r_width, y_offset, - g_mask_images.r_width, size.height()); + fill_image, rect.right() - g_mask_images.r_width, rect.y(), + g_mask_images.r_width, rect.height()); gfx::ImageSkia theme_r = gfx::ImageSkiaOperations::CreateMaskedImage( tab_r, *g_mask_images.image_r); canvas->DrawImageInt(theme_r, 0, 0, theme_r.width(), theme_r.height() - toolbar_overlap, - size.width() - theme_r.width(), 0, theme_r.width(), + rect.width() - theme_r.width(), 0, theme_r.width(), theme_r.height() - toolbar_overlap, false); // Draw center. Instead of masking out the top portion we simply skip over it // by incrementing by the top padding, since it's a simple rectangle. - canvas->TileImageInt( - *fill_image, x_offset + g_mask_images.l_width, - y_offset + tab_insets.top(), g_mask_images.l_width, tab_insets.top(), - size.width() - g_mask_images.l_width - g_mask_images.r_width, - size.height() - tab_insets.top() - toolbar_overlap); + rect.Inset(g_mask_images.l_width, tab_insets.top(), g_mask_images.r_width, + toolbar_overlap); + canvas->TileImageInt(fill_image, rect.x(), rect.y(), g_mask_images.l_width, + tab_insets.top(), rect.width(), rect.height()); +} + +void PaintTabBackgroundUsingParams(gfx::Canvas* fill_canvas, + gfx::Canvas* stroke_canvas, + views::GlowHoverController* hc, + const PaintBackgroundParams& params) { + const gfx::Rect& rect = params.rect; + const SkScalar kMinHoverRadius = 16; + const SkScalar radius = + std::max(SkFloatToScalar(rect.width() / 4.f), kMinHoverRadius); + const bool draw_hover = !params.is_active && hc; + SkPoint hover_location( + gfx::PointToSkPoint(draw_hover ? hc->location() : gfx::Point())); + const SkColor hover_color = + SkColorSetA(params.toolbar_color, draw_hover ? hc->GetAlpha() : 255); + + if (ui::MaterialDesignController::IsModeMaterial()) { + gfx::Path fill; + SkPaint paint; + paint.setAntiAlias(true); + + // Draw the fill. + { + gfx::ScopedCanvas scoped_canvas(fill_canvas); + const float scale = fill_canvas->UndoDeviceScaleFactor(); + + fill = GetFillPath(scale, rect.size()); + { + gfx::ScopedCanvas clip_scoper(fill_canvas); + fill_canvas->ClipPath(fill, true); + if (!params.fill_image.isNull()) { + gfx::ScopedCanvas scale_scoper(fill_canvas); + fill_canvas->sk_canvas()->scale(scale, scale); + fill_canvas->TileImageInt(params.fill_image, rect.x(), rect.y(), 0, 0, + rect.width(), rect.height()); + } else { + paint.setColor(params.is_active ? params.toolbar_color + : params.background_tab_color); + fill_canvas->DrawRect( + gfx::ScaleToEnclosingRect(gfx::Rect(rect.size()), scale), + paint); + } + if (draw_hover) { + hover_location.scale(SkFloatToScalar(scale)); + DrawHighlight(fill_canvas, hover_location, radius * scale, + hover_color); + } + } + } + + // Draw the stroke. + { + gfx::ScopedCanvas scoped_canvas(stroke_canvas); + const float scale = stroke_canvas->UndoDeviceScaleFactor(); + + gfx::Path stroke = GetBorderPath(scale, false, false, rect.size()); + Op(stroke, fill, kDifference_SkPathOp, &stroke); + if (!params.is_active) { + // Clip out the bottom line; this will be drawn for us by + // TabStrip::PaintChildren(). + stroke_canvas->ClipRect(gfx::RectF(rect.width() * scale, + rect.height() * scale - 1)); + } + paint.setColor(params.stroke_color); + stroke_canvas->DrawPath(stroke, paint); + } + } else { + gfx::Canvas* canvas = stroke_canvas; + if (draw_hover) { + // Draw everything to a temporary canvas so we can extract an image for + // use in masking the hover glow. + gfx::Canvas background_canvas(rect.size(), canvas->image_scale(), false); + PaintTabFill(&background_canvas, params.fill_image, rect, + params.is_active); + gfx::ImageSkia background_image(background_canvas.ExtractImageRep()); + canvas->DrawImageInt(background_image, 0, 0); + + gfx::Canvas hover_canvas(rect.size(), canvas->image_scale(), false); + DrawHighlight(&hover_canvas, hover_location, radius, hover_color); + gfx::ImageSkia result = gfx::ImageSkiaOperations::CreateMaskedImage( + gfx::ImageSkia(hover_canvas.ExtractImageRep()), background_image); + canvas->DrawImageInt(result, 0, 0); + } else { + PaintTabFill(canvas, params.fill_image, rect, params.is_active); + } + + // Now draw the stroke, highlights, and shadows around the tab edge. + TabImages* stroke_images = + params.is_active ? &g_active_images : &g_inactive_images; + canvas->DrawImageInt(*stroke_images->image_l, 0, 0); + canvas->TileImageInt( + *stroke_images->image_c, stroke_images->l_width, 0, + rect.width() - stroke_images->l_width - stroke_images->r_width, + rect.height()); + canvas->DrawImageInt(*stroke_images->image_r, + rect.width() - stroke_images->r_width, 0); + } } } // namespace @@ -545,35 +674,6 @@ const char* GetClassName() const override { return kTabCloseButtonName; } private: - // Returns the rectangular bounds of parent tab's visible region in the - // local coordinate space of |this|. - gfx::Rect GetTabBounds() const { - gfx::Path tab_mask; - tab_->GetHitTestMask(&tab_mask); - - gfx::RectF tab_bounds_f(gfx::SkRectToRectF(tab_mask.getBounds())); - views::View::ConvertRectToTarget(tab_, this, &tab_bounds_f); - return gfx::ToEnclosingRect(tab_bounds_f); - } - - // Returns the rectangular bounds of the tab close button in the local - // coordinate space of |this|, not including clipped regions on the top - // or bottom of the button. |tab_bounds| is the rectangular bounds of - // the parent tab's visible region in the local coordinate space of |this|. - gfx::Rect GetTabCloseButtonBounds(const gfx::Rect& tab_bounds) const { - gfx::Rect button_bounds(GetContentsBounds()); - button_bounds.set_x(GetMirroredXForRect(button_bounds)); - - int top_overflow = tab_bounds.y() - button_bounds.y(); - int bottom_overflow = button_bounds.bottom() - tab_bounds.bottom(); - if (top_overflow > 0) - button_bounds.set_y(tab_bounds.y()); - else if (bottom_overflow > 0) - button_bounds.set_height(button_bounds.height() - bottom_overflow); - - return button_bounds; - } - // views::MaskedTargeterDelegate: View* TargetForRect(View* root, const gfx::Rect& rect) override { CHECK_EQ(root, this); @@ -592,7 +692,9 @@ // reached, it may be from someone calling GetEventHandlerForPoint() while a // touch happens to be occurring. In such a case, maybe we don't want this // code to run? It's possible this block should be removed, or maybe this - // whole function deleted. + // whole function deleted. Note that in these cases, we should probably + // also remove the padding on the close button bounds (see Tab::Layout()), + // as it will be pointless. if (aura::Env::GetInstance()->is_touch_down()) contents_bounds = GetLocalBounds(); #endif @@ -602,45 +704,10 @@ // We need to define this so hit-testing won't include the border region. bool GetHitTestMask(gfx::Path* mask) const override { - DCHECK(mask); - mask->reset(); - - // The parent tab may be partially occluded by another tab if we are - // in stacked tab mode, which means that the tab close button may also - // be partially occluded. Define the hit test mask of the tab close - // button to be the intersection of the parent tab's visible bounds - // and the bounds of the tab close button. - gfx::Rect tab_bounds(GetTabBounds()); - gfx::Rect button_bounds(GetTabCloseButtonBounds(tab_bounds)); - gfx::Rect intersection(gfx::IntersectRects(tab_bounds, button_bounds)); - - if (!intersection.IsEmpty()) { - mask->addRect(RectToSkRect(intersection)); - return true; - } - - return false; - } - - bool DoesIntersectRect(const View* target, - const gfx::Rect& rect) const override { - CHECK_EQ(target, this); - - // If the request is not made in response to a gesture, use the - // default implementation. - if (views::UsePointBasedTargeting(rect)) - return MaskedTargeterDelegate::DoesIntersectRect(target, rect); - - // The hit test request is in response to a gesture. Return false if any - // part of the tab close button is hidden from the user. - // TODO(tdanderson): Consider always returning the intersection if the - // non-rectangular shape of the tab can be accounted for. - gfx::Rect tab_bounds(GetTabBounds()); - gfx::Rect button_bounds(GetTabCloseButtonBounds(tab_bounds)); - if (!tab_bounds.Contains(button_bounds)) - return false; - - return MaskedTargeterDelegate::DoesIntersectRect(target, rect); + gfx::Rect button_bounds(GetContentsBounds()); + button_bounds.set_x(GetMirroredXForRect(button_bounds)); + mask->addRect(gfx::RectToSkRect(button_bounds)); + return true; } Tab* tab_; @@ -1028,27 +1095,13 @@ // Tab, views::MaskedTargeterDelegate overrides: bool Tab::GetHitTestMask(gfx::Path* mask) const { - const float scale = GetWidget()->GetCompositor()->device_scale_factor(); // When the window is maximized we don't want to shave off the edges or top // shadow of the tab, such that the user can click anywhere along the top // edge of the screen to select a tab. Ditto for immersive fullscreen. const views::Widget* widget = GetWidget(); - const bool extend_to_top = - widget && (widget->IsMaximized() || widget->IsFullscreen()); - *mask = GetBorderPath(scale, true, extend_to_top, size()); - - // It is possible for a portion of the tab to be occluded if tabs are - // stacked, so modify the hit test mask to only include the visible - // region of the tab. - gfx::Rect clip; - controller_->ShouldPaintTab(this, &clip); - if (clip.size().GetArea()) { - SkRect intersection(mask->getBounds()); - mask->reset(); - if (!intersection.intersect(RectToSkRect(clip))) - return false; - mask->addRect(intersection); - } + *mask = GetBorderPath( + GetWidget()->GetCompositor()->device_scale_factor(), true, + widget && (widget->IsMaximized() || widget->IsFullscreen()), size()); return true; } @@ -1069,21 +1122,16 @@ if (width() < GetMinimumInactiveSize().width() && !data().pinned) return; - gfx::Rect clip; - if (!controller_->ShouldPaintTab(this, &clip)) + gfx::Path clip; + if (!controller_->ShouldPaintTab( + this, base::Bind(&GetBorderPath, canvas->image_scale(), true, false), + &clip)) return; - if (!clip.IsEmpty()) { - canvas->Save(); - canvas->ClipRect(clip); - } if (controller_->IsImmersiveStyle()) PaintImmersiveTab(canvas); else - PaintTab(canvas); - - if (!clip.IsEmpty()) - canvas->Restore(); + PaintTab(canvas, clip); } void Tab::Layout() { @@ -1108,10 +1156,12 @@ // The close button should be as large as possible so that there is a larger // hit-target for touch events. So the close button bounds extends to the // edges of the tab. However, the larger hit-target should be active only - // for mouse events, and the close-image should show up in the right place. + // for touch events, and the close-image should show up in the right place. // So a border is added to the button with necessary padding. The close - // button (BaseTab::TabCloseButton) makes sure the padding is a hit-target - // only for touch events. + // button (Tab::TabCloseButton) makes sure the padding is a hit-target only + // for touch events. + // TODO(pkasting): The padding should maybe be removed, see comments in + // TabCloseButton::TargetForRect(). close_button_->SetBorder(views::Border::NullBorder()); const gfx::Size close_button_size(close_button_->GetPreferredSize()); const int top = lb.y() + (lb.height() - close_button_size.height() + 1) / 2; @@ -1370,22 +1420,22 @@ StopPulse(); } -void Tab::PaintTab(gfx::Canvas* canvas) { +void Tab::PaintTab(gfx::Canvas* canvas, const gfx::Path& clip) { const int kActiveTabFillId = IDR_THEME_TOOLBAR; const bool has_custom_image = GetThemeProvider()->HasCustomImage(kActiveTabFillId); const int y_offset = -GetYInsetForActiveTabBackground(); if (IsActive()) { - PaintTabBackgroundUsingFillId(canvas, true, kActiveTabFillId, + PaintTabBackgroundUsingFillId(canvas, canvas, true, kActiveTabFillId, has_custom_image, y_offset); } else { - PaintInactiveTabBackground(canvas); + PaintInactiveTabBackground(canvas, clip); const double throb_value = GetThrobValue(); if (throb_value > 0) { canvas->SaveLayerAlpha(gfx::ToRoundedInt(throb_value * 0xff), GetLocalBounds()); - PaintTabBackgroundUsingFillId(canvas, true, kActiveTabFillId, + PaintTabBackgroundUsingFillId(canvas, canvas, true, kActiveTabFillId, has_custom_image, y_offset); canvas->Restore(); } @@ -1439,7 +1489,8 @@ } } -void Tab::PaintInactiveTabBackground(gfx::Canvas* canvas) { +void Tab::PaintInactiveTabBackground(gfx::Canvas* canvas, + const gfx::Path& clip) { bool has_custom_image; int fill_id = controller_->GetBackgroundResourceId(&has_custom_image); @@ -1455,119 +1506,80 @@ // We only cache the image when it's the default image and we're not hovered, // to avoid caching a background image that isn't the same for all tabs. if (has_custom_image || hover_controller_.ShouldDraw()) { - PaintTabBackgroundUsingFillId(canvas, false, fill_id, has_custom_image, - y_offset); + PaintTabBackgroundUsingFillId(canvas, canvas, false, fill_id, + has_custom_image, y_offset); return; } + // For efficiency, we don't use separate fill and stroke images unless we + // really need to clip the stroke and not the fill (for stacked tabs). This + // saves memory and avoids an extra image draw at the cost of recalculating + // the images when MaySetClip() toggles. + const bool use_fill_and_stroke_images = + controller_->MaySetClip() && + ui::MaterialDesignController::IsModeMaterial(); + const ImageCacheEntryMetadata metadata( fill_id, tp->GetColor(ThemeProperties::COLOR_BACKGROUND_TAB), - controller_->GetToolbarTopSeparatorColor(), + controller_->GetToolbarTopSeparatorColor(), use_fill_and_stroke_images, ui::GetSupportedScaleFactor(canvas->image_scale()), size()); auto it = std::find_if( g_image_cache->begin(), g_image_cache->end(), [&metadata](const ImageCacheEntry& e) { return e.metadata == metadata; }); if (it == g_image_cache->end()) { gfx::Canvas tmp_canvas(size(), canvas->image_scale(), false); - PaintTabBackgroundUsingFillId(&tmp_canvas, false, fill_id, false, y_offset); - g_image_cache->emplace_front(metadata, - gfx::ImageSkia(tmp_canvas.ExtractImageRep())); + if (use_fill_and_stroke_images) { + gfx::Canvas tmp_fill_canvas(size(), canvas->image_scale(), false); + PaintTabBackgroundUsingFillId(&tmp_fill_canvas, &tmp_canvas, false, + fill_id, false, y_offset); + g_image_cache->emplace_front( + metadata, gfx::ImageSkia(tmp_fill_canvas.ExtractImageRep()), + gfx::ImageSkia(tmp_canvas.ExtractImageRep())); + } else { + PaintTabBackgroundUsingFillId(&tmp_canvas, &tmp_canvas, false, fill_id, + false, y_offset); + g_image_cache->emplace_front( + metadata, gfx::ImageSkia(), + gfx::ImageSkia(tmp_canvas.ExtractImageRep())); + } if (g_image_cache->size() > kMaxImageCacheSize) g_image_cache->pop_back(); it = g_image_cache->begin(); } - canvas->DrawImageInt(it->image, 0, 0); + + gfx::ScopedCanvas scoped_canvas( + use_fill_and_stroke_images ? canvas : nullptr); + if (use_fill_and_stroke_images) { + canvas->DrawImageInt(it->fill_image, 0, 0); + canvas->sk_canvas()->clipPath(clip, SkRegion::kDifference_Op, true); + } + canvas->DrawImageInt(it->stroke_image, 0, 0); } -void Tab::PaintTabBackgroundUsingFillId(gfx::Canvas* canvas, +void Tab::PaintTabBackgroundUsingFillId(gfx::Canvas* fill_canvas, + gfx::Canvas* stroke_canvas, bool is_active, int fill_id, bool has_custom_image, int y_offset) { - const ui::ThemeProvider* tp = GetThemeProvider(); - const SkColor toolbar_color = tp->GetColor(ThemeProperties::COLOR_TOOLBAR); - gfx::ImageSkia* fill_image = tp->GetImageSkiaNamed(fill_id); + views::GlowHoverController* hc = + hover_controller_.ShouldDraw() ? &hover_controller_ : nullptr; + gfx::ImageSkia* fill_image = + has_custom_image || !ui::MaterialDesignController::IsModeMaterial() + ? GetThemeProvider()->GetImageSkiaNamed(fill_id) + : nullptr; // The tab image needs to be lined up with the background image // so that it feels partially transparent. These offsets represent the tab // position within the frame background image. - const int x_offset = GetMirroredX() + background_offset_.x(); + gfx::Rect rect(GetLocalBounds()); + rect.Offset(GetMirroredX() + background_offset_.x(), y_offset); + PaintBackgroundParams params( + is_active, fill_image, has_custom_image, rect, + controller_->GetToolbarTopSeparatorColor(), + GetThemeProvider()->GetColor(ThemeProperties::COLOR_TOOLBAR), + GetThemeProvider()->GetColor(ThemeProperties::COLOR_BACKGROUND_TAB)); - const SkScalar kMinHoverRadius = 16; - const SkScalar radius = - std::max(SkFloatToScalar(width() / 4.f), kMinHoverRadius); - const bool draw_hover = !is_active && hover_controller_.ShouldDraw(); - SkPoint hover_location(gfx::PointToSkPoint(hover_controller_.location())); - const SkColor hover_color = - SkColorSetA(toolbar_color, hover_controller_.GetAlpha()); - - if (ui::MaterialDesignController::IsModeMaterial()) { - gfx::ScopedCanvas scoped_canvas(canvas); - const float scale = canvas->UndoDeviceScaleFactor(); - - // Draw the fill. - gfx::Path fill = GetFillPath(scale, size()); - SkPaint paint; - paint.setAntiAlias(true); - { - gfx::ScopedCanvas clip_scoper(canvas); - canvas->ClipPath(fill, true); - if (has_custom_image) { - gfx::ScopedCanvas scale_scoper(canvas); - canvas->sk_canvas()->scale(scale, scale); - canvas->TileImageInt(*fill_image, x_offset, y_offset, 0, 0, width(), - height()); - } else { - paint.setColor( - is_active ? toolbar_color - : tp->GetColor(ThemeProperties::COLOR_BACKGROUND_TAB)); - canvas->DrawRect(gfx::ScaleToEnclosingRect(GetLocalBounds(), scale), - paint); - } - if (draw_hover) { - hover_location.scale(SkFloatToScalar(scale)); - DrawHighlight(canvas, hover_location, radius * scale, hover_color); - } - } - - // Draw the stroke. - gfx::Path stroke = GetBorderPath(scale, false, false, size()); - Op(stroke, fill, kDifference_SkPathOp, &stroke); - if (!is_active) { - // Clip out the bottom line; this will be drawn for us by - // TabStrip::PaintChildren(). - canvas->ClipRect(gfx::RectF(width() * scale, height() * scale - 1)); - } - paint.setColor(controller_->GetToolbarTopSeparatorColor()); - canvas->DrawPath(stroke, paint); - } else { - if (draw_hover) { - // Draw everything to a temporary canvas so we can extract an image for - // use in masking the hover glow. - gfx::Canvas background_canvas(size(), canvas->image_scale(), false); - PaintTabFill(&background_canvas, fill_image, x_offset, y_offset, size(), - is_active); - gfx::ImageSkia background_image(background_canvas.ExtractImageRep()); - canvas->DrawImageInt(background_image, 0, 0); - - gfx::Canvas hover_canvas(size(), canvas->image_scale(), false); - DrawHighlight(&hover_canvas, hover_location, radius, hover_color); - gfx::ImageSkia result = gfx::ImageSkiaOperations::CreateMaskedImage( - gfx::ImageSkia(hover_canvas.ExtractImageRep()), background_image); - canvas->DrawImageInt(result, 0, 0); - } else { - PaintTabFill(canvas, fill_image, x_offset, y_offset, size(), is_active); - } - - // Now draw the stroke, highlights, and shadows around the tab edge. - TabImages* stroke_images = - is_active ? &g_active_images : &g_inactive_images; - canvas->DrawImageInt(*stroke_images->image_l, 0, 0); - canvas->TileImageInt( - *stroke_images->image_c, stroke_images->l_width, 0, - width() - stroke_images->l_width - stroke_images->r_width, height()); - canvas->DrawImageInt(*stroke_images->image_r, - width() - stroke_images->r_width, 0); - } + PaintTabBackgroundUsingParams(fill_canvas, stroke_canvas, hc, params); } void Tab::PaintPinnedTabTitleChangedIndicatorAndIcon(
diff --git a/chrome/browser/ui/views/tabs/tab.h b/chrome/browser/ui/views/tabs/tab.h index 74f2fdaa..af3269c 100644 --- a/chrome/browser/ui/views/tabs/tab.h +++ b/chrome/browser/ui/views/tabs/tab.h
@@ -231,15 +231,17 @@ // Invoked from SetData after |data_| has been updated to the new data. void DataChanged(const TabRendererData& old); - // Paint with the normal tab style. - void PaintTab(gfx::Canvas* canvas); + // Paint with the normal tab style. If |clip| is non-empty, the tab border + // should be clipped against it. + void PaintTab(gfx::Canvas* canvas, const gfx::Path& clip); // Paint with the "immersive mode" light-bar style. void PaintImmersiveTab(gfx::Canvas* canvas); // Paint various portions of the Tab. - void PaintInactiveTabBackground(gfx::Canvas* canvas); - void PaintTabBackgroundUsingFillId(gfx::Canvas* canvas, + void PaintInactiveTabBackground(gfx::Canvas* canvas, const gfx::Path& clip); + void PaintTabBackgroundUsingFillId(gfx::Canvas* fill_canvas, + gfx::Canvas* stroke_canvas, bool is_active, int fill_id, bool has_custom_image,
diff --git a/chrome/browser/ui/views/tabs/tab_controller.h b/chrome/browser/ui/views/tabs/tab_controller.h index 90d0d0d3..88e61a184 100644 --- a/chrome/browser/ui/views/tabs/tab_controller.h +++ b/chrome/browser/ui/views/tabs/tab_controller.h
@@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_UI_VIEWS_TABS_TAB_CONTROLLER_H_ #define CHROME_BROWSER_UI_VIEWS_TABS_TAB_CONTROLLER_H_ +#include "base/callback_forward.h" #include "chrome/browser/ui/views/tabs/tab_strip_types.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/base/ui_base_types.h" @@ -12,6 +13,7 @@ class Tab; namespace gfx { +class Path; class Point; class Size; } @@ -37,6 +39,9 @@ // to be hidden. virtual bool ShouldHideCloseButtonForInactiveTabs() = 0; + // Returns true if ShouldPaintTab() could return a non-empty clip path. + virtual bool MaySetClip() = 0; + // Selects the tab. virtual void SelectTab(Tab* tab) = 0; @@ -92,10 +97,16 @@ virtual void OnMouseEventInTab(views::View* source, const ui::MouseEvent& event) = 0; - // Returns true if |tab| needs to be painted. If false is returned the tab is - // not painted. If true is returned the tab should be painted and |clip| is - // set to the clip (if |clip| is empty means no clip). - virtual bool ShouldPaintTab(const Tab* tab, gfx::Rect* clip) = 0; + // Returns whether |tab| needs to be painted. When this returns true, |clip| + // is set to the path which should be clipped out of the current tab's region + // (for hit testing or painting), if any. |clip| is only non-empty when + // stacking tabs; if it is empty, no clipping is needed. |border_callback| is + // a callback which returns a tab's border given its size, and is used in + // computing |clip|. + virtual bool ShouldPaintTab( + const Tab* tab, + const base::Callback<gfx::Path(const gfx::Size&)>& border_callback, + gfx::Path* clip) = 0; // Returns true if tab loading throbbers can be painted to a composited layer. // This can only be done when the TabController can guarantee that nothing
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc index 0df1f6f8..e2919b6 100644 --- a/chrome/browser/ui/views/tabs/tab_strip.cc +++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -109,12 +109,6 @@ // Amount of time we delay before resizing after a close from a touch. const int kTouchResizeLayoutTimeMS = 2000; -// Amount to adjust the clip by when the tab is stacked before the active index. -const int kStackedTabLeftClip = 20; - -// Amount to adjust the clip by when the tab is stacked after the active index. -const int kStackedTabRightClip = 20; - #if defined(OS_MACOSX) const int kPinnedToNonPinnedOffset = 2; #else @@ -1165,6 +1159,11 @@ switches::kDisableHideInactiveStackedTabCloseButtons); } +bool TabStrip::MaySetClip() { + // Only touch layout needs to restrict the clip. + return touch_layout_ || IsStackingDraggedTabs(); +} + void TabStrip::SelectTab(Tab* tab) { int model_index = GetModelIndexOfTab(tab); if (IsValidModelIndex(model_index)) @@ -1346,9 +1345,11 @@ UpdateStackedLayoutFromMouseEvent(source, event); } -bool TabStrip::ShouldPaintTab(const Tab* tab, gfx::Rect* clip) { - // Only touch layout needs to restrict the clip. - if (!touch_layout_ && !IsStackingDraggedTabs()) +bool TabStrip::ShouldPaintTab( + const Tab* tab, + const base::Callback<gfx::Path(const gfx::Size&)>& border_callback, + gfx::Path* clip) { + if (!MaySetClip()) return true; int index = GetModelIndexOfTab(tab); @@ -1369,9 +1370,8 @@ if (current_x > next_x) return true; // Can happen during dragging. - clip->SetRect( - 0, 0, next_x - current_x + kStackedTabLeftClip, - tab_at(index)->height()); + *clip = border_callback.Run(tab_at(index + 1)->size()); + clip->offset(SkIntToScalar(next_x - current_x), 0); } else if (index > active_index && index > 0) { const gfx::Rect& previous_bounds(tab_at(index - 1)->bounds()); const int previous_x = previous_bounds.x(); @@ -1383,9 +1383,8 @@ if (previous_bounds.right() - GetLayoutConstant(TABSTRIP_TAB_OVERLAP) != current_x) { - int x = previous_bounds.right() - current_x - kStackedTabRightClip; - const gfx::Rect& tab_bounds(tab_at(index)->bounds()); - clip->SetRect(x, 0, tab_bounds.width() - x, tab_bounds.height()); + *clip = border_callback.Run(tab_at(index - 1)->size()); + clip->offset(SkIntToScalar(previous_x - current_x), 0); } } return true; @@ -1474,8 +1473,8 @@ // We pass false for |lcd_text_requires_opaque_layer| so that background // tab titles will get LCD AA. These are rendered opaquely on an opaque tab // background before the layer is composited, so this is safe. - ui::CompositingRecorder opacity_recorder(context, size(), - GetInactiveAlpha(false), false); + ui::CompositingRecorder opacity_recorder(context, GetInactiveAlpha(false), + false); PaintClosingTabs(tab_count(), context); @@ -1534,8 +1533,8 @@ // NewTabButton::PaintFill() for why we don't do this for the pressed state. // This call doesn't need to set |lcd_text_requires_opaque_layer| to false // because no text will be drawn. - ui::CompositingRecorder opacity_recorder(context, size(), - GetInactiveAlpha(true), true); + ui::CompositingRecorder opacity_recorder(context, GetInactiveAlpha(true), + true); newtab_button_->Paint(context); } else { newtab_button_->Paint(context);
diff --git a/chrome/browser/ui/views/tabs/tab_strip.h b/chrome/browser/ui/views/tabs/tab_strip.h index 2a5ee0c..1a29593 100644 --- a/chrome/browser/ui/views/tabs/tab_strip.h +++ b/chrome/browser/ui/views/tabs/tab_strip.h
@@ -210,6 +210,7 @@ const ui::ListSelectionModel& GetSelectionModel() const override; bool SupportsMultipleSelection() override; bool ShouldHideCloseButtonForInactiveTabs() override; + bool MaySetClip() override; void SelectTab(Tab* tab) override; void ExtendSelectionTo(Tab* tab) override; void ToggleSelected(Tab* tab) override; @@ -231,7 +232,10 @@ Tab* GetTabAt(Tab* tab, const gfx::Point& tab_in_tab_coordinates) override; void OnMouseEventInTab(views::View* source, const ui::MouseEvent& event) override; - bool ShouldPaintTab(const Tab* tab, gfx::Rect* clip) override; + bool ShouldPaintTab( + const Tab* tab, + const base::Callback<gfx::Path(const gfx::Size&)>& border_callback, + gfx::Path* clip) override; bool CanPaintThrobberToLayer() const override; bool IsImmersiveStyle() const override; SkColor GetToolbarTopSeparatorColor() const override;
diff --git a/chrome/browser/ui/views/tabs/tab_unittest.cc b/chrome/browser/ui/views/tabs/tab_unittest.cc index 5cfe9d1b..cfd659e 100644 --- a/chrome/browser/ui/views/tabs/tab_unittest.cc +++ b/chrome/browser/ui/views/tabs/tab_unittest.cc
@@ -39,6 +39,7 @@ bool ShouldHideCloseButtonForInactiveTabs() override { return false; } + bool MaySetClip() override { return false; } void SelectTab(Tab* tab) override {} void ExtendSelectionTo(Tab* tab) override {} void ToggleSelected(Tab* tab) override {} @@ -63,7 +64,12 @@ } void OnMouseEventInTab(views::View* source, const ui::MouseEvent& event) override {} - bool ShouldPaintTab(const Tab* tab, gfx::Rect* clip) override { return true; } + bool ShouldPaintTab( + const Tab* tab, + const base::Callback<gfx::Path(const gfx::Size&)>& border_callback, + gfx::Path* clip) override { + return true; + } bool CanPaintThrobberToLayer() const override { return paint_throbber_to_layer_; }
diff --git a/chrome/browser/ui/views/toolbar/app_menu.cc b/chrome/browser/ui/views/toolbar/app_menu.cc index 99f143d5..059863a 100644 --- a/chrome/browser/ui/views/toolbar/app_menu.cc +++ b/chrome/browser/ui/views/toolbar/app_menu.cc
@@ -818,7 +818,7 @@ // so we get the taller menu style. PopulateMenu(root_, model); - int32_t types = views::MenuRunner::HAS_MNEMONICS; + int32_t types = views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::ASYNC; if (for_drop()) { // We add NESTED_DRAG since currently the only operation to open the app // menu for is an extension action drag, which is controlled by the child @@ -833,22 +833,8 @@ views::View::ConvertPointToScreen(host, &screen_loc); gfx::Rect bounds(screen_loc, host->size()); content::RecordAction(UserMetricsAction("ShowAppMenu")); - if (menu_runner_->RunMenuAt(host->GetWidget(), - host, - bounds, - views::MENU_ANCHOR_TOPRIGHT, - ui::MENU_SOURCE_NONE) == - views::MenuRunner::MENU_DELETED) - return; - if (bookmark_menu_delegate_.get()) { - BookmarkModel* model = - BookmarkModelFactory::GetForBrowserContext(browser_->profile()); - if (model) - model->RemoveObserver(this); - } - if (selected_menu_model_) { - selected_menu_model_->ActivatedAt(selected_index_); - } + menu_runner_->RunMenuAt(host->GetWidget(), host, bounds, + views::MENU_ANCHOR_TOPRIGHT, ui::MENU_SOURCE_NONE); } void AppMenu::CloseMenu() { @@ -1069,6 +1055,18 @@ return false; } +void AppMenu::OnMenuClosed(views::MenuItemView* menu, + views::MenuRunner::RunResult result) { + if (bookmark_menu_delegate_.get()) { + BookmarkModel* model = + BookmarkModelFactory::GetForBrowserContext(browser_->profile()); + if (model) + model->RemoveObserver(this); + } + if (selected_menu_model_) + selected_menu_model_->ActivatedAt(selected_index_); +} + void AppMenu::BookmarkModelChanged() { DCHECK(bookmark_menu_delegate_.get()); if (!bookmark_menu_delegate_->is_mutating_model())
diff --git a/chrome/browser/ui/views/toolbar/app_menu.h b/chrome/browser/ui/views/toolbar/app_menu.h index 98e8ce7..1cae0174 100644 --- a/chrome/browser/ui/views/toolbar/app_menu.h +++ b/chrome/browser/ui/views/toolbar/app_menu.h
@@ -103,6 +103,8 @@ void WillShowMenu(views::MenuItemView* menu) override; void WillHideMenu(views::MenuItemView* menu) override; bool ShouldCloseOnDragComplete() override; + void OnMenuClosed(views::MenuItemView* menu, + views::MenuRunner::RunResult result) override; // bookmarks::BaseBookmarkModelObserver overrides: void BookmarkModelChanged() override;
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc b/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc index e27c0eeb..0e56223 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc
@@ -41,8 +41,7 @@ // menu is open, and handles actually clicking on the action. // |button| specifies the mouse button to click with. void TestOverflowedToolbarAction(Browser* browser, - ui_controls::MouseButton button, - const base::Closure& quit_closure) { + ui_controls::MouseButton button) { // A bunch of plumbing to safely get at the overflowed toolbar action. AppMenuButton* app_menu_button = GetAppButtonFromBrowser(browser); EXPECT_TRUE(app_menu_button->IsMenuShowing()); @@ -62,27 +61,7 @@ gfx::Point action_view_loc = ui_test_utils::GetCenterInScreenCoordinates(action_view); ui_controls::SendMouseMove(action_view_loc.x(), action_view_loc.y()); - ui_controls::SendMouseEventsNotifyWhenDone( - button, ui_controls::DOWN | ui_controls::UP, quit_closure); -} - -void ActivateOverflowedActionWithKeyboard(Browser* browser, - const base::Closure& closure) { - AppMenuButton* app_menu_button = GetAppButtonFromBrowser(browser); - EXPECT_TRUE(app_menu_button->IsMenuShowing()); - // We need to dispatch key events to the menu's native window, rather than the - // browser's. - gfx::NativeWindow native_window = - views::MenuController::GetActiveInstance()->owner()->GetNativeWindow(); - - // Send a key down event followed by the return key. - // The key down event targets the toolbar action in the app menu. - ui_controls::SendKeyPress(native_window, - ui::VKEY_DOWN, - false, false, false, false); - ui_controls::SendKeyPressNotifyWhenDone(native_window, - ui::VKEY_RETURN, - false, false, false, false, closure); + ui_controls::SendMouseEvents(button, ui_controls::DOWN | ui_controls::UP); } // Tests the context menu of an overflowed action. @@ -215,18 +194,18 @@ // Click on the app button. gfx::Point app_button_loc = ui_test_utils::GetCenterInScreenCoordinates(app_menu_button); - base::RunLoop loop; ui_controls::SendMouseMove(app_button_loc.x(), app_button_loc.y()); - ui_controls::SendMouseEventsNotifyWhenDone( - ui_controls::LEFT, ui_controls::DOWN | ui_controls::UP, - base::Bind(&TestOverflowedToolbarAction, browser(), ui_controls::LEFT, - loop.QuitClosure())); - loop.Run(); - // The app menu should no longer be showing. - EXPECT_FALSE(app_menu_button->IsMenuShowing()); + ui_controls::SendMouseEvents(ui_controls::LEFT, + ui_controls::DOWN | ui_controls::UP); + base::RunLoop().RunUntilIdle(); - // And the extension should have been activated. + TestOverflowedToolbarAction(browser(), ui_controls::LEFT); + + // The extension should have been activated. listener.WaitUntilSatisfied(); + + // And the app menu should no longer be showing. + EXPECT_FALSE(app_menu_button->IsMenuShowing()); } #if defined(USE_OZONE) @@ -278,13 +257,13 @@ // Click on the app button, and then right-click on the first toolbar action. gfx::Point app_button_loc = ui_test_utils::GetCenterInScreenCoordinates(app_menu_button); - base::RunLoop loop; ui_controls::SendMouseMove(app_button_loc.x(), app_button_loc.y()); - ui_controls::SendMouseEventsNotifyWhenDone( - ui_controls::LEFT, ui_controls::DOWN | ui_controls::UP, - base::Bind(&TestOverflowedToolbarAction, browser(), ui_controls::RIGHT, - loop.QuitClosure())); - loop.Run(); + ui_controls::SendMouseEvents(ui_controls::LEFT, + ui_controls::DOWN | ui_controls::UP); + + base::RunLoop().RunUntilIdle(); + TestOverflowedToolbarAction(browser(), ui_controls::RIGHT); + base::RunLoop().RunUntilIdle(); // Test is continued first in TestOverflowedToolbarAction() to right click on // the action, followed by OnContextMenuWillShow() and @@ -387,16 +366,24 @@ AppMenuButton* app_menu_button = GetAppButtonFromBrowser(browser()); gfx::Point app_button_loc = ui_test_utils::GetCenterInScreenCoordinates(app_menu_button); - base::RunLoop loop; ui_controls::SendMouseMove(app_button_loc.x(), app_button_loc.y()); - ui_controls::SendMouseEventsNotifyWhenDone( - ui_controls::LEFT, ui_controls::DOWN | ui_controls::UP, - base::Bind(&ActivateOverflowedActionWithKeyboard, - browser(), loop.QuitClosure())); - loop.Run(); + ui_controls::SendMouseEvents(ui_controls::LEFT, + ui_controls::DOWN | ui_controls::UP); - // The app menu should no longer be showing. - EXPECT_FALSE(app_menu_button->IsMenuShowing()); - // And the extension should have been activated. + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(app_menu_button->IsMenuShowing()); + gfx::NativeWindow native_window = + views::MenuController::GetActiveInstance()->owner()->GetNativeWindow(); + // Send a key down event followed by the return key. + // The key down event targets the toolbar action in the app menu. + ui_controls::SendKeyPress(native_window, ui::VKEY_DOWN, false, false, false, + false); + ui_controls::SendKeyPress(native_window, ui::VKEY_RETURN, false, false, false, + false); + + // The extension should have been activated. EXPECT_TRUE(listener.WaitUntilSatisfied()); + // And the menu should be closed + EXPECT_FALSE(app_menu_button->IsMenuShowing()); }
diff --git a/chrome/browser/ui/website_settings/website_settings.cc b/chrome/browser/ui/website_settings/website_settings.cc index 21a35e9..4a5fb69a 100644 --- a/chrome/browser/ui/website_settings/website_settings.cc +++ b/chrome/browser/ui/website_settings/website_settings.cc
@@ -485,6 +485,11 @@ case SecurityStateModel::NO_DEPRECATED_SHA1: // Nothing to do. break; + case SecurityStateModel::UNKNOWN_SHA1: + // UNKNOWN_SHA1 should only appear when certificate info has not been + // initialized, in which case this if-statement should not be running + // because there is no other cert info. + NOTREACHED(); } } } else {
diff --git a/chrome/browser/ui/webui/DEPS b/chrome/browser/ui/webui/DEPS index d174939..e795119 100644 --- a/chrome/browser/ui/webui/DEPS +++ b/chrome/browser/ui/webui/DEPS
@@ -11,6 +11,7 @@ # Generated files "+js2webui/chrome/test/data", + "+third_party/cld", # Other libraries. "+third_party/angle", # For ANGLE version.
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc index 5546b86..2d06fdd 100644 --- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc +++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -55,6 +55,7 @@ #include "chrome/browser/ui/webui/supervised_user_internals_ui.h" #include "chrome/browser/ui/webui/sync_internals_ui.h" #include "chrome/browser/ui/webui/translate_internals/translate_internals_ui.h" +#include "chrome/browser/ui/webui/usb_internals/usb_internals_ui.h" #include "chrome/browser/ui/webui/user_actions/user_actions_ui.h" #include "chrome/browser/ui/webui/version_ui.h" #include "chrome/common/chrome_features.h" @@ -376,6 +377,8 @@ return &NewWebUI<WebDialogUI>; if (url.host() == chrome::kChromeUITranslateInternalsHost) return &NewWebUI<TranslateInternalsUI>; + if (url.host() == chrome::kChromeUIUsbInternalsHost) + return &NewWebUI<UsbInternalsUI>; if (url.host() == chrome::kChromeUIUserActionsHost) return &NewWebUI<UserActionsUI>; if (url.host() == chrome::kChromeUIVersionHost)
diff --git a/chrome/browser/ui/webui/md_feedback/md_feedback_dialog_controller.cc b/chrome/browser/ui/webui/md_feedback/md_feedback_dialog_controller.cc new file mode 100644 index 0000000..d866afb8 --- /dev/null +++ b/chrome/browser/ui/webui/md_feedback/md_feedback_dialog_controller.cc
@@ -0,0 +1,82 @@ +// 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 "chrome/browser/ui/webui/md_feedback/md_feedback_dialog_controller.h" + +#include "chrome/browser/ui/browser_dialogs.h" +#include "chrome/common/url_constants.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/web_contents.h" +#include "ui/web_dialogs/web_dialog_delegate.h" +#include "url/gurl.h" + +namespace { + +// The WebDialogDelegate that specifies what the MD Feedback dialog will look +// like. +class MdFeedbackDialogDelegate : public ui::WebDialogDelegate { + public: + MdFeedbackDialogDelegate() {} + ~MdFeedbackDialogDelegate() override {} + + ui::ModalType GetDialogModalType() const override { + return ui::MODAL_TYPE_SYSTEM; + } + + base::string16 GetDialogTitle() const override { + return base::string16(); + } + + GURL GetDialogContentURL() const override { + return GURL(chrome::kChromeUIFeedbackURL); + } + + void GetWebUIMessageHandlers( + std::vector<content::WebUIMessageHandler*>* handlers) const override {} + + void GetDialogSize(gfx::Size* size) const override { + // TODO(apacible): Update when WebUI sizing behavior is finalized. + size->SetSize(400, 600); + } + + std::string GetDialogArgs() const override { + return std::string(); + } + + void OnDialogClosed(const std::string& json_retval) override { + delete this; + } + + void OnCloseContents( + content::WebContents* source, bool* out_close_dialog) override {} + + bool ShouldShowDialogTitle() const override { + return false; + } + + bool HandleContextMenu(const content::ContextMenuParams& params) override { + // Do not show the contextual menu. + return true; + } +}; + +} // namespace + +// static +MdFeedbackDialogController* MdFeedbackDialogController::GetInstance() { + return base::Singleton<MdFeedbackDialogController>::get(); +} + +void MdFeedbackDialogController::Show( + content::BrowserContext* browser_context) { + // TODO(apacible): Platform dependent implementations. +#if !defined(OS_MACOSX) + // TODO(apacible): If a feedback dialog is already open, bring that dialog + // to the front rather than creating a new dialog. + chrome::ShowWebDialog(nullptr, browser_context, + new MdFeedbackDialogDelegate()); +#endif // !defined(OS_MACOSX) +} + +MdFeedbackDialogController::MdFeedbackDialogController() {}
diff --git a/chrome/browser/ui/webui/md_feedback/md_feedback_dialog_controller.h b/chrome/browser/ui/webui/md_feedback/md_feedback_dialog_controller.h new file mode 100644 index 0000000..1251ba97 --- /dev/null +++ b/chrome/browser/ui/webui/md_feedback/md_feedback_dialog_controller.h
@@ -0,0 +1,31 @@ +// 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 CHROME_BROWSER_UI_WEBUI_MD_FEEDBACK_MD_FEEDBACK_DIALOG_CONTROLLER_H_ +#define CHROME_BROWSER_UI_WEBUI_MD_FEEDBACK_MD_FEEDBACK_DIALOG_CONTROLLER_H_ + +#include "base/memory/singleton.h" +#include "content/public/browser/browser_context.h" + +// Manages MD Feedback dialog creation, destruction, and showing a constrained +// web dialog with the feedback contents. This controller is implemented as a +// singleton. +class MdFeedbackDialogController { + public: + static MdFeedbackDialogController* GetInstance(); + + // Show the feedback dialog. This WebUI dialog is not anchored to the browser + // window but tied to a profile. + void Show(content::BrowserContext* browser_context); + + private: + friend struct base::DefaultSingletonTraits<MdFeedbackDialogController>; + + MdFeedbackDialogController(); + ~MdFeedbackDialogController() = default; + + DISALLOW_COPY_AND_ASSIGN(MdFeedbackDialogController); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_MD_FEEDBACK_MD_FEEDBACK_DIALOG_CONTROLLER_H_
diff --git a/chrome/browser/ui/webui/md_feedback/md_feedback_ui.cc b/chrome/browser/ui/webui/md_feedback/md_feedback_ui.cc index 67a56bea..645618a1 100644 --- a/chrome/browser/ui/webui/md_feedback/md_feedback_ui.cc +++ b/chrome/browser/ui/webui/md_feedback/md_feedback_ui.cc
@@ -7,12 +7,8 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/common/url_constants.h" #include "chrome/grit/generated_resources.h" -#include "content/public/browser/browser_context.h" -#include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui_data_source.h" #include "grit/browser_resources.h" -#include "ui/web_dialogs/web_dialog_delegate.h" -#include "url/gurl.h" #if !defined(OS_MACOSX) #include "chrome/browser/ui/browser_dialogs.h" @@ -20,58 +16,6 @@ namespace { -// The WebDialogDelegate that specifies what the MD Feedback dialog will look -// like. -class MdFeedbackDialogDelegate : public ui::WebDialogDelegate { - public: - MdFeedbackDialogDelegate() {} - ~MdFeedbackDialogDelegate() override {} - - ui::ModalType GetDialogModalType() const override { - return ui::MODAL_TYPE_SYSTEM; - } - - base::string16 GetDialogTitle() const override { - return base::string16(); - } - - GURL GetDialogContentURL() const override { - return GURL(chrome::kChromeUIFeedbackURL); - } - - void GetWebUIMessageHandlers( - std::vector<content::WebUIMessageHandler*>* handlers) const override {} - - void GetDialogSize(gfx::Size* size) const override { - // TODO(apacible): Update when WebUI sizing behavior is finalized. - size->SetSize(400, 600); - } - - std::string GetDialogArgs() const override { - return std::string(); - } - - void OnDialogClosed(const std::string& json_retval) override { - delete this; - } - - void OnCloseContents( - content::WebContents* source, bool* out_close_dialog) override {} - - bool ShouldShowDialogTitle() const override { - return false; - } - - bool HandleContextMenu(const content::ContextMenuParams& params) override { - // Do not show the contextual menu. - return true; - } -}; - -} // namespace - -namespace { - content::WebUIDataSource* CreateMdFeedbackUIHTMLSource(Profile* profile) { content::WebUIDataSource* html_source = content::WebUIDataSource::Create(chrome::kChromeUIFeedbackHost); @@ -127,13 +71,3 @@ } MdFeedbackUI::~MdFeedbackUI() {} - -void ShowFeedbackWebDialog( - content::BrowserContext* browser_context) { - // TODO(apacible): Platform dependent implementations. -#if !defined(OS_MACOSX) - // TODO(apacible): If a feedback dialog is already open, bring that dialog - // to the front rather than creating a new dialog. - chrome::ShowWebDialog(NULL, browser_context, new MdFeedbackDialogDelegate()); -#endif // !OS_MACOSX -}
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.cc b/chrome/browser/ui/webui/options/browser_options_handler.cc index 058d344..a9314bd 100644 --- a/chrome/browser/ui/webui/options/browser_options_handler.cc +++ b/chrome/browser/ui/webui/options/browser_options_handler.cc
@@ -430,6 +430,8 @@ IDS_OPTIONS_SETTINGS_ACCESSIBILITY_STICKY_KEYS_DESCRIPTION }, { "accessibilitySwitchAccess", IDS_OPTIONS_SETTINGS_ACCESSIBILITY_SWITCH_ACCESS_DESCRIPTION }, + { "accessibilityTalkBackSettings", + IDS_OPTIONS_SETTINGS_ACCESSIBILITY_TALKBACK_SETTINGS }, { "accessibilityTapDragging", IDS_OPTIONS_SETTINGS_ACCESSIBILITY_TOUCHPAD_TAP_DRAGGING_DESCRIPTION }, { "accessibilityVirtualKeyboard", @@ -800,6 +802,10 @@ "showAndroidAppsSettings", base::Bind(&BrowserOptionsHandler::ShowAndroidAppsSettings, base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "showAccessibilityTalkBackSettings", + base::Bind(&BrowserOptionsHandler::ShowAccessibilityTalkBackSettings, + base::Unretained(this))); #else web_ui()->RegisterMessageCallback( "becomeDefaultBrowser", @@ -1934,6 +1940,18 @@ arc::LaunchAndroidSettingsApp(profile); } +void BrowserOptionsHandler::ShowAccessibilityTalkBackSettings( + const base::ListValue *args) { + Profile* profile = Profile::FromWebUI(web_ui()); + // Settings in secondary profile cannot access ARC. + if (!arc::ArcAuthService::IsAllowedForProfile(profile)) { + LOG(WARNING) << "Settings can't be invoked for non-primary profile"; + return; + } + + arc::ShowTalkBackSettings(); +} + void BrowserOptionsHandler::SetupAccessibilityFeatures() { PrefService* pref_service = g_browser_process->local_state(); base::FundamentalValue virtual_keyboard_enabled(
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.h b/chrome/browser/ui/webui/options/browser_options_handler.h index 5e53a1c..77b15d9 100644 --- a/chrome/browser/ui/webui/options/browser_options_handler.h +++ b/chrome/browser/ui/webui/options/browser_options_handler.h
@@ -337,6 +337,9 @@ // Called to show Android apps settings. void ShowAndroidAppsSettings(const base::ListValue* args); + + // Called to show TalkBack settings. + void ShowAccessibilityTalkBackSettings(const base::ListValue *args); #endif // Setup the visibility for the metrics reporting setting.
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc index 5cc0624..6337e83 100644 --- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -63,6 +63,7 @@ LocalizedString localized_strings[] = { {"add", IDS_ADD}, {"cancel", IDS_CANCEL}, + {"confirm", IDS_CONFIRM}, {"disable", IDS_DISABLE}, {"learnMore", IDS_LEARN_MORE}, {"ok", IDS_OK}, @@ -842,41 +843,36 @@ {"manageOtherPeople", IDS_SETTINGS_PEOPLE_MANAGE_OTHER_PEOPLE}, {"manageSupervisedUsers", IDS_SETTINGS_PEOPLE_MANAGE_SUPERVISED_USERS}, #if defined(OS_CHROMEOS) + {"configurePinChoosePinTitle", + IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_CHOOSE_PIN_TITLE}, + {"configurePinConfirmPinTitle", + IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_CONFIRM_PIN_TITLE}, + {"configurePinContinueButton", + IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_CONTINUE_BUTTON}, + {"configurePinMismatched", IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_MISMATCHED}, + {"configurePinTooShort", IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_TOO_SHORT}, + {"configurePinWeakPin", IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_WEAK_PIN}, {"enableScreenlock", IDS_SETTINGS_PEOPLE_ENABLE_SCREENLOCK}, + {"lockScreenChangePinButton", + IDS_SETTINGS_PEOPLE_LOCK_SCREEN_CHANGE_PIN_BUTTON}, + {"lockScreenNone", IDS_SETTINGS_PEOPLE_LOCK_SCREEN_NONE}, + {"lockScreenPasswordOnly", IDS_SETTINGS_PEOPLE_LOCK_SCREEN_PASSWORD_ONLY}, + {"lockScreenPinOrPassword", + IDS_SETTINGS_PEOPLE_LOCK_SCREEN_PIN_OR_PASSWORD}, + {"lockScreenSetupPinButton", + IDS_SETTINGS_PEOPLE_LOCK_SCREEN_SETUP_PIN_BUTTON}, + {"lockScreenTitle", IDS_SETTINGS_PEOPLE_LOCK_SCREEN_TITLE}, + {"passwordPromptEnterPassword", + IDS_SETTINGS_PEOPLE_PASSWORD_PROMPT_ENTER_PASSWORD}, + {"passwordPromptInvalidPassword", + IDS_SETTINGS_PEOPLE_PASSWORD_PROMPT_INVALID_PASSWORD}, + {"passwordPromptPasswordLabel", + IDS_SETTINGS_PEOPLE_PASSWORD_PROMPT_PASSWORD_LABEL}, + {"passwordPromptTitle", IDS_SETTINGS_PEOPLE_PASSWORD_PROMPT_TITLE}, {"pinKeyboardPlaceholderPin", IDS_PIN_KEYBOARD_HINT_TEXT_PIN}, {"pinKeyboardPlaceholderPinPassword", - IDS_PIN_KEYBOARD_HINT_TEXT_PIN_PASSWORD}, + IDS_PIN_KEYBOARD_HINT_TEXT_PIN_PASSWORD}, {"pinKeyboardClear", IDS_PIN_KEYBOARD_CLEAR}, - {"quickUnlockTitle", IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_TITLE}, - {"quickUnlockConfirmLogin", IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_CONFIRM_LOGIN}, - {"quickUnlockPasswordLabel", - IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_PASSWORD_LABEL}, - {"quickUnlockInvalidPassword", - IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_INVALID_PASSWORD}, - {"quickUnlockChooseUnlockMethod", - IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_CHOOSE_UNLOCK_METHOD}, - {"quickUnlockUnlockMethodPassword", - IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_UNLOCK_METHOD_PASSWORD}, - {"quickUnlockUnlockMethodPinAndPassword", - IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_UNLOCK_METHOD_PIN_AND_PASSWORD}, - {"quickUnlockUnlockMethodNone", - IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_UNLOCK_METHOD_NONE}, - {"quickUnlockConfigurePinButton", - IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_CONFIGURE_PIN_BUTTON}, - {"quickUnlockConfigurePinChoosePinTitle", - IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_CONFIGURE_PIN_CHOOSE_PIN_TITLE}, - {"quickUnlockConfigurePinChoosePinWeakPinWarning", - IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_CONFIGURE_PIN_CHOOSE_PIN_WEAK_PIN_WARNING}, - {"quickUnlockConfigurePinChoosePinTooShort", - IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_CONFIGURE_PIN_CHOOSE_PIN_TOO_SHORT}, - {"quickUnlockConfigurePinContinueButton", - IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_CONFIGURE_PIN_CONTINUE_BUTTON}, - {"quickUnlockConfigurePinConfirmPinTitle", - IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_CONFIGURE_PIN_CONFIRM_PIN_TITLE}, - {"quickUnlockConfigurePinMismatchedPins", - IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_CONFIGURE_PIN_MISMATCHED_PINS}, - {"quickUnlockConfigurePinBackButton", - IDS_SETTINGS_PEOPLE_QUICK_UNLOCK_CONFIGURE_PIN_BACK_BUTTON}, {"changePictureTitle", IDS_SETTINGS_CHANGE_PICTURE_DIALOG_TITLE}, {"changePicturePageDescription", IDS_SETTINGS_CHANGE_PICTURE_DIALOG_TEXT}, {"takePhoto", IDS_SETTINGS_CHANGE_PICTURE_TAKE_PHOTO},
diff --git a/chrome/browser/ui/webui/snippets_internals_message_handler.cc b/chrome/browser/ui/webui/snippets_internals_message_handler.cc index 2b0d34c..e2705a8 100644 --- a/chrome/browser/ui/webui/snippets_internals_message_handler.cc +++ b/chrome/browser/ui/webui/snippets_internals_message_handler.cc
@@ -15,12 +15,13 @@ #include "base/i18n/time_formatting.h" #include "base/logging.h" #include "base/memory/ptr_util.h" +#include "base/optional.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/values.h" -#include "chrome/browser/android/chrome_feature_list.h" #include "chrome/browser/ntp_snippets/content_suggestions_service_factory.h" #include "chrome/browser/profiles/profile.h" +#include "components/ntp_snippets/category_info.h" #include "components/ntp_snippets/features.h" #include "components/ntp_snippets/ntp_snippet.h" #include "components/ntp_snippets/switches.h" @@ -28,37 +29,12 @@ using ntp_snippets::ContentSuggestion; using ntp_snippets::Category; +using ntp_snippets::CategoryInfo; using ntp_snippets::CategoryStatus; using ntp_snippets::KnownCategories; namespace { -std::unique_ptr<base::DictionaryValue> PrepareSnippet( - const ntp_snippets::NTPSnippet& snippet, - int index, - bool dismissed) { - std::unique_ptr<base::DictionaryValue> entry(new base::DictionaryValue); - entry->SetString("snippetId", snippet.id()); - entry->SetString("title", snippet.title()); - entry->SetString("siteTitle", snippet.best_source().publisher_name); - entry->SetString("snippet", snippet.snippet()); - entry->SetString("published", - TimeFormatShortDateAndTime(snippet.publish_date())); - entry->SetString("expires", - TimeFormatShortDateAndTime(snippet.expiry_date())); - entry->SetString("url", snippet.best_source().url.spec()); - entry->SetString("ampUrl", snippet.best_source().amp_url.spec()); - entry->SetString("salientImageUrl", snippet.salient_image_url().spec()); - entry->SetDouble("score", snippet.score()); - - if (dismissed) - entry->SetString("id", "dismissed-snippet-" + base::IntToString(index)); - else - entry->SetString("id", "snippet-" + base::IntToString(index)); - - return entry; -} - std::unique_ptr<base::DictionaryValue> PrepareSuggestion( const ContentSuggestion& suggestion, int index) { @@ -75,20 +51,6 @@ return entry; } -// TODO(pke): Replace this as soon as the service delivers the title directly. -std::string GetCategoryTitle(Category category) { - if (category.IsKnownCategory(KnownCategories::ARTICLES)) { - return "Articles"; - } - if (category.IsKnownCategory(KnownCategories::OFFLINE_PAGES)) { - return "Offline pages (continue browsing)"; - } - if (category.IsKnownCategory(KnownCategories::BOOKMARKS)) { - return "Recently visited bookmarks"; - } - return std::string(); -} - std::string GetCategoryStatusName(CategoryStatus status) { switch (status) { case CategoryStatus::INITIALIZING: @@ -121,22 +83,6 @@ SnippetsInternalsMessageHandler::~SnippetsInternalsMessageHandler() {} -void SnippetsInternalsMessageHandler::OnNewSuggestions() { - if (!dom_loaded_) - return; - SendContentSuggestions(); -} - -void SnippetsInternalsMessageHandler::OnCategoryStatusChanged( - Category category, - CategoryStatus new_status) { - if (!dom_loaded_) - return; - SendContentSuggestions(); -} - -void SnippetsInternalsMessageHandler::ContentSuggestionsServiceShutdown() {} - void SnippetsInternalsMessageHandler::RegisterMessages() { // additional initialization (web_ui() does not work from the constructor) Profile* profile = Profile::FromWebUI(web_ui()); @@ -153,19 +99,10 @@ base::Unretained(this))); web_ui()->RegisterMessageCallback( - "clear", base::Bind(&SnippetsInternalsMessageHandler::HandleClear, - base::Unretained(this))); - - web_ui()->RegisterMessageCallback( "download", base::Bind(&SnippetsInternalsMessageHandler::HandleDownload, base::Unretained(this))); web_ui()->RegisterMessageCallback( - "clearDismissed", - base::Bind(&SnippetsInternalsMessageHandler::HandleClearDismissed, - base::Unretained(this))); - - web_ui()->RegisterMessageCallback( "clearCachedSuggestions", base::Bind(&SnippetsInternalsMessageHandler::HandleClearCachedSuggestions, base::Unretained(this))); @@ -177,6 +114,22 @@ base::Unretained(this))); } +void SnippetsInternalsMessageHandler::OnNewSuggestions(Category category) { + if (!dom_loaded_) + return; + SendContentSuggestions(); +} + +void SnippetsInternalsMessageHandler::OnCategoryStatusChanged( + Category category, + CategoryStatus new_status) { + if (!dom_loaded_) + return; + SendContentSuggestions(); +} + +void SnippetsInternalsMessageHandler::ContentSuggestionsServiceShutdown() {} + void SnippetsInternalsMessageHandler::HandleRefreshContent( const base::ListValue* args) { DCHECK_EQ(0u, args->GetSize()); @@ -186,20 +139,6 @@ SendAllContent(); } -void SnippetsInternalsMessageHandler::HandleClear(const base::ListValue* args) { - DCHECK_EQ(0u, args->GetSize()); - - ntp_snippets_service_->ClearCachedSuggestionsForDebugging(); -} - -void SnippetsInternalsMessageHandler::HandleClearDismissed( - const base::ListValue* args) { - DCHECK_EQ(0u, args->GetSize()); - - ntp_snippets_service_->ClearDismissedSuggestionsForDebugging(); - SendDismissedSnippets(); -} - void SnippetsInternalsMessageHandler::HandleDownload( const base::ListValue* args) { DCHECK_EQ(1u, args->GetSize()); @@ -207,7 +146,8 @@ SendString("hosts-status", std::string()); std::string hosts_string; - args->GetString(0, &hosts_string); + if (!args->GetString(0, &hosts_string)) + return; std::vector<std::string> hosts_vector = base::SplitString( hosts_string, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); @@ -218,16 +158,32 @@ void SnippetsInternalsMessageHandler::HandleClearCachedSuggestions( const base::ListValue* args) { - DCHECK_EQ(0u, args->GetSize()); + DCHECK_EQ(1u, args->GetSize()); - content_suggestions_service_->ClearCachedSuggestionsForDebugging(); + int category_id; + if (!args->GetInteger(0, &category_id)) + return; + + Category category = + content_suggestions_service_->category_factory()->FromIDValue( + category_id); + content_suggestions_service_->ClearCachedSuggestionsForDebugging(category); + SendContentSuggestions(); } void SnippetsInternalsMessageHandler::HandleClearDismissedSuggestions( const base::ListValue* args) { - DCHECK_EQ(0u, args->GetSize()); + DCHECK_EQ(1u, args->GetSize()); - content_suggestions_service_->ClearDismissedSuggestionsForDebugging(); + int category_id; + if (!args->GetInteger(0, &category_id)) + return; + + Category category = + content_suggestions_service_->category_factory()->FromIDValue( + category_id); + content_suggestions_service_->ClearDismissedSuggestionsForDebugging(category); + SendContentSuggestions(); } void SnippetsInternalsMessageHandler::SendAllContent() { @@ -238,7 +194,7 @@ SendBoolean("flag-offline-page-suggestions", base::FeatureList::IsEnabled( - chrome::android::kNTPOfflinePageSuggestionsFeature)); + ntp_snippets::kOfflinePageSuggestionsFeature)); web_ui()->CallJavascriptFunctionUnsafe( "chrome.SnippetsInternals.setHostRestricted", @@ -265,43 +221,9 @@ base::StringValue( ntp_snippets_service_->snippets_fetcher()->last_json())); - SendSnippets(); - SendDismissedSnippets(); SendContentSuggestions(); } -void SnippetsInternalsMessageHandler::SendSnippets() { - std::unique_ptr<base::ListValue> snippets_list(new base::ListValue); - - int index = 0; - for (const std::unique_ptr<ntp_snippets::NTPSnippet>& snippet : - ntp_snippets_service_->snippets()) - snippets_list->Append(PrepareSnippet(*snippet, index++, false)); - - base::DictionaryValue result; - result.Set("list", std::move(snippets_list)); - web_ui()->CallJavascriptFunctionUnsafe( - "chrome.SnippetsInternals.receiveSnippets", result); - - const std::string& status = - ntp_snippets_service_->snippets_fetcher()->last_status(); - if (!status.empty()) - SendString("hosts-status", "Finished: " + status); -} - -void SnippetsInternalsMessageHandler::SendDismissedSnippets() { - std::unique_ptr<base::ListValue> snippets_list(new base::ListValue); - - int index = 0; - for (const auto& snippet : ntp_snippets_service_->dismissed_snippets()) - snippets_list->Append(PrepareSnippet(*snippet, index++, true)); - - base::DictionaryValue result; - result.Set("list", std::move(snippets_list)); - web_ui()->CallJavascriptFunctionUnsafe( - "chrome.SnippetsInternals.receiveDismissedSnippets", result); -} - void SnippetsInternalsMessageHandler::SendHosts() { std::unique_ptr<base::ListValue> hosts_list(new base::ListValue); @@ -327,19 +249,35 @@ for (Category category : content_suggestions_service_->GetCategories()) { CategoryStatus status = content_suggestions_service_->GetCategoryStatus(category); + base::Optional<CategoryInfo> info = + content_suggestions_service_->GetCategoryInfo(category); + DCHECK(info); const std::vector<ContentSuggestion>& suggestions = content_suggestions_service_->GetSuggestionsForCategory(category); + std::vector<ContentSuggestion> dismissed_suggestions = + content_suggestions_service_->GetDismissedSuggestionsForDebugging( + category); std::unique_ptr<base::ListValue> suggestions_list(new base::ListValue); for (const ContentSuggestion& suggestion : suggestions) { suggestions_list->Append(PrepareSuggestion(suggestion, index++)); } + std::unique_ptr<base::ListValue> dismissed_list(new base::ListValue); + for (const ContentSuggestion& suggestion : dismissed_suggestions) { + dismissed_list->Append(PrepareSuggestion(suggestion, index++)); + } + std::unique_ptr<base::DictionaryValue> category_entry( new base::DictionaryValue); - category_entry->SetString("title", GetCategoryTitle(category)); + category_entry->SetInteger("categoryId", category.id()); + category_entry->SetString( + "dismissedContainerId", + "dismissed-suggestions-" + base::IntToString(category.id())); + category_entry->SetString("title", info->title()); category_entry->SetString("status", GetCategoryStatusName(status)); category_entry->Set("suggestions", std::move(suggestions_list)); + category_entry->Set("dismissedSuggestions", std::move(dismissed_list)); categories_list->Append(std::move(category_entry)); }
diff --git a/chrome/browser/ui/webui/snippets_internals_message_handler.h b/chrome/browser/ui/webui/snippets_internals_message_handler.h index 0e127d8..14b2e5a 100644 --- a/chrome/browser/ui/webui/snippets_internals_message_handler.h +++ b/chrome/browser/ui/webui/snippets_internals_message_handler.h
@@ -32,22 +32,18 @@ void RegisterMessages() override; // ntp_snippets::ContentSuggestionsService::Observer: - void OnNewSuggestions() override; + void OnNewSuggestions(ntp_snippets::Category category) override; void OnCategoryStatusChanged( ntp_snippets::Category category, ntp_snippets::CategoryStatus new_status) override; void ContentSuggestionsServiceShutdown() override; void HandleRefreshContent(const base::ListValue* args); - void HandleClear(const base::ListValue* args); - void HandleClearDismissed(const base::ListValue* args); void HandleDownload(const base::ListValue* args); void HandleClearCachedSuggestions(const base::ListValue* args); void HandleClearDismissedSuggestions(const base::ListValue* args); void SendAllContent(); - void SendSnippets(); - void SendDismissedSnippets(); void SendHosts(); void SendContentSuggestions(); void SendBoolean(const std::string& name, bool value);
diff --git a/chrome/browser/ui/webui/translate_internals/translate_internals_ui.cc b/chrome/browser/ui/webui/translate_internals/translate_internals_ui.cc index 1c8fe0b3..86e9384f 100644 --- a/chrome/browser/ui/webui/translate_internals/translate_internals_ui.cc +++ b/chrome/browser/ui/webui/translate_internals/translate_internals_ui.cc
@@ -19,6 +19,7 @@ #include "content/public/browser/web_ui.h" #include "content/public/browser/web_ui_data_source.h" #include "grit/translate_internals_resources.h" +#include "third_party/cld/cld_version.h" #include "ui/base/l10n/l10n_util.h" namespace { @@ -62,7 +63,13 @@ std::string cld_version = ""; // The version string is hardcoded here to avoid linking with the CLD // library, see http://crbug.com/297777. +#if BUILDFLAG(CLD_VERSION) == 2 cld_version = "2"; +#elif BUILDFLAG(CLD_VERSION) == 3 + cld_version = "3"; +#else +# error "CLD_VERSION must be 2 or 3" +#endif source->AddString("cld-version", cld_version); return source;
diff --git a/chrome/browser/ui/webui/usb_internals/BUILD.gn b/chrome/browser/ui/webui/usb_internals/BUILD.gn new file mode 100644 index 0000000..4d0059e3 --- /dev/null +++ b/chrome/browser/ui/webui/usb_internals/BUILD.gn
@@ -0,0 +1,16 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//mojo/public/tools/bindings/mojom.gni") + +mojom("mojo_bindings") { + sources = [ + "usb_internals.mojom", + ] + + public_deps = [ + "//url/mojo:url_mojom_gurl", + "//url/mojo:url_mojom_origin", + ] +}
diff --git a/ash/sysui/public/interfaces/OWNERS b/chrome/browser/ui/webui/usb_internals/OWNERS similarity index 100% copy from ash/sysui/public/interfaces/OWNERS copy to chrome/browser/ui/webui/usb_internals/OWNERS
diff --git a/chrome/browser/ui/webui/usb_internals/usb_internals.mojom b/chrome/browser/ui/webui/usb_internals/usb_internals.mojom new file mode 100644 index 0000000..e6a77a92 --- /dev/null +++ b/chrome/browser/ui/webui/usb_internals/usb_internals.mojom
@@ -0,0 +1,30 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module mojom; + +import "url/mojo/origin.mojom"; +import "url/mojo/url.mojom"; + +struct TestDeviceInfo { + string guid; + string name; + string serial_number; + url.mojom.Url landing_page; + url.mojom.Origin allowed_origin; +}; + +interface UsbInternalsPageHandler { + // Simulate the connection of a new device with the given properties. + AddDeviceForTesting(string name, + string serial_number, + string landing_page, + string allowed_origin) => (bool success, string message); + + // Simulate the disconnection of a device added with the function above. + RemoveDeviceForTesting(string guid) => (); + + // Retrieves the list of test devices added with this API. + GetTestDevices() => (array<TestDeviceInfo> devices); +};
diff --git a/chrome/browser/ui/webui/usb_internals/usb_internals_page_handler.cc b/chrome/browser/ui/webui/usb_internals/usb_internals_page_handler.cc new file mode 100644 index 0000000..5f9117e --- /dev/null +++ b/chrome/browser/ui/webui/usb_internals/usb_internals_page_handler.cc
@@ -0,0 +1,127 @@ +// 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 "chrome/browser/ui/webui/usb_internals/usb_internals_page_handler.h" + +#include "base/macros.h" +#include "base/strings/string16.h" +#include "base/strings/utf_string_conversions.h" +#include "device/core/device_client.h" +#include "device/usb/usb_device.h" +#include "device/usb/usb_device_handle.h" +#include "device/usb/usb_service.h" +#include "device/usb/webusb_descriptors.h" +#include "url/gurl.h" + +namespace { + +class TestUsbDevice : public device::UsbDevice { + public: + TestUsbDevice(const std::string& name, + const std::string& serial_number, + const GURL& landing_page, + const GURL& allowed_origin); + + // device::UsbDevice overrides: + void Open(const OpenCallback& callback) override; + + private: + ~TestUsbDevice() override; + + DISALLOW_COPY_AND_ASSIGN(TestUsbDevice); +}; + +TestUsbDevice::TestUsbDevice(const std::string& name, + const std::string& serial_number, + const GURL& landing_page, + const GURL& allowed_origin) + : UsbDevice(0x0210, + 0xff, + 0xff, + 0xff, + 0x0000, + 0x000, + 0x0100, + base::string16(), + base::UTF8ToUTF16(name), + base::UTF8ToUTF16(serial_number)) { + webusb_allowed_origins_.reset(new device::WebUsbAllowedOrigins()); + webusb_allowed_origins_->origins.push_back(allowed_origin); + webusb_landing_page_ = landing_page; +} + +void TestUsbDevice::Open(const OpenCallback& callback) { + callback.Run(nullptr); +} + +TestUsbDevice::~TestUsbDevice() {} + +} // namespace + +UsbInternalsPageHandler::UsbInternalsPageHandler( + mojom::UsbInternalsPageHandlerRequest request) + : binding_(this, std::move(request)) {} + +UsbInternalsPageHandler::~UsbInternalsPageHandler() {} + +void UsbInternalsPageHandler::AddDeviceForTesting( + const std::string& name, + const std::string& serial_number, + const std::string& landing_page, + const std::string& allowed_origin, + const AddDeviceForTestingCallback& callback) { + device::UsbService* service = device::DeviceClient::Get()->GetUsbService(); + if (service) { + GURL landing_page_url(landing_page); + if (!landing_page_url.is_valid()) { + callback.Run(false, "Landing page URL is invalid."); + return; + } + + GURL allowed_origin_url(allowed_origin); + if (!allowed_origin_url.is_valid()) { + callback.Run(false, "Allowed origin is invalid."); + return; + } + + service->AddDeviceForTesting(new TestUsbDevice( + name, serial_number, landing_page_url, allowed_origin_url)); + callback.Run(true, "Added."); + } else { + callback.Run(false, "USB service unavailable."); + } +} + +void UsbInternalsPageHandler::RemoveDeviceForTesting( + const std::string& guid, + const RemoveDeviceForTestingCallback& callback) { + device::UsbService* service = device::DeviceClient::Get()->GetUsbService(); + if (service) + service->RemoveDeviceForTesting(guid); + callback.Run(); +} + +void UsbInternalsPageHandler::GetTestDevices( + const GetTestDevicesCallback& callback) { + std::vector<scoped_refptr<device::UsbDevice>> devices; + device::UsbService* service = device::DeviceClient::Get()->GetUsbService(); + if (service) + service->GetTestDevices(&devices); + std::vector<mojom::TestDeviceInfoPtr> result; + result.reserve(devices.size()); + for (const auto& device : devices) { + auto device_info = mojom::TestDeviceInfo::New(); + device_info->guid = device->guid(); + device_info->name = base::UTF16ToUTF8(device->product_string()); + device_info->serial_number = base::UTF16ToUTF8(device->serial_number()); + device_info->landing_page = device->webusb_landing_page(); + if (device->webusb_allowed_origins() && + !device->webusb_allowed_origins()->origins.empty()) { + device_info->allowed_origin = + url::Origin(device->webusb_allowed_origins()->origins.front()); + } + result.push_back(std::move(device_info)); + } + callback.Run(std::move(result)); +}
diff --git a/chrome/browser/ui/webui/usb_internals/usb_internals_page_handler.h b/chrome/browser/ui/webui/usb_internals/usb_internals_page_handler.h new file mode 100644 index 0000000..c978a30 --- /dev/null +++ b/chrome/browser/ui/webui/usb_internals/usb_internals_page_handler.h
@@ -0,0 +1,38 @@ +// 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 CHROME_BROWSER_UI_WEBUI_USB_INTERNALS_USB_INTERNALS_PAGE_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_USB_INTERNALS_USB_INTERNALS_PAGE_HANDLER_H_ + +#include "base/macros.h" +#include "chrome/browser/ui/webui/mojo_web_ui_handler.h" +#include "chrome/browser/ui/webui/usb_internals/usb_internals.mojom.h" +#include "mojo/public/cpp/bindings/binding.h" + +class UsbInternalsPageHandler : public mojom::UsbInternalsPageHandler, + public MojoWebUIHandler { + public: + explicit UsbInternalsPageHandler( + mojom::UsbInternalsPageHandlerRequest request); + ~UsbInternalsPageHandler() override; + + // mojom::UsbInternalsPageHandler overrides: + void AddDeviceForTesting( + const std::string& name, + const std::string& serial_number, + const std::string& landing_page, + const std::string& allowed_origin, + const AddDeviceForTestingCallback& callback) override; + void RemoveDeviceForTesting( + const std::string& guid, + const RemoveDeviceForTestingCallback& callback) override; + void GetTestDevices(const GetTestDevicesCallback& callback) override; + + private: + mojo::Binding<mojom::UsbInternalsPageHandler> binding_; + + DISALLOW_COPY_AND_ASSIGN(UsbInternalsPageHandler); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_USB_INTERNALS_USB_INTERNALS_PAGE_HANDLER_H_
diff --git a/chrome/browser/ui/webui/usb_internals/usb_internals_ui.cc b/chrome/browser/ui/webui/usb_internals/usb_internals_ui.cc new file mode 100644 index 0000000..8f0ad17 --- /dev/null +++ b/chrome/browser/ui/webui/usb_internals/usb_internals_ui.cc
@@ -0,0 +1,35 @@ +// 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 "chrome/browser/ui/webui/usb_internals/usb_internals_ui.h" + +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/webui/usb_internals/usb_internals_page_handler.h" +#include "chrome/common/url_constants.h" +#include "chrome/grit/browser_resources.h" +#include "content/public/browser/web_ui_data_source.h" + +UsbInternalsUI::UsbInternalsUI(content::WebUI* web_ui) + : MojoWebUIController(web_ui) { + // Set up the chrome://usb-internals source. + content::WebUIDataSource* source = + content::WebUIDataSource::Create(chrome::kChromeUIUsbInternalsHost); + source->AddResourcePath("usb_internals.css", IDR_USB_INTERNALS_CSS); + source->AddResourcePath("usb_internals.js", IDR_USB_INTERNALS_JS); + source->AddResourcePath( + "chrome/browser/ui/webui/usb_internals/usb_internals.mojom", + IDR_USB_INTERNALS_MOJO_JS); + source->AddResourcePath("url/mojo/origin.mojom", IDR_ORIGIN_MOJO_JS); + source->AddResourcePath("url/mojo/url.mojom", IDR_URL_MOJO_JS); + source->SetDefaultResource(IDR_USB_INTERNALS_HTML); + + content::WebUIDataSource::Add(Profile::FromWebUI(web_ui), source); +} + +UsbInternalsUI::~UsbInternalsUI() {} + +void UsbInternalsUI::BindUIHandler( + mojom::UsbInternalsPageHandlerRequest request) { + page_handler_.reset(new UsbInternalsPageHandler(std::move(request))); +}
diff --git a/chrome/browser/ui/webui/usb_internals/usb_internals_ui.h b/chrome/browser/ui/webui/usb_internals/usb_internals_ui.h new file mode 100644 index 0000000..0b0a343 --- /dev/null +++ b/chrome/browser/ui/webui/usb_internals/usb_internals_ui.h
@@ -0,0 +1,30 @@ +// 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 CHROME_BROWSER_UI_WEBUI_USB_INTERNALS_USB_INTERNALS_UI_H_ +#define CHROME_BROWSER_UI_WEBUI_USB_INTERNALS_USB_INTERNALS_UI_H_ + +#include "base/macros.h" +#include "chrome/browser/ui/webui/mojo_web_ui_controller.h" +#include "chrome/browser/ui/webui/usb_internals/usb_internals.mojom.h" + +class UsbInternalsPageHandler; + +// The WebUI for chrome://usb-internals. +class UsbInternalsUI + : public MojoWebUIController<mojom::UsbInternalsPageHandler> { + public: + explicit UsbInternalsUI(content::WebUI* web_ui); + ~UsbInternalsUI() override; + + private: + // MojoWebUIController overrides: + void BindUIHandler(mojom::UsbInternalsPageHandlerRequest request) override; + + std::unique_ptr<UsbInternalsPageHandler> page_handler_; + + DISALLOW_COPY_AND_ASSIGN(UsbInternalsUI); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_USB_INTERNALS_USB_INTERNALS_UI_H_
diff --git a/chrome/browser/web_dev_style/html_checker.py b/chrome/browser/web_dev_style/html_checker.py index 0c8df98e..bfa063d 100644 --- a/chrome/browser/web_dev_style/html_checker.py +++ b/chrome/browser/web_dev_style/html_checker.py
@@ -67,8 +67,9 @@ def LabelCheck(self, line_number, line): regex = self.input_api.re.compile(""" - (?:^|\s) # start of line or whitespace - (for=) # for= + (?:^|\s) # start of line or whitespace + <label[^>]+? # <label tag + (for=) # for= """, self.input_api.re.VERBOSE) return regex_check.RegexCheck(self.input_api.re, line_number, line, regex,
diff --git a/chrome/browser/web_dev_style/html_checker_test.py b/chrome/browser/web_dev_style/html_checker_test.py index 6767ba40..1a37f46 100755 --- a/chrome/browser/web_dev_style/html_checker_test.py +++ b/chrome/browser/web_dev_style/html_checker_test.py
@@ -170,10 +170,10 @@ def testLabelCheckFails(self): lines = [ - ' for="abc"', - "for= ", - " \tfor= ", - " for=" + ' <label for="abc"', + " <label for= ", + " <label\tfor= ", + ' <label\n blah="1" blee="3"\n for="goop"', ] for line in lines: self.ShouldFailCheck(line, self.checker.LabelCheck) @@ -183,6 +183,7 @@ ' my-for="abc" ', ' myfor="abc" ', " <for", + ' <paper-tooltip for="id-name"', ] for line in lines: self.ShouldPassCheck(line, self.checker.LabelCheck)
diff --git a/chrome/browser/win/jumplist.cc b/chrome/browser/win/jumplist.cc index ab37c55..753c8e55 100644 --- a/chrome/browser/win/jumplist.cc +++ b/chrome/browser/win/jumplist.cc
@@ -399,18 +399,17 @@ const int kRecentlyClosedCount = 4; sessions::TabRestoreService* tab_restore_service = TabRestoreServiceFactory::GetForProfile(profile_); - const sessions::TabRestoreService::Entries& entries = - tab_restore_service->entries(); - for (sessions::TabRestoreService::Entries::const_iterator it = - entries.begin(); - it != entries.end(); ++it) { - const sessions::TabRestoreService::Entry* entry = *it; - if (entry->type == sessions::TabRestoreService::TAB) { - AddTab(static_cast<const sessions::TabRestoreService::Tab*>(entry), - &temp_list, kRecentlyClosedCount); - } else if (entry->type == sessions::TabRestoreService::WINDOW) { - AddWindow(static_cast<const sessions::TabRestoreService::Window*>(entry), - &temp_list, kRecentlyClosedCount); + for (const auto& entry : tab_restore_service->entries()) { + switch (entry->type) { + case sessions::TabRestoreService::TAB: + AddTab(static_cast<const sessions::TabRestoreService::Tab&>(*entry), + &temp_list, kRecentlyClosedCount); + break; + case sessions::TabRestoreService::WINDOW: + AddWindow( + static_cast<const sessions::TabRestoreService::Window&>(*entry), + &temp_list, kRecentlyClosedCount); + break; } } // Lock recently_closed_pages and copy temp_list into it. @@ -427,7 +426,7 @@ void JumpList::TabRestoreServiceDestroyed( sessions::TabRestoreService* service) {} -bool JumpList::AddTab(const sessions::TabRestoreService::Tab* tab, +bool JumpList::AddTab(const sessions::TabRestoreService::Tab& tab, ShellLinkItemList* list, size_t max_items) { DCHECK(CalledOnValidThread()); @@ -439,7 +438,7 @@ scoped_refptr<ShellLinkItem> link = CreateShellLink(); const sessions::SerializedNavigationEntry& current_navigation = - tab->navigations.at(tab->current_navigation_index); + tab.navigations.at(tab.current_navigation_index); std::string url = current_navigation.virtual_url().spec(); link->GetCommandLine()->AppendArgNative(base::UTF8ToWide(url)); link->GetCommandLine()->AppendSwitchASCII( @@ -454,17 +453,17 @@ return true; } -void JumpList::AddWindow(const sessions::TabRestoreService::Window* window, +void JumpList::AddWindow(const sessions::TabRestoreService::Window& window, ShellLinkItemList* list, size_t max_items) { DCHECK(CalledOnValidThread()); // This code enumerates al the tabs in the given window object and add their // URLs and titles to the list. - DCHECK(!window->tabs.empty()); + DCHECK(!window.tabs.empty()); - for (size_t i = 0; i < window->tabs.size(); ++i) { - if (!AddTab(&window->tabs[i], list, max_items)) + for (const auto& tab : window.tabs) { + if (!AddTab(*tab, list, max_items)) return; } }
diff --git a/chrome/browser/win/jumplist.h b/chrome/browser/win/jumplist.h index 24ca8a54..738832c 100644 --- a/chrome/browser/win/jumplist.h +++ b/chrome/browser/win/jumplist.h
@@ -116,10 +116,10 @@ // given list. // These functions are copied from the RecentlyClosedTabsHandler class for // compatibility with the new-tab page. - bool AddTab(const sessions::TabRestoreService::Tab* tab, + bool AddTab(const sessions::TabRestoreService::Tab& tab, ShellLinkItemList* list, size_t max_items); - void AddWindow(const sessions::TabRestoreService::Window* window, + void AddWindow(const sessions::TabRestoreService::Window& window, ShellLinkItemList* list, size_t max_items);
diff --git a/chrome/browser/win/private_working_set_snapshot.cc b/chrome/browser/win/private_working_set_snapshot.cc index c3747db..46269b0 100644 --- a/chrome/browser/win/private_working_set_snapshot.cc +++ b/chrome/browser/win/private_working_set_snapshot.cc
@@ -143,14 +143,14 @@ // Allocate enough space for the results of both queries. std::vector<char> buffer(buffer_size1 * 2); // Retrieve the process ID data. - auto process_id_data = + auto* process_id_data = reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(&buffer[0]); if (PdhGetFormattedCounterArray(counter_pair.process_id_handle, PDH_FMT_LONG, &buffer_size1, &item_count1, process_id_data) != ERROR_SUCCESS) continue; // Retrieve the private working set data. - auto private_ws_data = + auto* private_ws_data = reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(&buffer[buffer_size1]); if (PdhGetFormattedCounterArray(counter_pair.private_ws_handle, PDH_FMT_LARGE, &buffer_size1, &item_count1,
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 84cb63e..51cf1d1a 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi
@@ -40,10 +40,6 @@ 'browser/background_sync/background_sync_permission_context.h', 'browser/bad_message.cc', 'browser/bad_message.h', - 'browser/banners/app_banner_data_fetcher.cc', - 'browser/banners/app_banner_data_fetcher.h', - 'browser/banners/app_banner_debug_log.cc', - 'browser/banners/app_banner_debug_log.h', 'browser/banners/app_banner_manager.cc', 'browser/banners/app_banner_manager.h', 'browser/banners/app_banner_metrics.cc', @@ -618,6 +614,8 @@ 'browser/storage/durable_storage_permission_context.h', 'browser/storage/storage_info_fetcher.cc', 'browser/storage/storage_info_fetcher.h', + 'browser/subresource_filter/chrome_subresource_filter_client.cc', + 'browser/subresource_filter/chrome_subresource_filter_client.h', 'browser/tab_contents/navigation_metrics_recorder.cc', 'browser/tab_contents/navigation_metrics_recorder.h', 'browser/tab_contents/origins_seen_service_factory.cc', @@ -716,8 +714,6 @@ 'browser/android/appmenu/app_menu_drag_helper.h', 'browser/android/background_sync_launcher_android.cc', 'browser/android/background_sync_launcher_android.h', - 'browser/android/banners/app_banner_data_fetcher_android.cc', - 'browser/android/banners/app_banner_data_fetcher_android.h', 'browser/android/banners/app_banner_infobar_delegate_android.cc', 'browser/android/banners/app_banner_infobar_delegate_android.h', 'browser/android/banners/app_banner_manager_android.cc', @@ -1234,14 +1230,10 @@ 'browser/accessibility/invert_bubble_prefs.h', 'browser/background/background_contents.cc', 'browser/background/background_contents.h', - 'browser/banners/app_banner_data_fetcher_desktop.cc', - 'browser/banners/app_banner_data_fetcher_desktop.h', 'browser/banners/app_banner_infobar_delegate_desktop.cc', 'browser/banners/app_banner_infobar_delegate_desktop.h', 'browser/banners/app_banner_manager_desktop.cc', 'browser/banners/app_banner_manager_desktop.h', - 'browser/banners/app_banner_manager_emulation.cc', - 'browser/banners/app_banner_manager_emulation.h', 'browser/bookmarks/bookmark_html_writer.cc', 'browser/bookmarks/bookmark_html_writer.h', 'browser/certificate_viewer.cc', @@ -2391,6 +2383,8 @@ 'browser/permissions/delegation_tracker.h', 'browser/permissions/permission_context_base.cc', 'browser/permissions/permission_context_base.h', + 'browser/permissions/permission_decision_auto_blocker.cc', + 'browser/permissions/permission_decision_auto_blocker.h', 'browser/permissions/permission_infobar_delegate.cc', 'browser/permissions/permission_infobar_delegate.h', 'browser/permissions/permission_manager.cc',
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi index 23f3d83..d67a046 100644 --- a/chrome/chrome_browser_ui.gypi +++ b/chrome/chrome_browser_ui.gypi
@@ -385,6 +385,10 @@ 'browser/ui/webui/translate_internals/translate_internals_handler.h', 'browser/ui/webui/translate_internals/translate_internals_ui.cc', 'browser/ui/webui/translate_internals/translate_internals_ui.h', + 'browser/ui/webui/usb_internals/usb_internals_page_handler.cc', + 'browser/ui/webui/usb_internals/usb_internals_page_handler.h', + 'browser/ui/webui/usb_internals/usb_internals_ui.cc', + 'browser/ui/webui/usb_internals/usb_internals_ui.h', 'browser/ui/webui/user_actions/user_actions_ui.cc', 'browser/ui/webui/user_actions/user_actions_ui.h', 'browser/ui/webui/user_actions/user_actions_ui_handler.cc', @@ -1907,6 +1911,8 @@ 'browser/ui/webui/md_downloads/md_downloads_dom_handler.h', 'browser/ui/webui/md_downloads/md_downloads_ui.cc', 'browser/ui/webui/md_downloads/md_downloads_ui.h', + 'browser/ui/webui/md_feedback/md_feedback_dialog_controller.cc', + 'browser/ui/webui/md_feedback/md_feedback_dialog_controller.h', 'browser/ui/webui/md_feedback/md_feedback_ui.cc', 'browser/ui/webui/md_feedback/md_feedback_ui.h', 'browser/ui/webui/md_history_ui.cc',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index fd2e766c..4275191 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi
@@ -77,7 +77,7 @@ 'browser/autofill/autofill_server_browsertest.cc', 'browser/autofill/content_autofill_driver_browsertest.cc', 'browser/autofill/form_structure_browsertest.cc', - 'browser/banners/app_banner_data_fetcher_browsertest.cc', + 'browser/banners/app_banner_manager_browsertest.cc', 'browser/bitmap_fetcher/bitmap_fetcher_browsertest.cc', 'browser/browser_encoding_browsertest.cc', 'browser/browsing_data/autofill_counter_browsertest.cc',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index 30a94de..a381b73 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi
@@ -39,7 +39,6 @@ 'browser/autocomplete/shortcuts_provider_extension_unittest.cc', 'browser/background_sync/background_sync_controller_impl_unittest.cc', 'browser/background_sync/background_sync_permission_context_unittest.cc', - 'browser/banners/app_banner_data_fetcher_unittest.cc', 'browser/banners/app_banner_settings_helper_unittest.cc', 'browser/bitmap_fetcher/bitmap_fetcher_service_unittest.cc', 'browser/bookmarks/managed_bookmark_service_unittest.cc', @@ -181,6 +180,7 @@ 'browser/permissions/chooser_context_base_unittest.cc', 'browser/permissions/delegation_tracker_unittest.cc', 'browser/permissions/permission_context_base_unittest.cc', + 'browser/permissions/permission_decision_auto_blocker_unittest.cc', 'browser/permissions/permission_manager_unittest.cc', 'browser/permissions/permission_uma_util_unittest.cc', 'browser/permissions/permission_util_unittest.cc', @@ -1115,6 +1115,7 @@ 'browser/chromeos/power/renderer_freezer_unittest.cc', 'browser/chromeos/preferences_unittest.cc', 'browser/chromeos/printer_detector/printer_detector_unittest.cc', + 'browser/chromeos/printing/printer_pref_manager_unittest.cc', 'browser/chromeos/profiles/profile_list_chromeos_unittest.cc', 'browser/chromeos/proxy_config_service_impl_unittest.cc', 'browser/chromeos/resource_reporter/resource_reporter_unittest.cc',
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc index e6e4089e..dd6ee356 100644 --- a/chrome/common/chrome_features.cc +++ b/chrome/common/chrome_features.cc
@@ -34,6 +34,11 @@ "BackspaceGoesBack", base::FEATURE_DISABLED_BY_DEFAULT }; +// Enables or disables whether permission prompts are automatically blocked +// after the user has explicitly dismissed them too many times. +const base::Feature kBlockPromptsIfDismissedOften{ + "BlockPromptsIfDismissedOften", base::FEATURE_DISABLED_BY_DEFAULT}; + // Experiment to disable small cross-origin content. (http://crbug.com/608886) const base::Feature kBlockSmallContent{"BlockSmallPluginContent", base::FEATURE_DISABLED_BY_DEFAULT}; @@ -72,6 +77,9 @@ const base::Feature kMaterialDesignExtensions{ "MaterialDesignExtensions", base::FEATURE_DISABLED_BY_DEFAULT}; #endif +// Enables YouTube Flash videos to be overriden. +const base::Feature kOverrideYouTubeFlashEmbed{ + "override-youtube-flash-emed", base::FEATURE_ENABLED_BY_DEFAULT}; // Enables or disables the Material Design version of chrome://history. const base::Feature kMaterialDesignHistory{
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h index 0c3fb8ea..8214ec0 100644 --- a/chrome/common/chrome_features.h +++ b/chrome/common/chrome_features.h
@@ -29,6 +29,8 @@ extern const base::Feature kBackspaceGoesBackFeature; +extern const base::Feature kBlockPromptsIfDismissedOften; + extern const base::Feature kBlockSmallContent; extern const base::Feature kBrowserHangFixesExperiment; @@ -55,6 +57,8 @@ extern const base::Feature kPreferHtmlOverPlugins; +extern const base::Feature kOverrideYouTubeFlashEmbed; + #if defined(OS_CHROMEOS) extern const base::Feature kRuntimeMemoryLeakDetector; #endif // defined(OS_CHROMEOS)
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index abcd3fa..7985e3e 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc
@@ -1081,9 +1081,6 @@ // Sets the market URL for Chrome for use in testing. const char kMarketUrlForTesting[] = "market-url-for-testing"; -// Turns on auto-merging of tabs in multi-instance mode. -const char kMultiInstanceMergeTabs[] = "multi-instance-merge-tabs"; - // Switch to an existing tab for a suggestion opened from the New Tab Page. const char kNtpSwitchToExistingTab[] = "ntp-switch-to-existing-tab"; @@ -1109,9 +1106,6 @@ #endif // defined(OS_ANDROID) #if defined(OS_CHROMEOS) -// Enables the intent picker so the user can handle URL links with ARC apps. -const char kEnableIntentPicker[] = "enable-intent-picker"; - // Enables native cups integration const char kEnableNativeCups[] = "enable-native-cups"; #endif // defined(OS_CHROMEOS)
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index b6aa0cbf..64a2e84 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h
@@ -300,7 +300,6 @@ extern const char kForceShowUpdateMenuItemNewFeaturesSummary[]; extern const char kForceShowUpdateMenuItemSummary[]; extern const char kMarketUrlForTesting[]; -extern const char kMultiInstanceMergeTabs[]; extern const char kNtpSwitchToExistingTab[]; extern const char kProgressBarAnimation[]; extern const char kTabManagementExperimentTypeAnise[]; @@ -313,7 +312,6 @@ #endif // defined(OS_ANDROID) #if defined(OS_CHROMEOS) -extern const char kEnableIntentPicker[]; extern const char kEnableNativeCups[]; #endif // defined(OS_CHROMEOS)
diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json index ac89fe8..7a605d5 100644 --- a/chrome/common/extensions/api/_permission_features.json +++ b/chrome/common/extensions/api/_permission_features.json
@@ -969,7 +969,11 @@ // Hangouts test extension "80B9DC58E5210749F052F5B4DB239C50CF72AEB6", // Hangout Services component extension. - "DF84F03F9B960409CCDE0D895B9650EBE81C0A8E" + "DF84F03F9B960409CCDE0D895B9650EBE81C0A8E", + // Media Router dev extension + "63ED55E43214C211F82122ED56407FF1A807F2A3", + // Media Router release extension + "226CF815E39A363090A1E547D53063472B8279FA" ] }, "webstorePrivate": {
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc index 2c663ce..4cde4ae 100644 --- a/chrome/common/url_constants.cc +++ b/chrome/common/url_constants.cc
@@ -250,6 +250,7 @@ const char kChromeUITranslateInternalsHost[] = "translate-internals"; const char kChromeUIUberFrameHost[] = "uber-frame"; const char kChromeUIUberHost[] = "chrome"; +const char kChromeUIUsbInternalsHost[] = "usb-internals"; const char kChromeUIUserActionsHost[] = "user-actions"; const char kChromeUIVersionHost[] = "version"; const char kChromeUIWorkersHost[] = "workers"; @@ -625,6 +626,7 @@ kChromeUITermsHost, kChromeUIThumbnailListHost, kChromeUITranslateInternalsHost, + kChromeUIUsbInternalsHost, kChromeUIUserActionsHost, kChromeUIVersionHost, content::kChromeUIAccessibilityHost,
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h index c0b81bc..aea5622 100644 --- a/chrome/common/url_constants.h +++ b/chrome/common/url_constants.h
@@ -233,6 +233,7 @@ extern const char kChromeUITranslateInternalsHost[]; extern const char kChromeUIUberFrameHost[]; extern const char kChromeUIUberHost[]; +extern const char kChromeUIUsbInternalsHost[]; extern const char kChromeUIUserActionsHost[]; extern const char kChromeUIVersionHost[]; extern const char kChromeUIWorkersHost[];
diff --git a/chrome/installer/mac/BUILD.gn b/chrome/installer/mac/BUILD.gn index 0bf5b56..90510059 100644 --- a/chrome/installer/mac/BUILD.gn +++ b/chrome/installer/mac/BUILD.gn
@@ -10,7 +10,7 @@ public_deps = [ ":copies", ":make_signers", - "app:mac_installer", + "app:mac_installer_app", ] }
diff --git a/chrome/installer/mac/app/AppDelegate.h b/chrome/installer/mac/app/AppDelegate.h new file mode 100644 index 0000000..2e841f8d --- /dev/null +++ b/chrome/installer/mac/app/AppDelegate.h
@@ -0,0 +1,16 @@ +// 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 CHROME_INSTALLER_MAC_APP_APPDELEGATE_H_ +#define CHROME_INSTALLER_MAC_APP_APPDELEGATE_H_ + +#import <AppKit/AppKit.h> + +#import "Downloader.h" +#import "OmahaCommunication.h" + +@interface AppDelegate : NSObject<NSApplicationDelegate> +@end + +#endif // CHROME_INSTALLER_MAC_APP_APPDELEGATE_H_
diff --git a/chrome/installer/mac/app/AppDelegate.m b/chrome/installer/mac/app/AppDelegate.m new file mode 100644 index 0000000..f60f0db --- /dev/null +++ b/chrome/installer/mac/app/AppDelegate.m
@@ -0,0 +1,102 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "AppDelegate.h" + +#import "InstallerWindowController.h" +#import "NSError+ChromeInstallerAdditions.h" +#import "NSAlert+ChromeInstallerAdditions.h" + +@interface NSAlert () +- (void)beginSheetModalForWindow:(NSWindow*)sheetWindow + completionHandler: + (void (^__nullable)(NSModalResponse returnCode))handler; +@end + +@interface AppDelegate ()<OmahaCommunicationDelegate, DownloaderDelegate> { + InstallerWindowController* installerWindowController_; +} +@property(strong) NSWindow* window; +@end + +@implementation AppDelegate +@synthesize window = window_; + +// Sets up the main window and begins the downloading process. +- (void)applicationDidFinishLaunching:(NSNotification*)aNotification { + installerWindowController_ = + [[InstallerWindowController alloc] initWithWindow:window_]; + [self startDownload]; +} + +- (void)applicationWillTerminate:(NSNotification*)aNotification { +} + +- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender { + return YES; +} + +- (void)startDownload { + [installerWindowController_ updateStatusDescription:@"Initializing..."]; + OmahaCommunication* omahaMessenger = [[OmahaCommunication alloc] init]; + omahaMessenger.delegate = self; + + [omahaMessenger fetchDownloadURLs]; +} + +- (void)onOmahaSuccessWithURLs:(NSArray*)URLs { + [installerWindowController_ updateStatusDescription:@"Downloading..."]; + Downloader* download = [[Downloader alloc] init]; + download.delegate = self; + [download downloadChromeImageToDownloadsDirectory:[URLs firstObject]]; +} + +- (void)onOmahaFailureWithError:(NSError*)error { + NSError* networkError = + [NSError errorForAlerts:@"Network Error" + withDescription:@"Could not connect to Chrome server." + isRecoverable:YES]; + [self displayError:networkError]; +} + +// Bridge method from Downloader to InstallerWindowController. Allows Downloader +// to update the progressbar without having direct access to any UI obejcts. +- (void)didDownloadData:(double)downloadProgressPercentage { + [installerWindowController_ + updateDownloadProgress:(double)downloadProgressPercentage]; +} + +- (void)downloader:(Downloader*)download + onDownloadSuccess:(NSURL*)diskImagePath { + [installerWindowController_ updateStatusDescription:@"Done."]; + // TODO: replace the line of code below with real code someday +} + +- (void)downloader:(Downloader*)download + onDownloadFailureWithError:(NSError*)error { + NSError* downloadError = + [NSError errorForAlerts:@"Download Failure" + withDescription:@"Unable to download Google Chrome." + isRecoverable:NO]; + [self displayError:downloadError]; +} + +// Displays an alert on the main window using the contents of the passed in +// error. +- (void)displayError:(NSError*)error { + NSAlert* alertForUser = [NSAlert alertWithError:error]; + + dispatch_sync(dispatch_get_main_queue(), ^{ + [alertForUser beginSheetModalForWindow:window_ + completionHandler:^(NSModalResponse returnCode) { + if (returnCode != [alertForUser quitButton]) { + [self startDownload]; + } else { + [NSApp terminate:nil]; + } + }]; + }); +} + +@end
diff --git a/chrome/installer/mac/app/BUILD.gn b/chrome/installer/mac/app/BUILD.gn index c5545e8..31101a70 100644 --- a/chrome/installer/mac/app/BUILD.gn +++ b/chrome/installer/mac/app/BUILD.gn
@@ -3,12 +3,13 @@ # found in the LICENSE file. import("//testing/test.gni") +import("//build/config/mac/rules.gni") -static_library("mac_installer_base") { +source_set("mac_installer_base") { sources = [ "Downloader.m", - "MainDelegate.m", - "NetworkCommunication.m", + "NSAlert+ChromeInstallerAdditions.m", + "NSError+ChromeInstallerAdditions.m", "OmahaCommunication.m", "OmahaXMLParser.m", "OmahaXMLRequest.m", @@ -16,6 +17,32 @@ ] } +mac_app_bundle("mac_installer_app") { + info_plist = "Info.plist" + extra_substitutions = [ "MACOSX_DEPLOYMENT_TARGET=10.9" ] + sources = [ + "AppDelegate.m", + "InstallerWindowController.m", + "main.m", + ] + + deps = [ + ":mac_installer_base", + ":mac_installer_xibs", + ] + + libs = [ + "AppKit.framework", + "CoreFoundation.framework", + ] +} + +mac_xib_bundle_data("mac_installer_xibs") { + sources = [ + "MainMenu.xib", + ] +} + executable("mac_installer") { sources = [ "main.m", @@ -23,10 +50,14 @@ deps = [ ":mac_installer_base", ] - libs = [ "Foundation.framework" ] + + libs = [ + "AppKit.framework", + "CoreFoundation.framework", + ] } -test("mac_installer_test") { +test("mac_installer_unittests") { sources = [ "testing/OmahaXMLRequest_test.mm", "testing/SystemInfo_test.mm", @@ -38,4 +69,9 @@ "//testing/gtest:gtest", ] libs = [ "Foundation.framework" ] + data = [ + "testing/requestCheck.dtd", + "testing/requestSample.xml", + "testing/responseExample.xml", + ] }
diff --git a/chrome/installer/mac/app/Downloader.h b/chrome/installer/mac/app/Downloader.h index 06e53931..72c63ad7 100644 --- a/chrome/installer/mac/app/Downloader.h +++ b/chrome/installer/mac/app/Downloader.h
@@ -7,24 +7,25 @@ #import <Foundation/Foundation.h> +@class Downloader; @protocol DownloaderDelegate -- (void)onDownloadSuccess; +- (void)didDownloadData:(double)downloadProgressPercentage; +- (void)downloader:(Downloader*)download + onDownloadSuccess:(NSURL*)diskImagePath; +- (void)downloader:(Downloader*)download + onDownloadFailureWithError:(NSError*)error; @end -@interface Downloader - : NSObject<NSXMLParserDelegate, NSURLSessionDownloadDelegate> +@interface Downloader : NSObject<NSURLSessionDownloadDelegate> @property(nonatomic, assign) id<DownloaderDelegate> delegate; -// Returns a path to a user's home download folder. -+ (NSString*)getDownloadsFilePath; - -- (NSMutableArray*)appendFilename:(NSString*)filename - toURLs:(NSArray*)incompleteURLs; - // Takes an NSData with a response XML from Omaha and writes the latest // version of chrome to the user's download directory. -- (BOOL)downloadChromeImageToDownloadsDirectory:(NSData*)omahaResponseXML; +- (void)downloadChromeImageToDownloadsDirectory:(NSURL*)chromeImageURL; + +// Returns a path to a user's home download folder. ++ (NSString*)getChromeDownloadFilePath; @end
diff --git a/chrome/installer/mac/app/Downloader.m b/chrome/installer/mac/app/Downloader.m index 25490da..ff773dc 100644 --- a/chrome/installer/mac/app/Downloader.m +++ b/chrome/installer/mac/app/Downloader.m
@@ -6,90 +6,39 @@ #include <assert.h> -#import "NetworkCommunication.h" -#import "OmahaXMLParser.h" - @implementation Downloader @synthesize delegate = delegate_; -// TODO: make this overrideable with commandline argument? or enviro variable -+ (NSString*)getDownloadsFilePath { ++ (NSString*)getChromeDownloadFilePath { NSArray* downloadPaths = NSSearchPathForDirectoriesInDomains( NSDownloadsDirectory, NSUserDomainMask, YES); - NSString* filePathToDownloads = [downloadPaths objectAtIndex:0]; - NSArray* filenameComposition = @[ filePathToDownloads, @"GoogleChrome.dmg" ]; - NSString* completeFilePath = - [NSString pathWithComponents:filenameComposition]; + NSString* completeFilePath = [NSString + pathWithComponents:@[ [downloadPaths firstObject], @"GoogleChrome.dmg" ]]; return completeFilePath; } -// The URLs extracted from parseXML are incomplete and need the filename (which -// is the same for all the links) appended to the end. Iterates through -// chromeIncompleteDownloadURLs_ and appends chromeImageFilename_ to each URL. -- (NSMutableArray*)appendFilename:(NSString*)filename - toURLs:(NSArray*)incompleteURLs { - NSMutableArray* completeURLs = [[NSMutableArray alloc] init]; - - for (NSString* URL in incompleteURLs) { - [completeURLs addObject:[NSURL URLWithString:filename - relativeToURL:[NSURL URLWithString:URL]]]; - } - return completeURLs; -} - -// Extract URLs and the filename from the omahaResponseXML. Then complete the -// URLs by appending filename and returns the first complete URL. -- (NSURL*)getChromeImageURLFromOmahaResponse:(NSData*)omahaResponseXML { - NSError* err = nil; - - OmahaXMLParser* parser = [[OmahaXMLParser alloc] init]; - NSArray* incompleteURLs = [parser parseXML:omahaResponseXML error:&err]; - - if ([incompleteURLs count] < 1) { - // TODO: Error handling and implement way to verify URL is working. Error - // information saved in "err". - } - - NSMutableArray* completeURLs = - [self appendFilename:parser.chromeImageFilename toURLs:incompleteURLs]; - - NSURL* chromeURL = [completeURLs firstObject]; - return chromeURL; -} - // Downloads contents of chromeURL to downloads folders and delegates the work // to the DownloadDelegate class. -- (BOOL)writeChromeImageToDownloadsDirectory:(NSURL*)chromeURL { - NetworkCommunication* downloadTask = - [[NetworkCommunication alloc] initWithDelegate:self]; - - // TODO: What if file already exists? - [downloadTask createRequestWithUrlAsString:[chromeURL absoluteString] - andXMLBody:nil]; - [downloadTask sendDownloadRequest]; - - NSFileManager* manager = [[NSFileManager alloc] init]; - return [manager fileExistsAtPath:[Downloader getDownloadsFilePath]]; +- (void)downloadChromeImageToDownloadsDirectory:(NSURL*)chromeImageURL { + NSURLSession* session = + [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration + defaultSessionConfiguration] + delegate:self + delegateQueue:nil]; + [[session downloadTaskWithURL:chromeImageURL] resume]; + [session finishTasksAndInvalidate]; } -// Pieces together the getting the URL portion and downloading the contents of -// URL portion. -- (BOOL)downloadChromeImageToDownloadsDirectory:(NSData*)omahaResponseXML { - NSURL* chromeURL = [self getChromeImageURLFromOmahaResponse:omahaResponseXML]; - BOOL writeWasSuccessful = - [self writeChromeImageToDownloadsDirectory:chromeURL]; - return writeWasSuccessful; -} - -// Skeleton of delegate method to provide download progress updates. -// TODO: Make use of (totalBytesWritten/totalBytesExpectedToWrite)*100 -// to generate download progress percentage. +// Provides updates to download progress. - (void)URLSession:(NSURLSession*)session downloadTask:(NSURLSessionDownloadTask*)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite { + double downloadProgressPercentage = + (double)totalBytesWritten / totalBytesExpectedToWrite * 100.0; + [delegate_ didDownloadData:downloadProgressPercentage]; } // Delegate method to move downloaded disk image to user's Download directory. @@ -97,22 +46,25 @@ downloadTask:(NSURLSessionDownloadTask*)downloadTask didFinishDownloadingToURL:(NSURL*)location { assert([location isFileURL]); - NSFileManager* manager = [[NSFileManager alloc] init]; + NSFileManager* manager = [NSFileManager defaultManager]; NSURL* downloadsDirectory = - [[NSURL alloc] initFileURLWithPath:[Downloader getDownloadsFilePath]]; - if ([manager fileExistsAtPath:location.path]) { - [manager moveItemAtURL:location toURL:downloadsDirectory error:nil]; - } else { - // TODO: Error Handling + [NSURL fileURLWithPath:[Downloader getChromeDownloadFilePath]]; + NSError* fileManagerError = nil; + [manager moveItemAtURL:location + toURL:downloadsDirectory + error:&fileManagerError]; + if (fileManagerError) { + [delegate_ downloader:self onDownloadFailureWithError:fileManagerError]; } + [delegate_ downloader:self onDownloadSuccess:location]; } - (void)URLSession:(NSURLSession*)session task:(NSURLSessionTask*)task didCompleteWithError:(NSError*)error { - // TODO: Error Handling - - [delegate_ onDownloadSuccess]; + if (error) { + [delegate_ downloader:self onDownloadFailureWithError:error]; + } } @end
diff --git a/chrome/installer/mac/app/Info.plist b/chrome/installer/mac/app/Info.plist new file mode 100644 index 0000000..c671e44 --- /dev/null +++ b/chrome/installer/mac/app/Info.plist
@@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>en</string> + <key>CFBundleExecutable</key> + <string>$(EXECUTABLE_NAME)</string> + <key>CFBundleIconFile</key> + <string></string> + <key>CFBundleIdentifier</key> + <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>$(PRODUCT_NAME)</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleShortVersionString</key> + <string>1.0</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleVersion</key> + <string>1</string> + <key>LSMinimumSystemVersion</key> + <string>$(MACOSX_DEPLOYMENT_TARGET)</string> + <key>NSHumanReadableCopyright</key> + <string>Copyright © 2016 Google. All rights reserved.</string> + <key>NSMainNibFile</key> + <string>MainMenu</string> + <key>NSPrincipalClass</key> + <string>NSApplication</string> + <key>NSAppTransportSecurity</key> + <dict> + <key>NSExceptionDomains</key> + <dict> + <key>google.com</key> + <dict> + <key>NSIncludesSubdomains</key> + <true/> + <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key> + <true/> + </dict> + <key>gvt1.com</key> + <dict> + <key>NSIncludesSubdomains</key> + <true/> + <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key> + <true/> + </dict> + </dict> + </dict> +</dict> +</plist>
diff --git a/chrome/installer/mac/app/InstallerWindowController.h b/chrome/installer/mac/app/InstallerWindowController.h new file mode 100644 index 0000000..4b30ad62 --- /dev/null +++ b/chrome/installer/mac/app/InstallerWindowController.h
@@ -0,0 +1,18 @@ +// 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 CHROME_INSTALLER_MAC_APP_INSTALLERWINDOWCONTROLLER_H_ +#define CHROME_INSTALLER_MAC_APP_INSTALLERWINDOWCONTROLLER_H_ + +#import <AppKit/AppKit.h> + +@interface InstallerWindowController : NSWindowController + +- (id)initWithWindow:(NSWindow*)window; +- (void)updateStatusDescription:(NSString*)text; +- (void)updateDownloadProgress:(double)progressPercent; + +@end + +#endif // CHROME_INSTALLER_MAC_APP_INSTALLERWINDOWCONTROLLER_H_
diff --git a/chrome/installer/mac/app/InstallerWindowController.m b/chrome/installer/mac/app/InstallerWindowController.m new file mode 100644 index 0000000..a69a562 --- /dev/null +++ b/chrome/installer/mac/app/InstallerWindowController.m
@@ -0,0 +1,117 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "InstallerWindowController.h" + +#import "AppDelegate.h" + +@interface InstallerWindowController () { + NSButton* importButton_; + NSButton* defaultBrowserButton_; + NSButton* optInButton_; + NSTextField* statusDescription_; + NSTextField* downloadProgressDescription_; + NSProgressIndicator* progressBar_; +} +@end + +@implementation InstallerWindowController + +// All buttons have the same style and differ only by their title, this method +// simplifies styling the buttons and provides an argument for the title. +- (void)stylizeButton:(NSButton*)button withTitle:(NSString*)title { + button.buttonType = NSSwitchButton; + button.bezelStyle = NSRoundedBezelStyle; + button.title = title; +} + +// Similar to stylizeButton except works with NSTextField objects instead. +- (void)stylizeTextField:(NSTextField*)textField + withDescription:(NSString*)description { + textField.backgroundColor = NSColor.clearColor; + textField.textColor = NSColor.blackColor; + textField.stringValue = description; + textField.bezeled = NO; + textField.editable = NO; +} + +// Positions and stylizes buttons. +- (void)setUpButtons { + importButton_ = [[NSButton alloc] initWithFrame:NSMakeRect(30, 20, 300, 25)]; + [self stylizeButton:importButton_ + withTitle:@"Import from... Wait import what?"]; + + defaultBrowserButton_.state = NSOnState; + defaultBrowserButton_ = + [[NSButton alloc] initWithFrame:NSMakeRect(30, 45, 300, 25)]; + [self stylizeButton:defaultBrowserButton_ + withTitle:@"Make Chrome the default browser."]; + + optInButton_ = [[NSButton alloc] initWithFrame:NSMakeRect(30, 70, 300, 25)]; + [self stylizeButton:optInButton_ withTitle:@"Say yes to UMA."]; +} + +// Positions and stylizes textfields. +- (void)setUpTextfields { + statusDescription_ = + [[NSTextField alloc] initWithFrame:NSMakeRect(20, 95, 300, 20)]; + [self stylizeTextField:statusDescription_ + withDescription:@"Working on it! While you're waiting..."]; + + downloadProgressDescription_ = + [[NSTextField alloc] initWithFrame:NSMakeRect(20, 160, 300, 20)]; + [self stylizeTextField:downloadProgressDescription_ + withDescription:@"Downloading... "]; +} + +// Positions and stylizes the progressbar for download and install. +- (void)setUpProgressBar { + progressBar_ = + [[NSProgressIndicator alloc] initWithFrame:NSMakeRect(20, 125, 400, 50)]; + progressBar_.indeterminate = NO; + progressBar_.style = NSProgressIndicatorBarStyle; + progressBar_.maxValue = 100.0; + progressBar_.minValue = 0.0; + progressBar_.doubleValue = 0.0; +} + +// Positions and adds the rest of the UI elements to main window. Prevents +// resizing the window so that the absolute position will look the same on all +// computers. Window is hidden until all positioning is finished. +- (id)initWithWindow:(NSWindow*)window { + if (self = [super initWithWindow:window]) { + [window setFrame:NSMakeRect(0, 0, 430, 220) display:YES]; + [window center]; + [window setStyleMask:[window styleMask] & ~NSResizableWindowMask]; + + [self setUpButtons]; + [self setUpProgressBar]; + [self setUpTextfields]; + + [window.contentView addSubview:importButton_]; + [window.contentView addSubview:defaultBrowserButton_]; + [window.contentView addSubview:optInButton_]; + [window.contentView addSubview:progressBar_]; + [window.contentView addSubview:statusDescription_]; + [window.contentView addSubview:downloadProgressDescription_]; + [NSApp activateIgnoringOtherApps:YES]; + [window makeKeyAndOrderFront:self]; + } + return self; +} + +- (void)updateStatusDescription:(NSString*)text { + // First setStringValue statement is required to clear the original string. + // Omitting the first line will cause occasional ghosting of the previous + // string. + // TODO: Find a real solution to the ghosting problem. + // downloadProgressDescription_.stringValue = @""; + downloadProgressDescription_.stringValue = text; +} + +- (void)updateDownloadProgress:(double)progressPercent { + progressBar_.doubleValue = progressPercent; +} + +@end
diff --git a/chrome/installer/mac/app/MainDelegate.h b/chrome/installer/mac/app/MainDelegate.h index efbe36f..3b2a03c0 100644 --- a/chrome/installer/mac/app/MainDelegate.h +++ b/chrome/installer/mac/app/MainDelegate.h
@@ -10,13 +10,8 @@ #import "Downloader.h" #import "OmahaCommunication.h" -// TODO: move this into the unpacking file when created -@protocol UnpackDelegate -- (void)onUnpackSuccess; -@end - @interface MainDelegate - : NSObject<OmahaCommunicationDelegate, DownloaderDelegate, UnpackDelegate> + : NSObject<OmahaCommunicationDelegate, DownloaderDelegate> - (void)runApplication; @end
diff --git a/chrome/installer/mac/app/MainDelegate.m b/chrome/installer/mac/app/MainDelegate.m index 9662b5b..0a9c28da 100644 --- a/chrome/installer/mac/app/MainDelegate.m +++ b/chrome/installer/mac/app/MainDelegate.m
@@ -7,30 +7,33 @@ @implementation MainDelegate - (void)runApplication { - OmahaCommunication* messenger = [[OmahaCommunication alloc] init]; - messenger.delegate = self; + OmahaCommunication* omahaMessenger = [[OmahaCommunication alloc] init]; + omahaMessenger.delegate = self; - [messenger sendRequest]; + [omahaMessenger fetchDownloadURLs]; } -- (void)onOmahaSuccessWithResponseBody:(NSData*)responseBody - AndError:(NSError*)error { - if (error) { - NSLog(@"error: %@", [error localizedDescription]); - exit(1); - } +- (void)onOmahaSuccessWithURLs:(NSArray*)URLs { Downloader* download = [[Downloader alloc] init]; download.delegate = self; - [download downloadChromeImageToDownloadsDirectory:responseBody]; + [download downloadChromeImageToDownloadsDirectory:[URLs firstObject]]; +} + +- (void)onOmahaFailureWithError:(NSError*)error { + NSLog(@"error: %@", [error localizedDescription]); + exit(1); } - (void)onDownloadSuccess { - // TODO: replace the line of code below with real code someday to unpack dmg + NSLog(@"end of program, exiting."); + NSLog(@"in the ideal world, we would be unpacking now"); exit(0); } -- (void)onUnpackSuccess { +- (void)onDownloadFailureWithError:(NSError*)error { + NSLog(@"error: %@", [error localizedDescription]); + exit(1); } @end
diff --git a/chrome/installer/mac/app/MainMenu.xib b/chrome/installer/mac/app/MainMenu.xib new file mode 100644 index 0000000..acd03d0b --- /dev/null +++ b/chrome/installer/mac/app/MainMenu.xib
@@ -0,0 +1,294 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="15G31" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct"> + <dependencies> + <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/> + </dependencies> + <objects> + <customObject id="-2" userLabel="File's Owner" customClass="NSApplication"> + <connections> + <outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/> + </connections> + </customObject> + <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/> + <customObject id="-3" userLabel="Application" customClass="NSObject"/> + <customObject id="Voe-Tx-rLC" customClass="AppDelegate"> + <connections> + <outlet property="window" destination="QvC-M9-y7g" id="gIp-Ho-8D9"/> + </connections> + </customObject> + <customObject id="YLy-65-1bz" customClass="NSFontManager"/> + <menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6"> + <items> + <menuItem title="Google Chrome Installer" id="1Xt-HY-uBw"> + <modifierMask key="keyEquivalentModifierMask"/> + <menu key="submenu" title="Google Chrome Installer" systemMenu="apple" id="uQy-DD-JDr"> + <items> + <menuItem title="Services" id="NMo-om-nkz"> + <modifierMask key="keyEquivalentModifierMask"/> + <menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/> + </menuItem> + <menuItem isSeparatorItem="YES" id="4je-JR-u6R"/> + <menuItem title="Hide Google Chrome Installer" keyEquivalent="h" id="Olw-nP-bQN"> + <connections> + <action selector="hide:" target="-1" id="PnN-Uc-m68"/> + </connections> + </menuItem> + <menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO"> + <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> + <connections> + <action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/> + </connections> + </menuItem> + <menuItem title="Show All" id="Kd2-mp-pUS"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/> + </connections> + </menuItem> + <menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/> + <menuItem title="Quit Google Chrome Installer" keyEquivalent="q" id="4sb-4s-VLi"> + <connections> + <action selector="terminate:" target="-1" id="Te7-pn-YzF"/> + </connections> + </menuItem> + </items> + </menu> + </menuItem> + <menuItem title="File" id="dMs-cI-mzQ"> + <modifierMask key="keyEquivalentModifierMask"/> + <menu key="submenu" title="File" id="bib-Uj-vzu"> + <items> + <menuItem title="Close" keyEquivalent="w" id="DVo-aG-piG"> + <connections> + <action selector="performClose:" target="-1" id="HmO-Ls-i7Q"/> + </connections> + </menuItem> + </items> + </menu> + </menuItem> + <menuItem title="Edit" id="5QF-Oa-p0T"> + <modifierMask key="keyEquivalentModifierMask"/> + <menu key="submenu" title="Edit" id="W48-6f-4Dl"> + <items> + <menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg"> + <connections> + <action selector="undo:" target="-1" id="M6e-cu-g7V"/> + </connections> + </menuItem> + <menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam"> + <connections> + <action selector="redo:" target="-1" id="oIA-Rs-6OD"/> + </connections> + </menuItem> + <menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/> + <menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG"> + <connections> + <action selector="cut:" target="-1" id="YJe-68-I9s"/> + </connections> + </menuItem> + <menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU"> + <connections> + <action selector="copy:" target="-1" id="G1f-GL-Joy"/> + </connections> + </menuItem> + <menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL"> + <connections> + <action selector="paste:" target="-1" id="UvS-8e-Qdg"/> + </connections> + </menuItem> + <menuItem title="Delete" id="pa3-QI-u2k"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="delete:" target="-1" id="0Mk-Ml-PaM"/> + </connections> + </menuItem> + <menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m"> + <connections> + <action selector="selectAll:" target="-1" id="VNm-Mi-diN"/> + </connections> + </menuItem> + <menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/> + <menuItem title="Spelling and Grammar" id="Dv1-io-Yv7"> + <modifierMask key="keyEquivalentModifierMask"/> + <menu key="submenu" title="Spelling" id="3IN-sU-3Bg"> + <items> + <menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI"> + <connections> + <action selector="showGuessPanel:" target="-1" id="vFj-Ks-hy3"/> + </connections> + </menuItem> + <menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7"> + <connections> + <action selector="checkSpelling:" target="-1" id="fz7-VC-reM"/> + </connections> + </menuItem> + <menuItem isSeparatorItem="YES" id="bNw-od-mp5"/> + <menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="toggleContinuousSpellChecking:" target="-1" id="7w6-Qz-0kB"/> + </connections> + </menuItem> + <menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="toggleGrammarChecking:" target="-1" id="muD-Qn-j4w"/> + </connections> + </menuItem> + <menuItem title="Correct Spelling Automatically" id="78Y-hA-62v"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="toggleAutomaticSpellingCorrection:" target="-1" id="2lM-Qi-WAP"/> + </connections> + </menuItem> + </items> + </menu> + </menuItem> + <menuItem title="Substitutions" id="9ic-FL-obx"> + <modifierMask key="keyEquivalentModifierMask"/> + <menu key="submenu" title="Substitutions" id="FeM-D8-WVr"> + <items> + <menuItem title="Show Substitutions" id="z6F-FW-3nz"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="orderFrontSubstitutionsPanel:" target="-1" id="oku-mr-iSq"/> + </connections> + </menuItem> + <menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/> + <menuItem title="Smart Copy/Paste" id="9yt-4B-nSM"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="toggleSmartInsertDelete:" target="-1" id="3IJ-Se-DZD"/> + </connections> + </menuItem> + <menuItem title="Smart Quotes" id="hQb-2v-fYv"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="ptq-xd-QOA"/> + </connections> + </menuItem> + <menuItem title="Smart Dashes" id="rgM-f4-ycn"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="toggleAutomaticDashSubstitution:" target="-1" id="oCt-pO-9gS"/> + </connections> + </menuItem> + <menuItem title="Smart Links" id="cwL-P1-jid"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="toggleAutomaticLinkDetection:" target="-1" id="Gip-E3-Fov"/> + </connections> + </menuItem> + <menuItem title="Data Detectors" id="tRr-pd-1PS"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="toggleAutomaticDataDetection:" target="-1" id="R1I-Nq-Kbl"/> + </connections> + </menuItem> + <menuItem title="Text Replacement" id="HFQ-gK-NFA"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="toggleAutomaticTextReplacement:" target="-1" id="DvP-Fe-Py6"/> + </connections> + </menuItem> + </items> + </menu> + </menuItem> + <menuItem title="Transformations" id="2oI-Rn-ZJC"> + <modifierMask key="keyEquivalentModifierMask"/> + <menu key="submenu" title="Transformations" id="c8a-y6-VQd"> + <items> + <menuItem title="Make Upper Case" id="vmV-6d-7jI"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="uppercaseWord:" target="-1" id="sPh-Tk-edu"/> + </connections> + </menuItem> + <menuItem title="Make Lower Case" id="d9M-CD-aMd"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="lowercaseWord:" target="-1" id="iUZ-b5-hil"/> + </connections> + </menuItem> + <menuItem title="Capitalize" id="UEZ-Bs-lqG"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="capitalizeWord:" target="-1" id="26H-TL-nsh"/> + </connections> + </menuItem> + </items> + </menu> + </menuItem> + <menuItem title="Speech" id="xrE-MZ-jX0"> + <modifierMask key="keyEquivalentModifierMask"/> + <menu key="submenu" title="Speech" id="3rS-ZA-NoH"> + <items> + <menuItem title="Start Speaking" id="Ynk-f8-cLZ"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="startSpeaking:" target="-1" id="654-Ng-kyl"/> + </connections> + </menuItem> + <menuItem title="Stop Speaking" id="Oyz-dy-DGm"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="stopSpeaking:" target="-1" id="dX8-6p-jy9"/> + </connections> + </menuItem> + </items> + </menu> + </menuItem> + </items> + </menu> + </menuItem> + <menuItem title="Window" id="aUF-d1-5bR"> + <modifierMask key="keyEquivalentModifierMask"/> + <menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo"> + <items> + <menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV"> + <connections> + <action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/> + </connections> + </menuItem> + <menuItem title="Zoom" id="R4o-n2-Eq4"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="performZoom:" target="-1" id="DIl-cC-cCs"/> + </connections> + </menuItem> + <menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/> + <menuItem title="Bring All to Front" id="LE2-aR-0XJ"> + <modifierMask key="keyEquivalentModifierMask"/> + <connections> + <action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/> + </connections> + </menuItem> + </items> + </menu> + </menuItem> + <menuItem title="Help" id="wpr-3q-Mcd"> + <modifierMask key="keyEquivalentModifierMask"/> + <menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ"> + <items> + <menuItem title="Google Chrome Installer Help" keyEquivalent="?" id="FKE-Sm-Kum"> + <connections> + <action selector="showHelp:" target="-1" id="y7X-2Q-9no"/> + </connections> + </menuItem> + </items> + </menu> + </menuItem> + </items> + </menu> + <window title="Google Chrome Installer" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="QvC-M9-y7g"> + <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/> + <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/> + <rect key="contentRect" x="0.0" y="0.0" width="480" height="360"/> + <rect key="screenRect" x="0.0" y="0.0" width="1920" height="1177"/> + <view key="contentView" id="EiT-Mj-1SZ"> + <rect key="frame" x="0.0" y="0.0" width="430" height="220"/> + <autoresizingMask key="autoresizingMask"/> + </view> + </window> + </objects> +</document>
diff --git a/chrome/installer/mac/app/NSAlert+ChromeInstallerAdditions.h b/chrome/installer/mac/app/NSAlert+ChromeInstallerAdditions.h new file mode 100644 index 0000000..a74509a --- /dev/null +++ b/chrome/installer/mac/app/NSAlert+ChromeInstallerAdditions.h
@@ -0,0 +1,15 @@ +// 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 CHROME_INSTALLER_MAC_APP_NSALERT_CHROMEINSTALLERADDITIONS_H_ +#define CHROME_INSTALLER_MAC_APP_NSALERT_CHROMEINSTALLERADDITIONS_H_ + +#import <AppKit/AppKit.h> + +typedef NSInteger NSModalResponse; +@interface NSAlert (ChromeInstallerAdditions) +- (NSModalResponse)quitButton; +@end + +#endif // CHROME_INSTALLER_MAC_APP_NSALERT_CHROMEINSTALLERADDITIONS_H_
diff --git a/chrome/installer/mac/app/NSAlert+ChromeInstallerAdditions.m b/chrome/installer/mac/app/NSAlert+ChromeInstallerAdditions.m new file mode 100644 index 0000000..ff92d2f --- /dev/null +++ b/chrome/installer/mac/app/NSAlert+ChromeInstallerAdditions.m
@@ -0,0 +1,15 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "NSAlert+ChromeInstallerAdditions.h" + +@implementation NSAlert (ChromeInstallerAdditions) +// In the one-button scenario, the button would be just "Quit." In the +// two-button scenario, the first button would allow the user to "Retry" and +// the second button would provide the "Quit" option. +- (NSModalResponse)quitButton { + return ([[self buttons] count] == 1) ? NSAlertFirstButtonReturn + : NSAlertSecondButtonReturn; +} +@end
diff --git a/chrome/installer/mac/app/NSError+ChromeInstallerAdditions.h b/chrome/installer/mac/app/NSError+ChromeInstallerAdditions.h new file mode 100644 index 0000000..8a9bef7 --- /dev/null +++ b/chrome/installer/mac/app/NSError+ChromeInstallerAdditions.h
@@ -0,0 +1,16 @@ +// 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 CHROME_INSTALLER_MAC_APP_NSERROR_CHROMEINSTALLERADDITIONS_H_ +#define CHROME_INSTALLER_MAC_APP_NSERROR_CHROMEINSTALLERADDITIONS_H_ + +#import <Foundation/Foundation.h> + +@interface NSError (ChromeInstallerAdditions) ++ (NSError*)errorForAlerts:(NSString*)message + withDescription:(NSString*)description + isRecoverable:(BOOL)recoverable; +@end + +#endif // CHROME_INSTALLER_MAC_APP_NSERROR_CHROMEINSTALLERADDITIONS_H_
diff --git a/chrome/installer/mac/app/NSError+ChromeInstallerAdditions.m b/chrome/installer/mac/app/NSError+ChromeInstallerAdditions.m new file mode 100644 index 0000000..4cb23ed --- /dev/null +++ b/chrome/installer/mac/app/NSError+ChromeInstallerAdditions.m
@@ -0,0 +1,29 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "NSError+ChromeInstallerAdditions.h" + +@implementation NSError (ChromeInstallerAdditions) +// Creates a custom error object to be used as the popup alert that the user +// will be shown. ++ (NSError*)errorForAlerts:(NSString*)message + withDescription:(NSString*)description + isRecoverable:(BOOL)recoverable { + NSArray* options = @[]; + if (recoverable) { + options = @[ @"Try Again", @"Quit" ]; + } else { + options = @[ @"Quit" ]; + } + + NSDictionary* errorContents = @{ + NSLocalizedDescriptionKey : NSLocalizedString(message, nil), + NSLocalizedRecoveryOptionsErrorKey : options, + NSLocalizedRecoverySuggestionErrorKey : NSLocalizedString(description, nil) + }; + return [NSError errorWithDomain:@"ChromeErrorDomain" + code:-1 + userInfo:errorContents]; +} +@end
diff --git a/chrome/installer/mac/app/NetworkCommunication.h b/chrome/installer/mac/app/NetworkCommunication.h deleted file mode 100644 index c616a207..0000000 --- a/chrome/installer/mac/app/NetworkCommunication.h +++ /dev/null
@@ -1,33 +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 CHROME_INSTALLER_MAC_APP_NETWORKCOMMUNICATION_H_ -#define CHROME_INSTALLER_MAC_APP_NETWORKCOMMUNICATION_H_ - -#import <Foundation/Foundation.h> - -// TODO: talk to @sdy about this class -@interface NetworkCommunication : NSObject - -typedef void (^DataTaskCompletionHandler)(NSData*, NSURLResponse*, NSError*); - -@property(nonatomic, copy) NSMutableURLRequest* request; -@property(nonatomic, copy) NSURLSession* session; -@property(nonatomic, copy) DataTaskCompletionHandler dataResponseHandler; - -- (id)init; -- (id)initWithDelegate:(id)delegate; - -// Creates a mutable URLRequest object as an instance variable, then returns it -// so the caller has a chance to edit it before sending the request out. -- (NSMutableURLRequest*)createRequestWithUrlAsString:(NSString*)urlString - andXMLBody:(NSXMLDocument*)body; -// Adds a data task to the run loop using the request instance variable. -- (void)sendDataRequest; -// Adds a download task to the run loop using the request instance variable. -- (void)sendDownloadRequest; - -@end - -#endif // CHROME_INSTALLER_MAC_APP_NETWORKCOMMUNICATION_H_
diff --git a/chrome/installer/mac/app/NetworkCommunication.m b/chrome/installer/mac/app/NetworkCommunication.m deleted file mode 100644 index a5ffde9..0000000 --- a/chrome/installer/mac/app/NetworkCommunication.m +++ /dev/null
@@ -1,72 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "NetworkCommunication.h" - -@interface NSURLSession (PartialAvailability) -- (NSURLSessionDataTask*)dataTaskWithRequest:(NSURLRequest*)request - completionHandler: - (void (^)(NSData* data, - NSURLResponse* response, - NSError* error))completionHandler; -- (NSURLSessionDownloadTask*) -downloadTaskWithRequest:(NSURLRequest*)request - completionHandler:(void (^)(NSURL* location, - NSURLResponse* response, - NSError* error))completionHandler; -@end - -@implementation NetworkCommunication : NSObject - -@synthesize session = session_; -@synthesize request = request_; -@synthesize dataResponseHandler = dataResponseHandler_; - -- (id)init { - return [self initWithDelegate:nil]; -} - -- (id)initWithDelegate:(id)delegate { - if ((self = [super init])) { - NSURLSessionConfiguration* sessionConfig = - [NSURLSessionConfiguration defaultSessionConfiguration]; - session_ = [NSURLSession sessionWithConfiguration:sessionConfig - delegate:delegate - delegateQueue:nil]; - } - return self; -} - -- (NSMutableURLRequest*)createRequestWithUrlAsString:(NSString*)urlString - andXMLBody:(NSXMLDocument*)body { - NSURL* requestURL = [NSURL URLWithString:urlString]; - request_ = [NSMutableURLRequest requestWithURL:requestURL]; - if (body) { - [request_ addValue:@"text/xml" forHTTPHeaderField:@"Content-Type"]; - NSData* requestBody = - [[body XMLString] dataUsingEncoding:NSUTF8StringEncoding]; - request_.HTTPBody = requestBody; - } - return request_; -} - -- (void)sendDataRequest { - NSURLSessionDataTask* dataTask; - if (dataResponseHandler_) { - dataTask = [session_ dataTaskWithRequest:request_ - completionHandler:dataResponseHandler_]; - } else { - dataTask = [session_ dataTaskWithRequest:request_]; - } - - [dataTask resume]; -} - -- (void)sendDownloadRequest { - NSURLSessionDownloadTask* downloadTask = - [session_ downloadTaskWithRequest:request_]; - [downloadTask resume]; -} - -@end
diff --git a/chrome/installer/mac/app/OmahaCommunication.h b/chrome/installer/mac/app/OmahaCommunication.h index 5bfae67..6b1e9a9 100644 --- a/chrome/installer/mac/app/OmahaCommunication.h +++ b/chrome/installer/mac/app/OmahaCommunication.h
@@ -7,27 +7,22 @@ #import <Foundation/Foundation.h> -#import "NetworkCommunication.h" - @protocol OmahaCommunicationDelegate -- (void)onOmahaSuccessWithResponseBody:(NSData*)responseBody - AndError:(NSError*)error; +- (void)onOmahaSuccessWithURLs:(NSArray*)URLs; +- (void)onOmahaFailureWithError:(NSError*)error; @end -@interface OmahaCommunication : NSObject<NSURLSessionDataDelegate> { - id<OmahaCommunicationDelegate> _delegate; -} +@interface OmahaCommunication : NSObject<NSURLSessionDataDelegate> @property(nonatomic, copy) NSXMLDocument* requestXMLBody; -// TODO: talk to @sdy about use of NetworkCommunication -@property(nonatomic, copy) NetworkCommunication* sessionHelper; @property(nonatomic, assign) id<OmahaCommunicationDelegate> delegate; - (id)init; - (id)initWithBody:(NSXMLDocument*)xmlBody; -// Sends the request created using the session helper. -- (void)sendRequest; +// Asks the Omaha servers for the most updated version of Chrome by sending a +// request using this function. +- (void)fetchDownloadURLs; @end
diff --git a/chrome/installer/mac/app/OmahaCommunication.m b/chrome/installer/mac/app/OmahaCommunication.m index 8368ff7..9f1d8cb 100644 --- a/chrome/installer/mac/app/OmahaCommunication.m +++ b/chrome/installer/mac/app/OmahaCommunication.m
@@ -5,11 +5,22 @@ #import "OmahaCommunication.h" #import "OmahaXMLRequest.h" +#import "OmahaXMLParser.h" + +static NSString* const omahaURLPath = + @"https://tools.google.com/service/update2"; + +@interface NSURLSession () +- (NSURLSessionDataTask*)dataTaskWithRequest:(NSURLRequest*)request + completionHandler: + (void (^)(NSData* data, + NSURLResponse* response, + NSError* error))completionHandler; +@end @implementation OmahaCommunication @synthesize requestXMLBody = requestXMLBody_; -@synthesize sessionHelper = sessionHelper_; @synthesize delegate = delegate_; - (id)init { @@ -18,29 +29,38 @@ - (id)initWithBody:(NSXMLDocument*)xmlBody { if ((self = [super init])) { - sessionHelper_ = [[NetworkCommunication alloc] initWithDelegate:self]; requestXMLBody_ = xmlBody; - [self createOmahaRequest]; } return self; } -- (NSURLRequest*)createOmahaRequest { - // TODO: turn this string to a comand-line flag - NSMutableURLRequest* request = [sessionHelper_ - createRequestWithUrlAsString:@"https://tools.google.com/service/update2" - andXMLBody:requestXMLBody_]; +- (void)fetchDownloadURLs { + // TODO: turn this string to a command-line flag + NSURL* requestURL = [NSURL URLWithString:omahaURLPath]; + NSMutableURLRequest* request = + [NSMutableURLRequest requestWithURL:requestURL]; + [request addValue:@"text/xml" forHTTPHeaderField:@"Content-Type"]; + NSData* requestBody = + [[requestXMLBody_ XMLString] dataUsingEncoding:NSUTF8StringEncoding]; + request.HTTPBody = requestBody; request.HTTPMethod = @"POST"; - return request; -} - -- (void)sendRequest { - [sessionHelper_ setDataResponseHandler:^(NSData* _Nullable data, - NSURLResponse* _Nullable response, - NSError* _Nullable error) { - [delegate_ onOmahaSuccessWithResponseBody:data AndError:error]; - }]; - [sessionHelper_ sendDataRequest]; + [[[NSURLSession sharedSession] + dataTaskWithRequest:request + completionHandler:^(NSData* data, NSURLResponse* response, + NSError* error) { + NSArray* completeURLs = nil; + if (!error) { + completeURLs = [OmahaXMLParser parseXML:data error:&error]; + } + // Deals with errors both from the network error and the + // parsing error, as the user only needs to know there was a problem + // talking with the Google Update server. + if (error) { + [delegate_ onOmahaFailureWithError:error]; + } else { + [delegate_ onOmahaSuccessWithURLs:completeURLs]; + } + }] resume]; } @end \ No newline at end of file
diff --git a/chrome/installer/mac/app/OmahaXMLParser.h b/chrome/installer/mac/app/OmahaXMLParser.h index 1d686db..687c5dae 100644 --- a/chrome/installer/mac/app/OmahaXMLParser.h +++ b/chrome/installer/mac/app/OmahaXMLParser.h
@@ -7,18 +7,11 @@ #import <Foundation/Foundation.h> -@interface OmahaXMLParser : NSObject<NSXMLParserDelegate> { - NSMutableArray* chromeIncompleteDownloadURLs_; - NSString* chromeImageFilename_; -} - -- (NSMutableArray*)chromeIncompleteDownloadURLs; - -- (NSString*)chromeImageFilename; +@interface OmahaXMLParser : NSObject // Parses an XML document and extracts all the URL's it finds as well as the // filename. Adds each URL into the array chromeIncompleteDownloadURLs_. -- (NSArray*)parseXML:(NSData*)omahaResponseXML error:(NSError**)error; ++ (NSArray*)parseXML:(NSData*)omahaResponseXML error:(NSError**)error; @end
diff --git a/chrome/installer/mac/app/OmahaXMLParser.m b/chrome/installer/mac/app/OmahaXMLParser.m index 4986e00..016adb500 100644 --- a/chrome/installer/mac/app/OmahaXMLParser.m +++ b/chrome/installer/mac/app/OmahaXMLParser.m
@@ -4,27 +4,41 @@ #import "OmahaXMLParser.h" -@implementation OmahaXMLParser +@interface OmahaXMLParser ()<NSXMLParserDelegate> +@end -- (NSMutableArray*)chromeIncompleteDownloadURLs { - return chromeIncompleteDownloadURLs_; -} - -- (NSString*)chromeImageFilename { - return chromeImageFilename_; +@implementation OmahaXMLParser { + NSMutableArray* chromeIncompleteDownloadURLs_; + NSString* chromeImageFilename_; } // Sets up instance of NSXMLParser and calls on delegate methods to do actual // parsing work. -- (NSArray*)parseXML:(NSData*)omahaResponseXML error:(NSError**)error { ++ (NSArray*)parseXML:(NSData*)omahaResponseXML error:(NSError**)error { NSXMLParser* parser = [[NSXMLParser alloc] initWithData:omahaResponseXML]; - [parser setDelegate:self]; - BOOL success = [parser parse]; - if (!success) { + + OmahaXMLParser* omahaParser = [[OmahaXMLParser alloc] init]; + [parser setDelegate:omahaParser]; + if (![parser parse]) { *error = [parser parserError]; + // TODO: pass up error object to indicate error occurred so + // InstallerWindowController can create custom user error message. + return nil; } - return chromeIncompleteDownloadURLs_; + NSMutableArray* completeDownloadURLs = [[NSMutableArray alloc] init]; + for (NSString* URL in omahaParser->chromeIncompleteDownloadURLs_) { + [completeDownloadURLs + addObject:[NSURL URLWithString:omahaParser->chromeImageFilename_ + relativeToURL:[NSURL URLWithString:URL]]]; + } + + if ([completeDownloadURLs count] < 1) { + *error = [NSError errorWithDomain:@"ChromeErrorDomain" code:1 userInfo:nil]; + return nil; + } + + return completeDownloadURLs; } // Method implementation for XMLParserDelegate. @@ -46,8 +60,17 @@ [chromeIncompleteDownloadURLs_ addObject:extractedURL]; } if ([elementName isEqualToString:@"package"]) { - chromeImageFilename_ = [[NSString alloc] - initWithFormat:@"%@", [attributeDict objectForKey:@"name"]]; + chromeImageFilename_ = + [[NSString alloc] initWithString:[attributeDict objectForKey:@"name"]]; + } +} + +// If either component of the URL is empty then the complete URL cannot +// be generated so both variables are set to nil to flag errors. +- (void)parserDidEndDocument:(NSXMLParser*)parser { + if (!chromeIncompleteDownloadURLs_ || !chromeImageFilename_) { + chromeIncompleteDownloadURLs_ = nil; + chromeImageFilename_ = nil; } }
diff --git a/chrome/installer/mac/app/OmahaXMLRequest.m b/chrome/installer/mac/app/OmahaXMLRequest.m index 995d0b26..8ade5721 100644 --- a/chrome/installer/mac/app/OmahaXMLRequest.m +++ b/chrome/installer/mac/app/OmahaXMLRequest.m
@@ -23,8 +23,9 @@ // user attributes that Omaha actually looks at. The other parameters are useful // for logging purposes but otherwise not directly used. + (NSXMLDocument*)createXMLRequestBody { - // NOTE: might be a good idea in the future to add a version# for this - // installer + // TODO: might be a good idea in the future to add a version# for this + // installer using [[NSBundle mainBundle] + // objectForInfoDictionaryKey:@"CFBundleShortVersionString"]] NSString* protocol = @"3.0"; NSString* platform = @"mac";
diff --git a/chrome/installer/mac/app/SystemInfo.h b/chrome/installer/mac/app/SystemInfo.h index 431f9cde..42998b74 100644 --- a/chrome/installer/mac/app/SystemInfo.h +++ b/chrome/installer/mac/app/SystemInfo.h
@@ -14,9 +14,10 @@ @interface SystemInfo : NSObject // Gets the CPU architecture type of the client's system, which will be used // when crafting the query to Omaha. This will return either "x84_64h" for -// systems running on Intel Haswell chips, "x86_64" for other Intel machines, +// systems running on Intel Haswell chips, "i486" for other Intel machines, // or strings representing other CPU types ("amd", "pentium", and "i686", for -// example, are all valid). +// example, are all possible; however, due to the above macro, we limit the +// possible return strings to either "x84_64h" or "i486"). + (NSString*)getArch; // Gets the operating system version of the client. This function may return
diff --git a/chrome/installer/mac/app/main.m b/chrome/installer/mac/app/main.m index 5dfad4c..33d21bf 100644 --- a/chrome/installer/mac/app/main.m +++ b/chrome/installer/mac/app/main.m
@@ -2,14 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import <Foundation/Foundation.h> - -#import "MainDelegate.h" +#import <AppKit/AppKit.h> int main(int argc, const char* argv[]) { - MainDelegate* delegate = [[MainDelegate alloc] init]; - [delegate runApplication]; - - [[NSRunLoop mainRunLoop] run]; - return 1; + return NSApplicationMain(argc, argv); }
diff --git a/chrome/installer/setup/uninstall.cc b/chrome/installer/setup/uninstall.cc index 17978ed76..4a2760b 100644 --- a/chrome/installer/setup/uninstall.cc +++ b/chrome/installer/setup/uninstall.cc
@@ -30,7 +30,6 @@ #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_result_codes.h" -#include "chrome/installer/setup/app_launcher_installer.h" #include "chrome/installer/setup/install.h" #include "chrome/installer/setup/install_worker.h" #include "chrome/installer/setup/setup_constants.h" @@ -712,7 +711,7 @@ bool DeleteUserRegistryKeys(const std::vector<const base::string16*>* key_paths, const wchar_t* user_sid, base::win::RegKey* key) { - for (const auto& key_path : *key_paths) { + for (const auto* key_path : *key_paths) { LONG result = key->DeleteKey(key_path->c_str()); if (result == ERROR_SUCCESS) { VLOG(1) << "Deleted " << user_sid << "\\" << *key_path;
diff --git a/chrome/installer/util/channel_info.cc b/chrome/installer/util/channel_info.cc index 3e138563f..8d1eb726 100644 --- a/chrome/installer/util/channel_info.cc +++ b/chrome/installer/util/channel_info.cc
@@ -298,34 +298,16 @@ return SetModifier(MOD_READY_MODE, value, &value_); } -bool ChannelInfo::SetStage(const wchar_t* stage) { +bool ChannelInfo::ClearStage() { base::string16::size_type position; base::string16::size_type length; - bool have_modifier = FindModifier(MOD_STAGE, value_, &position, &length); - if (stage != NULL && *stage != L'\0') { - base::string16 stage_str(kModStage); - stage_str.append(stage); - if (!have_modifier) { - value_.insert(FindInsertionPoint(MOD_STAGE, value_), stage_str); - return true; - } - if (value_.compare(position, length, stage_str) != 0) { - value_.replace(position, length, stage_str); - return true; - } - } else { - if (have_modifier) { - value_.erase(position, length); - return true; - } + if (FindModifier(MOD_STAGE, value_, &position, &length)) { + value_.erase(position, length); + return true; } return false; } -base::string16 ChannelInfo::GetStage() const { - return GetModifierValue(MOD_STAGE, value_); -} - base::string16 ChannelInfo::GetStatsDefault() const { return GetModifierValue(MOD_STATS_DEFAULT, value_); }
diff --git a/chrome/installer/util/channel_info.h b/chrome/installer/util/channel_info.h index ed9f95b..76bb255 100644 --- a/chrome/installer/util/channel_info.h +++ b/chrome/installer/util/channel_info.h
@@ -79,14 +79,8 @@ // modified. bool SetReadyMode(bool value); - // Adds the -stage: modifier with the given string (if |stage| is non-NULL) or - // removes the -stage: modifier (otherwise), returning true if the value is - // modified. - bool SetStage(const wchar_t* stage); - - // Returns the string identifying the current stage, or an empty string if the - // -stage: modifier is not present in the value. - base::string16 GetStage() const; + // Removes the -stage: modifier, returning true if the value is modified. + bool ClearStage(); // Returns the string identifying the stats default state (i.e., the starting // value of the "send usage stats" checkbox during install), or an empty
diff --git a/chrome/installer/util/channel_info_unittest.cc b/chrome/installer/util/channel_info_unittest.cc index 239f4a74..e25163d 100644 --- a/chrome/installer/util/channel_info_unittest.cc +++ b/chrome/installer/util/channel_info_unittest.cc
@@ -205,35 +205,33 @@ EXPECT_TRUE(ci.IsChrome()); } -TEST(ChannelInfoTest, GetStage) { +TEST(ChannelInfoTest, ClearStage) { ChannelInfo ci; ci.set_value(L""); - EXPECT_EQ(L"", ci.GetStage()); - ci.set_value(L"-stage"); - EXPECT_EQ(L"", ci.GetStage()); - ci.set_value(L"-stage:"); - EXPECT_EQ(L"", ci.GetStage()); + EXPECT_FALSE(ci.ClearStage()); + EXPECT_EQ(L"", ci.value()); ci.set_value(L"-stage:spammy"); - EXPECT_EQ(L"spammy", ci.GetStage()); + EXPECT_TRUE(ci.ClearStage()); + EXPECT_EQ(L"", ci.value()); ci.set_value(L"-multi"); - EXPECT_EQ(L"", ci.GetStage()); - ci.set_value(L"-stage-multi"); - EXPECT_EQ(L"", ci.GetStage()); - ci.set_value(L"-stage:-multi"); - EXPECT_EQ(L"", ci.GetStage()); + EXPECT_FALSE(ci.ClearStage()); + EXPECT_EQ(L"-multi", ci.value()); ci.set_value(L"-stage:spammy-multi"); - EXPECT_EQ(L"spammy", ci.GetStage()); + EXPECT_TRUE(ci.ClearStage()); + EXPECT_EQ(L"-multi", ci.value()); ci.set_value(L"2.0-beta-multi"); - EXPECT_EQ(L"", ci.GetStage()); - ci.set_value(L"2.0-beta-stage-multi"); - EXPECT_EQ(L"", ci.GetStage()); - ci.set_value(L"2.0-beta-stage:-multi"); - EXPECT_EQ(L"", ci.GetStage()); + EXPECT_FALSE(ci.ClearStage()); + EXPECT_EQ(L"2.0-beta-multi", ci.value()); ci.set_value(L"2.0-beta-stage:spammy-multi"); - EXPECT_EQ(L"spammy", ci.GetStage()); + EXPECT_TRUE(ci.ClearStage()); + EXPECT_EQ(L"2.0-beta-multi", ci.value()); + + ci.set_value(L"2.0-beta-stage:-multi"); + EXPECT_TRUE(ci.ClearStage()); + EXPECT_EQ(L"2.0-beta-multi", ci.value()); } TEST(ChannelInfoTest, GetStatsDefault) { @@ -276,53 +274,6 @@ } } -TEST(ChannelInfoTest, SetStage) { - ChannelInfo ci; - - ci.set_value(L""); - EXPECT_FALSE(ci.SetStage(NULL)); - EXPECT_EQ(L"", ci.value()); - EXPECT_TRUE(ci.SetStage(L"spammy")); - EXPECT_EQ(L"-stage:spammy", ci.value()); - EXPECT_FALSE(ci.SetStage(L"spammy")); - EXPECT_EQ(L"-stage:spammy", ci.value()); - EXPECT_TRUE(ci.SetStage(NULL)); - EXPECT_EQ(L"", ci.value()); - EXPECT_TRUE(ci.SetStage(L"spammy")); - EXPECT_TRUE(ci.SetStage(L"")); - EXPECT_EQ(L"", ci.value()); - - ci.set_value(L"-multi"); - EXPECT_FALSE(ci.SetStage(NULL)); - EXPECT_EQ(L"-multi", ci.value()); - EXPECT_TRUE(ci.SetStage(L"spammy")); - EXPECT_EQ(L"-stage:spammy-multi", ci.value()); - EXPECT_FALSE(ci.SetStage(L"spammy")); - EXPECT_EQ(L"-stage:spammy-multi", ci.value()); - EXPECT_TRUE(ci.SetStage(NULL)); - EXPECT_EQ(L"-multi", ci.value()); - EXPECT_TRUE(ci.SetStage(L"spammy")); - EXPECT_TRUE(ci.SetStage(L"")); - EXPECT_EQ(L"-multi", ci.value()); - - ci.set_value(L"2.0-beta-multi"); - EXPECT_FALSE(ci.SetStage(NULL)); - EXPECT_EQ(L"2.0-beta-multi", ci.value()); - EXPECT_TRUE(ci.SetStage(L"spammy")); - EXPECT_EQ(L"2.0-beta-stage:spammy-multi", ci.value()); - EXPECT_FALSE(ci.SetStage(L"spammy")); - EXPECT_EQ(L"2.0-beta-stage:spammy-multi", ci.value()); - EXPECT_TRUE(ci.SetStage(NULL)); - EXPECT_EQ(L"2.0-beta-multi", ci.value()); - EXPECT_TRUE(ci.SetStage(L"spammy")); - EXPECT_TRUE(ci.SetStage(L"")); - EXPECT_EQ(L"2.0-beta-multi", ci.value()); - - ci.set_value(L"2.0-beta-stage:-multi"); - EXPECT_TRUE(ci.SetStage(NULL)); - EXPECT_EQ(L"2.0-beta-multi", ci.value()); -} - TEST(ChannelInfoTest, RemoveAllModifiersAndSuffixes) { ChannelInfo ci;
diff --git a/chrome/installer/util/google_update_settings.cc b/chrome/installer/util/google_update_settings.cc index 0ab8bdda..5f68f93 100644 --- a/chrome/installer/util/google_update_settings.cc +++ b/chrome/installer/util/google_update_settings.cc
@@ -585,6 +585,12 @@ modified = true; } + if (value->ClearStage()) { + VLOG(1) << "Removed (legacy) stage information; switching to channel: " + << value->value(); + modified = true; + } + return modified; }
diff --git a/chrome/installer/util/google_update_settings.h b/chrome/installer/util/google_update_settings.h index 03eb879..58553a9 100644 --- a/chrome/installer/util/google_update_settings.h +++ b/chrome/installer/util/google_update_settings.h
@@ -203,6 +203,8 @@ // There is no fall-back for full installer :) // - Unconditionally remove "-multifail" since we haven't crashed. // |state_key| should be obtained via InstallerState::state_key(). + // - Unconditionally clear a legacy "-stage:" modifier since such information + // is now propagated through Google Update's InstallerExtraCode1 value. static void UpdateInstallStatus(bool system_install, installer::ArchiveType archive_type, int install_return_code,
diff --git a/chrome/installer/util/install_util.cc b/chrome/installer/util/install_util.cc index 4e9a1cf..53b9b9f 100644 --- a/chrome/installer/util/install_util.cc +++ b/chrome/installer/util/install_util.cc
@@ -46,52 +46,6 @@ const char kEnvProgramFilesPath[] = "CHROME_PROBED_PROGRAM_FILES_PATH"; const wchar_t kRegDowngradeVersion[] = L"DowngradeVersion"; -const wchar_t kStageBinaryPatching[] = L"binary_patching"; -const wchar_t kStageBuilding[] = L"building"; -const wchar_t kStageConfiguringAutoLaunch[] = L"configuring_auto_launch"; -const wchar_t kStageCopyingPreferencesFile[] = L"copying_prefs"; -const wchar_t kStageCreatingShortcuts[] = L"creating_shortcuts"; -const wchar_t kStageEnsemblePatching[] = L"ensemble_patching"; -const wchar_t kStageExecuting[] = L"executing"; -const wchar_t kStageFinishing[] = L"finishing"; -const wchar_t kStagePreconditions[] = L"preconditions"; -const wchar_t kStageRefreshingPolicy[] = L"refreshing_policy"; -const wchar_t kStageRegisteringChrome[] = L"registering_chrome"; -const wchar_t kStageRemovingOldVersions[] = L"removing_old_ver"; -const wchar_t kStageRollingback[] = L"rollingback"; -const wchar_t kStageUncompressing[] = L"uncompressing"; -const wchar_t kStageUnpacking[] = L"unpacking"; -const wchar_t kStageUpdatingChannels[] = L"updating_channels"; -const wchar_t kStageCreatingVisualManifest[] = L"creating_visual_manifest"; -const wchar_t kStageUninstallingBinaries[] = L"uninstalling_binaries"; -const wchar_t kStageUninstallingChromeFrame[] = L"uninstalling_chrome_frame"; - -const wchar_t* const kStages[] = { - NULL, - kStagePreconditions, - kStageUncompressing, - kStageEnsemblePatching, - kStageBinaryPatching, - kStageUnpacking, - kStageBuilding, - kStageExecuting, - kStageRollingback, - kStageRefreshingPolicy, - kStageUpdatingChannels, - kStageCopyingPreferencesFile, - kStageCreatingShortcuts, - kStageRegisteringChrome, - kStageRemovingOldVersions, - kStageFinishing, - kStageConfiguringAutoLaunch, - kStageCreatingVisualManifest, - nullptr, // Deprecated with InstallerStage(18) in util_constants.h. - kStageUninstallingBinaries, - kStageUninstallingChromeFrame, -}; - -static_assert(installer::NUM_STAGES == arraysize(kStages), - "kStages disagrees with Stage; they must match!"); // Creates a zero-sized non-decorated foreground window that doesn't appear // in the taskbar. This is used as a parent window for calls to ShellExecuteEx @@ -350,15 +304,6 @@ << "Failed writing installer stage to " << state_key_path << "; result: " << result; } - // TODO(grt): Remove code below here once we're convinced that our use of - // Google Update's new InstallerExtraCode1 value is good. - installer::ChannelInfo channel_info; - // This will return false if the "ap" value isn't present, which is fine. - channel_info.Initialize(state_key); - if (channel_info.SetStage(kStages[stage]) && - !channel_info.Write(&state_key)) { - LOG(ERROR) << "Failed writing installer stage to " << state_key_path; - } } else { LOG(ERROR) << "Failed opening " << state_key_path << " to update installer stage; result: " << result;
diff --git a/chrome/installer/util/install_util_unittest.cc b/chrome/installer/util/install_util_unittest.cc index 10b9780a..921ee5d 100644 --- a/chrome/installer/util/install_util_unittest.cc +++ b/chrome/installer/util/install_util_unittest.cc
@@ -107,53 +107,6 @@ } } -TEST_F(InstallUtilTest, UpdateInstallerStageAP) { - const bool system_level = false; - const HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; - std::wstring state_key_path(L"PhonyClientState"); - - // Update the stage when there's no "ap" value. - { - ResetRegistryOverrides(); - RegKey(root, state_key_path.c_str(), KEY_SET_VALUE); - InstallUtil::UpdateInstallerStage(system_level, state_key_path, - installer::BUILDING); - std::wstring value; - EXPECT_EQ(ERROR_SUCCESS, - RegKey(root, state_key_path.c_str(), KEY_QUERY_VALUE) - .ReadValue(google_update::kRegApField, &value)); - EXPECT_EQ(L"-stage:building", value); - } - - // Update the stage when there is an "ap" value. - { - ResetRegistryOverrides(); - RegKey(root, state_key_path.c_str(), KEY_SET_VALUE) - .WriteValue(google_update::kRegApField, L"2.0-dev"); - InstallUtil::UpdateInstallerStage(system_level, state_key_path, - installer::BUILDING); - std::wstring value; - EXPECT_EQ(ERROR_SUCCESS, - RegKey(root, state_key_path.c_str(), KEY_QUERY_VALUE) - .ReadValue(google_update::kRegApField, &value)); - EXPECT_EQ(L"2.0-dev-stage:building", value); - } - - // Clear the stage. - { - ResetRegistryOverrides(); - RegKey(root, state_key_path.c_str(), KEY_SET_VALUE) - .WriteValue(google_update::kRegApField, L"2.0-dev-stage:building"); - InstallUtil::UpdateInstallerStage(system_level, state_key_path, - installer::NO_STAGE); - std::wstring value; - EXPECT_EQ(ERROR_SUCCESS, - RegKey(root, state_key_path.c_str(), KEY_QUERY_VALUE) - .ReadValue(google_update::kRegApField, &value)); - EXPECT_EQ(L"2.0-dev", value); - } -} - TEST_F(InstallUtilTest, UpdateInstallerStage) { const bool system_level = false; const HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
diff --git a/chrome/installer/util/installer_state.cc b/chrome/installer/util/installer_state.cc index 1a53a774..ca92d15b8 100644 --- a/chrome/installer/util/installer_state.cc +++ b/chrome/installer/util/installer_state.cc
@@ -623,7 +623,7 @@ if (is_multi_install()) { // Remove the -stage: modifier since we don't want to propagate that to // the other app_guids. - channel_info.SetStage(NULL); + channel_info.ClearStage(); // Synchronize the other products and the package with this one. ChannelInfo other_info;
diff --git a/chrome/renderer/DEPS b/chrome/renderer/DEPS index 1b9e887e..fc80ec98 100644 --- a/chrome/renderer/DEPS +++ b/chrome/renderer/DEPS
@@ -54,3 +54,10 @@ "+skia", "+storage/common", ] + +specific_include_rules = { + "chrome_content_renderer_client_browsertest\.cc" : [ + "+chrome/browser/ui", + "+chrome/browser/ui/tabs", + ], +}
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc index 38364ef..98ffc3a 100644 --- a/chrome/renderer/chrome_content_renderer_client.cc +++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -21,6 +21,7 @@ #include "base/values.h" #include "build/build_config.h" #include "chrome/common/channel_info.h" +#include "chrome/common/chrome_features.h" #include "chrome/common/chrome_isolated_world_ids.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" @@ -182,8 +183,17 @@ using content::WebPluginInfo; using extensions::Extension; +namespace internal { +const char kFlashYouTubeRewriteUMA[] = "Plugin.Flash.YouTubeRewrite"; +} // namespace internal + namespace { +void RecordYouTubeRewriteUMA(internal::YouTubeRewriteStatus status) { + UMA_HISTOGRAM_ENUMERATION(internal::kFlashYouTubeRewriteUMA, status, + internal::NUM_PLUGIN_ERROR); +} + // Whitelist PPAPI for Android Runtime for Chromium. (See crbug.com/383937) #if defined(ENABLE_PLUGINS) const char* const kPredefinedAllowedCameraDeviceOrigins[] = { @@ -798,7 +808,8 @@ std::unique_ptr<content::PluginInstanceThrottler> throttler; if (power_saver_info.power_saver_enabled) { - throttler = PluginInstanceThrottler::Create(); + throttler = + PluginInstanceThrottler::Create(RenderFrame::RECORD_DECISION); // PluginPreroller manages its own lifetime. new PluginPreroller( render_frame, frame, params, info, identifier, group_name, @@ -1394,3 +1405,70 @@ return true; #endif } + +GURL ChromeContentRendererClient::OverrideFlashEmbedWithHTML(const GURL& url) { + if (!base::FeatureList::IsEnabled(features::kOverrideYouTubeFlashEmbed)) + return GURL(); + + if (!url.is_valid()) + return GURL(); + + // We'll only modify YouTube Flash embeds. The URLs can be recognized since + // they're in the following form: youtube.com/v/VIDEO_ID. So, we check to see + // if the given URL does follow that format. + if (!url.DomainIs("youtube.com") && !url.DomainIs("youtube-nocookie.com")) + return GURL(); + if (url.path().find("/v/") != 0) + return GURL(); + + std::string url_str = url.spec(); + internal::YouTubeRewriteStatus result = internal::NUM_PLUGIN_ERROR; + + // If the website is using an invalid YouTube URL, we'll try and + // fix the URL by ensuring that if there are multiple parameters, + // the parameter string begins with a "?" and then follows with a "&" + // for each subsequent parameter. We do this because the Flash video player + // has some URL correction capabilities so we don't want this move to HTML5 + // to break webpages that used to work. + size_t index = url_str.find_first_of("&?"); + bool invalid_url = index != std::string::npos && url_str.at(index) == '&'; + + if (invalid_url) { + // ? should appear first before all parameters + url_str.replace(index, 1, "?"); + + // Replace all instances of ? (after the first) with & + for (size_t pos = index + 1; + (pos = url_str.find("?", pos)) != std::string::npos; pos += 1) { + url_str.replace(pos, 1, "&"); + } + } + + GURL corrected_url = GURL(url_str); + // Unless we're on an Android device, we don't modify any URLs that contain + // the enablejsapi=1 parameter since the page may be interacting with the + // YouTube Flash player in Javascript and we don't want to break working + // content. If we're on an Android device and the URL contains the + // enablejsapi=1 parameter, we do override the URL. + if (corrected_url.query().find("enablejsapi=1") != std::string::npos) { +#if defined(OS_ANDROID) + result = internal::SUCCESS_ENABLEJSAPI; +#else + RecordYouTubeRewriteUMA(internal::FAILURE_ENABLEJSAPI); + return GURL(); +#endif + } + + // Change the path to use the YouTube HTML5 API + std::string path = corrected_url.path(); + path.replace(path.find("/v/"), 3, "/embed/"); + + url::Replacements<char> r; + r.SetPath(path.c_str(), url::Component(0, path.length())); + + if (result == internal::NUM_PLUGIN_ERROR) + result = invalid_url ? internal::SUCCESS_PARAMS_REWRITE : internal::SUCCESS; + + RecordYouTubeRewriteUMA(result); + return corrected_url.ReplaceComponents(r); +}
diff --git a/chrome/renderer/chrome_content_renderer_client.h b/chrome/renderer/chrome_content_renderer_client.h index 4adf285d..564cc5a 100644 --- a/chrome/renderer/chrome_content_renderer_client.h +++ b/chrome/renderer/chrome_content_renderer_client.h
@@ -78,6 +78,26 @@ class WebRtcLoggingMessageFilter; #endif +namespace internal { + +extern const char kFlashYouTubeRewriteUMA[]; + +// Used for UMA. Values should not be reorderer or reused. +// SUCCESS refers to an embed properly rewritten. SUCCESS_PARAMS_REWRITE refers +// to an embed rewritten with the params fixed. SUCCESS_ENABLEJSAPI refers to +// a rewritten embed even though the JS API was enabled (Chrome Android only). +// FAILURE_ENABLEJSAPI indicates the embed was not rewritten because the +// JS API was enabled. +enum YouTubeRewriteStatus { + SUCCESS = 0, + SUCCESS_PARAMS_REWRITE = 1, + SUCCESS_ENABLEJSAPI = 2, + FAILURE_ENABLEJSAPI = 3, + NUM_PLUGIN_ERROR // should be kept last +}; + +} // namespace internal + class ChromeContentRendererClient : public content::ContentRendererClient { public: ChromeContentRendererClient(); @@ -166,6 +186,7 @@ int embedded_worker_id, const GURL& url) override; bool ShouldEnforceWebRTCRoutingPreferences() override; + GURL OverrideFlashEmbedWithHTML(const GURL& url) override; #if defined(ENABLE_SPELLCHECK) // Sets a new |spellcheck|. Used for testing only.
diff --git a/chrome/renderer/chrome_content_renderer_client_browsertest.cc b/chrome/renderer/chrome_content_renderer_client_browsertest.cc index e61b4f9..e04e8e73 100644 --- a/chrome/renderer/chrome_content_renderer_client_browsertest.cc +++ b/chrome/renderer/chrome_content_renderer_client_browsertest.cc
@@ -10,18 +10,27 @@ #include "base/command_line.h" #include "base/strings/utf_string_conversions.h" #include "base/threading/thread_task_runner_handle.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/render_messages.h" #include "chrome/grit/generated_resources.h" #include "chrome/renderer/chrome_content_renderer_client.h" #include "chrome/test/base/chrome_render_view_test.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/ui_test_utils.h" #include "content/public/common/content_constants.h" #include "content/public/renderer/render_frame.h" #include "content/public/renderer/render_view.h" +#include "content/public/test/browser_test_utils.h" #include "content/public/test/mock_render_thread.h" +#include "content/public/test/test_utils.h" #include "ipc/ipc_listener.h" #include "ipc/ipc_sender.h" #include "ipc/ipc_test_sink.h" +#include "net/dns/mock_host_resolver.h" +#include "net/test/embedded_test_server/http_request.h" +#include "net/test/embedded_test_server/http_response.h" #include "testing/gmock/include/gmock/gmock.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" #include "third_party/WebKit/public/web/WebPluginParams.h" @@ -33,6 +42,9 @@ typedef ChromeRenderViewTest InstantProcessNavigationTest; +const base::FilePath::CharType kDocRoot[] = + FILE_PATH_LITERAL("chrome/test/data"); + // Tests that renderer-initiated navigations from an Instant render process get // bounced back to the browser to be rebucketed into a non-Instant renderer if // necessary. @@ -70,3 +82,95 @@ GetMainFrame(), GURL("http://example.com/"), "GET", false, false, &unused)); } + +class ChromeContentRendererClientBrowserTest : public InProcessBrowserTest { + public: + void MonitorRequestHandler(const net::test_server::HttpRequest& request) { + // We're only interested in YouTube video embeds + if (request.headers.at("Host").find("youtube.com") == std::string::npos) + return; + + if (request.relative_url.find("/embed") != 0 && + request.relative_url.find("/v") != 0) + return; + + auto type = request.headers.find("Accept"); + EXPECT_NE(std::string::npos, type->second.find("text/html")); + + EXPECT_EQ(request.relative_url, expected_url_); + content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, + message_runner_->QuitClosure()); + } + + void WaitForYouTubeRequest() { + message_runner_ = new content::MessageLoopRunner(); + message_runner_->Run(); + } + + void set_expected_url(std::string given) { expected_url_ = given; } + + private: + std::string expected_url_; + scoped_refptr<content::MessageLoopRunner> message_runner_; +}; + +// These tests examine Youtube requests that use the Flash API and ensure that +// the requests have been modified to instead use HTML5. The tests also check +// the MIME type of the request to ensure that it is "text/html". +IN_PROC_BROWSER_TEST_F(ChromeContentRendererClientBrowserTest, + RewriteYouTubeFlashEmbed) { + ASSERT_TRUE(embedded_test_server()->Start()); + + host_resolver()->AddRule("*", "127.0.0.1"); + + embedded_test_server()->ServeFilesFromSourceDirectory( + base::FilePath(kDocRoot)); + embedded_test_server()->RegisterRequestMonitor( + base::Bind(&ChromeContentRendererClientBrowserTest::MonitorRequestHandler, + base::Unretained(this))); + + GURL url(embedded_test_server()->GetURL("/flash_embeds.html")); + + ui_test_utils::NavigateToURL(browser(), url); + + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + std::string port = std::to_string(embedded_test_server()->port()); + + // Valid URL, no parameters + std::string video_url = "http://www.youtube.com:" + port + "/v/deadbeef"; + std::string mime_type = "application/x-shockwave-flash"; + set_expected_url("/embed/deadbeef"); + EXPECT_TRUE(ExecuteScript( + web_contents, "appendToDOM('" + video_url + "','" + mime_type + "');")); + WaitForYouTubeRequest(); + + // Valid URL, no parameters, subdomain + video_url = "http://www.foo.youtube.com:" + port + "/v/deadbeef"; + set_expected_url("/embed/deadbeef"); + EXPECT_TRUE(ExecuteScript( + web_contents, "appendToDOM('" + video_url + "','" + mime_type + "');")); + WaitForYouTubeRequest(); + + // Valid URL, many parameters + video_url = "http://www.youtube.com:" + port + "/v/deadbeef?start=4&fs=1"; + set_expected_url("/embed/deadbeef?start=4&fs=1"); + EXPECT_TRUE(ExecuteScript( + web_contents, "appendToDOM('" + video_url + "','" + mime_type + "');")); + WaitForYouTubeRequest(); + + // Invalid parameter construct, many parameters + video_url = "http://www.youtube.com:" + port + "/v/deadbeef&bar=4&foo=6"; + set_expected_url("/embed/deadbeef?bar=4&foo=6"); + EXPECT_TRUE(ExecuteScript( + web_contents, "appendToDOM('" + video_url + "','" + mime_type + "');")); + WaitForYouTubeRequest(); + + // Valid URL, enablejsapi=1 + video_url = "http://www.youtube.com:" + port + "/v/deadbeef?enablejsapi=1"; + mime_type = ""; + set_expected_url("/v/deadbeef?enablejsapi=1"); + EXPECT_TRUE(ExecuteScript( + web_contents, "appendToDOM('" + video_url + "','" + mime_type + "');")); + WaitForYouTubeRequest(); +}
diff --git a/chrome/renderer/chrome_content_renderer_client_unittest.cc b/chrome/renderer/chrome_content_renderer_client_unittest.cc index 898916f..4a4e831 100644 --- a/chrome/renderer/chrome_content_renderer_client_unittest.cc +++ b/chrome/renderer/chrome_content_renderer_client_unittest.cc
@@ -8,7 +8,9 @@ #include <vector> +#include "base/metrics/histogram_samples.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/histogram_tester.h" #include "build/build_config.h" #include "chrome/renderer/searchbox/search_bouncer.h" #include "content/public/common/webplugininfo.h" @@ -408,3 +410,322 @@ SearchBouncer::GetInstance()->OnSetSearchURLs( std::vector<GURL>(), GURL::EmptyGURL()); } + +// These are tests that are common for both Android and desktop browsers. +TEST_F(ChromeContentRendererClientTest, RewriteEmbedCommon) { + struct TestData { + std::string original; + std::string expected; + } test_data[] = { + // { original, expected } + {"youtube.com", ""}, + {"www.youtube.com", ""}, + {"http://www.youtube.com", ""}, + {"https://www.youtube.com", ""}, + {"http://www.foo.youtube.com", ""}, + {"https://www.foo.youtube.com", ""}, + // Non-YouTube domains shouldn't be modified + {"http://www.plus.google.com", ""}, + // URL isn't using Flash + {"http://www.youtube.com/embed/deadbeef", ""}, + // URL isn't using Flash, no www + {"http://youtube.com/embed/deadbeef", ""}, + // URL isn't using Flash, invalid parameter construct + {"http://www.youtube.com/embed/deadbeef&start=4", ""}, + // URL is using Flash, no www + {"http://youtube.com/v/deadbeef", "http://youtube.com/embed/deadbeef"}, + // URL is using Flash, is valid, https + {"https://www.youtube.com/v/deadbeef", + "https://www.youtube.com/embed/deadbeef"}, + // URL is using Flash, is valid, http + {"http://www.youtube.com/v/deadbeef", + "http://www.youtube.com/embed/deadbeef"}, + // URL is using Flash, is valid, not a complete URL, no www or protocol + {"youtube.com/v/deadbeef", ""}, + // URL is using Flash, is valid, not a complete URL,or protocol + {"www.youtube.com/v/deadbeef", ""}, + // URL is using Flash, valid + {"https://www.foo.youtube.com/v/deadbeef", + "https://www.foo.youtube.com/embed/deadbeef"}, + // URL is using Flash, is valid, has one parameter + {"http://www.youtube.com/v/deadbeef?start=4", + "http://www.youtube.com/embed/deadbeef?start=4"}, + // URL is using Flash, is valid, has multiple parameters + {"http://www.youtube.com/v/deadbeef?start=4&fs=1", + "http://www.youtube.com/embed/deadbeef?start=4&fs=1"}, + // URL is using Flash, invalid parameter construct, has one parameter + {"http://www.youtube.com/v/deadbeef&start=4", + "http://www.youtube.com/embed/deadbeef?start=4"}, + // URL is using Flash, invalid parameter construct, has multiple + // parameters + {"http://www.youtube.com/v/deadbeef&start=4&fs=1?foo=bar", + "http://www.youtube.com/embed/deadbeef?start=4&fs=1&foo=bar"}, + // URL is using Flash, invalid parameter construct, has multiple + // parameters + {"http://www.youtube.com/v/deadbeef&start=4&fs=1", + "http://www.youtube.com/embed/deadbeef?start=4&fs=1"}, + // Invalid parameter construct + {"http://www.youtube.com/abcd/v/deadbeef", ""}, + // Invalid parameter construct + {"http://www.youtube.com/v/abcd/", "http://www.youtube.com/embed/abcd/"}, + // Invalid parameter construct + {"http://www.youtube.com/v/123/", "http://www.youtube.com/embed/123/"}, + // youtube-nocookie.com + {"http://www.youtube-nocookie.com/v/123/", + "http://www.youtube-nocookie.com/embed/123/"}, + // youtube-nocookie.com, isn't using flash + {"http://www.youtube-nocookie.com/embed/123/", ""}, + // youtube-nocookie.com, has one parameter + {"http://www.youtube-nocookie.com/v/123?start=foo", + "http://www.youtube-nocookie.com/embed/123?start=foo"}, + // youtube-nocookie.com, has multiple parameters + {"http://www.youtube-nocookie.com/v/123?start=foo&bar=baz", + "http://www.youtube-nocookie.com/embed/123?start=foo&bar=baz"}, + // youtube-nocookie.com, invalid parameter construct, has one parameter + {"http://www.youtube-nocookie.com/v/123&start=foo", + "http://www.youtube-nocookie.com/embed/123?start=foo"}, + // youtube-nocookie.com, invalid parameter construct, has multiple + // parameters + {"http://www.youtube-nocookie.com/v/123&start=foo&bar=baz", + "http://www.youtube-nocookie.com/embed/123?start=foo&bar=baz"}, + // youtube-nocookie.com, https + {"https://www.youtube-nocookie.com/v/123/", + "https://www.youtube-nocookie.com/embed/123/"}, + }; + + ChromeContentRendererClient client; + + for (const auto& data : test_data) + EXPECT_EQ(GURL(data.expected), + client.OverrideFlashEmbedWithHTML(GURL(data.original))); +} + +#if defined(OS_ANDROID) +TEST_F(ChromeContentRendererClientTest, RewriteEmbedAndroid) { + struct TestData { + std::string original; + std::string expected; + } test_data[] = { + // URL isn't using Flash, has JS API enabled + {"http://www.youtube.com/embed/deadbeef?enablejsapi=1", ""}, + // URL is using Flash, has JS API enabled + {"http://www.youtube.com/v/deadbeef?enablejsapi=1", + "http://www.youtube.com/embed/deadbeef?enablejsapi=1"}, + // youtube-nocookie.com, has JS API enabled + {"http://www.youtube-nocookie.com/v/123?enablejsapi=1", + "http://www.youtube-nocookie.com/embed/123?enablejsapi=1"}, + // URL is using Flash, has JS API enabled, invalid parameter construct + {"http://www.youtube.com/v/deadbeef&enablejsapi=1", + "http://www.youtube.com/embed/deadbeef?enablejsapi=1"}, + // URL is using Flash, has JS API enabled, invalid parameter construct, + // has multiple parameters + {"http://www.youtube.com/v/deadbeef&start=4&enablejsapi=1", + "http://www.youtube.com/embed/deadbeef?start=4&enablejsapi=1"}, + }; + + ChromeContentRendererClient client; + + for (const auto& data : test_data) { + EXPECT_EQ(GURL(data.expected), + client.OverrideFlashEmbedWithHTML(GURL(data.original))); + } +} +#else +TEST_F(ChromeContentRendererClientTest, RewriteEmbedDesktop) { + struct TestData { + std::string original; + std::string expected; + } test_data[] = { + // URL isn't using Flash, has JS API enabled + {"http://www.youtube.com/embed/deadbeef?enablejsapi=1", ""}, + // URL is using Flash, has JS API enabled + {"http://www.youtube.com/v/deadbeef?enablejsapi=1", ""}, + // youtube-nocookie.com, has JS API enabled + {"http://www.youtube-nocookie.com/v/123?enablejsapi=1", ""}, + // URL is using Flash, has JS API enabled, invalid parameter construct + {"http://www.youtube.com/v/deadbeef&enablejsapi=1", ""}, + // URL is using Flash, has JS API enabled, invalid parameter construct, + // has multiple parameters + {"http://www.youtube.com/v/deadbeef&start=4&enablejsapi=1", ""}, + }; + + ChromeContentRendererClient client; + + for (const auto& data : test_data) { + EXPECT_EQ(GURL(data.expected), + client.OverrideFlashEmbedWithHTML(GURL(data.original))); + } +} +#endif +class ChromeContentRendererClientMetricsTest : public testing::Test { + public: + ChromeContentRendererClientMetricsTest() = default; + + std::unique_ptr<base::HistogramSamples> GetHistogramSamples() { + return histogram_tester_.GetHistogramSamplesSinceCreation( + internal::kFlashYouTubeRewriteUMA); + } + + void OverrideFlashEmbed(const GURL& gurl) { + client_.OverrideFlashEmbedWithHTML(gurl); + } + + private: + ChromeContentRendererClient client_; + base::HistogramTester histogram_tester_; + + DISALLOW_COPY_AND_ASSIGN(ChromeContentRendererClientMetricsTest); +}; + +TEST_F(ChromeContentRendererClientMetricsTest, RewriteEmbedIneligibleURL) { + std::unique_ptr<base::HistogramSamples> samples = GetHistogramSamples(); + EXPECT_EQ(0, samples->TotalCount()); + + const std::string test_data[] = { + // HTTP, www, no flash + "http://www.youtube.com", + // No flash, subdomain + "http://www.foo.youtube.com", + // No flash + "youtube.com", + // Not youtube + "http://www.plus.google.com", + // Already using HTML5 + "http://youtube.com/embed/deadbeef", + // Already using HTML5, enablejsapi=1 + "http://www.youtube.com/embed/deadbeef?enablejsapi=1"}; + + for (const auto& data : test_data) { + GURL gurl = GURL(data); + OverrideFlashEmbed(gurl); + samples = GetHistogramSamples(); + EXPECT_EQ(0, samples->GetCount(internal::SUCCESS)); + EXPECT_EQ(0, samples->TotalCount()); + } +} + +TEST_F(ChromeContentRendererClientMetricsTest, RewriteEmbedSuccess) { + ChromeContentRendererClient client; + + std::unique_ptr<base::HistogramSamples> samples = GetHistogramSamples(); + auto total_count = 0; + EXPECT_EQ(total_count, samples->TotalCount()); + + const std::string test_data[] = { + // HTTP, www, flash + "http://www.youtube.com/v/deadbeef", + // HTTP, no www, flash + "http://youtube.com/v/deadbeef", + // HTTPS, www, flash + "https://www.youtube.com/v/deadbeef", + // HTTPS, no www, flash + "https://youtube.com/v/deadbeef", + // Invalid parameter construct + "http://www.youtube.com/v/abcd/", + // Invalid parameter construct + "http://www.youtube.com/v/1234/", + }; + + for (const auto& data : test_data) { + ++total_count; + GURL gurl = GURL(data); + OverrideFlashEmbed(gurl); + samples = GetHistogramSamples(); + EXPECT_EQ(total_count, samples->GetCount(internal::SUCCESS)); + EXPECT_EQ(total_count, samples->TotalCount()); + } + + // Invalid parameter construct + GURL gurl = GURL("http://www.youtube.com/abcd/v/deadbeef"); + samples = GetHistogramSamples(); + EXPECT_EQ(total_count, samples->GetCount(internal::SUCCESS)); + EXPECT_EQ(total_count, samples->TotalCount()); +} + +TEST_F(ChromeContentRendererClientMetricsTest, RewriteEmbedSuccessRewrite) { + ChromeContentRendererClient client; + + std::unique_ptr<base::HistogramSamples> samples = GetHistogramSamples(); + auto total_count = 0; + EXPECT_EQ(total_count, samples->TotalCount()); + + const std::string test_data[] = { + // Invalid parameter construct, one parameter + "http://www.youtube.com/v/deadbeef&start=4", + // Invalid parameter construct, has multiple parameters + "http://www.youtube.com/v/deadbeef&start=4&fs=1?foo=bar", + }; + + for (const auto& data : test_data) { + ++total_count; + GURL gurl = GURL(data); + client.OverrideFlashEmbedWithHTML(gurl); + samples = GetHistogramSamples(); + EXPECT_EQ(total_count, samples->GetCount(internal::SUCCESS_PARAMS_REWRITE)); + EXPECT_EQ(total_count, samples->TotalCount()); + } + + // Invalid parameter construct, not flash + GURL gurl = GURL("http://www.youtube.com/embed/deadbeef&start=4"); + OverrideFlashEmbed(gurl); + samples = GetHistogramSamples(); + EXPECT_EQ(total_count, samples->GetCount(internal::SUCCESS_PARAMS_REWRITE)); + EXPECT_EQ(total_count, samples->TotalCount()); +} + +#if defined(OS_ANDROID) +TEST_F(ChromeContentRendererClientMetricsTest, + RewriteEmbedFailureJSAPIAndroid) { + ChromeContentRendererClient client; + + std::unique_ptr<base::HistogramSamples> samples = GetHistogramSamples(); + auto total_count = 0; + EXPECT_EQ(total_count, samples->TotalCount()); + + const std::string test_data[] = { + // Valid parameter construct, one parameter + "http://www.youtube.com/v/deadbeef?enablejsapi=1", + // Valid parameter construct, has multiple parameters + "http://www.youtube.com/v/deadbeef?enablejsapi=1&foo=2", + // Invalid parameter construct, one parameter + "http://www.youtube.com/v/deadbeef&enablejsapi=1", + // Invalid parameter construct, has multiple parameters + "http://www.youtube.com/v/deadbeef&enablejsapi=1&foo=2"}; + + for (const auto& data : test_data) { + ++total_count; + GURL gurl = GURL(data); + OverrideFlashEmbed(gurl); + samples = GetHistogramSamples(); + EXPECT_EQ(total_count, samples->GetCount(internal::SUCCESS_ENABLEJSAPI)); + EXPECT_EQ(total_count, samples->TotalCount()); + } +} + +#else +TEST_F(ChromeContentRendererClientMetricsTest, + RewriteEmbedFailureJSAPIDesktop) { + ChromeContentRendererClient client; + + std::unique_ptr<base::HistogramSamples> samples = GetHistogramSamples(); + auto total_count = 0; + EXPECT_EQ(total_count, samples->TotalCount()); + + const std::string test_data[] = { + // Valid parameter construct, one parameter + "http://www.youtube.com/v/deadbeef?enablejsapi=1", + // Invalid parameter construct, one parameter + "http://www.youtube.com/v/deadbeef&enablejsapi=1", + // Invalid parameter construct, has multiple parameters + "http://www.youtube.com/v/deadbeef&start=4&enablejsapi=1?foo=2"}; + + for (const auto& data : test_data) { + ++total_count; + GURL gurl = GURL(data); + OverrideFlashEmbed(gurl); + samples = GetHistogramSamples(); + EXPECT_EQ(total_count, samples->GetCount(internal::FAILURE_ENABLEJSAPI)); + EXPECT_EQ(total_count, samples->TotalCount()); + } +} +#endif
diff --git a/chrome/renderer/chrome_render_frame_observer_browsertest.cc b/chrome/renderer/chrome_render_frame_observer_browsertest.cc index c297cd5..0d0fa21 100644 --- a/chrome/renderer/chrome_render_frame_observer_browsertest.cc +++ b/chrome/renderer/chrome_render_frame_observer_browsertest.cc
@@ -8,17 +8,66 @@ #include "base/test/histogram_tester.h" #include "chrome/test/base/chrome_render_view_test.h" -#include "components/translate/content/common/translate_messages.h" +#include "components/translate/content/common/translate.mojom.h" #include "components/translate/content/renderer/translate_helper.h" #include "components/translate/core/common/translate_constants.h" #include "content/public/renderer/render_frame.h" #include "content/public/renderer/render_view.h" +#include "mojo/public/cpp/bindings/binding_set.h" +#include "services/shell/public/cpp/interface_provider.h" #include "third_party/WebKit/public/web/WebView.h" +namespace { + +class FakeContentTranslateDriver + : public translate::mojom::ContentTranslateDriver { + public: + FakeContentTranslateDriver() + : called_new_page_(false), page_needs_translation_(false) {} + ~FakeContentTranslateDriver() override {} + + void BindHandle(mojo::ScopedMessagePipeHandle handle) { + bindings_.AddBinding( + this, mojo::MakeRequest<translate::mojom::ContentTranslateDriver>( + std::move(handle))); + } + + // translate::mojom::ContentTranslateDriver implementation. + void RegisterPage(translate::mojom::PagePtr page, + const translate::LanguageDetectionDetails& details, + bool page_needs_translation) override { + called_new_page_ = true; + page_needs_translation_ = page_needs_translation; + } + + bool called_new_page_; + bool page_needs_translation_; + + private: + mojo::BindingSet<translate::mojom::ContentTranslateDriver> bindings_; +}; + +} // namespace + // Constants for UMA statistic collection. static const char kTranslateCaptureText[] = "Translate.CaptureText"; -class ChromeRenderFrameObserverTest : public ChromeRenderViewTest {}; +class ChromeRenderFrameObserverTest : public ChromeRenderViewTest { + protected: + void SetUp() override { + ChromeRenderViewTest::SetUp(); + + shell::InterfaceProvider* remote_interfaces = + view_->GetMainRenderFrame()->GetRemoteInterfaces(); + shell::InterfaceProvider::TestApi test_api(remote_interfaces); + test_api.SetBinderForName( + translate::mojom::ContentTranslateDriver::Name_, + base::Bind(&FakeContentTranslateDriver::BindHandle, + base::Unretained(&fake_translate_driver_))); + } + + FakeContentTranslateDriver fake_translate_driver_; +}; TEST_F(ChromeRenderFrameObserverTest, SkipCapturingSubFrames) { base::HistogramTester histogram_tester; @@ -28,12 +77,11 @@ "<iframe srcdoc=\"This a document in an iframe.\">" "</body>"); view_->GetWebView()->updateAllLifecyclePhases(); - const IPC::Message* message = render_thread_->sink().GetUniqueMessageMatching( - ChromeFrameHostMsg_TranslateLanguageDetermined::ID); - ASSERT_NE(static_cast<IPC::Message*>(NULL), message); - ChromeFrameHostMsg_TranslateLanguageDetermined::Param params; - ChromeFrameHostMsg_TranslateLanguageDetermined::Read(message, ¶ms); - EXPECT_TRUE(std::get<1>(params)) << "Page should be translatable."; + + base::RunLoop().RunUntilIdle(); + ASSERT_TRUE(fake_translate_driver_.called_new_page_); + EXPECT_TRUE(fake_translate_driver_.page_needs_translation_) + << "Page should be translatable."; // Should have 2 samples: one for preliminary capture, one for final capture. // If there are more, then subframes are being captured more than once. histogram_tester.ExpectTotalCount(kTranslateCaptureText, 2);
diff --git a/chrome/renderer/page_load_histograms.cc b/chrome/renderer/page_load_histograms.cc index 843176f..df435a6 100644 --- a/chrome/renderer/page_load_histograms.cc +++ b/chrome/renderer/page_load_histograms.cc
@@ -13,6 +13,7 @@ #include "base/logging.h" #include "base/metrics/field_trial.h" #include "base/metrics/histogram.h" +#include "base/metrics/persistent_histogram_allocator.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" @@ -876,16 +877,15 @@ // Log the PLT to the info log. LogPageLoadTime(document_state, frame->dataSource()); - // Since there are currently no guarantees that renderer histograms will be - // sent to the browser, we initiate a PostTask here to be sure that we send - // the histograms we generated. Without this call, pages that don't have an - // on-close-handler might generate data that is lost when the renderer is - // shutdown abruptly (perchance because the user closed the tab). - // TODO(jar) BUG=33233: This needs to be moved to a PostDelayedTask, and it - // should post when the onload is complete, so that it doesn't interfere with - // the next load. - content::RenderThread::Get()->UpdateHistograms( - content::kHistogramSynchronizerReservedSequenceNumber); + // If persistent histograms are not enabled, initiate a PostTask here to be + // sure that we send the histograms generated. Without this call, pages + // that don't have an on-close-handler might generate data that is lost if + // the renderer is shutdown abruptly (e.g. the user closed the tab). + // TODO(bcwhite): Remove completely when persistence is on-by-default. + if (!base::GlobalHistogramAllocator::Get()) { + content::RenderThread::Get()->UpdateHistograms( + content::kHistogramSynchronizerReservedSequenceNumber); + } } void PageLoadHistograms::FrameWillClose(WebFrame* frame) {
diff --git a/chrome/renderer/plugins/chrome_plugin_placeholder.cc b/chrome/renderer/plugins/chrome_plugin_placeholder.cc index 200de44..67f82bf 100644 --- a/chrome/renderer/plugins/chrome_plugin_placeholder.cc +++ b/chrome/renderer/plugins/chrome_plugin_placeholder.cc
@@ -383,7 +383,9 @@ // If the plugin has already been marked essential in its placeholder form, // we shouldn't create a new throttler and start the process all over again. if (power_saver_enabled()) { - throttler = content::PluginInstanceThrottler::Create(); + throttler = content::PluginInstanceThrottler::Create( + heuristic_run_before_ ? content::RenderFrame::DONT_RECORD_DECISION + : content::RenderFrame::RECORD_DECISION); // PluginPreroller manages its own lifetime. new PluginPreroller(render_frame(), GetFrame(), GetPluginParams(), GetPluginInfo(), GetIdentifier(), title_,
diff --git a/chrome/renderer/plugins/power_saver_info.cc b/chrome/renderer/plugins/power_saver_info.cc index 6209b64..995b5c9 100644 --- a/chrome/renderer/plugins/power_saver_info.cc +++ b/chrome/renderer/plugins/power_saver_info.cc
@@ -102,7 +102,8 @@ auto status = render_frame->GetPeripheralContentStatus( render_frame->GetWebFrame()->top()->getSecurityOrigin(), - url::Origin(params.url), gfx::Size()); + url::Origin(params.url), gfx::Size(), + content::RenderFrame::RECORD_DECISION); // Early-exit from the whole Power Saver system if the content is // same-origin or whitelisted-origin. We ignore the other possibilities,
diff --git a/chrome/renderer/spellchecker/spellcheck_provider.cc b/chrome/renderer/spellchecker/spellcheck_provider.cc index 53b30a95..84ad8e4 100644 --- a/chrome/renderer/spellchecker/spellcheck_provider.cc +++ b/chrome/renderer/spellchecker/spellcheck_provider.cc
@@ -144,23 +144,6 @@ } } -void SpellCheckProvider::checkTextOfParagraph( - const blink::WebString& text, - blink::WebTextCheckingTypeMask mask, - blink::WebVector<blink::WebTextCheckingResult>* results) { - if (!results) - return; - - if (!(mask & blink::WebTextCheckingTypeSpelling)) - return; - - // TODO(groby): As far as I can tell, this method is never invoked. - // UMA results seem to support that. Investigate, clean up if true. - NOTREACHED(); - spellcheck_->SpellCheckParagraph(text, results); - UMA_HISTOGRAM_COUNTS("SpellCheck.api.paragraph", text.length()); -} - void SpellCheckProvider::requestCheckingOfText( const WebString& text, const WebVector<uint32_t>& markers, @@ -175,6 +158,14 @@ UMA_HISTOGRAM_COUNTS("SpellCheck.api.async", text.length()); } +void SpellCheckProvider::cancelAllPendingRequests() { + for (WebTextCheckCompletions::iterator iter(&text_check_completions_); + !iter.IsAtEnd(); iter.Advance()) { + iter.GetCurrentValue()->didCancelCheckingText(); + } + text_check_completions_.Clear(); +} + void SpellCheckProvider::showSpellingUI(bool show) { #if defined(USE_BROWSER_SPELLCHECKER) UMA_HISTOGRAM_BOOLEAN("SpellCheck.api.showUI", show);
diff --git a/chrome/renderer/spellchecker/spellcheck_provider.h b/chrome/renderer/spellchecker/spellcheck_provider.h index 822b4090..1a6ddcd 100644 --- a/chrome/renderer/spellchecker/spellcheck_provider.h +++ b/chrome/renderer/spellchecker/spellcheck_provider.h
@@ -80,10 +80,6 @@ int& offset, int& length, blink::WebVector<blink::WebString>* optional_suggestions) override; - void checkTextOfParagraph( - const blink::WebString& text, - blink::WebTextCheckingTypeMask mask, - blink::WebVector<blink::WebTextCheckingResult>* results) override; void requestCheckingOfText( const blink::WebString& text, @@ -91,6 +87,7 @@ const blink::WebVector<unsigned>& marker_offsets, blink::WebTextCheckingCompletion* completion) override; + void cancelAllPendingRequests() override; void showSpellingUI(bool show) override; bool isShowingSpellingUI() override; void updateSpellingUIWithMisspelledWord(
diff --git a/chrome/renderer/translate/translate_helper_browsertest.cc b/chrome/renderer/translate/translate_helper_browsertest.cc index 501b3d9..dca087f4 100644 --- a/chrome/renderer/translate/translate_helper_browsertest.cc +++ b/chrome/renderer/translate/translate_helper_browsertest.cc
@@ -9,12 +9,14 @@ #include "base/time/time.h" #include "chrome/common/chrome_isolated_world_ids.h" #include "chrome/test/base/chrome_render_view_test.h" -#include "components/translate/content/common/translate_messages.h" +#include "components/translate/content/common/translate.mojom.h" #include "components/translate/content/renderer/translate_helper.h" #include "components/translate/core/common/translate_constants.h" #include "content/public/renderer/render_frame.h" #include "content/public/renderer/render_view.h" #include "extensions/common/constants.h" +#include "mojo/public/cpp/bindings/binding_set.h" +#include "services/shell/public/cpp/interface_provider.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" @@ -23,6 +25,46 @@ using testing::Return; using testing::_; +namespace { + +class FakeContentTranslateDriver + : public translate::mojom::ContentTranslateDriver { + public: + FakeContentTranslateDriver() + : called_new_page_(false), page_needs_translation_(false) {} + ~FakeContentTranslateDriver() override {} + + void BindHandle(mojo::ScopedMessagePipeHandle handle) { + bindings_.AddBinding( + this, mojo::MakeRequest<translate::mojom::ContentTranslateDriver>( + std::move(handle))); + } + + // translate::mojom::ContentTranslateDriver implementation. + void RegisterPage(translate::mojom::PagePtr page, + const translate::LanguageDetectionDetails& details, + bool page_needs_translation) override { + called_new_page_ = true; + details_ = details; + page_needs_translation_ = page_needs_translation; + } + + void ResetNewPageValues() { + called_new_page_ = false; + details_ = base::nullopt; + page_needs_translation_ = false; + } + + bool called_new_page_; + base::Optional<translate::LanguageDetectionDetails> details_; + bool page_needs_translation_; + + private: + mojo::BindingSet<translate::mojom::ContentTranslateDriver> bindings_; +}; + +} // namespace + class TestTranslateHelper : public translate::TranslateHelper { public: explicit TestTranslateHelper(content::RenderFrame* render_frame) @@ -40,7 +82,31 @@ void TranslatePage(const std::string& source_lang, const std::string& target_lang, const std::string& translate_script) { - OnTranslatePage(0, translate_script, source_lang, target_lang); + // Reset result values firstly. + page_translated_ = false; + trans_result_cancelled_ = false; + trans_result_original_lang_ = base::nullopt; + trans_result_translated_lang_ = base::nullopt; + trans_result_error_type_ = translate::TranslateErrors::NONE; + + // Will get new result values via OnPageTranslated. + Translate(translate_script, source_lang, target_lang, + base::Bind(&TestTranslateHelper::OnPageTranslated, + base::Unretained(this))); + } + + bool GetPageTranslatedResult(std::string* original_lang, + std::string* target_lang, + translate::TranslateErrors::Type* error) { + if (!page_translated_) + return false; + if (original_lang) + *original_lang = *trans_result_original_lang_; + if (target_lang) + *target_lang = *trans_result_translated_lang_; + if (error) + *error = trans_result_error_type_; + return true; } MOCK_METHOD0(IsTranslateLibAvailable, bool()); @@ -56,6 +122,23 @@ MOCK_METHOD1(ExecuteScriptAndGetDoubleResult, double(const std::string&)); private: + void OnPageTranslated(bool cancelled, + const std::string& original_lang, + const std::string& translated_lang, + translate::TranslateErrors::Type error_type) { + page_translated_ = true; + trans_result_cancelled_ = cancelled; + trans_result_original_lang_ = original_lang; + trans_result_translated_lang_ = translated_lang; + trans_result_error_type_ = error_type; + } + + bool page_translated_; + bool trans_result_cancelled_; + base::Optional<std::string> trans_result_original_lang_; + base::Optional<std::string> trans_result_translated_lang_; + translate::TranslateErrors::Type trans_result_error_type_; + DISALLOW_COPY_AND_ASSIGN(TestTranslateHelper); }; @@ -67,6 +150,14 @@ void SetUp() override { ChromeRenderViewTest::SetUp(); translate_helper_ = new TestTranslateHelper(view_->GetMainRenderFrame()); + + shell::InterfaceProvider* remote_interfaces = + view_->GetMainRenderFrame()->GetRemoteInterfaces(); + shell::InterfaceProvider::TestApi test_api(remote_interfaces); + test_api.SetBinderForName( + translate::mojom::ContentTranslateDriver::Name_, + base::Bind(&FakeContentTranslateDriver::BindHandle, + base::Unretained(&fake_translate_driver_))); } void TearDown() override { @@ -74,27 +165,8 @@ ChromeRenderViewTest::TearDown(); } - bool GetPageTranslatedMessage(std::string* original_lang, - std::string* target_lang, - translate::TranslateErrors::Type* error) { - const IPC::Message* message = - render_thread_->sink().GetUniqueMessageMatching( - ChromeFrameHostMsg_PageTranslated::ID); - if (!message) - return false; - std::tuple<std::string, std::string, translate::TranslateErrors::Type> - translate_param; - ChromeFrameHostMsg_PageTranslated::Read(message, &translate_param); - if (original_lang) - *original_lang = std::get<0>(translate_param); - if (target_lang) - *target_lang = std::get<1>(translate_param); - if (error) - *error = std::get<2>(translate_param); - return true; - } - TestTranslateHelper* translate_helper_; + FakeContentTranslateDriver fake_translate_driver_; private: DISALLOW_COPY_AND_ASSIGN(TranslateHelperBrowserTest); @@ -118,7 +190,7 @@ base::RunLoop().RunUntilIdle(); translate::TranslateErrors::Type error; - ASSERT_TRUE(GetPageTranslatedMessage(NULL, NULL, &error)); + ASSERT_TRUE(translate_helper_->GetPageTranslatedResult(NULL, NULL, &error)); EXPECT_EQ(translate::TranslateErrors::INITIALIZATION_ERROR, error); } @@ -157,9 +229,8 @@ std::string received_original_lang; std::string received_target_lang; translate::TranslateErrors::Type error; - ASSERT_TRUE(GetPageTranslatedMessage(&received_original_lang, - &received_target_lang, - &error)); + ASSERT_TRUE(translate_helper_->GetPageTranslatedResult( + &received_original_lang, &received_target_lang, &error)); EXPECT_EQ(original_lang, received_original_lang); EXPECT_EQ(target_lang, received_target_lang); EXPECT_EQ(translate::TranslateErrors::NONE, error); @@ -198,7 +269,7 @@ base::RunLoop().RunUntilIdle(); translate::TranslateErrors::Type error; - ASSERT_TRUE(GetPageTranslatedMessage(NULL, NULL, &error)); + ASSERT_TRUE(translate_helper_->GetPageTranslatedResult(NULL, NULL, &error)); EXPECT_EQ(translate::TranslateErrors::TRANSLATION_ERROR, error); } @@ -236,7 +307,8 @@ translate::TranslateErrors::Type error; std::string original_lang; std::string target_lang; - ASSERT_TRUE(GetPageTranslatedMessage(&original_lang, &target_lang, &error)); + ASSERT_TRUE(translate_helper_->GetPageTranslatedResult(&original_lang, + &target_lang, &error)); EXPECT_EQ("de", original_lang); EXPECT_EQ("fr", target_lang); EXPECT_EQ(translate::TranslateErrors::NONE, error); @@ -275,9 +347,8 @@ std::string received_original_lang; std::string received_target_lang; translate::TranslateErrors::Type error; - ASSERT_TRUE(GetPageTranslatedMessage(&received_original_lang, - &received_target_lang, - &error)); + ASSERT_TRUE(translate_helper_->GetPageTranslatedResult( + &received_original_lang, &received_target_lang, &error)); EXPECT_EQ(original_lang, received_original_lang); EXPECT_EQ(target_lang, received_target_lang); EXPECT_EQ(translate::TranslateErrors::NONE, error); @@ -313,9 +384,8 @@ std::string received_original_lang; std::string received_target_lang; translate::TranslateErrors::Type error; - ASSERT_TRUE(GetPageTranslatedMessage(&received_original_lang, - &received_target_lang, - &error)); + ASSERT_TRUE(translate_helper_->GetPageTranslatedResult( + &received_original_lang, &received_target_lang, &error)); EXPECT_EQ(original_lang, received_original_lang); EXPECT_EQ(new_target_lang, received_target_lang); EXPECT_EQ(translate::TranslateErrors::NONE, error); @@ -323,144 +393,117 @@ // Tests that we send the right translate language message for a page and that // we respect the "no translate" meta-tag. -TEST_F(ChromeRenderViewTest, TranslatablePage) { +TEST_F(TranslateHelperBrowserTest, TranslatablePage) { LoadHTML("<html><body>A random page with random content.</body></html>"); - const IPC::Message* message = render_thread_->sink().GetUniqueMessageMatching( - ChromeFrameHostMsg_TranslateLanguageDetermined::ID); - ASSERT_NE(static_cast<IPC::Message*>(NULL), message); - ChromeFrameHostMsg_TranslateLanguageDetermined::Param params; - ChromeFrameHostMsg_TranslateLanguageDetermined::Read(message, ¶ms); - EXPECT_TRUE(std::get<1>(params)) << "Page should be translatable."; - render_thread_->sink().ClearMessages(); + base::RunLoop().RunUntilIdle(); + ASSERT_TRUE(fake_translate_driver_.called_new_page_); + EXPECT_TRUE(fake_translate_driver_.page_needs_translation_) + << "Page should be translatable."; + fake_translate_driver_.ResetNewPageValues(); // Now the page specifies the META tag to prevent translation. LoadHTML("<html><head><meta name=\"google\" value=\"notranslate\"></head>" "<body>A random page with random content.</body></html>"); - message = render_thread_->sink().GetUniqueMessageMatching( - ChromeFrameHostMsg_TranslateLanguageDetermined::ID); - ASSERT_NE(static_cast<IPC::Message*>(NULL), message); - ChromeFrameHostMsg_TranslateLanguageDetermined::Read(message, ¶ms); - EXPECT_FALSE(std::get<1>(params)) << "Page should not be translatable."; - render_thread_->sink().ClearMessages(); + base::RunLoop().RunUntilIdle(); + ASSERT_TRUE(fake_translate_driver_.called_new_page_); + EXPECT_FALSE(fake_translate_driver_.page_needs_translation_) + << "Page should not be translatable."; + fake_translate_driver_.ResetNewPageValues(); // Try the alternate version of the META tag (content instead of value). LoadHTML("<html><head><meta name=\"google\" content=\"notranslate\"></head>" "<body>A random page with random content.</body></html>"); - message = render_thread_->sink().GetUniqueMessageMatching( - ChromeFrameHostMsg_TranslateLanguageDetermined::ID); - ASSERT_NE(static_cast<IPC::Message*>(NULL), message); - ChromeFrameHostMsg_TranslateLanguageDetermined::Read(message, ¶ms); - EXPECT_FALSE(std::get<1>(params)) << "Page should not be translatable."; + base::RunLoop().RunUntilIdle(); + ASSERT_TRUE(fake_translate_driver_.called_new_page_); + EXPECT_FALSE(fake_translate_driver_.page_needs_translation_) + << "Page should not be translatable."; } // Tests that the language meta tag takes precedence over the CLD when reporting // the page's language. -TEST_F(ChromeRenderViewTest, LanguageMetaTag) { +TEST_F(TranslateHelperBrowserTest, LanguageMetaTag) { LoadHTML("<html><head><meta http-equiv=\"content-language\" content=\"es\">" "</head><body>A random page with random content.</body></html>"); - const IPC::Message* message = render_thread_->sink().GetUniqueMessageMatching( - ChromeFrameHostMsg_TranslateLanguageDetermined::ID); - ASSERT_NE(static_cast<IPC::Message*>(NULL), message); - ChromeFrameHostMsg_TranslateLanguageDetermined::Param params; - ChromeFrameHostMsg_TranslateLanguageDetermined::Read(message, ¶ms); - EXPECT_EQ("es", std::get<0>(params).adopted_language); - render_thread_->sink().ClearMessages(); + base::RunLoop().RunUntilIdle(); + ASSERT_TRUE(fake_translate_driver_.called_new_page_); + EXPECT_EQ("es", fake_translate_driver_.details_->adopted_language); + fake_translate_driver_.ResetNewPageValues(); // Makes sure we support multiple languages specified. LoadHTML("<html><head><meta http-equiv=\"content-language\" " "content=\" fr , es,en \">" "</head><body>A random page with random content.</body></html>"); - message = render_thread_->sink().GetUniqueMessageMatching( - ChromeFrameHostMsg_TranslateLanguageDetermined::ID); - ASSERT_NE(static_cast<IPC::Message*>(NULL), message); - ChromeFrameHostMsg_TranslateLanguageDetermined::Read(message, ¶ms); - EXPECT_EQ("fr", std::get<0>(params).adopted_language); + + base::RunLoop().RunUntilIdle(); + ASSERT_TRUE(fake_translate_driver_.called_new_page_); + EXPECT_EQ("fr", fake_translate_driver_.details_->adopted_language); } // Tests that the language meta tag works even with non-all-lower-case. // http://code.google.com/p/chromium/issues/detail?id=145689 -TEST_F(ChromeRenderViewTest, LanguageMetaTagCase) { +TEST_F(TranslateHelperBrowserTest, LanguageMetaTagCase) { LoadHTML("<html><head><meta http-equiv=\"Content-Language\" content=\"es\">" "</head><body>A random page with random content.</body></html>"); - const IPC::Message* message = render_thread_->sink().GetUniqueMessageMatching( - ChromeFrameHostMsg_TranslateLanguageDetermined::ID); - ASSERT_NE(static_cast<IPC::Message*>(NULL), message); - ChromeFrameHostMsg_TranslateLanguageDetermined::Param params; - ChromeFrameHostMsg_TranslateLanguageDetermined::Read(message, ¶ms); - EXPECT_EQ("es", std::get<0>(params).adopted_language); - render_thread_->sink().ClearMessages(); + base::RunLoop().RunUntilIdle(); + ASSERT_TRUE(fake_translate_driver_.called_new_page_); + EXPECT_EQ("es", fake_translate_driver_.details_->adopted_language); + fake_translate_driver_.ResetNewPageValues(); // Makes sure we support multiple languages specified. LoadHTML("<html><head><meta http-equiv=\"Content-Language\" " "content=\" fr , es,en \">" "</head><body>A random page with random content.</body></html>"); - message = render_thread_->sink().GetUniqueMessageMatching( - ChromeFrameHostMsg_TranslateLanguageDetermined::ID); - ASSERT_NE(static_cast<IPC::Message*>(NULL), message); - ChromeFrameHostMsg_TranslateLanguageDetermined::Read(message, ¶ms); - EXPECT_EQ("fr", std::get<0>(params).adopted_language); + base::RunLoop().RunUntilIdle(); + ASSERT_TRUE(fake_translate_driver_.called_new_page_); + EXPECT_EQ("fr", fake_translate_driver_.details_->adopted_language); } // Tests that the language meta tag is converted to Chrome standard of dashes // instead of underscores and proper capitalization. // http://code.google.com/p/chromium/issues/detail?id=159487 -TEST_F(ChromeRenderViewTest, LanguageCommonMistakesAreCorrected) { +TEST_F(TranslateHelperBrowserTest, LanguageCommonMistakesAreCorrected) { LoadHTML("<html><head><meta http-equiv='Content-Language' content='EN_us'>" "</head><body>A random page with random content.</body></html>"); - const IPC::Message* message = render_thread_->sink().GetUniqueMessageMatching( - ChromeFrameHostMsg_TranslateLanguageDetermined::ID); - ASSERT_NE(static_cast<IPC::Message*>(NULL), message); - ChromeFrameHostMsg_TranslateLanguageDetermined::Param params; - ChromeFrameHostMsg_TranslateLanguageDetermined::Read(message, ¶ms); - EXPECT_EQ("en", std::get<0>(params).adopted_language); - render_thread_->sink().ClearMessages(); + base::RunLoop().RunUntilIdle(); + ASSERT_TRUE(fake_translate_driver_.called_new_page_); + EXPECT_EQ("en", fake_translate_driver_.details_->adopted_language); + fake_translate_driver_.ResetNewPageValues(); LoadHTML("<html><head><meta http-equiv='Content-Language' content='ZH_tw'>" "</head><body>A random page with random content.</body></html>"); - message = render_thread_->sink().GetUniqueMessageMatching( - ChromeFrameHostMsg_TranslateLanguageDetermined::ID); - ASSERT_NE(static_cast<IPC::Message*>(NULL), message); - ChromeFrameHostMsg_TranslateLanguageDetermined::Read(message, ¶ms); - EXPECT_EQ("zh-TW", std::get<0>(params).adopted_language); - render_thread_->sink().ClearMessages(); + base::RunLoop().RunUntilIdle(); + ASSERT_TRUE(fake_translate_driver_.called_new_page_); + EXPECT_EQ("zh-TW", fake_translate_driver_.details_->adopted_language); } // Tests that a back navigation gets a translate language message. -TEST_F(ChromeRenderViewTest, BackToTranslatablePage) { +TEST_F(TranslateHelperBrowserTest, BackToTranslatablePage) { LoadHTML("<html><head><meta http-equiv=\"content-language\" content=\"zh\">" "</head><body>This page is in Chinese.</body></html>"); - const IPC::Message* message = render_thread_->sink().GetUniqueMessageMatching( - ChromeFrameHostMsg_TranslateLanguageDetermined::ID); - ASSERT_NE(static_cast<IPC::Message*>(NULL), message); - ChromeFrameHostMsg_TranslateLanguageDetermined::Param params; - ChromeFrameHostMsg_TranslateLanguageDetermined::Read(message, ¶ms); - EXPECT_EQ("zh", std::get<0>(params).adopted_language); - render_thread_->sink().ClearMessages(); + base::RunLoop().RunUntilIdle(); + ASSERT_TRUE(fake_translate_driver_.called_new_page_); + EXPECT_EQ("zh", fake_translate_driver_.details_->adopted_language); + fake_translate_driver_.ResetNewPageValues(); content::PageState back_state = GetCurrentPageState(); LoadHTML("<html><head><meta http-equiv=\"content-language\" content=\"fr\">" "</head><body>This page is in French.</body></html>"); - message = render_thread_->sink().GetUniqueMessageMatching( - ChromeFrameHostMsg_TranslateLanguageDetermined::ID); - ASSERT_NE(static_cast<IPC::Message*>(NULL), message); - ChromeFrameHostMsg_TranslateLanguageDetermined::Read(message, ¶ms); - EXPECT_EQ("fr", std::get<0>(params).adopted_language); - render_thread_->sink().ClearMessages(); + base::RunLoop().RunUntilIdle(); + ASSERT_TRUE(fake_translate_driver_.called_new_page_); + EXPECT_EQ("fr", fake_translate_driver_.details_->adopted_language); + fake_translate_driver_.ResetNewPageValues(); GoBack(GURL("data:text/html;charset=utf-8,<html><head>" "<meta http-equiv=\"content-language\" content=\"zh\">" "</head><body>This page is in Chinese.</body></html>"), back_state); - message = render_thread_->sink().GetUniqueMessageMatching( - ChromeFrameHostMsg_TranslateLanguageDetermined::ID); - ASSERT_NE(static_cast<IPC::Message*>(NULL), message); - ChromeFrameHostMsg_TranslateLanguageDetermined::Read(message, ¶ms); - EXPECT_EQ("zh", std::get<0>(params).adopted_language); - render_thread_->sink().ClearMessages(); + base::RunLoop().RunUntilIdle(); + ASSERT_TRUE(fake_translate_driver_.called_new_page_); + EXPECT_EQ("zh", fake_translate_driver_.details_->adopted_language); }
diff --git a/chrome/test/base/in_process_browser_test.cc b/chrome/test/base/in_process_browser_test.cc index e277349d..354e5fcb 100644 --- a/chrome/test/base/in_process_browser_test.cc +++ b/chrome/test/base/in_process_browser_test.cc
@@ -275,17 +275,17 @@ *error_message = "browser is NULL"; return false; } - auto tab_strip = browser()->tab_strip_model(); + auto* tab_strip = browser()->tab_strip_model(); if (!tab_strip) { *error_message = "tab_strip is NULL"; return false; } - auto web_contents = tab_strip->GetActiveWebContents(); + auto* web_contents = tab_strip->GetActiveWebContents(); if (!web_contents) { *error_message = "web_contents is NULL"; return false; } - auto focused_frame = web_contents->GetFocusedFrame(); + auto* focused_frame = web_contents->GetFocusedFrame(); if (!focused_frame) { *error_message = "focused_frame is NULL"; return false;
diff --git a/chrome/test/chromedriver/capabilities.cc b/chrome/test/chromedriver/capabilities.cc index 5ad8a490..75d021b 100644 --- a/chrome/test/chromedriver/capabilities.cc +++ b/chrome/test/chromedriver/capabilities.cc
@@ -426,6 +426,9 @@ parser_map["perfLoggingPrefs"] = base::Bind(&ParsePerfLoggingPrefs); parser_map["windowTypes"] = base::Bind(&ParseWindowTypes); + // Compliance is read when session is initialized and correct response is + // sent if not parsed correctly. + parser_map["w3c"] = base::Bind(&IgnoreCapability); if (is_android) { parser_map["androidActivity"] =
diff --git a/chrome/test/chromedriver/chrome/devtools_client.h b/chrome/test/chromedriver/chrome/devtools_client.h index 9365830..aa9df41 100644 --- a/chrome/test/chromedriver/chrome/devtools_client.h +++ b/chrome/test/chromedriver/chrome/devtools_client.h
@@ -56,6 +56,10 @@ const Timeout* timeout, std::unique_ptr<base::DictionaryValue>* result) = 0; + virtual Status SendCommandAndIgnoreResponse( + const std::string& method, + const base::DictionaryValue& params) = 0; + // Adds a listener. This must only be done when the client is disconnected. virtual void AddListener(DevToolsEventListener* listener) = 0;
diff --git a/chrome/test/chromedriver/chrome/devtools_client_impl.cc b/chrome/test/chromedriver/chrome/devtools_client_impl.cc index 00dea56d..470fe35b 100644 --- a/chrome/test/chromedriver/chrome/devtools_client_impl.cc +++ b/chrome/test/chromedriver/chrome/devtools_client_impl.cc
@@ -179,14 +179,14 @@ const base::DictionaryValue& params, const Timeout* timeout) { std::unique_ptr<base::DictionaryValue> result; - return SendCommandInternal(method, params, &result, true, timeout); + return SendCommandInternal(method, params, &result, true, true, timeout); } Status DevToolsClientImpl::SendAsyncCommand( const std::string& method, const base::DictionaryValue& params) { std::unique_ptr<base::DictionaryValue> result; - return SendCommandInternal(method, params, &result, false, nullptr); + return SendCommandInternal(method, params, &result, false, false, nullptr); } Status DevToolsClientImpl::SendCommandAndGetResult( @@ -203,7 +203,7 @@ std::unique_ptr<base::DictionaryValue>* result) { std::unique_ptr<base::DictionaryValue> intermediate_result; Status status = SendCommandInternal( - method, params, &intermediate_result, true, timeout); + method, params, &intermediate_result, true, true, timeout); if (status.IsError()) return status; if (!intermediate_result) @@ -212,6 +212,12 @@ return Status(kOk); } +Status DevToolsClientImpl::SendCommandAndIgnoreResponse( + const std::string& method, + const base::DictionaryValue& params) { + return SendCommandInternal(method, params, nullptr, true, false, nullptr); +} + void DevToolsClientImpl::AddListener(DevToolsEventListener* listener) { CHECK(listener); listeners_.push_back(listener); @@ -252,6 +258,7 @@ const std::string& method, const base::DictionaryValue& params, std::unique_ptr<base::DictionaryValue>* result, + bool expect_response, bool wait_for_response, const Timeout* timeout) { if (!socket_->IsConnected()) @@ -270,30 +277,35 @@ if (!socket_->Send(message)) return Status(kDisconnected, "unable to send message to renderer"); - if (wait_for_response) { + if (expect_response) { linked_ptr<ResponseInfo> response_info = make_linked_ptr(new ResponseInfo(method)); if (timeout) response_info->command_timeout = *timeout; response_info_map_[command_id] = response_info; - while (response_info->state == kWaiting) { - Status status = ProcessNextMessage( - command_id, Timeout(base::TimeDelta::FromMinutes(10), timeout)); - if (status.IsError()) { - if (response_info->state == kReceived) - response_info_map_.erase(command_id); - return status; + + if (wait_for_response) { + while (response_info->state == kWaiting) { + Status status = ProcessNextMessage( + command_id, Timeout(base::TimeDelta::FromMinutes(10), timeout)); + if (status.IsError()) { + if (response_info->state == kReceived) + response_info_map_.erase(command_id); + return status; + } } + if (response_info->state == kBlocked) { + response_info->state = kIgnored; + return Status(kUnexpectedAlertOpen); + } + CHECK_EQ(response_info->state, kReceived); + internal::InspectorCommandResponse& response = response_info->response; + if (!response.result) + return ParseInspectorError(response.error); + *result = std::move(response.result); } - if (response_info->state == kBlocked) { - response_info->state = kIgnored; - return Status(kUnexpectedAlertOpen); - } - CHECK_EQ(response_info->state, kReceived); - internal::InspectorCommandResponse& response = response_info->response; - if (!response.result) - return ParseInspectorError(response.error); - *result = std::move(response.result); + } else { + CHECK(!wait_for_response); } return Status(kOk); }
diff --git a/chrome/test/chromedriver/chrome/devtools_client_impl.h b/chrome/test/chromedriver/chrome/devtools_client_impl.h index 8b84f331..bcd66ce1 100644 --- a/chrome/test/chromedriver/chrome/devtools_client_impl.h +++ b/chrome/test/chromedriver/chrome/devtools_client_impl.h
@@ -104,6 +104,9 @@ const base::DictionaryValue& params, const Timeout* timeout, std::unique_ptr<base::DictionaryValue>* result) override; + Status SendCommandAndIgnoreResponse( + const std::string& method, + const base::DictionaryValue& params) override; void AddListener(DevToolsEventListener* listener) override; Status HandleEventsUntil(const ConditionalFunc& conditional_func, const Timeout& timeout) override; @@ -136,6 +139,7 @@ const std::string& method, const base::DictionaryValue& params, std::unique_ptr<base::DictionaryValue>* result, + bool expect_response, bool wait_for_response, const Timeout* timeout); Status ProcessNextMessage(int expected_id, const Timeout& timeout);
diff --git a/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc b/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc index 18ea9591..a272b31 100644 --- a/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc +++ b/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc
@@ -1106,3 +1106,72 @@ ASSERT_EQ("cmd", listener2.msgs_.front()); ASSERT_EQ("event", listener2.msgs_.back()); } + +namespace { + +class MockSyncWebSocket7 : public SyncWebSocket { + public: + MockSyncWebSocket7() : id_(-1), sent_messages_(0), sent_responses_(0) {} + ~MockSyncWebSocket7() override {} + + bool IsConnected() override { return true; } + + bool Connect(const GURL& url) override { return true; } + + bool Send(const std::string& message) override { + std::unique_ptr<base::Value> value = base::JSONReader::Read(message); + base::DictionaryValue* dict = nullptr; + EXPECT_TRUE(value->GetAsDictionary(&dict)); + if (!dict) + return false; + EXPECT_TRUE(dict->GetInteger("id", &id_)); + std::string method; + EXPECT_TRUE(dict->GetString("method", &method)); + EXPECT_STREQ("method", method.c_str()); + base::DictionaryValue* params = nullptr; + EXPECT_TRUE(dict->GetDictionary("params", ¶ms)); + if (!params) + return false; + sent_messages_++; + return true; + } + + SyncWebSocket::StatusCode ReceiveNextMessage( + std::string* message, + const Timeout& timeout) override { + EXPECT_LE(sent_responses_, 1); + EXPECT_EQ(sent_messages_, 2); + base::DictionaryValue response; + if (sent_responses_ == 0) + response.SetInteger("id", 1); + else + response.SetInteger("id", 2); + base::DictionaryValue result; + result.SetInteger("param", 1); + response.Set("result", result.DeepCopy()); + base::JSONWriter::Write(response, message); + sent_responses_++; + return SyncWebSocket::kOk; + } + + bool HasNextMessage() override { return sent_messages_ > sent_responses_; } + +private: + int id_; + int sent_messages_; + int sent_responses_; +}; + +} // namespace + +TEST_F(DevToolsClientImplTest, SendCommandAndIgnoreResponse) { + SyncWebSocketFactory factory = + base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket7>); + DevToolsClientImpl client(factory, "http://url", "id", + base::Bind(&CloserFunc)); + ASSERT_EQ(kOk, client.ConnectIfNecessary().code()); + base::DictionaryValue params; + params.SetInteger("param", 1); + ASSERT_EQ(kOk, client.SendCommandAndIgnoreResponse("method", params).code()); + ASSERT_EQ(kOk, client.SendCommand("method", params).code()); +}
diff --git a/chrome/test/chromedriver/chrome/status.cc b/chrome/test/chromedriver/chrome/status.cc index 4eaaf58..e6451f3 100644 --- a/chrome/test/chromedriver/chrome/status.cc +++ b/chrome/test/chromedriver/chrome/status.cc
@@ -4,6 +4,7 @@ #include "chrome/test/chromedriver/chrome/status.h" +#include "base/debug/stack_trace.h" #include "base/strings/stringprintf.h" namespace { @@ -67,17 +68,25 @@ } // namespace Status::Status(StatusCode code) - : code_(code), msg_(DefaultMessageForStatusCode(code)) {} + : code_(code), msg_(DefaultMessageForStatusCode(code)) { + if (code != kOk) + stack_trace_ = base::debug::StackTrace().ToString(); +} Status::Status(StatusCode code, const std::string& details) : code_(code), msg_(DefaultMessageForStatusCode(code) + std::string(": ") + details) { + if (code != kOk) + stack_trace_ = base::debug::StackTrace().ToString(); } Status::Status(StatusCode code, const Status& cause) : code_(code), msg_(DefaultMessageForStatusCode(code) + std::string("\nfrom ") + - cause.message()) {} + cause.message()) { + if (code != kOk) + stack_trace_ = cause.stack_trace(); +} Status::Status(StatusCode code, const std::string& details, @@ -85,6 +94,8 @@ : code_(code), msg_(DefaultMessageForStatusCode(code) + std::string(": ") + details + "\nfrom " + cause.message()) { + if (code != kOk) + stack_trace_ = cause.stack_trace(); } Status::~Status() {} @@ -108,3 +119,7 @@ const std::string& Status::message() const { return msg_; } + +const std::string& Status::stack_trace() const { + return stack_trace_; +}
diff --git a/chrome/test/chromedriver/chrome/status.h b/chrome/test/chromedriver/chrome/status.h index ce64765d..4d69d8c 100644 --- a/chrome/test/chromedriver/chrome/status.h +++ b/chrome/test/chromedriver/chrome/status.h
@@ -54,9 +54,12 @@ const std::string& message() const; + const std::string& stack_trace() const; + private: StatusCode code_; std::string msg_; + std::string stack_trace_; }; #endif // CHROME_TEST_CHROMEDRIVER_CHROME_STATUS_H_
diff --git a/chrome/test/chromedriver/chrome/stub_devtools_client.cc b/chrome/test/chromedriver/chrome/stub_devtools_client.cc index 288464682..85b041f 100644 --- a/chrome/test/chromedriver/chrome/stub_devtools_client.cc +++ b/chrome/test/chromedriver/chrome/stub_devtools_client.cc
@@ -61,6 +61,12 @@ return SendCommandAndGetResult(method, params, result); } +Status StubDevToolsClient::SendCommandAndIgnoreResponse( + const std::string& method, + const base::DictionaryValue& params) { + return SendCommand(method, params); +} + void StubDevToolsClient::AddListener(DevToolsEventListener* listener) { listeners_.push_back(listener); }
diff --git a/chrome/test/chromedriver/chrome/stub_devtools_client.h b/chrome/test/chromedriver/chrome/stub_devtools_client.h index e405e7f..27e3527f 100644 --- a/chrome/test/chromedriver/chrome/stub_devtools_client.h +++ b/chrome/test/chromedriver/chrome/stub_devtools_client.h
@@ -47,6 +47,9 @@ const base::DictionaryValue& params, const Timeout* timeout, std::unique_ptr<base::DictionaryValue>* result) override; + Status SendCommandAndIgnoreResponse( + const std::string& method, + const base::DictionaryValue& params) override; void AddListener(DevToolsEventListener* listener) override; Status HandleEventsUntil(const ConditionalFunc& conditional_func, const Timeout& timeout) override;
diff --git a/chrome/test/chromedriver/chrome/web_view_impl_unittest.cc b/chrome/test/chromedriver/chrome/web_view_impl_unittest.cc index 179a8bb3..7545980 100644 --- a/chrome/test/chromedriver/chrome/web_view_impl_unittest.cc +++ b/chrome/test/chromedriver/chrome/web_view_impl_unittest.cc
@@ -65,6 +65,11 @@ std::unique_ptr<base::DictionaryValue>* result) override { return SendCommandAndGetResult(method, params, result); } + Status SendCommandAndIgnoreResponse( + const std::string& method, + const base::DictionaryValue& params) override { + return SendCommandAndGetResult(method, params, nullptr); + } void AddListener(DevToolsEventListener* listener) override {} Status HandleEventsUntil(const ConditionalFunc& conditional_func, const Timeout& timeout) override {
diff --git a/chrome/test/chromedriver/chrome_launcher.cc b/chrome/test/chromedriver/chrome_launcher.cc index 0e257d0..3448ba6 100644 --- a/chrome/test/chromedriver/chrome_launcher.cc +++ b/chrome/test/chromedriver/chrome_launcher.cc
@@ -133,9 +133,9 @@ base::CommandLine command(program); Switches switches; - for (const auto& common_switch : kCommonSwitches) + for (auto* common_switch : kCommonSwitches) switches.SetUnparsedSwitch(common_switch); - for (const auto& desktop_switch : kDesktopSwitches) + for (auto* desktop_switch : kDesktopSwitches) switches.SetUnparsedSwitch(desktop_switch); switches.SetSwitch("remote-debugging-port", base::UintToString(port)); for (const auto& excluded_switch : capabilities.exclude_switches) { @@ -483,9 +483,9 @@ return status; Switches switches(capabilities.switches); - for (auto common_switch : kCommonSwitches) + for (auto* common_switch : kCommonSwitches) switches.SetUnparsedSwitch(common_switch); - for (auto android_switch : kAndroidSwitches) + for (auto* android_switch : kAndroidSwitches) switches.SetUnparsedSwitch(android_switch); for (auto excluded_switch : capabilities.exclude_switches) switches.RemoveSwitch(excluded_switch);
diff --git a/chrome/test/chromedriver/client/chromedriver.py b/chrome/test/chromedriver/client/chromedriver.py index 44b9216..f211bb4 100644 --- a/chrome/test/chromedriver/client/chromedriver.py +++ b/chrome/test/chromedriver/client/chromedriver.py
@@ -20,12 +20,18 @@ pass class StaleElementReference(ChromeDriverException): pass +class ElementNotVisible(ChromeDriverException): + pass +class InvalidElementState(ChromeDriverException): + pass class UnknownError(ChromeDriverException): pass class JavaScriptError(ChromeDriverException): pass class XPathLookupError(ChromeDriverException): pass +class Timeout(ChromeDriverException): + pass class NoSuchWindow(ChromeDriverException): pass class InvalidCookieDomain(ChromeDriverException): @@ -40,20 +46,26 @@ pass class UnexpectedAlertOpen(ChromeDriverException): pass +class NoAlertOpen(ChromeDriverException): + pass -def _ExceptionForResponse(response): +def _ExceptionForLegacyResponse(response): exception_class_map = { 6: NoSuchSession, 7: NoSuchElement, 8: NoSuchFrame, 9: UnknownCommand, 10: StaleElementReference, + 11: ElementNotVisible, + 12: InvalidElementState, 13: UnknownError, 17: JavaScriptError, 19: XPathLookupError, + 21: Timeout, 23: NoSuchWindow, 24: InvalidCookieDomain, 26: UnexpectedAlertOpen, + 27: NoAlertOpen, 28: ScriptTimeout, 32: InvalidSelector, 33: SessionNotCreatedException @@ -62,6 +74,31 @@ msg = response['value']['message'] return exception_class_map.get(status, ChromeDriverException)(msg) +def _ExceptionForStandardResponse(response): + exception_map = { + 'no such session' : NoSuchSession, + 'no such element': NoSuchElement, + 'no such frame': NoSuchFrame, + 'unknown command': UnknownCommand, + 'stale element reference': StaleElementReference, + 'element not visible': ElementNotVisible, + 'invalid element state': InvalidElementState, + 'unknown error': UnknownError, + 'javascript error': JavaScriptError, + 'xpath lookup error': XPathLookupError, + 'timeout': Timeout, + 'no such window': NoSuchWindow, + 'invalid cookie domain': InvalidCookieDomain, + 'unexpected alert open': UnexpectedAlertOpen, + 'no alert open': NoAlertOpen, + 'asynchronous script timeout': ScriptTimeout, + 'invalid selector': InvalidSelector, + 'session not created exception': SessionNotCreatedException + } + + error = response['error'] + msg = response['message'] + return exception_map.get(error, ChromeDriverException)(msg) class ChromeDriver(object): """Starts and controls a single Chrome instance on this machine.""" @@ -72,8 +109,9 @@ chrome_extensions=None, chrome_log_path=None, debugger_address=None, logging_prefs=None, mobile_emulation=None, experimental_options=None, - download_dir=None, page_load_strategy=None, - network_connection=None): + download_dir=None, network_connection=None, + send_w3c_capability=None, send_w3c_request=None, + page_load_strategy=None): self._executor = command_executor.CommandExecutor(server_url) options = {} @@ -138,6 +176,9 @@ options['prefs']['download'] = {} options['prefs']['download']['default_directory'] = download_dir + if send_w3c_capability: + options['w3c'] = send_w3c_capability + params = { 'desiredCapabilities': { 'chromeOptions': options, @@ -153,7 +194,17 @@ params['desiredCapabilities']['networkConnectionEnabled'] = ( network_connection) + if send_w3c_request: + params = {'capabilities': params} + response = self._ExecuteCommand(Command.NEW_SESSION, params) + if isinstance(response['status'], basestring): + self.w3c_compliant = True + elif isinstance(response['status'], int): + self.w3c_compliant = False + else: + raise UnknownError("unexpected response") + self._session_id = response['sessionId'] self.capabilities = self._UnwrapValue(response['value']) @@ -190,8 +241,11 @@ def _ExecuteCommand(self, command, params={}): params = self._WrapValue(params) response = self._executor.Execute(command, params) - if response['status'] != 0: - raise _ExceptionForResponse(response) + if ('status' in response and isinstance(response['status'], int) and + response['status'] != 0): + raise _ExceptionForLegacyResponse(response) + elif 'error' in response: + raise _ExceptionForStandardResponse(response) return response def ExecuteCommand(self, command, params={}):
diff --git a/chrome/test/chromedriver/client/command_executor.py b/chrome/test/chromedriver/client/command_executor.py index 650d82e..2003f76d 100644 --- a/chrome/test/chromedriver/client/command_executor.py +++ b/chrome/test/chromedriver/client/command_executor.py
@@ -182,7 +182,8 @@ if response.status == 303: self._http_client.request(_Method.GET, response.getheader('location')) response = self._http_client.getresponse() - if response.status != 200: + result = json.loads(response.read()) + if response.status != 200 and 'error' not in result: raise RuntimeError('Server returned error: ' + response.reason) - return json.loads(response.read()) + return result
diff --git a/chrome/test/chromedriver/command.h b/chrome/test/chromedriver/command.h index 399677f..f461ac7 100644 --- a/chrome/test/chromedriver/command.h +++ b/chrome/test/chromedriver/command.h
@@ -18,7 +18,7 @@ class Status; typedef base::Callback< - void(const Status&, std::unique_ptr<base::Value>, const std::string&)> + void(const Status&, std::unique_ptr<base::Value>, const std::string&, bool)> CommandCallback; typedef base::Callback<void(
diff --git a/chrome/test/chromedriver/commands.cc b/chrome/test/chromedriver/commands.cc index 85ecac8..9978510 100644 --- a/chrome/test/chromedriver/commands.cc +++ b/chrome/test/chromedriver/commands.cc
@@ -49,7 +49,7 @@ info.Set("build", build.DeepCopy()); info.Set("os", os.DeepCopy()); callback.Run(Status(kOk), std::unique_ptr<base::Value>(info.DeepCopy()), - std::string()); + std::string(), false); } void ExecuteCreateSession( @@ -66,7 +66,8 @@ if (!thread->Start()) { callback.Run( Status(kUnknownError, "failed to start a thread for the new session"), - std::unique_ptr<base::Value>(), std::string()); + std::unique_ptr<base::Value>(), std::string(), + session->w3c_compliant); return; } @@ -84,7 +85,8 @@ base::ListValue* session_list, const Status& status, std::unique_ptr<base::Value> value, - const std::string& session_id) { + const std::string& session_id, + bool w3c_compliant) { if (!session_remaining_count) return; @@ -113,7 +115,7 @@ std::unique_ptr<base::ListValue> session_list(new base::ListValue()); if (!get_remaining_count) { - callback.Run(Status(kOk), std::move(session_list), session_id); + callback.Run(Status(kOk), std::move(session_list), session_id, false); return; } @@ -135,7 +137,7 @@ base::MessageLoop::current()->SetNestableTasksAllowed(true); run_loop.Run(); - callback.Run(Status(kOk), std::move(session_list), session_id); + callback.Run(Status(kOk), std::move(session_list), session_id, false); } namespace { @@ -144,7 +146,8 @@ const base::Closure& all_quit_func, const Status& status, std::unique_ptr<base::Value> value, - const std::string& session_id) { + const std::string& session_id, + bool w3c_compliant) { // |quit_remaining_count| may no longer be valid if a timeout occurred. if (!quit_remaining_count) return; @@ -165,7 +168,8 @@ size_t quit_remaining_count = session_thread_map->size(); base::WeakPtrFactory<size_t> weak_ptr_factory(&quit_remaining_count); if (!quit_remaining_count) { - callback.Run(Status(kOk), std::unique_ptr<base::Value>(), session_id); + callback.Run(Status(kOk), std::unique_ptr<base::Value>(), + session_id, false); return; } base::RunLoop run_loop; @@ -184,7 +188,8 @@ // commands have executed, or the timeout expires. base::MessageLoop::current()->SetNestableTasksAllowed(true); run_loop.Run(); - callback.Run(Status(kOk), std::unique_ptr<base::Value>(), session_id); + callback.Run(Status(kOk), std::unique_ptr<base::Value>(), + session_id, false); } namespace { @@ -209,7 +214,8 @@ base::Bind(callback_on_cmd, Status(return_ok_without_session ? kOk : kNoSuchSession), base::Passed(std::unique_ptr<base::Value>()), - std::string())); + std::string(), + false)); return; } @@ -285,7 +291,8 @@ cmd_task_runner->PostTask( FROM_HERE, - base::Bind(callback_on_cmd, status, base::Passed(&value), session->id)); + base::Bind(callback_on_cmd, status, base::Passed(&value), session->id, + session->w3c_compliant)); if (session->quit) { SetThreadLocalSession(std::unique_ptr<Session>()); @@ -307,7 +314,7 @@ SessionThreadMap::iterator iter = session_thread_map->find(session_id); if (iter == session_thread_map->end()) { Status status(return_ok_without_session ? kOk : kNoSuchSession); - callback.Run(status, std::unique_ptr<base::Value>(), session_id); + callback.Run(status, std::unique_ptr<base::Value>(), session_id, false); } else { iter->second->task_runner()->PostTask( FROM_HERE, base::Bind(&ExecuteSessionCommandOnSessionThread,
diff --git a/chrome/test/chromedriver/commands_unittest.cc b/chrome/test/chromedriver/commands_unittest.cc index c33643e..5e678f8 100644 --- a/chrome/test/chromedriver/commands_unittest.cc +++ b/chrome/test/chromedriver/commands_unittest.cc
@@ -36,7 +36,8 @@ void OnGetStatus(const Status& status, std::unique_ptr<base::Value> value, - const std::string& session_id) { + const std::string& session_id, + bool w3c_compliant) { ASSERT_EQ(kOk, status.code()); base::DictionaryValue* dict; ASSERT_TRUE(value->GetAsDictionary(&dict)); @@ -73,12 +74,13 @@ capabilities->Set("capability1", new base::StringValue("test1")); capabilities->Set("capability2", new base::StringValue("test2")); - callback.Run(Status(kOk), std::move(capabilities), session_id); + callback.Run(Status(kOk), std::move(capabilities), session_id, false); } void OnGetSessions(const Status& status, std::unique_ptr<base::Value> value, - const std::string& session_id) { + const std::string& session_id, + bool w3c_compliant) { ASSERT_EQ(kOk, status.code()); ASSERT_TRUE(value.get()); base::ListValue* sessions; @@ -162,12 +164,13 @@ EXPECT_STREQ("id2", session_id.c_str()); } (*count)++; - callback.Run(Status(kOk), std::unique_ptr<base::Value>(), session_id); + callback.Run(Status(kOk), std::unique_ptr<base::Value>(), session_id, false); } void OnQuitAll(const Status& status, std::unique_ptr<base::Value> value, - const std::string& session_id) { + const std::string& session_id, + bool w3c_compliant) { ASSERT_EQ(kOk, status.code()); ASSERT_FALSE(value.get()); } @@ -209,7 +212,8 @@ base::Value* expected_value, const Status& status, std::unique_ptr<base::Value> value, - const std::string& session_id) { + const std::string& session_id, + bool w3c_compliant) { ASSERT_EQ(kOk, status.code()); ASSERT_TRUE(expected_value->Equals(value.get())); ASSERT_EQ(expected_session_id, session_id); @@ -258,14 +262,16 @@ void OnNoSuchSession(const Status& status, std::unique_ptr<base::Value> value, - const std::string& session_id) { + const std::string& session_id, + bool w3c_compliant) { EXPECT_EQ(kNoSuchSession, status.code()); EXPECT_FALSE(value.get()); } void OnNoSuchSessionIsOk(const Status& status, std::unique_ptr<base::Value> value, - const std::string& session_id) { + const std::string& session_id, + bool w3c_compliant) { EXPECT_EQ(kOk, status.code()); EXPECT_FALSE(value.get()); } @@ -301,7 +307,8 @@ void OnNoSuchSessionAndQuit(base::RunLoop* run_loop, const Status& status, std::unique_ptr<base::Value> value, - const std::string& session_id) { + const std::string& session_id, + bool w3c_compliant) { run_loop->Quit(); EXPECT_EQ(kNoSuchSession, status.code()); EXPECT_FALSE(value.get()); @@ -695,7 +702,8 @@ void OnSessionCommand(base::RunLoop* run_loop, const Status& status, std::unique_ptr<base::Value> value, - const std::string& session_id) { + const std::string& session_id, + bool w3c_compliant) { ASSERT_EQ(kOk, status.code()); run_loop->Quit(); } @@ -778,7 +786,8 @@ void OnFailBecauseErrorNotifyingListeners(base::RunLoop* run_loop, const Status& status, std::unique_ptr<base::Value> value, - const std::string& session_id) { + const std::string& session_id, + bool w3c_compliant) { EXPECT_EQ(kUnknownError, status.code()); EXPECT_FALSE(value.get()); run_loop->Quit();
diff --git a/chrome/test/chromedriver/performance_logger.cc b/chrome/test/chromedriver/performance_logger.cc index e67074f..0bad2ae 100644 --- a/chrome/test/chromedriver/performance_logger.cc +++ b/chrome/test/chromedriver/performance_logger.cc
@@ -42,7 +42,7 @@ // Returns whether |command| is in kRequestTraceCommands[] (case-insensitive). bool ShouldRequestTraceEvents(const std::string& command) { - for (const auto& request_command : kRequestTraceCommands) { + for (auto* request_command : kRequestTraceCommands) { if (base::EqualsCaseInsensitiveASCII(command, request_command)) return true; } @@ -51,7 +51,7 @@ // Returns whether the event belongs to one of kDomains. bool ShouldLogEvent(const std::string& method) { - for (const auto& domain : kDomains) { + for (auto* domain : kDomains) { if (base::StartsWith(method, domain, base::CompareCase::SENSITIVE)) return true; }
diff --git a/chrome/test/chromedriver/server/http_handler.cc b/chrome/test/chromedriver/server/http_handler.cc index 6323b24..364bc18 100644 --- a/chrome/test/chromedriver/server/http_handler.cc +++ b/chrome/test/chromedriver/server/http_handler.cc
@@ -48,14 +48,6 @@ const char kSessionStorage[] = "sessionStorage"; const char kShutdownPath[] = "shutdown"; -void UnimplementedCommand( - const base::DictionaryValue& params, - const std::string& session_id, - const CommandCallback& callback) { - callback.Run(Status(kUnknownCommand), std::unique_ptr<base::Value>(), - session_id); -} - } // namespace CommandMapping::CommandMapping(HttpMethod method, @@ -203,12 +195,14 @@ kGet, "session/:sessionId/chromium/heap_snapshot", WrapToCommand("HeapSnapshot", base::Bind(&ExecuteTakeHeapSnapshot))), - CommandMapping(kPost, - "session/:sessionId/visible", - base::Bind(&UnimplementedCommand)), - CommandMapping(kGet, - "session/:sessionId/visible", - base::Bind(&UnimplementedCommand)), + CommandMapping( + kPost, + "session/:sessionId/visible", + WrapToCommand("Visible", base::Bind(&ExecuteUnimplementedCommand))), + CommandMapping( + kGet, + "session/:sessionId/visible", + WrapToCommand("Visible", base::Bind(&ExecuteUnimplementedCommand))), CommandMapping( kPost, "session/:sessionId/element", @@ -350,9 +344,10 @@ CommandMapping(kDelete, "session/:sessionId/window", WrapToCommand("CloseWindow", base::Bind(&ExecuteClose))), - CommandMapping(kPost, - "session/:sessionId/element/:id/drag", - base::Bind(&UnimplementedCommand)), + CommandMapping( + kPost, + "session/:sessionId/element/:id/drag", + WrapToCommand("Drag", base::Bind(&ExecuteUnimplementedCommand))), CommandMapping( kGet, "session/:sessionId/element/:id/css/:propertyName", @@ -370,9 +365,11 @@ kPost, "session/:sessionId/timeouts", WrapToCommand("SetTimeout", base::Bind(&ExecuteSetTimeout))), - CommandMapping(kPost, - "session/:sessionId/execute_sql", - base::Bind(&UnimplementedCommand)), + CommandMapping( + kPost, + "session/:sessionId/execute_sql", + WrapToCommand("ExecuteSql", + base::Bind(&ExecuteUnimplementedCommand))), CommandMapping( kGet, "session/:sessionId/location", @@ -409,12 +406,16 @@ CommandMapping(kGet, "session/:sessionId/application_cache/status", base::Bind(&ExecuteGetStatus)), - CommandMapping(kGet, - "session/:sessionId/browser_connection", - base::Bind(&UnimplementedCommand)), - CommandMapping(kPost, - "session/:sessionId/browser_connection", - base::Bind(&UnimplementedCommand)), + CommandMapping( + kGet, + "session/:sessionId/browser_connection", + WrapToCommand("GetBrowserConnection", + base::Bind(&ExecuteUnimplementedCommand))), + CommandMapping( + kPost, + "session/:sessionId/browser_connection", + WrapToCommand("SetBrowserConnection", + base::Bind(&ExecuteUnimplementedCommand))), CommandMapping( kGet, "session/:sessionId/local_storage/key/:key", @@ -475,12 +476,16 @@ "session/:sessionId/session_storage/size", WrapToCommand("GetSessionStorageSize", base::Bind(&ExecuteGetStorageSize, kSessionStorage))), - CommandMapping(kGet, - "session/:sessionId/orientation", - base::Bind(&UnimplementedCommand)), - CommandMapping(kPost, - "session/:sessionId/orientation", - base::Bind(&UnimplementedCommand)), + CommandMapping( + kGet, + "session/:sessionId/orientation", + WrapToCommand("GetOrientation", + base::Bind(&ExecuteUnimplementedCommand))), + CommandMapping( + kPost, + "session/:sessionId/orientation", + WrapToCommand("SetOrientation", + base::Bind(&ExecuteUnimplementedCommand))), CommandMapping(kPost, "session/:sessionId/click", WrapToCommand("Click", base::Bind(&ExecuteMouseClick))), @@ -506,19 +511,27 @@ WrapToCommand("Type", base::Bind(&ExecuteSendKeysToActiveElement))), CommandMapping(kGet, "session/:sessionId/ime/available_engines", - base::Bind(&UnimplementedCommand)), - CommandMapping(kGet, - "session/:sessionId/ime/active_engine", - base::Bind(&UnimplementedCommand)), - CommandMapping(kGet, - "session/:sessionId/ime/activated", - base::Bind(&UnimplementedCommand)), - CommandMapping(kPost, - "session/:sessionId/ime/deactivate", - base::Bind(&UnimplementedCommand)), - CommandMapping(kPost, - "session/:sessionId/ime/activate", - base::Bind(&UnimplementedCommand)), + WrapToCommand("GetAvailableEngines", + base::Bind(&ExecuteUnimplementedCommand))), + CommandMapping( + kGet, + "session/:sessionId/ime/active_engine", + WrapToCommand("GetActiveEngine", + base::Bind(&ExecuteUnimplementedCommand))), + CommandMapping( + kGet, + "session/:sessionId/ime/activated", + WrapToCommand("Activated", + base::Bind(&ExecuteUnimplementedCommand))), + CommandMapping( + kPost, + "session/:sessionId/ime/deactivate", + WrapToCommand("Deactivate", + base::Bind(&ExecuteUnimplementedCommand))), + CommandMapping( + kPost, + "session/:sessionId/ime/activate", + WrapToCommand("Activate", base::Bind(&ExecuteUnimplementedCommand))), CommandMapping(kPost, "session/:sessionId/touch/click", WrapToCommand("Tap", base::Bind(&ExecuteTouchSingleTap))), @@ -553,7 +566,10 @@ "session/:sessionId/log/types", WrapToCommand("GetLogTypes", base::Bind(&ExecuteGetAvailableLogTypes))), - CommandMapping(kPost, "logs", base::Bind(&UnimplementedCommand)), + CommandMapping( + kPost, + "Logs", + WrapToCommand("Logs", base::Bind(&ExecuteUnimplementedCommand))), CommandMapping(kGet, "status", base::Bind(&ExecuteGetStatus)), // Custom Chrome commands: @@ -689,16 +705,24 @@ const HttpResponseSenderFunc& send_response_func, const Status& status, std::unique_ptr<base::Value> value, - const std::string& session_id) { + const std::string& session_id, + bool w3c_compliant) { CHECK(thread_checker_.CalledOnValidThread()); - std::unique_ptr<net::HttpServerResponseInfo> response = - PrepareResponseHelper(trimmed_path, status, std::move(value), session_id); + std::unique_ptr<net::HttpServerResponseInfo> response; + if (w3c_compliant) + response = PrepareStandardResponse( + trimmed_path, status, std::move(value), session_id); + else + response = PrepareLegacyResponse(trimmed_path, + status, + std::move(value), + session_id); send_response_func.Run(std::move(response)); if (trimmed_path == kShutdownPath) quit_func_.Run(); } -std::unique_ptr<net::HttpServerResponseInfo> HttpHandler::PrepareResponseHelper( +std::unique_ptr<net::HttpServerResponseInfo> HttpHandler::PrepareLegacyResponse( const std::string& trimmed_path, const Status& status, std::unique_ptr<base::Value> value, @@ -739,6 +763,83 @@ return response; } +std::unique_ptr<net::HttpServerResponseInfo> +HttpHandler::PrepareStandardResponse( + const std::string& trimmed_path, + const Status& status, + std::unique_ptr<base::Value> value, + const std::string& session_id) { + std::unique_ptr<net::HttpServerResponseInfo> response; + switch (status.code()) { + case kOk: + response.reset(new net::HttpServerResponseInfo(net::HTTP_OK)); + break; + case kNoSuchFrame: + case kStaleElementReference: + case kElementNotVisible: + case kInvalidElementState: + case kNoSuchWindow: + case kInvalidCookieDomain: + case kInvalidSelector: + case kXPathLookupError: + case kNoAlertOpen: + case kNoSuchExecutionContext: + response.reset(new net::HttpServerResponseInfo(net::HTTP_BAD_REQUEST)); + break; + case kNoSuchSession: + case kNoSuchElement: + case kUnknownCommand: + response.reset(new net::HttpServerResponseInfo(net::HTTP_NOT_FOUND)); + break; + case kTimeout: + case kScriptTimeout: + response.reset( + new net::HttpServerResponseInfo(net::HTTP_REQUEST_TIMEOUT)); + break; + case kUnknownError: + case kJavaScriptError: + case kUnexpectedAlertOpen: + case kSessionNotCreatedException: + case kChromeNotReachable: + case kDisconnected: + case kForbidden: + case kTabCrashed: + response.reset( + new net::HttpServerResponseInfo(net::HTTP_INTERNAL_SERVER_ERROR)); + break; + } + + if (!value) + value = base::Value::CreateNullValue(); + + base::DictionaryValue body_params; + if (status.IsError()){ + // Separates status default message from additional details. + std::vector<std::string> status_details = base::SplitString( + status.message(), ":\n", base::TRIM_WHITESPACE, + base::SPLIT_WANT_NONEMPTY); + std::string message; + for (size_t i=1; i<status_details.size();++i) + message += status_details[i]; + + body_params.SetString("error", status_details[0]); + body_params.SetString("message", message); + body_params.SetString("stacktrace", status.stack_trace()); + } else { + body_params.SetString("sessionId", session_id); + body_params.SetString("status", status.message()); + body_params.Set("value", value.release()); + } + + std::string body; + base::JSONWriter::WriteWithOptions( + body_params, base::JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION, + &body); + response->SetBody(body, "application/json; charset=utf-8"); + return response; +} + + namespace internal { const char kNewSessionPathPattern[] = "session";
diff --git a/chrome/test/chromedriver/server/http_handler.h b/chrome/test/chromedriver/server/http_handler.h index 104ca07..9c37a2fa 100644 --- a/chrome/test/chromedriver/server/http_handler.h +++ b/chrome/test/chromedriver/server/http_handler.h
@@ -94,8 +94,15 @@ const HttpResponseSenderFunc& send_response_func, const Status& status, std::unique_ptr<base::Value> value, - const std::string& session_id); - std::unique_ptr<net::HttpServerResponseInfo> PrepareResponseHelper( + const std::string& session_id, + bool w3c_compliant); + std::unique_ptr<net::HttpServerResponseInfo> PrepareLegacyResponse( + const std::string& trimmed_path, + const Status& status, + std::unique_ptr<base::Value> value, + const std::string& session_id); + + std::unique_ptr<net::HttpServerResponseInfo> PrepareStandardResponse( const std::string& trimmed_path, const Status& status, std::unique_ptr<base::Value> value,
diff --git a/chrome/test/chromedriver/server/http_handler_unittest.cc b/chrome/test/chromedriver/server/http_handler_unittest.cc index 73f5f13..7e66d90 100644 --- a/chrome/test/chromedriver/server/http_handler_unittest.cc +++ b/chrome/test/chromedriver/server/http_handler_unittest.cc
@@ -27,7 +27,8 @@ const CommandCallback& callback) { callback.Run(status, std::unique_ptr<base::Value>(new base::FundamentalValue(1)), - "session_id"); + "session_id", + false); } void OnResponse(net::HttpServerResponseInfo* response_to_set,
diff --git a/chrome/test/chromedriver/session.cc b/chrome/test/chromedriver/session.cc index 160a328a..90dad58 100644 --- a/chrome/test/chromedriver/session.cc +++ b/chrome/test/chromedriver/session.cc
@@ -34,6 +34,7 @@ Session::Session(const std::string& id) : id(id), + w3c_compliant(false), quit(false), detach(false), force_devtools_screenshot(false), @@ -44,6 +45,7 @@ Session::Session(const std::string& id, std::unique_ptr<Chrome> chrome) : id(id), + w3c_compliant(false), quit(false), detach(false), force_devtools_screenshot(false),
diff --git a/chrome/test/chromedriver/session.h b/chrome/test/chromedriver/session.h index 1ee7368..f1db7621 100644 --- a/chrome/test/chromedriver/session.h +++ b/chrome/test/chromedriver/session.h
@@ -55,6 +55,7 @@ std::string GetFirstBrowserError() const; const std::string id; + bool w3c_compliant; bool quit; bool detach; bool force_devtools_screenshot;
diff --git a/chrome/test/chromedriver/session_commands.cc b/chrome/test/chromedriver/session_commands.cc index 096ad75..d885472 100644 --- a/chrome/test/chromedriver/session_commands.cc +++ b/chrome/test/chromedriver/session_commands.cc
@@ -160,7 +160,13 @@ session->driver_log.reset( new WebDriverLog(WebDriverLog::kDriverType, Log::kAll)); const base::DictionaryValue* desired_caps; - if (!params.GetDictionary("desiredCapabilities", &desired_caps)) + bool w3c_capability = false; + if (params.GetDictionary("capabilities.desiredCapabilities", &desired_caps) + && desired_caps->GetBoolean("chromeOptions.w3c", &w3c_capability) + && w3c_capability) + session->w3c_compliant = true; + else if (!params.GetDictionary("desiredCapabilities", &desired_caps) && + !params.GetDictionary("capabilities.desiredCapabilities", &desired_caps)) return Status(kUnknownError, "cannot find dict 'desiredCapabilities'"); Capabilities capabilities; @@ -821,3 +827,10 @@ session->auto_reporting_enabled = enabled; return Status(kOk); } + + +Status ExecuteUnimplementedCommand(Session* session, + const base::DictionaryValue& params, + std::unique_ptr<base::Value>* value) { + return Status(kUnknownCommand); +}
diff --git a/chrome/test/chromedriver/session_commands.h b/chrome/test/chromedriver/session_commands.h index fa9c2953..76d766e 100644 --- a/chrome/test/chromedriver/session_commands.h +++ b/chrome/test/chromedriver/session_commands.h
@@ -158,4 +158,8 @@ const base::DictionaryValue& params, std::unique_ptr<base::Value>* value); +Status ExecuteUnimplementedCommand(Session* session, + const base::DictionaryValue& params, + std::unique_ptr<base::Value>* value); + #endif // CHROME_TEST_CHROMEDRIVER_SESSION_COMMANDS_H_
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py index c2ddc68..bd12fd55 100755 --- a/chrome/test/chromedriver/test/run_py_tests.py +++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -1893,6 +1893,28 @@ network = driver.GetNetworkConnection() self.assertEquals(network['connection_type'], connection_type) + def testW3cCompliantResponses(self): + # Asserts that chromedriver has received the correct response. + # W3C compliant responses should only be received when the capability has + # been set and the request was sent in the correct format. + driver = self.CreateDriver(send_w3c_request=True) + self.assertFalse(driver.w3c_compliant) + + driver = self.CreateDriver(send_w3c_capability=True) + self.assertFalse(driver.w3c_compliant) + + driver = self.CreateDriver(send_w3c_capability=True, send_w3c_request=True) + self.assertTrue(driver.w3c_compliant) + + # Asserts that errors are being raised correctly in the test client + # with a w3c compliant driver. + self.assertRaises(chromedriver.UnknownError, + driver.GetNetworkConnection) + + def testNonCompliantByDefault(self): + driver = self.CreateDriver(); + self.assertFalse(driver.w3c_compliant) + class ChromeDriverLogTest(ChromeDriverBaseTest): """Tests that chromedriver produces the expected log file."""
diff --git a/chrome/test/chromedriver/util.py b/chrome/test/chromedriver/util.py index 35ac499..382212d 100644 --- a/chrome/test/chromedriver/util.py +++ b/chrome/test/chromedriver/util.py
@@ -16,6 +16,8 @@ import urlparse import zipfile +import chrome_paths + def GetPlatformName(): """Return a string to be used in paths for the platform.""" @@ -41,6 +43,25 @@ def Is64Bit(): + # This function checks whether the target (not host) word size is 64-bits. + # Since 64-bit hosts can cross-compile 32-bit binaries, check the GN args to + # see what CPU we're targetting. + try: + args_gn = os.path.join(chrome_paths.GetBuildDir(['args.gn']), 'args.gn') + with open(args_gn) as build_args: + for build_arg in build_args: + decommented = build_arg.split('#')[0] + key_and_value = decommented.split('=') + if len(key_and_value) != 2: + continue + key = key_and_value[0].strip() + value = key_and_value[1].strip() + if key == 'target_cpu': + return value.endswith('64') + except: + pass + # If we don't find anything, or if there is no GN args file, default to the + # host architecture. return platform.architecture()[0] == '64bit'
diff --git a/chrome/test/data/android/payments/metrics.js b/chrome/test/data/android/payments/metrics.js index 3f128838..fe9dd0ab 100644 --- a/chrome/test/data/android/payments/metrics.js +++ b/chrome/test/data/android/payments/metrics.js
@@ -12,7 +12,7 @@ /** * Launches the PaymentRequest UI that accepts credit cards. */ -function buy() { // eslint-disable-line no-unused-vars +function ccBuy() { // eslint-disable-line no-unused-vars try { request = new PaymentRequest( [{supportedMethods: ['visa']}], { @@ -44,13 +44,12 @@ } /** - * Launches the PaymentRequest UI which accepts a supported payment method but - * does not accept credit cards. + * Launches the PaymentRequest UI which accepts only Android Pay. */ -function noMatching() { // eslint-disable-line no-unused-vars +function androidPayBuy() { // eslint-disable-line no-unused-vars try { request = new PaymentRequest( - [{supportedMethods: ['https://bobpay.com']}], { + [{supportedMethods: ['https://android.com/pay']}], { total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}}, shippingOptions: [{ id: 'freeShippingOption',
diff --git a/chrome/test/data/android/payments/payment_request_metrics_test.html b/chrome/test/data/android/payments/payment_request_metrics_test.html index 00f6ea70..d2eab70c 100644 --- a/chrome/test/data/android/payments/payment_request_metrics_test.html +++ b/chrome/test/data/android/payments/payment_request_metrics_test.html
@@ -11,8 +11,8 @@ <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> </head> <body> -<button onclick="buy()" id="buy">Metrics Test</button><br> -<button onclick="noMatching()" id="noMatching">No Matching Method Test</button><br> +<button onclick="ccBuy()" id="ccBuy">CC Buy Test</button><br> +<button onclick="androidPayBuy()" id="androidPayBuy">Android Pay Buy Test</button><br> <button onclick="noSupported()" id="noSupported">No Supported Method Test</button><br> <button onclick="abort()" id="abort">Abort</button> <pre id="result"></pre>
diff --git a/chrome/test/data/extensions/api_test/i18n/test.js b/chrome/test/data/extensions/api_test/i18n/test.js index 3569ad5a..bd37cffc 100644 --- a/chrome/test/data/extensions/api_test/i18n/test.js +++ b/chrome/test/data/extensions/api_test/i18n/test.js
@@ -60,22 +60,23 @@ chrome.test.succeed(); }, function detectLanguage() { - var text = "undef"; + var text = ""; chrome.i18n.detectLanguage(text, function (result) { chrome.test.assertEq([], result.languages); }); - text = "This text is obviously in English"; + text = "Αυτό το κείμενο είναι γραμμένο στα ελληνικά"; chrome.i18n.detectLanguage(text, function (result) { - chrome.test.assertEq([{ "language": "en", "percentage": 97 }], + chrome.test.assertEq([{ "language": "el", "percentage": 100 }], result.languages); }); - text = "Данный текст явно не на английском языке. \ - But this one definitely is. Welcome to Google!"; + text = "Αυτό το κομμάτι του κειμένου είναι γραμμένο στα ελληνικά \ + ข้อความสั้น Short piece of text in English"; chrome.i18n.detectLanguage(text, function (result) { - chrome.test.assertEq([{ "language": "ru", "percentage": 61 }, - { "language": "en", "percentage": 37 }], result.languages); + chrome.test.assertEq([{ "language": "el", "percentage": 61 }, + { "language": "th", "percentage": 20 }, + { "language": "en", "percentage": 18}], result.languages); }); chrome.test.succeed();
diff --git a/chrome/test/data/flash_embeds.html b/chrome/test/data/flash_embeds.html new file mode 100644 index 0000000..0b945d49 --- /dev/null +++ b/chrome/test/data/flash_embeds.html
@@ -0,0 +1,16 @@ +<!DOCTYPE html> +<html> + <head></head> + <body> + </body> + <script> + function appendToDOM(url, type) { + var object = document.createElement("object"); + var embed = document.createElement("embed"); + embed.src = url; + embed.setAttribute("type", type); + object.appendChild(embed); + document.body.appendChild(object); + } + </script> +</html>
diff --git a/chrome/test/data/webui/md_history/history_list_test.js b/chrome/test/data/webui/md_history/history_list_test.js index cbcaa78d..6dd1804 100644 --- a/chrome/test/data/webui/md_history/history_list_test.js +++ b/chrome/test/data/webui/md_history/history_list_test.js
@@ -306,10 +306,29 @@ }); }); + test('clicking file:// url sends message to chrome', function(done) { + var fileURL = 'file:///home/myfile'; + app.historyResult(createHistoryInfo(), [ + createHistoryEntry('2016-03-15', fileURL), + ]); + flush().then(function() { + var items = + Polymer.dom(element.root).querySelectorAll('history-item'); + + registerMessageCallback('navigateToUrl', this, function(info) { + assertEquals(fileURL, info[0]); + done(); + }); + + MockInteractions.tap(items[0].$.title); + }); + }); + teardown(function() { element.historyData_ = []; registerMessageCallback('removeVisits', this, undefined); registerMessageCallback('queryHistory', this, function() {}); + registerMessageCallback('navigateToUrl', this, undefined); app.queryState_.queryingDisabled = true; app.set('queryState_.searchTerm', ''); return flush();
diff --git a/chrome/test/data/webui/md_history/history_synced_tabs_test.js b/chrome/test/data/webui/md_history/history_synced_tabs_test.js index 748eb41..00fe411 100644 --- a/chrome/test/data/webui/md_history/history_synced_tabs_test.js +++ b/chrome/test/data/webui/md_history/history_synced_tabs_test.js
@@ -40,7 +40,15 @@ var getCards = function() { return Polymer.dom(element.root). querySelectorAll('history-synced-device-card'); - } + }; + + var assertNoSyncedTabsMessageShown = function(stringID) { + assertFalse(element.$['no-synced-tabs'].hidden); + var message = loadTimeData.getString(stringID); + assertNotEquals( + -1, + element.$['no-synced-tabs'].textContent.indexOf(message)); + }; suiteSetup(function() { app = $('history-app'); @@ -237,10 +245,7 @@ return flush(); }).then(function() { // When user signs in, first show loading message. - assertFalse(element.$['no-synced-tabs'].hidden); - var loading = loadTimeData.getString('loading'); - assertNotEquals( - -1, element.$['no-synced-tabs'].textContent.indexOf(loading)); + assertNoSyncedTabsMessageShown('loading'); var sessionList = []; setForeignSessions(sessionList, true); @@ -249,13 +254,9 @@ cards = getCards(); assertEquals(0, cards.length); // If no synced tabs are fetched, show 'no synced tabs'. - assertFalse(element.$['no-synced-tabs'].hidden); - var noSyncedResults = loadTimeData.getString('noSyncedResults'); - assertNotEquals( - -1, - element.$['no-synced-tabs'].textContent.indexOf(noSyncedResults)); + assertNoSyncedTabsMessageShown('noSyncedResults'); - var sessionList = [ + sessionList = [ createSession( 'Nexus 5', [createWindow(['http://www.google.com', 'http://example.com'])] @@ -278,6 +279,34 @@ }); }); + test('enable and disable tab sync', function() { + updateSignInState(true); + var sessionList = [ + createSession( + 'Nexus 5', + [createWindow(['http://www.google.com', 'http://example.com'])] + ) + ]; + // Open tabs sync is enabled. + setForeignSessions(sessionList, true); + + return flush().then(function() { + var cards = getCards(); + assertEquals(1, cards.length); + assertTrue(element.$['no-synced-tabs'].hidden); + + // Open tabs sync is disabled. + setForeignSessions(sessionList, false); + + return flush(); + }).then(function() { + cards = getCards(); + assertEquals(0, cards.length); + // If tab sync is disabled, show 'no synced tabs'. + assertNoSyncedTabsMessageShown('noSyncedResults'); + }); + }); + test('hide sign in promo in guest mode', function() { element.guestSession_ = true; return flush().then(function() {
diff --git a/chrome/test/data/webui/md_user_manager/create_profile_tests.js b/chrome/test/data/webui/md_user_manager/create_profile_tests.js index f4d34e1..ba29a33 100644 --- a/chrome/test/data/webui/md_user_manager/create_profile_tests.js +++ b/chrome/test/data/webui/md_user_manager/create_profile_tests.js
@@ -118,7 +118,9 @@ // Create is not in progress. assertFalse(createProfileElement.createInProgress_); // Message container is visible. - assertFalse(createProfileElement.$$('#message-container').hidden); + var messageContainer = + createProfileElement.$$('#message-container'); + assertTrue(messageContainer.clientHeight > 0); // Error message is set. assertEquals( loadTimeData.getString('custodianAccountNotSelectedError'), @@ -146,7 +148,9 @@ // Create is not in progress. assertFalse(createProfileElement.createInProgress_); // Message container is visible. - assertFalse(createProfileElement.$$('#message-container').hidden); + var messageContainer = + createProfileElement.$$('#message-container'); + assertTrue(messageContainer.clientHeight > 0); // Error message is set. var message = loadTimeData.getString( 'managedProfilesExistingLocalSupervisedUser'); @@ -175,7 +179,9 @@ // Create is not in progress. assertFalse(createProfileElement.createInProgress_); // Message container is visible. - assertFalse(createProfileElement.$$('#message-container').hidden); + var messageContainer = + createProfileElement.$$('#message-container'); + assertTrue(messageContainer.clientHeight > 0); // Error message contains a link to import the supervised user. var message = createProfileElement.$.message; assertTrue( @@ -183,6 +189,36 @@ }); }); + test('Displays error if custodian has no supervised users', function() { + browserProxy.setExistingSupervisedUsers([]); + + // Simulate checking the checkbox. + MockInteractions.tap(createProfileElement.$$('paper-checkbox')); + Polymer.dom.flush(); + + // Select the first signed in user. + var dropdownMenu = createProfileElement.$$('paper-dropdown-menu'); + var selector = dropdownMenu.querySelector('paper-listbox'); + selector.selected = 0; + + // Simulate clicking 'Import supervised user'. + MockInteractions.tap(createProfileElement.$$('#import-user')); + + return browserProxy.whenCalled('getExistingSupervisedUsers').then( + function(args) { + // Create is not in progress. + assertFalse(createProfileElement.createInProgress_); + // Message container is visible. + var messageContainer = + createProfileElement.$$('#message-container'); + assertTrue(messageContainer.clientHeight > 0); + // Error message is set. + var message = loadTimeData.getString( + 'noSupervisedUserImportText'); + assertEquals(message, createProfileElement.$.message.innerHTML); + }); + }); + test('Create supervised profile', function() { // Simulate checking the checkbox. MockInteractions.tap(createProfileElement.$$('paper-checkbox'));
diff --git a/chrome/test/data/webui/md_user_manager/import_supervised_user_tests.js b/chrome/test/data/webui/md_user_manager/import_supervised_user_tests.js index de22003..dc6b3c3 100644 --- a/chrome/test/data/webui/md_user_manager/import_supervised_user_tests.js +++ b/chrome/test/data/webui/md_user_manager/import_supervised_user_tests.js
@@ -41,37 +41,6 @@ assertFalse(importElement.$.dialog.opened); }); - test('Dialog shows when there are no supervised users', function() { - // The dialog is initially not visible. - assertFalse(importElement.$.dialog.opened); - - importElement.show({username: 'username', - profilePath: 'path/to/profile'}, - []); - Polymer.dom.flush(); - - // The dialog becomes visible. - assertTrue(importElement.$.dialog.opened); - - // The correct message is displayed. - assertEquals(loadTimeData.getString('noSupervisedUserImportText'), - importElement.$$('#message').textContent.trim()); - - var selectorElement = importElement.$$('paper-listbox'); - assertTrue(!!selectorElement); - - // There are no supervised users to choose from. - var items = selectorElement.querySelectorAll('paper-item'); - assertEquals(0, items.length); - - // Simulate clicking 'Cancel' - MockInteractions.tap(importElement.$$('#cancel')); - - Polymer.dom.flush(); - // The dialog is no longer visible. - assertFalse(importElement.$.dialog.opened); - }); - test('Can import supervised user', function() { return new Promise(function(resolve, reject) { /** @type {!SignedInUser} */
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js index d117682..7b8dd08 100644 --- a/chrome/test/data/webui/settings/cr_settings_browsertest.js +++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -545,6 +545,30 @@ mocha.run(); }); +/** + * Test fixture for + * chrome/browser/resources/settings/settings_page/settings_subpage.html. + * @constructor + * @extends {CrSettingsBrowserTest} +*/ +function CrSettingsSubpageTest() {} + +CrSettingsSubpageTest.prototype = { + __proto__: CrSettingsBrowserTest.prototype, + + /** @override */ + browsePreload: 'chrome://md-settings/settings_page/settings_subpage.html', + + extraLibraries: CrSettingsBrowserTest.prototype.extraLibraries.concat([ + 'settings_subpage_test.js', + ]), +}; + +TEST_F('CrSettingsSubpageTest', 'SettingsSubpage', function() { + settings_subpage.registerTests(); + mocha.run(); +}); + GEN('#if !defined(OS_CHROMEOS)'); /** * @constructor
diff --git a/chrome/test/data/webui/settings/settings_subpage_test.js b/chrome/test/data/webui/settings/settings_subpage_test.js new file mode 100644 index 0000000..ceb88fd --- /dev/null +++ b/chrome/test/data/webui/settings/settings_subpage_test.js
@@ -0,0 +1,47 @@ +// 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. + +cr.define('settings_subpage', function() { + function registerTests() { + suite('SettingsSubpage', function() { + test('can navigate to parent', function() { + PolymerTest.clearBody(); + + // Choose CERTIFICATES since it is not a descendant of BASIC. + settings.navigateTo(settings.Route.CERTIFICATES); + assertEquals(settings.Route.CERTIFICATES, settings.getCurrentRoute()); + + var subpage = document.createElement('settings-subpage'); + document.body.appendChild(subpage); + + MockInteractions.tap(subpage.$$('paper-icon-button')); + assertEquals(settings.Route.PRIVACY, settings.getCurrentRoute()); + }); + + test('can navigate to grandparent using window.back()', function(done) { + PolymerTest.clearBody(); + + settings.navigateTo(settings.Route.BASIC); + settings.navigateTo(settings.Route.SYNC); + assertEquals(settings.Route.SYNC, settings.getCurrentRoute()); + + var subpage = document.createElement('settings-subpage'); + document.body.appendChild(subpage); + + MockInteractions.tap(subpage.$$('paper-icon-button')); + + // Since the previous history entry is an ancestor, we expect + // window.history.back() to be called and a popstate event to be fired. + window.addEventListener('popstate', function(event) { + assertEquals(settings.Route.BASIC, settings.getCurrentRoute()); + done(); + }); + }); + }); + } + + return { + registerTests: registerTests, + }; +});
diff --git a/chrome/test/data/webui/settings/site_list_tests.js b/chrome/test/data/webui/settings/site_list_tests.js index 8e48d95..72ca4bd 100644 --- a/chrome/test/data/webui/settings/site_list_tests.js +++ b/chrome/test/data/webui/settings/site_list_tests.js
@@ -263,7 +263,7 @@ browserProxy = new TestSiteSettingsPrefsBrowserProxy(); settings.SiteSettingsPrefsBrowserProxyImpl.instance_ = browserProxy; PolymerTest.clearBody(); - testElement = document.createElement('settings-site-list'); + testElement = document.createElement('site-list'); document.body.appendChild(testElement); }); @@ -355,7 +355,7 @@ assertEquals( settings.PermissionValues.ALLOW, testElement.categorySubtype); Polymer.dom.flush(); // Populates action menu. - assertMenu(['Block', 'Reset to ask'], testElement); + assertMenu(['Block', 'Remove'], testElement); assertEquals('Allow - 2', testElement.$.header.innerText.trim()); // Site list should show, no matter what category default is set @@ -386,7 +386,7 @@ assertEquals( settings.PermissionValues.BLOCK, testElement.categorySubtype); Polymer.dom.flush(); // Populates action menu. - assertMenu(['Allow', 'Reset to ask'], testElement); + assertMenu(['Allow', 'Remove'], testElement); assertEquals('Block - 2', testElement.$.header.innerText.trim()); // Site list should only show when category default is enabled. @@ -414,7 +414,7 @@ assertEquals(settings.PermissionValues.SESSION_ONLY, testElement.categorySubtype); Polymer.dom.flush(); // Populates action menu. - assertMenu(['Allow', 'Block', 'Reset to ask'], testElement); + assertMenu(['Allow', 'Block', 'Remove'], testElement); assertEquals('Clear on exit - 1', testElement.$.header.innerText.trim());
diff --git a/chrome/test/data/webui/util_test.html b/chrome/test/data/webui/util_test.html index 0c8c4ea..8125db6 100644 --- a/chrome/test/data/webui/util_test.html +++ b/chrome/test/data/webui/util_test.html
@@ -1,6 +1,9 @@ <!DOCTYPE html> <html> <body> +<a id="file" href="file:///path/to/file">File</a> +<a id="chrome" href="about:chrome">Chrome</a> +<a href="about:blank"><b id="blank">Click me</b></a> <script> function testQuoteString() { @@ -20,6 +23,22 @@ assertEquals(null, match); } +function testClickHandler() { + var clickArgs = null; + var oldSend = chrome.send; + chrome.send = function(message, args) { + assertEquals('navigateToUrl', message); + clickArgs = args; + }; + $('file').click(); + assertEquals('file:///path/to/file', clickArgs[0]); + $('chrome').click(); + assertEquals('about:chrome', clickArgs[0]); + $('blank').click(); + assertEquals('about:blank', clickArgs[0]); + chrome.send = oldSend; +} + </script> </body> </html>
diff --git a/chrome/test/media_router/resources/common.js b/chrome/test/media_router/resources/common.js index be92b2f2..42ce095f 100644 --- a/chrome/test/media_router/resources/common.js +++ b/chrome/test/media_router/resources/common.js
@@ -151,7 +151,7 @@ } startedConnection.onmessage = function(receivedMessage) { var expectedResponse = 'Pong: ' + message; - var actualResponse = JSON.parse(receivedMessage.data); + var actualResponse = receivedMessage.data; if (actualResponse != expectedResponse) { sendResult(false, 'Expected message: ' + expectedResponse + ', but got: ' + actualResponse);
diff --git a/chrome/test/mini_installer/config/chrome_single_user_installed.prop b/chrome/test/mini_installer/config/chrome_single_user_installed.prop index 5071126b..5d02054 100644 --- a/chrome/test/mini_installer/config/chrome_single_user_installed.prop +++ b/chrome/test/mini_installer/config/chrome_single_user_installed.prop
@@ -24,10 +24,7 @@ }, "HKEY_CURRENT_USER\\$LAUNCHER_UPDATE_REGISTRY_SUBKEY": { "condition": "'$CHROME_SHORT_NAME' == 'Chrome'", - "exists": "required", - "values": { - "pv": {"type": "SZ", "data": "$MINI_INSTALLER_FILE_VERSION"} - } + "exists": "forbidden" }, "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\$CHROME_LONG_NAME": { "exists": "required",
diff --git a/chrome/test/mini_installer/config/chrome_system_installed.prop b/chrome/test/mini_installer/config/chrome_system_installed.prop index baa4738..9a8dd5df3 100644 --- a/chrome/test/mini_installer/config/chrome_system_installed.prop +++ b/chrome/test/mini_installer/config/chrome_system_installed.prop
@@ -30,10 +30,7 @@ }, "HKEY_LOCAL_MACHINE\\$LAUNCHER_UPDATE_REGISTRY_SUBKEY": { "condition": "'$CHROME_SHORT_NAME' == 'Chrome'", - "exists": "required", - "values": { - "pv": {"type": "SZ", "data": "$MINI_INSTALLER_FILE_VERSION"} - } + "exists": "forbidden" }, "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\$CHROME_LONG_NAME": { "exists": "required",
diff --git a/chrome/test/mini_installer/config/chrome_user_installed.prop b/chrome/test/mini_installer/config/chrome_user_installed.prop index 930f597..0ec67d1 100644 --- a/chrome/test/mini_installer/config/chrome_user_installed.prop +++ b/chrome/test/mini_installer/config/chrome_user_installed.prop
@@ -30,10 +30,7 @@ }, "HKEY_CURRENT_USER\\$LAUNCHER_UPDATE_REGISTRY_SUBKEY": { "condition": "'$CHROME_SHORT_NAME' == 'Chrome'", - "exists": "required", - "values": { - "pv": {"type": "SZ", "data": "$MINI_INSTALLER_FILE_VERSION"} - } + "exists": "forbidden" }, "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\$CHROME_LONG_NAME": { "exists": "required",
diff --git a/chrome/utility/chrome_content_utility_client.cc b/chrome/utility/chrome_content_utility_client.cc index 4a8f8949..cfe37b08 100644 --- a/chrome/utility/chrome_content_utility_client.cc +++ b/chrome/utility/chrome_content_utility_client.cc
@@ -178,7 +178,7 @@ if (handled) return true; - for (const auto& handler : handlers_) { + for (auto* handler : handlers_) { // At least one of the utility process handlers adds a new handler to // |handlers_| when it handles a message. This causes any iterator over // |handlers_| to become invalid. Therefore, it is necessary to break the
diff --git a/chromecast/android/cast_metrics_helper_android.cc b/chromecast/android/cast_metrics_helper_android.cc index 439303f9..3b68ec3 100644 --- a/chromecast/android/cast_metrics_helper_android.cc +++ b/chromecast/android/cast_metrics_helper_android.cc
@@ -7,6 +7,8 @@ #include "chromecast/base/metrics/cast_metrics_helper.h" #include "jni/CastMetricsHelper_jni.h" +using base::android::JavaParamRef; + namespace chromecast { // static
diff --git a/chromecast/base/chromecast_config_android.cc b/chromecast/base/chromecast_config_android.cc index 238e345..8067664 100644 --- a/chromecast/base/chromecast_config_android.cc +++ b/chromecast/base/chromecast_config_android.cc
@@ -9,6 +9,8 @@ #include "base/lazy_instance.h" #include "jni/ChromecastConfigAndroid_jni.h" +using base::android::JavaParamRef; + namespace chromecast { namespace android {
diff --git a/chromecast/browser/BUILD.gn b/chromecast/browser/BUILD.gn index f85a0ca..687694e 100644 --- a/chromecast/browser/BUILD.gn +++ b/chromecast/browser/BUILD.gn
@@ -114,6 +114,7 @@ "//ui/compositor", "//ui/display", "//ui/gl", + "//ui/native_theme:native_theme", ] if (is_linux) {
diff --git a/chromecast/browser/DEPS b/chromecast/browser/DEPS index f8b1264..687b1f8 100644 --- a/chromecast/browser/DEPS +++ b/chromecast/browser/DEPS
@@ -30,6 +30,7 @@ "+ui/gfx", "+ui/gl", "+ui/display", + "+ui/native_theme", "+ui/ozone/platform/cast/overlay_manager_cast.h", # TODO(sanfin): Remove this by fixing the crash handler on android.
diff --git a/chromecast/browser/android/cast_window_manager.cc b/chromecast/browser/android/cast_window_manager.cc index a2ba453..eb4ee3610 100644 --- a/chromecast/browser/android/cast_window_manager.cc +++ b/chromecast/browser/android/cast_window_manager.cc
@@ -24,6 +24,8 @@ #include "jni/CastWindowManager_jni.h" #include "url/gurl.h" +using base::android::JavaParamRef; + namespace { base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >
diff --git a/chromecast/browser/cast_browser_main_parts.cc b/chromecast/browser/cast_browser_main_parts.cc index f673aa8a..2126d48 100644 --- a/chromecast/browser/cast_browser_main_parts.cc +++ b/chromecast/browser/cast_browser_main_parts.cc
@@ -59,6 +59,7 @@ #include "gpu/command_buffer/service/gpu_switches.h" #include "media/base/media.h" #include "ui/compositor/compositor_switches.h" +#include "ui/native_theme/native_theme_switches.h" #if !defined(OS_ANDROID) #include <signal.h> @@ -245,6 +246,7 @@ // Enable navigator.connection API. // TODO(derekjchow): Remove this switch when enabled by default. { switches::kEnableNetworkInformation, "" }, + { switches::kHideScrollbars, "" }, { NULL, NULL }, // Termination }; @@ -470,7 +472,7 @@ cast_browser_process_->browser_context(), cast_browser_process_->pref_service(), url_request_context_factory_->GetSystemGetter(), - video_plane_controller_.get(), media_caps_.get())); + video_plane_controller_.get())); cast_browser_process_->cast_service()->Initialize(); #if !defined(OS_ANDROID)
diff --git a/chromecast/browser/cast_content_browser_client.cc b/chromecast/browser/cast_content_browser_client.cc index 73ccf496..79a9d8bb 100644 --- a/chromecast/browser/cast_content_browser_client.cc +++ b/chromecast/browser/cast_content_browser_client.cc
@@ -127,8 +127,7 @@ content::BrowserContext* browser_context, PrefService* pref_service, net::URLRequestContextGetter* request_context_getter, - media::VideoPlaneController* video_plane_controller, - media::MediaCapsImpl* media_caps) { + media::VideoPlaneController* video_plane_controller) { return base::WrapUnique(new CastServiceSimple(browser_context, pref_service)); } @@ -158,6 +157,11 @@ } #endif // !defined(OS_ANDROID) +media::MediaCapsImpl* CastContentBrowserClient::media_caps() { + DCHECK(cast_browser_main_parts_); + return cast_browser_main_parts_->media_caps(); +} + void CastContentBrowserClient::SetMetricsClientId( const std::string& client_id) { }
diff --git a/chromecast/browser/cast_content_browser_client.h b/chromecast/browser/cast_content_browser_client.h index 929ade6..7b0cfff 100644 --- a/chromecast/browser/cast_content_browser_client.h +++ b/chromecast/browser/cast_content_browser_client.h
@@ -71,8 +71,7 @@ content::BrowserContext* browser_context, PrefService* pref_service, net::URLRequestContextGetter* request_context_getter, - media::VideoPlaneController* video_plane_controller, - media::MediaCapsImpl* media_caps); + media::VideoPlaneController* video_plane_controller); #if !defined(OS_ANDROID) // Returns the task runner that must be used for media IO. @@ -88,6 +87,7 @@ media::MediaPipelineBackendManager* media_pipeline_backend_manager(); #endif + media::MediaCapsImpl* media_caps(); // Invoked when the metrics client ID changes. virtual void SetMetricsClientId(const std::string& client_id);
diff --git a/chromecast/browser/media/BUILD.gn b/chromecast/browser/media/BUILD.gn index 94911c6..79a72a6 100644 --- a/chromecast/browser/media/BUILD.gn +++ b/chromecast/browser/media/BUILD.gn
@@ -40,6 +40,7 @@ "//chromecast/media", "//content/public/browser", "//media", + "//ui/gfx/geometry", ] if (!is_android) {
diff --git a/chromecast/browser/media/media_caps_impl.cc b/chromecast/browser/media/media_caps_impl.cc index ca4403a..90c1b4fb 100644 --- a/chromecast/browser/media/media_caps_impl.cc +++ b/chromecast/browser/media/media_caps_impl.cc
@@ -27,8 +27,19 @@ }); } +void MediaCapsImpl::ScreenResolutionChanged(unsigned width, unsigned height) { + screen_resolution_ = gfx::Size(width, height); + + observers_.ForAllPtrs( + [width, height](mojom::MediaCapsObserver* observer) { + observer->ScreenResolutionChanged(width, height); + }); +} + void MediaCapsImpl::AddObserver(mojom::MediaCapsObserverPtr observer) { observer->SupportedHdmiSinkCodecsChanged(supported_codecs_bitmask_); + observer->ScreenResolutionChanged(screen_resolution_.width(), + screen_resolution_.height()); observers_.AddPtr(std::move(observer)); }
diff --git a/chromecast/browser/media/media_caps_impl.h b/chromecast/browser/media/media_caps_impl.h index 9e97969b..389f10e 100644 --- a/chromecast/browser/media/media_caps_impl.h +++ b/chromecast/browser/media/media_caps_impl.h
@@ -9,6 +9,7 @@ #include "chromecast/common/media/media_caps.mojom.h" #include "mojo/public/cpp/bindings/binding_set.h" #include "mojo/public/cpp/bindings/interface_ptr_set.h" +#include "ui/gfx/geometry/size.h" namespace chromecast { namespace media { @@ -21,12 +22,14 @@ void AddBinding(mojom::MediaCapsRequest request); void SetSupportedHdmiSinkCodecs(unsigned int supported_codecs_bitmask); + void ScreenResolutionChanged(unsigned width, unsigned height); private: // chromecast::mojom::MediaCaps implementation. void AddObserver(mojom::MediaCapsObserverPtr observer) override; unsigned int supported_codecs_bitmask_; + gfx::Size screen_resolution_; mojo::InterfacePtrSet<mojom::MediaCapsObserver> observers_; mojo::BindingSet<mojom::MediaCaps> bindings_;
diff --git a/chromecast/common/media/media_caps.mojom b/chromecast/common/media/media_caps.mojom index 0d41e7b..3c25a92b 100644 --- a/chromecast/common/media/media_caps.mojom +++ b/chromecast/common/media/media_caps.mojom
@@ -11,4 +11,5 @@ interface MediaCapsObserver { // Bitmask values defined in enum HdmiSinkCodec SupportedHdmiSinkCodecsChanged(uint32 supported_codec_bitmask); + ScreenResolutionChanged(uint32 width, uint32 height); };
diff --git a/chromecast/media/DEPS b/chromecast/media/DEPS index 1e5aef8..4e0f954f 100644 --- a/chromecast/media/DEPS +++ b/chromecast/media/DEPS
@@ -3,4 +3,5 @@ "+media/audio", "+media/base", "+media/cdm", + "+ui/gfx/geometry", ]
diff --git a/chromecast/media/base/BUILD.gn b/chromecast/media/base/BUILD.gn index 6a37737..14c8dcc 100644 --- a/chromecast/media/base/BUILD.gn +++ b/chromecast/media/base/BUILD.gn
@@ -50,6 +50,7 @@ "//crypto", "//crypto:platform", "//media", + "//ui/gfx/geometry", ] }
diff --git a/chromecast/media/base/media_caps.cc b/chromecast/media/base/media_caps.cc index 6d568d4..d7b13015 100644 --- a/chromecast/media/base/media_caps.cc +++ b/chromecast/media/base/media_caps.cc
@@ -4,34 +4,44 @@ #include "chromecast/media/base/media_caps.h" +namespace chromecast { namespace media { -namespace { -unsigned int g_hdmi_codecs = 0; -} // namespace +unsigned int MediaCapabilities::g_hdmi_codecs = 0; +gfx::Size MediaCapabilities::g_screen_resolution(0, 0); -void SetHdmiSinkCodecs(unsigned int codecs_mask) { +void MediaCapabilities::SetHdmiSinkCodecs(unsigned int codecs_mask) { g_hdmi_codecs = codecs_mask; } -bool HdmiSinkSupportsAC3() { +bool MediaCapabilities::HdmiSinkSupportsAC3() { return g_hdmi_codecs & HdmiSinkCodec::kSinkCodecAc3; } -bool HdmiSinkSupportsDTS() { +bool MediaCapabilities::HdmiSinkSupportsDTS() { return g_hdmi_codecs & HdmiSinkCodec::kSinkCodecDts; } -bool HdmiSinkSupportsDTSHD() { +bool MediaCapabilities::HdmiSinkSupportsDTSHD() { return g_hdmi_codecs & HdmiSinkCodec::kSinkCodecDtsHd; } -bool HdmiSinkSupportsEAC3() { +bool MediaCapabilities::HdmiSinkSupportsEAC3() { return g_hdmi_codecs & HdmiSinkCodec::kSinkCodecEac3; } -bool HdmiSinkSupportsPcmSurroundSound() { +bool MediaCapabilities::HdmiSinkSupportsPcmSurroundSound() { return g_hdmi_codecs & HdmiSinkCodec::kSinkCodecPcmSurroundSound; } +void MediaCapabilities::ScreenResolutionChanged(const gfx::Size& res) { + VLOG(1) << __FUNCTION__ << " resolution=" << res.ToString(); + g_screen_resolution = res; +} + +gfx::Size MediaCapabilities::GetScreenResolution() { + return g_screen_resolution; +} + } // namespace media +} // namespace chromecast
diff --git a/chromecast/media/base/media_caps.h b/chromecast/media/base/media_caps.h index 1a24ffe0..7e2de93 100644 --- a/chromecast/media/base/media_caps.h +++ b/chromecast/media/base/media_caps.h
@@ -5,26 +5,40 @@ #ifndef CHROMECAST_MEDIA_BASE_MEDIA_CAPS_ #define CHROMECAST_MEDIA_BASE_MEDIA_CAPS_ +#include "ui/gfx/geometry/size.h" + +namespace chromecast { namespace media { -enum HdmiSinkCodec { - kSinkCodecAc3 = 1, - kSinkCodecDts = 1 << 1, - kSinkCodecDtsHd = 1 << 2, - kSinkCodecEac3 = 1 << 3, - kSinkCodecPcmSurroundSound = 1 << 4, +class MediaCapabilities { + public: + enum HdmiSinkCodec { + kSinkCodecAc3 = 1, + kSinkCodecDts = 1 << 1, + kSinkCodecDtsHd = 1 << 2, + kSinkCodecEac3 = 1 << 3, + kSinkCodecPcmSurroundSound = 1 << 4, + }; + + // Records the known supported codecs for the current HDMI sink, as a bit mask + // of HdmiSinkCodec values. + static void SetHdmiSinkCodecs(unsigned int codecs_mask); + + static bool HdmiSinkSupportsAC3(); + static bool HdmiSinkSupportsDTS(); + static bool HdmiSinkSupportsDTSHD(); + static bool HdmiSinkSupportsEAC3(); + static bool HdmiSinkSupportsPcmSurroundSound(); + + static void ScreenResolutionChanged(const gfx::Size& res); + static gfx::Size GetScreenResolution(); + + private: + static unsigned int g_hdmi_codecs; + static gfx::Size g_screen_resolution; }; -// Records the known supported codecs for the current HDMI sink, as a bit mask -// of HdmiSinkCodec values. -void SetHdmiSinkCodecs(unsigned int codecs_mask); - -bool HdmiSinkSupportsAC3(); -bool HdmiSinkSupportsDTS(); -bool HdmiSinkSupportsDTSHD(); -bool HdmiSinkSupportsEAC3(); -bool HdmiSinkSupportsPcmSurroundSound(); - } // namespace media +} // namespace chromecast #endif // CHROMECAST_MEDIA_BASE_MEDIA_CAPS_
diff --git a/chromecast/media/base/media_codec_support.cc b/chromecast/media/base/media_codec_support.cc index 8b744ee6..8a59659 100644 --- a/chromecast/media/base/media_codec_support.cc +++ b/chromecast/media/base/media_codec_support.cc
@@ -27,13 +27,13 @@ return false; if (codec == "aac51") { - return ::media::HdmiSinkSupportsPcmSurroundSound(); + return MediaCapabilities::HdmiSinkSupportsPcmSurroundSound(); } if (codec == "ac-3" || codec == "mp4a.a5" || codec == "mp4a.A5") { - return ::media::HdmiSinkSupportsAC3(); + return MediaCapabilities::HdmiSinkSupportsAC3(); } if (codec == "ec-3" || codec == "mp4a.a6" || codec == "mp4a.A6") { - return ::media::HdmiSinkSupportsEAC3(); + return MediaCapabilities::HdmiSinkSupportsEAC3(); } // This function is invoked from MimeUtil::AreSupportedCodecs to check if a
diff --git a/chromecast/renderer/media/BUILD.gn b/chromecast/renderer/media/BUILD.gn index 031628f..b8172ee2 100644 --- a/chromecast/renderer/media/BUILD.gn +++ b/chromecast/renderer/media/BUILD.gn
@@ -15,6 +15,7 @@ deps = [ "//chromecast/common/media:interfaces", "//chromecast/media/base", + "//ui/gfx/geometry", ] if (enable_cma) { @@ -43,7 +44,6 @@ "//gpu/command_buffer/common", "//ipc", "//media", - "//ui/gfx/geometry", ] } }
diff --git a/chromecast/renderer/media/media_caps_observer_impl.cc b/chromecast/renderer/media/media_caps_observer_impl.cc index d6b776f..1eef5c8 100644 --- a/chromecast/renderer/media/media_caps_observer_impl.cc +++ b/chromecast/renderer/media/media_caps_observer_impl.cc
@@ -16,7 +16,12 @@ void MediaCapsObserverImpl::SupportedHdmiSinkCodecsChanged( uint32_t codec_support_bitmask) { - ::media::SetHdmiSinkCodecs(codec_support_bitmask); + MediaCapabilities::SetHdmiSinkCodecs(codec_support_bitmask); +} + +void MediaCapsObserverImpl::ScreenResolutionChanged(uint32_t width, + uint32_t height) { + MediaCapabilities::ScreenResolutionChanged(gfx::Size(width, height)); } } // namespace media
diff --git a/chromecast/renderer/media/media_caps_observer_impl.h b/chromecast/renderer/media/media_caps_observer_impl.h index ba3bd00b..e1a6204a 100644 --- a/chromecast/renderer/media/media_caps_observer_impl.h +++ b/chromecast/renderer/media/media_caps_observer_impl.h
@@ -8,6 +8,7 @@ #include "base/macros.h" #include "chromecast/common/media/media_caps.mojom.h" #include "mojo/public/cpp/bindings/binding.h" +#include "ui/gfx/geometry/size.h" namespace chromecast { namespace media { @@ -20,6 +21,7 @@ private: void SupportedHdmiSinkCodecsChanged( uint32_t supported_codec_bitmask) override; + void ScreenResolutionChanged(uint32_t width, uint32_t height) override; mojo::Binding<mojom::MediaCapsObserver> binding_;
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index 2644fae..25ef5bf 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -8685.0.0 \ No newline at end of file +8689.0.0 \ No newline at end of file
diff --git a/chromeos/cryptohome/system_salt_getter.cc b/chromeos/cryptohome/system_salt_getter.cc index 48f565e..45461458 100644 --- a/chromeos/cryptohome/system_salt_getter.cc +++ b/chromeos/cryptohome/system_salt_getter.cc
@@ -42,6 +42,15 @@ callback)); } +void SystemSaltGetter::AddOnSystemSaltReady(const base::Closure& closure) { + if (!raw_salt_.empty()) { + closure.Run(); + return; + } + + on_system_salt_ready_.push_back(closure); +} + const SystemSaltGetter::RawSalt* SystemSaltGetter::GetRawSalt() const { return raw_salt_.empty() ? nullptr : &raw_salt_; } @@ -74,6 +83,12 @@ system_salt.size() % 2 == 0U) { raw_salt_ = system_salt; system_salt_ = ConvertRawSaltToHexString(system_salt); + + std::vector<base::Closure> callbacks; + callbacks.swap(on_system_salt_ready_); + for (const base::Closure& callback : callbacks) { + callback.Run(); + } } else { LOG(WARNING) << "System salt not available"; }
diff --git a/chromeos/cryptohome/system_salt_getter.h b/chromeos/cryptohome/system_salt_getter.h index a42dd25..a77d85c 100644 --- a/chromeos/cryptohome/system_salt_getter.h +++ b/chromeos/cryptohome/system_salt_getter.h
@@ -39,6 +39,10 @@ // an empty string (e.g. errors in D-Bus layer) void GetSystemSalt(const GetSystemSaltCallback& callback); + // Adds another callback to be called when system salt is received. + // (If system salt is available, closure will be called immediately). + void AddOnSystemSaltReady(const base::Closure& closure); + // Returns pointer to binary system salt if it is already known. // Returns nullptr if system salt is not known. const RawSalt* GetRawSalt() const; @@ -61,6 +65,9 @@ RawSalt raw_salt_; std::string system_salt_; + // List of callbacks waiting for system salt ready event. + std::vector<base::Closure> on_system_salt_ready_; + base::WeakPtrFactory<SystemSaltGetter> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(SystemSaltGetter);
diff --git a/chromeos/dbus/update_engine_client.cc b/chromeos/dbus/update_engine_client.cc index bb78f668..2abd1b0 100644 --- a/chromeos/dbus/update_engine_client.cc +++ b/chromeos/dbus/update_engine_client.cc
@@ -223,10 +223,6 @@ update_engine_proxy_ = bus->GetObjectProxy( update_engine::kUpdateEngineServiceName, dbus::ObjectPath(update_engine::kUpdateEngineServicePath)); - - // Monitor the D-Bus signal for brightness changes. Only the power - // manager knows the actual brightness level. We don't cache the - // brightness level in Chrome as it will make things less reliable. update_engine_proxy_->ConnectToSignal( update_engine::kUpdateEngineInterface, update_engine::kStatusUpdate, @@ -234,15 +230,22 @@ weak_ptr_factory_.GetWeakPtr()), base::Bind(&UpdateEngineClientImpl::StatusUpdateConnected, weak_ptr_factory_.GetWeakPtr())); - - // Get update engine status for the initial status. Update engine won't - // send StatusUpdate signal unless there is a status change. If chrome - // crashes after UPDATE_STATUS_UPDATED_NEED_REBOOT status is set, - // restarted chrome would not get this status. See crbug.com/154104. - GetUpdateEngineStatus(); + update_engine_proxy_->WaitForServiceToBeAvailable( + base::Bind(&UpdateEngineClientImpl::OnProxyAvailabilityChanged, + weak_ptr_factory_.GetWeakPtr())); } private: + void OnProxyAvailabilityChanged(bool service_is_available) { + if (service_is_available) { + // Get update engine status for the initial status. Update engine won't + // send StatusUpdate signal unless there is a status change. If chrome + // crashes after UPDATE_STATUS_UPDATED_NEED_REBOOT status is set, + // restarted chrome would not get this status. See crbug.com/154104. + GetUpdateEngineStatus(); + } + } + void GetUpdateEngineStatus() { dbus::MethodCall method_call( update_engine::kUpdateEngineInterface,
diff --git a/chromeos/network/network_state_unittest.cc b/chromeos/network/network_state_unittest.cc index 2ade45e..82bfa717 100644 --- a/chromeos/network/network_state_unittest.cc +++ b/chromeos/network/network_state_unittest.cc
@@ -130,10 +130,10 @@ TEST_F(NetworkStateTest, SsidLatin) { EXPECT_TRUE(SetStringProperty(shill::kTypeProperty, shill::kTypeWifi)); - std::string wifi_latin1 = "latin-1 \xc0\xcb\xcc\xd6\xfb"; + std::string wifi_latin1 = "latin-1 \x54\xe9\x6c\xe9\x63\x6f\x6d"; // Télécom std::string wifi_latin1_hex = base::HexEncode(wifi_latin1.c_str(), wifi_latin1.length()); - std::string wifi_latin1_result = "latin-1 \u00c0\u00cb\u00cc\u00d6\u00fb"; + std::string wifi_latin1_result = "latin-1 T\xc3\xa9\x6c\xc3\xa9\x63om"; EXPECT_TRUE(SetStringProperty(shill::kWifiHexSsid, wifi_latin1_hex)); EXPECT_TRUE(SignalInitialPropertiesReceived()); EXPECT_EQ(network_state_.name(), wifi_latin1_result);
diff --git a/chromeos/network/shill_property_util.cc b/chromeos/network/shill_property_util.cc index ed24a66..be78677 100644 --- a/chromeos/network/shill_property_util.cc +++ b/chromeos/network/shill_property_util.cc
@@ -8,7 +8,7 @@ #include <set> -#include "base/i18n/icu_encoding_detection.h" +#include "base/i18n/encoding_detection.h" #include "base/i18n/icu_string_conversions.h" #include "base/json/json_writer.h" #include "base/memory/ptr_util.h"
diff --git a/chromeos/printing/printer_configuration.h b/chromeos/printing/printer_configuration.h index 7039e7f2..a88b9cc 100644 --- a/chromeos/printing/printer_configuration.h +++ b/chromeos/printing/printer_configuration.h
@@ -19,17 +19,17 @@ // setup. struct PPDFile { // Identifier from the quirks server. -1 otherwise. - int id; + int id = -1; std::string file_name; // If there is a file with a later version on the quirks server, that file // should be used. The default value is 0. - int version_number; + int version_number = 0; // This will be true if the file was retrived from the quirks server. // Otherwise, the file was saved to disk by the user. - bool from_quirks_server; + bool from_quirks_server = false; }; // Constructs a printer object that is completely empty.
diff --git a/chromeos/printing/printer_translator.cc b/chromeos/printing/printer_translator.cc index a28e576..419f29d 100644 --- a/chromeos/printing/printer_translator.cc +++ b/chromeos/printing/printer_translator.cc
@@ -37,22 +37,12 @@ std::unique_ptr<Printer::PPDFile> DictionaryToPPDFile( const base::DictionaryValue* value) { std::unique_ptr<Printer::PPDFile> ppd = base::MakeUnique<Printer::PPDFile>(); - int id = -1; - value->GetInteger(kPPDid, &id); - ppd->id = id; - - std::string file_name; - if (value->GetString(kFileName, &file_name)) - ppd->file_name = file_name; - - int version_number = 0; - if (value->GetInteger(kVersionNumber, &version_number)) - ppd->version_number = version_number; - - bool from_quirks; - if (value->GetBoolean(kFromQuirks, &from_quirks)) - ppd->from_quirks_server = from_quirks; - + // struct PPDFile defines default values for these fields so there is no need + // to check return values. + value->GetInteger(kPPDid, &ppd->id); + value->GetString(kFileName, &ppd->file_name); + value->GetInteger(kVersionNumber, &ppd->version_number); + value->GetBoolean(kFromQuirks, &ppd->from_quirks_server); return ppd; }
diff --git a/chromeos/test/data/network/shill_wifi_non_utf8_ssid.json b/chromeos/test/data/network/shill_wifi_non_utf8_ssid.json index 3058d84..a915a58d 100644 --- a/chromeos/test/data/network/shill_wifi_non_utf8_ssid.json +++ b/chromeos/test/data/network/shill_wifi_non_utf8_ssid.json
@@ -5,7 +5,6 @@ "Passphrase":"some passphrase", "SecurityClass":"psk", "Type":"wifi", - // Hex of the latin-1, non UTF8 string "latin-1 \xc0\xcb\xcc\xd6\xfb" - "WiFi.HexSSID": "6C6174696E2D3120C0CBCCD6FB" + // Hex of the latin-1, non UTF8 string "latin-1 \x54\xe9\x6c\xe9\x63\x6f\x6d" + "WiFi.HexSSID": "6C6174696E2D312054E96CE9636F6D" } -
diff --git a/chromeos/test/data/network/translation_of_shill_wifi_non_utf8_ssid.onc b/chromeos/test/data/network/translation_of_shill_wifi_non_utf8_ssid.onc index aa1d208..28af659 100644 --- a/chromeos/test/data/network/translation_of_shill_wifi_non_utf8_ssid.onc +++ b/chromeos/test/data/network/translation_of_shill_wifi_non_utf8_ssid.onc
@@ -4,9 +4,9 @@ "Type":"WiFi", "WiFi":{ // Hex of the SSID field - "HexSSID": "6C6174696E2D3120C0CBCCD6FB", + "HexSSID": "6C6174696E2D312054E96CE9636F6D", "Passphrase":"some passphrase", "Security":"WPA-PSK", - "SSID": "latin-1 \u00c0\u00cb\u00cc\u00d6\u00fb" + "SSID": "latin-1 T\u00e9l\u00e9com" } }
diff --git a/components/BUILD.gn b/components/BUILD.gn index 609f3d3..56a4557 100644 --- a/components/BUILD.gn +++ b/components/BUILD.gn
@@ -198,7 +198,6 @@ "//components/precache/content:unit_tests", "//components/safe_browsing_db:unit_tests", "//components/safe_json:unit_tests", - "//components/scheduler:unit_tests", "//components/subresource_filter/content/browser:unit_tests", "//components/subresource_filter/content/renderer:unit_tests", "//components/test_runner:test_runner", @@ -251,6 +250,7 @@ "//ui/android:ui_java", "//ui/base", "//ui/gfx", + "//v8:v8_external_startup_data_assets", ] if (enable_configuration_policy) { @@ -475,10 +475,6 @@ test("components_perftests") { sources = [ - "scheduler/base/task_queue_manager_delegate_for_test.cc", - "scheduler/base/task_queue_manager_delegate_for_test.h", - "scheduler/base/task_queue_manager_perftest.cc", - "scheduler/base/test_task_time_tracker.h", "visitedlink/test/visitedlink_perftest.cc", ] @@ -489,7 +485,6 @@ "//base", "//base/test:test_support", "//base/test:test_support_perf", - "//components/scheduler", "//components/visitedlink/browser", "//content/test:test_support", "//testing/gtest",
diff --git a/components/arc/arc_bridge_service.cc b/components/arc/arc_bridge_service.cc index 12163e21..72607b5 100644 --- a/components/arc/arc_bridge_service.cc +++ b/components/arc/arc_bridge_service.cc
@@ -7,12 +7,20 @@ #include <utility> #include "base/command_line.h" +#include "base/feature_list.h" #include "base/sequenced_task_runner.h" #include "base/threading/thread_task_runner_handle.h" #include "chromeos/chromeos_switches.h" namespace arc { +namespace { + +const base::Feature kArcEnabledFeature{"EnableARC", + base::FEATURE_DISABLED_BY_DEFAULT}; + +} // namespace + // Weak pointer. This class is owned by ArcServiceManager. ArcBridgeService* g_arc_bridge_service = nullptr; @@ -40,7 +48,8 @@ // static bool ArcBridgeService::GetEnabled(const base::CommandLine* command_line) { - return command_line->HasSwitch(chromeos::switches::kEnableArc); + return command_line->HasSwitch(chromeos::switches::kEnableArc) || + base::FeatureList::IsEnabled(kArcEnabledFeature); } void ArcBridgeService::AddObserver(Observer* observer) {
diff --git a/components/arc/bluetooth/arc_bluetooth_bridge.cc b/components/arc/bluetooth/arc_bluetooth_bridge.cc index dbc6747b..41725f6 100644 --- a/components/arc/bluetooth/arc_bluetooth_bridge.cc +++ b/components/arc/bluetooth/arc_bluetooth_bridge.cc
@@ -180,13 +180,12 @@ ArcBluetoothBridge::ArcBluetoothBridge(ArcBridgeService* bridge_service) : ArcService(bridge_service), binding_(this), weak_factory_(this) { if (BluetoothAdapterFactory::IsBluetoothAdapterAvailable()) { - VLOG(1) << "registering bluetooth adapter"; + VLOG(1) << "Registering bluetooth adapter."; BluetoothAdapterFactory::GetAdapter(base::Bind( &ArcBluetoothBridge::OnAdapterInitialized, weak_factory_.GetWeakPtr())); } else { - VLOG(1) << "no bluetooth adapter available"; + VLOG(1) << "No bluetooth adapter available."; } - arc_bridge_service()->bluetooth()->AddObserver(this); } @@ -207,7 +206,14 @@ // so our adapter uses BlueZ. bluetooth_adapter_ = static_cast<bluez::BluetoothAdapterBlueZ*>(adapter.get()); - bluetooth_adapter_->AddObserver(this); + + // The ARC instance was ready before the Bluetooth adapter, hence we didn't + // register ourselves as an observer with it then. Since our adapter is + // ready, we should register it now. + if (!bluetooth_adapter_->HasObserver(this) && + arc_bridge_service()->bluetooth()->instance()) { + bluetooth_adapter_->AddObserver(this); + } } void ArcBluetoothBridge::OnInstanceReady() { @@ -218,7 +224,19 @@ << "but no bluetooth instance found"; return; } + bluetooth_instance->Init(binding_.CreateInterfacePtrAndBind()); + + // The Bluetooth adapter was ready before the ARC instance, hence we didn't + // register ourselves as an observer with it then. Since our instance is + // ready, we should register it now. + if (bluetooth_adapter_ && !bluetooth_adapter_->HasObserver(this)) + bluetooth_adapter_->AddObserver(this); +} + +void ArcBluetoothBridge::OnInstanceClosed() { + if (bluetooth_adapter_) + bluetooth_adapter_->RemoveObserver(this); } void ArcBluetoothBridge::AdapterPoweredChanged(BluetoothAdapter* adapter, @@ -249,11 +267,12 @@ mojom::BluetoothAddressPtr addr = mojom::BluetoothAddress::From(device->GetAddress()); - int rssi = device->GetInquiryRSSI(); + base::Optional<int8_t> rssi = device->GetInquiryRSSI(); mojo::Array<mojom::BluetoothAdvertisingDataPtr> adv_data = GetAdvertisingData(device); arc_bridge_service()->bluetooth()->instance()->OnLEDeviceFound( - std::move(addr), rssi, std::move(adv_data)); + std::move(addr), rssi.value_or(mojom::kUnknownPower), + std::move(adv_data)); } void ArcBluetoothBridge::DeviceChanged(BluetoothAdapter* adapter, @@ -1133,8 +1152,8 @@ const ReadRemoteRssiCallback& callback) { BluetoothDevice* device = bluetooth_adapter_->GetDevice(remote_addr->To<std::string>()); - int rssi = device->GetInquiryRSSI(); - callback.Run(rssi); + base::Optional<int8_t> rssi = device->GetInquiryRSSI(); + callback.Run(rssi.value_or(mojom::kUnknownPower)); } void ArcBluetoothBridge::OpenBluetoothSocket( @@ -1420,7 +1439,8 @@ if (type == mojom::BluetoothPropertyType::ALL || type == mojom::BluetoothPropertyType::REMOTE_RSSI) { mojom::BluetoothPropertyPtr btp = mojom::BluetoothProperty::New(); - btp->set_remote_rssi(device->GetInquiryRSSI()); + base::Optional<int8_t> rssi = device->GetInquiryRSSI(); + btp->set_remote_rssi(rssi.value_or(mojom::kUnknownPower)); properties.push_back(std::move(btp)); } // TODO(smbarber): Add remote version info @@ -1577,11 +1597,12 @@ if (arc_bridge_service()->bluetooth()->version() >= kMinBtleVersion) { mojom::BluetoothAddressPtr addr = mojom::BluetoothAddress::From(device->GetAddress()); - int rssi = device->GetInquiryRSSI(); + base::Optional<int8_t> rssi = device->GetInquiryRSSI(); mojo::Array<mojom::BluetoothAdvertisingDataPtr> adv_data = GetAdvertisingData(device); arc_bridge_service()->bluetooth()->instance()->OnLEDeviceFound( - std::move(addr), rssi, std::move(adv_data)); + std::move(addr), rssi.value_or(mojom::kUnknownPower), + std::move(adv_data)); } } } @@ -1615,11 +1636,12 @@ mojom::BluetoothAddress::From(device->GetAddress()); if (arc_bridge_service()->bluetooth()->version() >= kMinBtleVersion) { - int rssi = device->GetInquiryRSSI(); + base::Optional<int8_t> rssi = device->GetInquiryRSSI(); mojo::Array<mojom::BluetoothAdvertisingDataPtr> adv_data = GetAdvertisingData(device); arc_bridge_service()->bluetooth()->instance()->OnLEDeviceFound( - addr->Clone(), rssi, std::move(adv_data)); + addr->Clone(), rssi.value_or(mojom::kUnknownPower), + std::move(adv_data)); } // OnBondStateChanged must be called with mojom::BluetoothBondState::BONDING
diff --git a/components/arc/bluetooth/arc_bluetooth_bridge.h b/components/arc/bluetooth/arc_bluetooth_bridge.h index f8b7150c..db006387 100644 --- a/components/arc/bluetooth/arc_bluetooth_bridge.h +++ b/components/arc/bluetooth/arc_bluetooth_bridge.h
@@ -45,6 +45,7 @@ // Overridden from InstanceHolder<mojom::BluetoothInstance>::Observer: void OnInstanceReady() override; + void OnInstanceClosed() override; void OnAdapterInitialized(scoped_refptr<device::BluetoothAdapter> adapter);
diff --git a/components/arc/common/app.mojom b/components/arc/common/app.mojom index 1110e41b..32a9d828 100644 --- a/components/arc/common/app.mojom +++ b/components/arc/common/app.mojom
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Next MinVersion: 13 +// Next MinVersion: 15 module arc.mojom; @@ -56,11 +56,11 @@ MANAGE_LINKS = 1, }; -// Next method ID: 13 +// Next method ID: 14 interface AppHost { // Sends newly added ARC app to Chrome. This message is sent when ARC receives // package added notification. Multiple apps may be added in the one package. - [MinVersion=1] OnAppAdded@2(AppInfo app); + [MinVersion=1] OnAppAddedDeprecated@2(AppInfo app); // Receives an icon of required |scale_factor| for specific ARC app. The app // is defined by |package_name| and |activity|. The icon content cannot be @@ -77,6 +77,10 @@ // Notifies that a package has been added. [MinVersion=8] OnPackageAdded@8(ArcPackageInfo arcPackageInfo); + // Notifies that a package list of apps has been updated. + [MinVersion=14] OnPackageAppListRefreshed@13(string package_name, + array<AppInfo> apps); + // Receives a list of available ARC packages to Chrome. Members of // PackageInfo must contain non-empty string. [MinVersion=8] OnPackageListRefreshed@9(array<ArcPackageInfo> packages); @@ -91,8 +95,10 @@ [MinVersion=1] OnPackageRemoved@3(string package_name); // Sends information about newly created task. - [MinVersion=4] OnTaskCreated@4(int32 task_id, string package_name, - string activity); + [MinVersion=4] OnTaskCreated@4(int32 task_id@0, + string package_name@1, + string activity@2, + [MinVersion=13] string? name@3); // Notifies that task has been destroyed. [MinVersion=4] OnTaskDestroyed@5(int32 task_id);
diff --git a/components/arc/common/bluetooth.mojom b/components/arc/common/bluetooth.mojom index edb607ee..5d0e241 100644 --- a/components/arc/common/bluetooth.mojom +++ b/components/arc/common/bluetooth.mojom
@@ -165,6 +165,8 @@ array<uint8> value; }; +const int8 kUnknownPower = 127; + // Copy from Bluetooth Assigned Numbers Document, Generic Access Profile // https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile [Extensible]
diff --git a/components/arc/test/fake_app_instance.cc b/components/arc/test/fake_app_instance.cc index c9c06c6..2978f201 100644 --- a/components/arc/test/fake_app_instance.cc +++ b/components/arc/test/fake_app_instance.cc
@@ -63,6 +63,14 @@ app_host_->OnAppListRefreshed(mojo::Array<mojom::AppInfoPtr>::From(apps)); } +void FakeAppInstance::SendPackageAppListRefreshed( + const mojo::String& package_name, + const std::vector<mojom::AppInfo>& apps) { + app_host_->OnPackageAppListRefreshed( + package_name, + mojo::Array<mojom::AppInfoPtr>::From(apps)); +} + void FakeAppInstance::SendInstallShortcuts( const std::vector<mojom::ShortcutInfo>& shortcuts) { for (auto& shortcut : shortcuts) { @@ -74,9 +82,13 @@ app_host_->OnInstallShortcut(shortcut.Clone()); } +void FakeAppInstance::SendAppAdded(const mojom::AppInfo& app) { + app_host_->OnAppAddedDeprecated(mojom::AppInfo::From(app)); +} + void FakeAppInstance::SendTaskCreated(int32_t taskId, const mojom::AppInfo& app) { - app_host_->OnTaskCreated(taskId, app.package_name, app.activity); + app_host_->OnTaskCreated(taskId, app.package_name, app.activity, app.name); } void FakeAppInstance::SendTaskDestroyed(int32_t taskId) {
diff --git a/components/arc/test/fake_app_instance.h b/components/arc/test/fake_app_instance.h index 8b5dcc1..8e05bfa 100644 --- a/components/arc/test/fake_app_instance.h +++ b/components/arc/test/fake_app_instance.h
@@ -117,6 +117,9 @@ // Methods to reply messages. void SendRefreshAppList(const std::vector<mojom::AppInfo>& apps); + void SendAppAdded(const mojom::AppInfo& app); + void SendPackageAppListRefreshed(const mojo::String& package_name, + const std::vector<mojom::AppInfo>& apps); void SendTaskCreated(int32_t taskId, const mojom::AppInfo& app); void SendTaskDestroyed(int32_t taskId); bool GenerateAndSendIcon(const mojom::AppInfo& app,
diff --git a/components/autofill/core/browser/country_data.cc b/components/autofill/core/browser/country_data.cc index 4d066245..443b2f6 100644 --- a/components/autofill/core/browser/country_data.cc +++ b/components/autofill/core/browser/country_data.cc
@@ -20,8 +20,11 @@ // Maps country codes to localized label string identifiers. Keep this sorted // by country code. +// This list is comprized of countries appearing in both +// //third_party/icu/source/data/region/en.txt and +// //third_party/libaddressinput/src/cpp/src/region_data_constants.cc. const StaticCountryData kCountryData[] = { - // clang-format off + // clang-format off { "AC", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE, IDS_AUTOFILL_FIELD_LABEL_PROVINCE, ADDRESS_REQUIRES_CITY } }, @@ -112,6 +115,9 @@ { "BO", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE, IDS_AUTOFILL_FIELD_LABEL_PROVINCE, ADDRESS_REQUIREMENTS_UNKNOWN } }, + { "BQ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE, + IDS_AUTOFILL_FIELD_LABEL_PROVINCE, + ADDRESS_REQUIREMENTS_UNKNOWN } }, { "BR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE, IDS_AUTOFILL_FIELD_LABEL_STATE, ADDRESS_REQUIRES_CITY_STATE_ZIP } }, @@ -178,6 +184,9 @@ { "CV", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE, IDS_AUTOFILL_FIELD_LABEL_ISLAND, ADDRESS_REQUIREMENTS_UNKNOWN } }, + { "CW", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE, + IDS_AUTOFILL_FIELD_LABEL_PROVINCE, + ADDRESS_REQUIREMENTS_UNKNOWN } }, { "CX", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE, IDS_AUTOFILL_FIELD_LABEL_PROVINCE, ADDRESS_REQUIREMENTS_UNKNOWN } }, @@ -340,6 +349,9 @@ { "IQ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE, IDS_AUTOFILL_FIELD_LABEL_PROVINCE, ADDRESS_REQUIRES_CITY_STATE } }, + { "IR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE, + IDS_AUTOFILL_FIELD_LABEL_PROVINCE, + ADDRESS_REQUIREMENTS_UNKNOWN } }, { "IS", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE, IDS_AUTOFILL_FIELD_LABEL_PROVINCE, ADDRESS_REQUIREMENTS_UNKNOWN } }, @@ -451,6 +463,9 @@ { "ML", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE, IDS_AUTOFILL_FIELD_LABEL_PROVINCE, ADDRESS_REQUIREMENTS_UNKNOWN } }, + { "MM", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE, + IDS_AUTOFILL_FIELD_LABEL_PROVINCE, + ADDRESS_REQUIREMENTS_UNKNOWN } }, { "MN", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE, IDS_AUTOFILL_FIELD_LABEL_PROVINCE, ADDRESS_REQUIREMENTS_UNKNOWN } }, @@ -631,12 +646,18 @@ { "SR", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE, IDS_AUTOFILL_FIELD_LABEL_PROVINCE, ADDRESS_REQUIREMENTS_UNKNOWN } }, + { "SS", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE, + IDS_AUTOFILL_FIELD_LABEL_PROVINCE, + ADDRESS_REQUIREMENTS_UNKNOWN } }, { "ST", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE, IDS_AUTOFILL_FIELD_LABEL_PROVINCE, ADDRESS_REQUIREMENTS_UNKNOWN } }, { "SV", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE, IDS_AUTOFILL_FIELD_LABEL_PROVINCE, ADDRESS_REQUIRES_CITY_STATE } }, + { "SX", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE, + IDS_AUTOFILL_FIELD_LABEL_PROVINCE, + ADDRESS_REQUIREMENTS_UNKNOWN } }, { "SZ", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE, IDS_AUTOFILL_FIELD_LABEL_PROVINCE, ADDRESS_REQUIREMENTS_UNKNOWN } }, @@ -754,7 +775,7 @@ { "ZW", { IDS_AUTOFILL_FIELD_LABEL_POSTAL_CODE, IDS_AUTOFILL_FIELD_LABEL_PROVINCE, ADDRESS_REQUIREMENTS_UNKNOWN } }, - // clang-format on + // clang-format on }; // GetCountryCodes and GetCountryData compute the data for CountryDataMap
diff --git a/components/autofill/core/browser/personal_data_manager_unittest.cc b/components/autofill/core/browser/personal_data_manager_unittest.cc index 12263113..06d931a 100644 --- a/components/autofill/core/browser/personal_data_manager_unittest.cc +++ b/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -2047,6 +2047,136 @@ EXPECT_EQ(0, profile.Compare(*results2[0])); } +// Tests that no profile is inferred if the country is not recognized. +TEST_F(PersonalDataManagerTest, ImportAddressProfiles_UnrecognizedCountry) { + FormData form; + FormFieldData field; + test::CreateTestFormField("First name:", "first_name", "George", "text", + &field); + form.fields.push_back(field); + test::CreateTestFormField("Last name:", "last_name", "Washington", "text", + &field); + form.fields.push_back(field); + test::CreateTestFormField("Email:", "email", "theprez@gmail.com", "text", + &field); + form.fields.push_back(field); + test::CreateTestFormField("Address:", "address1", "21 Laussat St", "text", + &field); + form.fields.push_back(field); + test::CreateTestFormField("City:", "city", "San Francisco", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("State:", "state", "California", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Zip:", "zip", "94102", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Country:", "country", "Notacountry", "text", + &field); + form.fields.push_back(field); + + FormStructure form_structure(form); + form_structure.DetermineHeuristicTypes(); + EXPECT_FALSE(ImportAddressProfiles(form_structure)); + + // Since no refresh is expected, reload the data from the database to make + // sure no changes were written out. + ResetPersonalDataManager(USER_MODE_NORMAL); + + const std::vector<AutofillProfile*>& profiles = personal_data_->GetProfiles(); + ASSERT_EQ(0U, profiles.size()); + const std::vector<CreditCard*>& cards = personal_data_->GetCreditCards(); + ASSERT_EQ(0U, cards.size()); +} + +// Tests that a profile is created for countries with composed names. +TEST_F(PersonalDataManagerTest, + ImportAddressProfiles_CompleteComposedCountryName) { + FormData form; + FormFieldData field; + test::CreateTestFormField("First name:", "first_name", "George", "text", + &field); + form.fields.push_back(field); + test::CreateTestFormField("Last name:", "last_name", "Washington", "text", + &field); + form.fields.push_back(field); + test::CreateTestFormField("Email:", "email", "theprez@gmail.com", "text", + &field); + form.fields.push_back(field); + test::CreateTestFormField("Address:", "address1", "21 Laussat St", "text", + &field); + form.fields.push_back(field); + test::CreateTestFormField("City:", "city", "San Francisco", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("State:", "state", "California", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Zip:", "zip", "94102", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Country:", "country", "Myanmar [Burma]", "text", + &field); + form.fields.push_back(field); + + FormStructure form_structure(form); + form_structure.DetermineHeuristicTypes(); + EXPECT_TRUE(ImportAddressProfiles(form_structure)); + + // Verify that the web database has been updated and the notification sent. + EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()) + .WillOnce(QuitMainMessageLoop()); + base::RunLoop().Run(); + + AutofillProfile expected(base::GenerateGUID(), "https://www.example.com"); + test::SetProfileInfo(&expected, "George", nullptr, "Washington", + "theprez@gmail.com", nullptr, "21 Laussat St", nullptr, + "San Francisco", "California", "94102", "MM", nullptr); + const std::vector<AutofillProfile*>& results = personal_data_->GetProfiles(); + ASSERT_EQ(1U, results.size()); + EXPECT_EQ(0, expected.Compare(*results[0])); +} + +// TODO(crbug.com/634131): Create profiles if part of a standalone part of a +// composed country name is present. +// Tests that a profile is created if a standalone part of a composed country +// name is present. +TEST_F(PersonalDataManagerTest, + ImportAddressProfiles_IncompleteComposedCountryName) { + FormData form; + FormFieldData field; + test::CreateTestFormField("First name:", "first_name", "George", "text", + &field); + form.fields.push_back(field); + test::CreateTestFormField("Last name:", "last_name", "Washington", "text", + &field); + form.fields.push_back(field); + test::CreateTestFormField("Email:", "email", "theprez@gmail.com", "text", + &field); + form.fields.push_back(field); + test::CreateTestFormField("Address:", "address1", "21 Laussat St", "text", + &field); + form.fields.push_back(field); + test::CreateTestFormField("City:", "city", "San Francisco", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("State:", "state", "California", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Zip:", "zip", "94102", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("Country:", "country", + "Myanmar", // Missing the [Burma] part + "text", &field); + form.fields.push_back(field); + + FormStructure form_structure(form); + form_structure.DetermineHeuristicTypes(); + EXPECT_FALSE(ImportAddressProfiles(form_structure)); + + // Since no refresh is expected, reload the data from the database to make + // sure no changes were written out. + ResetPersonalDataManager(USER_MODE_NORMAL); + + const std::vector<AutofillProfile*>& profiles = personal_data_->GetProfiles(); + ASSERT_EQ(0U, profiles.size()); + const std::vector<CreditCard*>& cards = personal_data_->GetCreditCards(); + ASSERT_EQ(0U, cards.size()); +} + // ImportCreditCard tests. // Tests that a valid credit card is extracted.
diff --git a/components/autofill/ios/browser/js_autofill_manager.mm b/components/autofill/ios/browser/js_autofill_manager.mm index 68aa42d..b56be25 100644 --- a/components/autofill/ios/browser/js_autofill_manager.mm +++ b/components/autofill/ios/browser/js_autofill_manager.mm
@@ -30,10 +30,6 @@ return @"autofill_controller"; } -- (NSString*)presenceBeacon { - return @"__gCrWeb.autofill"; -} - - (void)fillActiveFormField:(NSString*)dataString completionHandler:(ProceduralBlock)completionHandler { web::JavaScriptCompletion resultHandler = ^void(NSString*, NSError*) {
diff --git a/components/autofill/ios/browser/js_suggestion_manager.mm b/components/autofill/ios/browser/js_suggestion_manager.mm index 829df69..368ad29 100644 --- a/components/autofill/ios/browser/js_suggestion_manager.mm +++ b/components/autofill/ios/browser/js_suggestion_manager.mm
@@ -27,10 +27,6 @@ return @"suggestion_controller"; } -- (NSString*)presenceBeacon { - return @"__gCrWeb.suggestion"; -} - - (void)selectNextElement { [self selectElementAfterForm:@"" field:@""]; }
diff --git a/components/bookmarks/browser/BUILD.gn b/components/bookmarks/browser/BUILD.gn index cac02195..05e8125 100644 --- a/components/bookmarks/browser/BUILD.gn +++ b/components/bookmarks/browser/BUILD.gn
@@ -117,11 +117,4 @@ "//ui/base", "//url", ] - - if (use_x11) { - deps += [ - "//ui/events/platform/x11", - "//ui/gfx/x", - ] - } }
diff --git a/components/bookmarks/browser/bookmark_node_data_unittest.cc b/components/bookmarks/browser/bookmark_node_data_unittest.cc index 650a293d..f27f94f 100644 --- a/components/bookmarks/browser/bookmark_node_data_unittest.cc +++ b/components/bookmarks/browser/bookmark_node_data_unittest.cc
@@ -17,7 +17,6 @@ #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/clipboard/clipboard.h" #include "ui/base/dragdrop/os_exchange_data.h" -#include "ui/events/platform/platform_event_source.h" #include "url/gurl.h" using base::ASCIIToUTF16; @@ -29,7 +28,6 @@ BookmarkNodeDataTest() {} void SetUp() override { - event_source_ = ui::PlatformEventSource::CreateDefault(); model_ = TestBookmarkClient::CreateModel(); test::WaitForBookmarkModelToLoad(model_.get()); bool success = profile_dir_.CreateUniqueTempDir(); @@ -38,7 +36,6 @@ void TearDown() override { model_.reset(); - event_source_.reset(); bool success = profile_dir_.Delete(); ASSERT_TRUE(success); ui::Clipboard::DestroyClipboardForCurrentThread(); @@ -54,7 +51,6 @@ private: base::ScopedTempDir profile_dir_; std::unique_ptr<BookmarkModel> model_; - std::unique_ptr<ui::PlatformEventSource> event_source_; base::MessageLoopForUI loop_; DISALLOW_COPY_AND_ASSIGN(BookmarkNodeDataTest);
diff --git a/components/bookmarks/browser/bookmark_utils_unittest.cc b/components/bookmarks/browser/bookmark_utils_unittest.cc index 54d89d7..dfd6e43 100644 --- a/components/bookmarks/browser/bookmark_utils_unittest.cc +++ b/components/bookmarks/browser/bookmark_utils_unittest.cc
@@ -20,15 +20,6 @@ #include "ui/base/clipboard/clipboard.h" #include "ui/base/clipboard/scoped_clipboard_writer.h" -#if defined(USE_GLIB) && defined(USE_X11) - -#include <memory> - -#include "ui/events/platform/x11/x11_event_source_glib.h" // nogncheck -#include "ui/gfx/x/x11_types.h" // nogncheck - -#endif // defined(USE_GLIB) && defined(USE_X11) - using base::ASCIIToUTF16; using std::string; @@ -39,11 +30,7 @@ public BaseBookmarkModelObserver { public: BookmarkUtilsTest() - : grouped_changes_beginning_count_(0), grouped_changes_ended_count_(0) { -#if defined(USE_GLIB) && defined(USE_X11) - event_source_.reset(new ui::X11EventSourceGlib(gfx::GetXDisplay())); -#endif // defined(USE_GLIB) && defined(USE_X11) - } + : grouped_changes_beginning_count_(0), grouped_changes_ended_count_(0) {} ~BookmarkUtilsTest() override {} @@ -86,11 +73,6 @@ // Clipboard requires a message loop. base::MessageLoopForUI loop_; -#if defined(USE_GLIB) && defined(USE_X11) - // On Linux, Clipboard also depends on an event source being present, to get - // the timestamp. - std::unique_ptr<ui::X11EventSourceGlib> event_source_; -#endif // defined(USE_GLIB) && defined(USE_X11) DISALLOW_COPY_AND_ASSIGN(BookmarkUtilsTest); };
diff --git a/components/components.gyp b/components/components.gyp index 025e7e9eb2..ee33fc3e 100644 --- a/components/components.gyp +++ b/components/components.gyp
@@ -68,6 +68,7 @@ 'os_crypt.gypi', 'ownership.gypi', 'password_manager.gypi', + 'physical_web.gypi', 'plugins.gypi', 'policy.gypi', 'precache.gypi',
diff --git a/components/components_tests.gyp b/components/components_tests.gyp index 44a6c44..300082b 100644 --- a/components/components_tests.gyp +++ b/components/components_tests.gyp
@@ -708,38 +708,6 @@ 'safe_json/json_sanitizer_unittest.cc', 'safe_json/testing_json_parser_unittest.cc', ], - 'scheduler_unittest_sources': [ - 'scheduler/base/long_task_tracker_unittest.cc', - 'scheduler/base/queueing_time_estimator_unittest.cc', - 'scheduler/base/task_queue_manager_delegate_for_test.cc', - 'scheduler/base/task_queue_manager_delegate_for_test.h', - 'scheduler/base/task_queue_manager_unittest.cc', - 'scheduler/base/task_queue_selector_unittest.cc', - 'scheduler/base/test_count_uses_time_source.cc', - 'scheduler/base/test_count_uses_time_source.h', - 'scheduler/base/test_task_time_tracker.h', - 'scheduler/base/test_time_source.cc', - 'scheduler/base/test_time_source.h', - 'scheduler/base/time_domain_unittest.cc', - 'scheduler/base/work_queue_sets_unittest.cc', - 'scheduler/child/idle_helper_unittest.cc', - 'scheduler/child/scheduler_helper_unittest.cc', - 'scheduler/child/scheduler_tqm_delegate_for_test.cc', - 'scheduler/child/scheduler_tqm_delegate_for_test.h', - 'scheduler/child/scheduler_tqm_delegate_impl_unittest.cc', - 'scheduler/child/webthread_impl_for_worker_scheduler_unittest.cc', - 'scheduler/child/worker_scheduler_impl_unittest.cc', - 'scheduler/renderer/auto_advancing_virtual_time_domain_unittest.cc', - 'scheduler/renderer/deadline_task_runner_unittest.cc', - 'scheduler/renderer/idle_time_estimator_unittest.cc', - 'scheduler/renderer/render_widget_signals_unittest.cpp', - 'scheduler/renderer/renderer_scheduler_impl_unittest.cc', - 'scheduler/renderer/task_cost_estimator_unittest.cc', - 'scheduler/renderer/throttling_helper_unittest.cc', - 'scheduler/renderer/user_model_unittest.cc', - 'scheduler/renderer/web_view_scheduler_impl_unittest.cc', - 'scheduler/renderer/webthread_impl_for_renderer_scheduler_unittest.cc', - ], 'search_unittest_sources': [ 'search/search_android_unittest.cc', 'search/search_unittest.cc', @@ -1424,7 +1392,6 @@ '<@(power_unittest_sources)', '<@(safe_browsing_db_unittest_sources)', '<@(safe_json_unittest_sources)', - '<@(scheduler_unittest_sources)', '<@(storage_monitor_unittest_sources)', '<@(subresource_filter_content_browser_unittest_sources)', '<@(subresource_filter_content_renderer_unittest_sources)', @@ -1488,7 +1455,6 @@ 'components.gyp:web_modal', 'components.gyp:web_modal_test_support', 'components.gyp:zoom', - 'scheduler/scheduler.gyp:scheduler', 'test_runner/test_runner.gyp:test_runner', 'tracing.gyp:proto_zero_testing_messages', 'tracing.gyp:tracing', @@ -1969,7 +1935,6 @@ '../testing/gtest.gyp:gtest', '../testing/perf/perf_test.gyp:perf_test', 'components.gyp:visitedlink_browser', - 'scheduler/scheduler.gyp:scheduler', ], 'include_dirs': [ '..',
diff --git a/components/content_settings/core/browser/website_settings_registry.cc b/components/content_settings/core/browser/website_settings_registry.cc index 0bbdeba..62ec02a 100644 --- a/components/content_settings/core/browser/website_settings_registry.cc +++ b/components/content_settings/core/browser/website_settings_registry.cc
@@ -139,6 +139,12 @@ WebsiteSettingsInfo::REQUESTING_ORIGIN_AND_TOP_LEVEL_ORIGIN_SCOPE, DESKTOP | PLATFORM_ANDROID, WebsiteSettingsInfo::DONT_INHERIT_IN_INCOGNITO); + Register(CONTENT_SETTINGS_TYPE_PROMPT_NO_DECISION_COUNT, + "prompt-no-decision-count", nullptr, WebsiteSettingsInfo::UNSYNCABLE, + WebsiteSettingsInfo::NOT_LOSSY, + WebsiteSettingsInfo::REQUESTING_ORIGIN_ONLY_SCOPE, + DESKTOP | PLATFORM_ANDROID, + WebsiteSettingsInfo::INHERIT_IN_INCOGNITO); } } // namespace content_settings
diff --git a/components/content_settings/core/common/content_settings.cc b/components/content_settings/core/common/content_settings.cc index b52c6c1c..c742698 100644 --- a/components/content_settings/core/common/content_settings.cc +++ b/components/content_settings/core/common/content_settings.cc
@@ -56,6 +56,7 @@ CONTENT_SETTINGS_TYPE_BLUETOOTH_GUARD, CONTENT_SETTINGS_TYPE_BACKGROUND_SYNC, CONTENT_SETTINGS_TYPE_AUTOPLAY, + CONTENT_SETTINGS_TYPE_PROMPT_NO_DECISION_COUNT, }; int ContentSettingTypeToHistogramValue(ContentSettingsType content_setting,
diff --git a/components/content_settings/core/common/content_settings_types.h b/components/content_settings/core/common/content_settings_types.h index cd21a9b..d1c601c 100644 --- a/components/content_settings/core/common/content_settings_types.h +++ b/components/content_settings/core/common/content_settings_types.h
@@ -45,6 +45,7 @@ CONTENT_SETTINGS_TYPE_KEYGEN, CONTENT_SETTINGS_TYPE_BACKGROUND_SYNC, CONTENT_SETTINGS_TYPE_AUTOPLAY, + CONTENT_SETTINGS_TYPE_PROMPT_NO_DECISION_COUNT, // WARNING: This enum is going to be removed soon. Do not depend on NUM_TYPES. CONTENT_SETTINGS_NUM_TYPES_DO_NOT_USE,
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn index 5789189..4298e99 100644 --- a/components/cronet/android/BUILD.gn +++ b/components/cronet/android/BUILD.gn
@@ -401,7 +401,7 @@ # "tested apk" are removed from the "instrumentation test apk". android_resources("cronet_sample_test_apk_resources") { resource_dirs = [ "sample/res" ] - android_manifest = "sample/AndroidManifest.xml" + android_manifest = "sample/javatests/AndroidManifest.xml" } instrumentation_test_apk("cronet_sample_test_apk") {
diff --git a/components/cronet/android/api/src/org/chromium/net/CronetEngine.java b/components/cronet/android/api/src/org/chromium/net/CronetEngine.java index b7013e2f..221f002 100644 --- a/components/cronet/android/api/src/org/chromium/net/CronetEngine.java +++ b/components/cronet/android/api/src/org/chromium/net/CronetEngine.java
@@ -648,6 +648,11 @@ throw new IllegalArgumentException("Hostname " + hostName + " is illegal." + " A hostname should not consist of digits and/or dots only."); } + // Workaround for crash, see crbug.com/634914 + if (hostName.length() > 255) { + throw new IllegalArgumentException("Hostname " + hostName + " is too long." + + " The name of the host does not comply with RFC 1122 and RFC 1123."); + } try { return IDN.toASCII(hostName, IDN.USE_STD3_ASCII_RULES); } catch (IllegalArgumentException ex) {
diff --git a/components/cronet/android/sample/javatests/src/org/chromium/cronet_sample_apk/CronetSampleTest.java b/components/cronet/android/sample/javatests/src/org/chromium/cronet_sample_apk/CronetSampleTest.java index debacc2..dbfd1473 100644 --- a/components/cronet/android/sample/javatests/src/org/chromium/cronet_sample_apk/CronetSampleTest.java +++ b/components/cronet/android/sample/javatests/src/org/chromium/cronet_sample_apk/CronetSampleTest.java
@@ -9,11 +9,12 @@ import android.net.Uri; import android.os.ConditionVariable; import android.test.ActivityInstrumentationTestCase2; +import android.test.suitebuilder.annotation.SmallTest; import android.text.Editable; import android.text.TextWatcher; import android.widget.TextView; -import org.chromium.base.test.util.FlakyTest; +import org.chromium.base.test.util.Feature; import org.chromium.net.test.EmbeddedTestServer; /** @@ -42,11 +43,8 @@ super.tearDown(); } - /* @SmallTest @Feature({"Cronet"}) - */ - @FlakyTest(message = "https://crbug.com/592444") public void testLoadUrl() throws Exception { CronetSampleActivity activity = launchCronetSampleWithUrl(mUrl); @@ -65,7 +63,7 @@ @Override public void onTextChanged(CharSequence s, int start, int before, int count) { - if (s.equals("Completed " + mUrl + " (200)")) { + if (s.toString().equals("Completed " + mUrl + " (200)")) { done.open(); } }
diff --git a/components/cronet/ios/BUILD.gn b/components/cronet/ios/BUILD.gn index 38dfb99..4153445 100644 --- a/components/cronet/ios/BUILD.gn +++ b/components/cronet/ios/BUILD.gn
@@ -64,6 +64,7 @@ ios_framework_bundle("cronet_framework") { output_name = "Cronet" info_plist_target = ":tweak_cronet_plist" + enable_code_signing = false deps = [ ":cronet_sources",
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc index 6014265..740aff20 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
@@ -237,6 +237,12 @@ if (data_reduction_proxy_request_options_) { data_reduction_proxy_request_options_->AddRequestHeader(headers); + // Data Reduction Proxy handles Accept-Encoding: Brotli correctly, but don't + // trust intermediate proxies. + if (proxy_info.is_https() || proxy_info.is_quic()) { + data_reduction_proxy_request_options_->AddBrotliAcceptEncoding(*request, + headers); + } } }
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc index d7de09c4..92aec76 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
@@ -810,6 +810,45 @@ 1); } +TEST_F(DataReductionProxyNetworkDelegateTest, TestAcceptEncodingBrotli) { + const struct { + net::ProxyServer proxy; + bool brotli_enabled; + std::string expected_accept_encoding; + } tests[] = { + {net::ProxyServer(net::ProxyServer::SCHEME_HTTPS, + net::HostPortPair("origin.net", 80)), + true, "gzip, br"}, + {net::ProxyServer(net::ProxyServer::SCHEME_QUIC, + net::HostPortPair("origin.net", 80)), + true, "gzip, br"}, + {net::ProxyServer(net::ProxyServer::SCHEME_HTTPS, + net::HostPortPair("origin.net", 80)), + false, "gzip"}, + {net::ProxyServer(net::ProxyServer::SCHEME_HTTP, + net::HostPortPair("origin.net", 80)), + true, "gzip"}, + }; + for (auto test : tests) { + net::ProxyInfo data_reduction_proxy_info; + data_reduction_proxy_info.UseProxyServer(test.proxy); + net::HttpRequestHeaders headers; + headers.SetHeader(net::HttpRequestHeaders::kAcceptEncoding, "gzip"); + context()->set_enable_brotli(test.brotli_enabled); + std::unique_ptr<net::URLRequest> request = context()->CreateRequest( + GURL("http://www.google.com/"), net::RequestPriority::IDLE, nullptr); + + network_delegate()->NotifyBeforeSendHeaders( + request.get(), data_reduction_proxy_info, net::ProxyRetryInfoMap(), + &headers); + + std::string got_accept_encoding; + EXPECT_TRUE(headers.GetHeader(net::HttpRequestHeaders::kAcceptEncoding, + &got_accept_encoding)); + EXPECT_EQ(test.expected_accept_encoding, got_accept_encoding); + } +} + } // namespace } // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc index 7f0382e2..057ac1cd5 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc
@@ -23,8 +23,10 @@ #include "crypto/random.h" #include "net/base/host_port_pair.h" #include "net/base/load_flags.h" +#include "net/http/http_request_headers.h" #include "net/proxy/proxy_server.h" #include "net/url_request/url_request.h" +#include "net/url_request/url_request_context.h" #if defined(USE_GOOGLE_API_KEYS_FOR_AUTH_KEY) #include "google_apis/google_api_keys.h" @@ -37,6 +39,17 @@ return name + "=" + value; } +bool HasBrotliAcceptEncoding(base::StringPiece accept_encoding_header) { + for (base::StringPiece encoding : base::SplitStringPiece( + accept_encoding_header, ",", base::TRIM_WHITESPACE, + base::SPLIT_WANT_NONEMPTY)) { + if (encoding == "br") { + return true; + } + } + return false; +} + } // namespace const char kSessionHeaderOption[] = "ps"; @@ -154,6 +167,24 @@ request_headers->SetHeader(kChromeProxyHeader, header_value); } +void DataReductionProxyRequestOptions::AddBrotliAcceptEncoding( + const net::URLRequest& request, + net::HttpRequestHeaders* request_headers) { + std::string accept_encoding_header; + if (!request.context()->enable_brotli() || + !request_headers->GetHeader(net::HttpRequestHeaders::kAcceptEncoding, + &accept_encoding_header) || + HasBrotliAcceptEncoding(accept_encoding_header)) + return; + if (accept_encoding_header.empty()) { + accept_encoding_header = "br"; + } else { + accept_encoding_header += ", br"; + } + request_headers->SetHeader(net::HttpRequestHeaders::kAcceptEncoding, + accept_encoding_header); +} + void DataReductionProxyRequestOptions::ComputeCredentials( const base::Time& now, std::string* session,
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h index 4cf3c7c..09f6379b 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h
@@ -63,6 +63,10 @@ // proxy authentication credentials. void AddRequestHeader(net::HttpRequestHeaders* request_headers); + // Adds 'br' to the Accept-Encoding header if Brotli is enabled. + void AddBrotliAcceptEncoding(const net::URLRequest& request, + net::HttpRequestHeaders* request_headers); + // Stores the supplied key and sets up credentials suitable for authenticating // with the data reduction proxy. // This can be called more than once. For example on a platform that does not
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc index 32cb51db..ade256b 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc
@@ -357,4 +357,43 @@ } } +TEST_F(DataReductionProxyRequestOptionsTest, AddBrotliAcceptEncoding) { + const struct { + const char* initial_accept_encoding; + bool brotli_enabled; + const char* expected_accept_encoding; + } tests[] = { + {nullptr, true, nullptr}, + {"", true, "br"}, + {"gzip", true, "gzip, br"}, + {"gzip,br,foo", true, "gzip,br,foo"}, + {"gzip, br , foo", true, "gzip, br , foo"}, + {"gzip", false, "gzip"}, + {"gzip, br", false, "gzip, br"}, + }; + + for (const auto& test : tests) { + net::URLRequestContext context; + context.set_enable_brotli(test.brotli_enabled); + auto request = context.CreateRequest(GURL("http://foo"), + net::DEFAULT_PRIORITY, nullptr); + net::HttpRequestHeaders request_headers; + if (test.initial_accept_encoding) { + request_headers.SetHeader(net::HttpRequestHeaders::kAcceptEncoding, + test.initial_accept_encoding); + } + + request_options()->AddBrotliAcceptEncoding(*request, &request_headers); + + std::string actual_accept_encoding; + EXPECT_EQ( + request_headers.GetHeader(net::HttpRequestHeaders::kAcceptEncoding, + &actual_accept_encoding), + test.expected_accept_encoding != nullptr); + if (test.expected_accept_encoding) { + EXPECT_EQ(test.expected_accept_encoding, actual_accept_encoding); + } + } +} + } // namespace data_reduction_proxy
diff --git a/components/display_compositor/BUILD.gn b/components/display_compositor/BUILD.gn index 6afe1e69..1e84a40 100644 --- a/components/display_compositor/BUILD.gn +++ b/components/display_compositor/BUILD.gn
@@ -30,6 +30,7 @@ "//gpu/command_buffer/client:gles2_interface", "//gpu/command_buffer/common", "//skia", + "//ui/display/types", "//ui/gfx", ] @@ -85,6 +86,7 @@ "//skia", "//testing/gmock", "//testing/gtest", + "//ui/display/types", "//ui/gl:test_support", ]
diff --git a/components/display_compositor/DEPS b/components/display_compositor/DEPS index 34fad93b..ee02c38 100644 --- a/components/display_compositor/DEPS +++ b/components/display_compositor/DEPS
@@ -7,6 +7,7 @@ "+gpu/ipc/common", "+third_party/khronos/GLES2", "+third_party/skia", + "+ui/display", "+ui/gfx", "+ui/gl", "+ui/ozone/public",
diff --git a/components/display_compositor/buffer_queue.cc b/components/display_compositor/buffer_queue.cc index bcdb62c3..5bd18aae 100644 --- a/components/display_compositor/buffer_queue.cc +++ b/components/display_compositor/buffer_queue.cc
@@ -14,6 +14,7 @@ #include "gpu/command_buffer/common/gpu_memory_buffer_support.h" #include "third_party/skia/include/core/SkRect.h" #include "third_party/skia/include/core/SkRegion.h" +#include "ui/display/types/display_snapshot.h" #include "ui/gfx/gpu_memory_buffer.h" #include "ui/gfx/skia_util.h" @@ -22,6 +23,7 @@ BufferQueue::BufferQueue(gpu::gles2::GLES2Interface* gl, uint32_t texture_target, uint32_t internal_format, + gfx::BufferFormat format, GLHelper* gl_helper, gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, gpu::SurfaceHandle surface_handle) @@ -30,9 +32,13 @@ allocated_count_(0), texture_target_(texture_target), internal_format_(internal_format), + format_(format), gl_helper_(gl_helper), gpu_memory_buffer_manager_(gpu_memory_buffer_manager), - surface_handle_(surface_handle) {} + surface_handle_(surface_handle) { + DCHECK(gpu::IsImageFormatCompatibleWithGpuMemoryBufferFormat(internal_format, + format_)); +} BufferQueue::~BufferQueue() { FreeAllSurfaces(); @@ -211,11 +217,9 @@ // We don't want to allow anything more than triple buffering. DCHECK_LT(allocated_count_, 4U); - std::unique_ptr<gfx::GpuMemoryBuffer> buffer( gpu_memory_buffer_manager_->AllocateGpuMemoryBuffer( - size_, gpu::DefaultBufferFormatForImageFormat(internal_format_), - gfx::BufferUsage::SCANOUT, surface_handle_)); + size_, format_, gfx::BufferUsage::SCANOUT, surface_handle_)); if (!buffer.get()) { gl_->DeleteTextures(1, &texture); DLOG(ERROR) << "Failed to allocate GPU memory buffer";
diff --git a/components/display_compositor/buffer_queue.h b/components/display_compositor/buffer_queue.h index 924a0ec..3ae123d 100644 --- a/components/display_compositor/buffer_queue.h +++ b/components/display_compositor/buffer_queue.h
@@ -15,6 +15,7 @@ #include "base/memory/ref_counted.h" #include "components/display_compositor/display_compositor_export.h" #include "gpu/ipc/common/surface_handle.h" +#include "ui/gfx/buffer_types.h" #include "ui/gfx/color_space.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" @@ -44,6 +45,7 @@ BufferQueue(gpu::gles2::GLES2Interface* gl, uint32_t texture_target, uint32_t internal_format, + gfx::BufferFormat format, GLHelper* gl_helper, gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, gpu::SurfaceHandle surface_handle); @@ -110,6 +112,7 @@ size_t allocated_count_; uint32_t texture_target_; uint32_t internal_format_; + gfx::BufferFormat format_; // This surface is currently bound. This may be nullptr if no surface has // been bound, or if allocation failed at bind. std::unique_ptr<AllocatedSurface> current_surface_;
diff --git a/components/display_compositor/buffer_queue_unittest.cc b/components/display_compositor/buffer_queue_unittest.cc index 78a0188..17ef79b 100644 --- a/components/display_compositor/buffer_queue_unittest.cc +++ b/components/display_compositor/buffer_queue_unittest.cc
@@ -19,6 +19,7 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/khronos/GLES2/gl2ext.h" +#include "ui/display/types/display_snapshot.h" using ::testing::_; using ::testing::Expectation; @@ -101,6 +102,7 @@ : BufferQueue(gl, target, internalformat, + ui::DisplaySnapshot::PrimaryFormat(), nullptr, gpu_memory_buffer_manager, kFakeSurfaceHandle) {} @@ -122,7 +124,7 @@ gpu_memory_buffer_manager_.reset(new StubGpuMemoryBufferManager); mock_output_surface_ = new MockBufferQueue(context_provider_->ContextGL(), gpu_memory_buffer_manager_.get(), - GL_TEXTURE_2D, GL_RGBA); + GL_TEXTURE_2D, GL_RGB); output_surface_.reset(mock_output_surface_); output_surface_->Initialize(); } @@ -262,8 +264,8 @@ gpu::gles2::GLES2Interface* gl, gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager) { std::unique_ptr<BufferQueue> buffer_queue( - new BufferQueue(gl, target, GL_RGBA, nullptr, gpu_memory_buffer_manager, - kFakeSurfaceHandle)); + new BufferQueue(gl, target, GL_RGB, ui::DisplaySnapshot::PrimaryFormat(), + nullptr, gpu_memory_buffer_manager, kFakeSurfaceHandle)); buffer_queue->Initialize(); return buffer_queue; } @@ -301,7 +303,7 @@ EXPECT_CALL(*context, bindTexture(target, Ne(0U))); EXPECT_CALL(*context, destroyImageCHROMIUM(1)); Expectation image = - EXPECT_CALL(*context, createImageCHROMIUM(_, 0, 0, GL_RGBA)) + EXPECT_CALL(*context, createImageCHROMIUM(_, 0, 0, GL_RGB)) .WillOnce(Return(1)); Expectation fb = EXPECT_CALL(*context, bindFramebuffer(GL_FRAMEBUFFER, Ne(0U))); @@ -330,9 +332,10 @@ gl_helper.reset(new GLHelper(context_provider->ContextGL(), context_provider->ContextSupport())); - output_surface.reset(new BufferQueue( - context_provider->ContextGL(), GL_TEXTURE_2D, GL_RGBA, gl_helper.get(), - gpu_memory_buffer_manager.get(), kFakeSurfaceHandle)); + output_surface.reset( + new BufferQueue(context_provider->ContextGL(), GL_TEXTURE_2D, GL_RGB, + ui::DisplaySnapshot::PrimaryFormat(), gl_helper.get(), + gpu_memory_buffer_manager.get(), kFakeSurfaceHandle)); output_surface->Initialize(); output_surface->Reshape(screen_size, 1.0f, gfx::ColorSpace()); // Trigger a sub-buffer copy to exercise all paths. @@ -581,7 +584,7 @@ // Expect all 4 images to be destroyed, 3 of the existing textures to be // copied from and 3 new images to be created. - EXPECT_CALL(*context_, createImageCHROMIUM(_, 0, 0, GL_RGBA)).Times(3); + EXPECT_CALL(*context_, createImageCHROMIUM(_, 0, 0, GL_RGB)).Times(3); Expectation copy1 = EXPECT_CALL(*mock_output_surface_, CopyBufferDamage(_, displayed->texture, _, _)) .Times(1);
diff --git a/components/error_page/renderer/BUILD.gn b/components/error_page/renderer/BUILD.gn index 5b778164..d80faa9d 100644 --- a/components/error_page/renderer/BUILD.gn +++ b/components/error_page/renderer/BUILD.gn
@@ -35,7 +35,6 @@ "//base", "//base/test:test_support", "//components/error_page/common", - "//components/test_runner", "//content/public/common", "//net", "//testing/gtest",
diff --git a/components/error_page/renderer/DEPS b/components/error_page/renderer/DEPS index 3d7c4ce..3238bc4 100644 --- a/components/error_page/renderer/DEPS +++ b/components/error_page/renderer/DEPS
@@ -1,5 +1,4 @@ include_rules = [ - "+components/test_runner", "+components/url_formatter", "+content/public/common", "+grit/components_strings.h",
diff --git a/components/error_page/renderer/net_error_helper_core_unittest.cc b/components/error_page/renderer/net_error_helper_core_unittest.cc index 943010d..d73ea28 100644 --- a/components/error_page/renderer/net_error_helper_core_unittest.cc +++ b/components/error_page/renderer/net_error_helper_core_unittest.cc
@@ -24,7 +24,6 @@ #include "build/build_config.h" #include "components/error_page/common/error_page_params.h" #include "components/error_page/common/net_error_info.h" -#include "components/test_runner/test_common.h" #include "content/public/common/url_constants.h" #include "net/base/net_errors.h" #include "testing/gtest/include/gtest/gtest.h" @@ -171,7 +170,6 @@ error_url_(GURL(content::kUnreachableWebDataURL)), tracking_request_count_(0) { SetUpCore(false, false, true); - test_runner::EnsureBlinkInitialized(); } ~NetErrorHelperCoreTest() override {
diff --git a/components/exo/BUILD.gn b/components/exo/BUILD.gn index c770897..fbc866c 100644 --- a/components/exo/BUILD.gn +++ b/components/exo/BUILD.gn
@@ -84,11 +84,12 @@ testonly = true sources = [ - "buffer_unittest.cc", - "display_unittest.cc", - "gamepad_unittest.cc", - "keyboard_unittest.cc", - "pointer_unittest.cc", + # Disable tests - they are flaky: crbug.com/630625 + # "buffer_unittest.cc", + # "display_unittest.cc", + # "gamepad_unittest.cc", + # "keyboard_unittest.cc", + # "pointer_unittest.cc", "shared_memory_unittest.cc", "shell_surface_unittest.cc", "sub_surface_unittest.cc",
diff --git a/components/exo/keyboard.cc b/components/exo/keyboard.cc index 88f6dbd..4aba4902 100644 --- a/components/exo/keyboard.cc +++ b/components/exo/keyboard.cc
@@ -43,15 +43,14 @@ // because key-down events do not mean any character inputs there. // (InsertChar issues a DOM "keypress" event, which is distinct from keydown.) // Unfortunately, this is not necessary the case for our clients that may - // treat keydown as a trigger of text inputs. We need suppression for keydown. - if (event->type() == ui::ET_KEY_PRESSED) { - // Same condition as components/arc/ime/arc_ime_service.cc#InsertChar. - const base::char16 ch = event->GetCharacter(); - const bool is_control_char = - (0x00 <= ch && ch <= 0x1f) || (0x7f <= ch && ch <= 0x9f); - if (!is_control_char && !ui::IsSystemKeyModifier(event->flags())) - return true; - } + // treat a key event as a trigger of text inputs. We need suppression. + + // Same condition as components/arc/ime/arc_ime_service.cc#InsertChar. + const base::char16 ch = event->GetCharacter(); + const bool is_control_char = + (0x00 <= ch && ch <= 0x1f) || (0x7f <= ch && ch <= 0x9f); + if (!is_control_char && !ui::IsSystemKeyModifier(event->flags())) + return true; // Case 3: // Workaround for apps that doesn't handle hardware keyboard events well.
diff --git a/components/exo/shell_surface.cc b/components/exo/shell_surface.cc index c820038a..72f11c5 100644 --- a/components/exo/shell_surface.cc +++ b/components/exo/shell_surface.cc
@@ -652,11 +652,13 @@ } bool ShellSurface::CanMaximize() const { - return true; + // Shell surfaces in system modal container cannot be maximized. + return container_ != ash::kShellWindowId_SystemModalContainer; } bool ShellSurface::CanMinimize() const { - return true; + // Shell surfaces in system modal container cannot be minimized. + return container_ != ash::kShellWindowId_SystemModalContainer; } base::string16 ShellSurface::GetWindowTitle() const {
diff --git a/components/ntp_snippets.gypi b/components/ntp_snippets.gypi index f82920e..27817218 100644 --- a/components/ntp_snippets.gypi +++ b/components/ntp_snippets.gypi
@@ -13,6 +13,7 @@ ], 'dependencies': [ '../base/base.gyp:base', + '../components/components_strings.gyp:components_strings', '../google_apis/google_apis.gyp:google_apis', '../net/net.gyp:net', '../url/url.gyp:url_lib', @@ -37,6 +38,8 @@ 'ntp_snippets/bookmarks/bookmark_suggestions_provider.h', 'ntp_snippets/category_factory.cc', 'ntp_snippets/category_factory.h', + 'ntp_snippets/category_info.cc', + 'ntp_snippets/category_info.h', 'ntp_snippets/category_status.cc', 'ntp_snippets/category_status.h', 'ntp_snippets/category.cc',
diff --git a/components/ntp_snippets/BUILD.gn b/components/ntp_snippets/BUILD.gn index 79449b73..596b376 100644 --- a/components/ntp_snippets/BUILD.gn +++ b/components/ntp_snippets/BUILD.gn
@@ -20,6 +20,8 @@ "category.h", "category_factory.cc", "category_factory.h", + "category_info.cc", + "category_info.h", "category_status.cc", "category_status.h", "content_suggestion.cc", @@ -73,9 +75,11 @@ "//components/metrics", "//components/ntp_snippets/proto", "//components/offline_pages", + "//components/strings", "//components/variations", "//components/variations/net", "//third_party/icu/", + "//ui/base", "//ui/gfx", ] } @@ -84,6 +88,7 @@ java_cpp_enum("ntp_snippets_java_enums_srcjar") { sources = [ "category.h", + "category_info.h", "category_status.h", ] } @@ -111,6 +116,7 @@ "//components/leveldb_proto:test_support", "//components/signin/core/browser:test_support", "//components/signin/core/common", + "//components/strings", "//components/sync_driver:test_support", "//components/variations", "//net:test_support",
diff --git a/components/ntp_snippets/DEPS b/components/ntp_snippets/DEPS index 02c7f3b..1dd9061 100644 --- a/components/ntp_snippets/DEPS +++ b/components/ntp_snippets/DEPS
@@ -9,9 +9,11 @@ "+components/suggestions", "+components/sync_driver", "+components/variations", + "+grit/components_strings.h", "+net/base", "+net/http", "+net/url_request", "+google_apis", + "+ui/base/l10n", "+ui/gfx", ]
diff --git a/components/ntp_snippets/bookmarks/bookmark_last_visit_utils.cc b/components/ntp_snippets/bookmarks/bookmark_last_visit_utils.cc index 2fd0195..77f659d1 100644 --- a/components/ntp_snippets/bookmarks/bookmark_last_visit_utils.cc +++ b/components/ntp_snippets/bookmarks/bookmark_last_visit_utils.cc
@@ -22,6 +22,7 @@ namespace { const char kBookmarkLastVisitDateKey[] = "last_visited"; +const char kBookmarkDismissedFromNTP[] = "dismissed_from_ntp"; base::Time ParseLastVisitDate(const std::string& date_string) { int64_t date = 0; @@ -50,9 +51,8 @@ // If there are bookmarks for |url|, set their last visit date to now. std::string now = FormatLastVisitDate(base::Time::Now()); - for (auto* node : bookmarks_for_url) { + for (const BookmarkNode* node : bookmarks_for_url) bookmark_model->SetNodeMetaInfo(node, kBookmarkLastVisitDateKey, now); - } } base::Time GetLastVisitDateForBookmark(const BookmarkNode* node) { @@ -62,23 +62,55 @@ std::string last_visit_date_string; node->GetMetaInfo(kBookmarkLastVisitDateKey, &last_visit_date_string); - if (last_visit_date_string.empty()) { - // Use creation date if no last visit info present. + // Use creation date if no last visit info present. + if (last_visit_date_string.empty()) return node->date_added(); - } return ParseLastVisitDate(last_visit_date_string); } +void MarkBookmarksDismissed(BookmarkModel* bookmark_model, const GURL& url) { + std::vector<const BookmarkNode*> nodes; + bookmark_model->GetNodesByURL(url, &nodes); + for (const BookmarkNode* node : nodes) + bookmark_model->SetNodeMetaInfo(node, kBookmarkDismissedFromNTP, "1"); +} + +bool IsDismissedFromNTPForBookmark(const BookmarkNode* node) { + if (!node) + return false; + + std::string dismissed_from_ntp; + bool result = + node->GetMetaInfo(kBookmarkDismissedFromNTP, &dismissed_from_ntp); + DCHECK(!result || dismissed_from_ntp == "1"); + return result; +} + +void MarkAllBookmarksUndismissed(BookmarkModel* bookmark_model) { + // Get all the bookmark URLs. + std::vector<BookmarkModel::URLAndTitle> bookmarks; + bookmark_model->GetBookmarks(&bookmarks); + + // Remove dismissed flag from all bookmarks + for (const BookmarkModel::URLAndTitle& bookmark : bookmarks) { + std::vector<const BookmarkNode*> nodes; + bookmark_model->GetNodesByURL(bookmark.url, &nodes); + for (const BookmarkNode* node : nodes) + bookmark_model->DeleteNodeMetaInfo(node, kBookmarkDismissedFromNTP); + } +} + std::vector<const BookmarkNode*> GetRecentlyVisitedBookmarks( BookmarkModel* bookmark_model, int max_count, const base::Time& min_visit_time) { - // Get all the bookmarks. + // Get all the bookmark URLs. std::vector<BookmarkModel::URLAndTitle> bookmarks; bookmark_model->GetBookmarks(&bookmarks); - // Remove bookmarks that have not been visited after |min_visit_time|. + // Remove the bookmark URLs whose bookmarks are all dismissed or whose most + // recent visit is older than |min_visit_time|. bookmarks.erase( std::remove_if(bookmarks.begin(), bookmarks.end(), [&bookmark_model, &min_visit_time]( @@ -88,12 +120,17 @@ bookmark_model->GetNodesByURL(bookmark.url, &bookmarks_for_url); - // Return false if there is a more recent visit time. - for (const auto* node : bookmarks_for_url) { + // Check if there is a recently visited bookmark and not + // all bookmarks are dismissed. + bool has_recent_visit = false; + bool all_dismissed = true; + for (const BookmarkNode* node : bookmarks_for_url) { if (GetLastVisitDateForBookmark(node) > min_visit_time) - return false; + has_recent_visit = true; + if (!IsDismissedFromNTPForBookmark(node)) + all_dismissed = false; } - return true; + return all_dismissed || !has_recent_visit; }), bookmarks.end()); @@ -117,4 +154,35 @@ return result; } +std::vector<const BookmarkNode*> GetDismissedBookmarksForDebugging( + BookmarkModel* bookmark_model) { + // Get all the bookmark URLs. + std::vector<BookmarkModel::URLAndTitle> bookmarks; + bookmark_model->GetBookmarks(&bookmarks); + + // Remove the bookmark URLs which have at least one non-dismissed bookmark. + bookmarks.erase( + std::remove_if( + bookmarks.begin(), bookmarks.end(), + [&bookmark_model](const BookmarkModel::URLAndTitle& bookmark) { + std::vector<const BookmarkNode*> bookmarks_for_url; + bookmark_model->GetNodesByURL(bookmark.url, &bookmarks_for_url); + + for (const BookmarkNode* node : bookmarks_for_url) { + if (!IsDismissedFromNTPForBookmark(node)) + return true; + } + return false; + }), + bookmarks.end()); + + // Insert into |result|. + std::vector<const BookmarkNode*> result; + for (const BookmarkModel::URLAndTitle& bookmark : bookmarks) { + result.push_back( + bookmark_model->GetMostRecentlyAddedUserNodeForURL(bookmark.url)); + } + return result; +} + } // namespace ntp_snippets
diff --git a/components/ntp_snippets/bookmarks/bookmark_last_visit_utils.h b/components/ntp_snippets/bookmarks/bookmark_last_visit_utils.h index f5d9172..36ff7db 100644 --- a/components/ntp_snippets/bookmarks/bookmark_last_visit_utils.h +++ b/components/ntp_snippets/bookmarks/bookmark_last_visit_utils.h
@@ -31,15 +31,30 @@ // this info, it returns it creation date. base::Time GetLastVisitDateForBookmark(const bookmarks::BookmarkNode* node); -// Returns the list of most recently visited bookmarks. For each bookmarked URL, -// it returns the most recently created bookmark. The result is ordered by visit -// time (the most recent first). Only bookmarks visited after -// |min_visit_time| are considered, at most |max_count| bookmarks are returned. +// Marks all bookmarks with the given URL as dismissed. +void MarkBookmarksDismissed(bookmarks::BookmarkModel* bookmark_model, + const GURL& url); + +// Gets the dismissed flag for a given bookmark |node|. Defaults to false. +bool IsDismissedFromNTPForBookmark(const bookmarks::BookmarkNode* node); + +// Removes the dismissed flag from all bookmarks (only for debugging). +void MarkAllBookmarksUndismissed(bookmarks::BookmarkModel* bookmark_model); + +// Returns the list of most recently visited, non-dismissed bookmarks. +// For each bookmarked URL, it returns the most recently created bookmark. +// The result is ordered by visit time (the most recent first). Only bookmarks +// visited after |min_visit_time| are considered, at most |max_count| bookmarks +// are returned. std::vector<const bookmarks::BookmarkNode*> GetRecentlyVisitedBookmarks( bookmarks::BookmarkModel* bookmark_model, int max_count, const base::Time& min_visit_time); +// Returns the list of all dismissed bookmarks. Only used for debugging. +std::vector<const bookmarks::BookmarkNode*> GetDismissedBookmarksForDebugging( + bookmarks::BookmarkModel* bookmark_model); + } // namespace ntp_snippets #endif // COMPONENTS_NTP_SNIPPETS_BOOKMARKS_BOOKMARK_LAST_VISIT_UTILS_H_
diff --git a/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc b/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc index 85457d2d..f77fcd4 100644 --- a/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc +++ b/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc
@@ -9,12 +9,17 @@ #include "base/bind.h" #include "base/location.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "base/threading/thread_task_runner_handle.h" #include "components/bookmarks/browser/bookmark_model.h" #include "components/ntp_snippets/bookmarks/bookmark_last_visit_utils.h" #include "components/ntp_snippets/category_factory.h" #include "components/ntp_snippets/content_suggestion.h" +#include "components/ntp_snippets/features.h" +#include "components/variations/variations_associated_data.h" +#include "grit/components_strings.h" +#include "ui/base/l10n/l10n_util.h" #include "ui/gfx/image/image.h" using bookmarks::BookmarkModel; @@ -25,8 +30,27 @@ const int kMaxBookmarks = 10; const int kMaxBookmarkAgeInDays = 42; +const char* kMaxBookmarksParamName = "max_count"; +const char* kMaxBookmarkAgeInDaysParamName = "max_age_in_days"; + base::Time GetThresholdTime() { - return base::Time::Now() - base::TimeDelta::FromDays(kMaxBookmarkAgeInDays); + std::string age_in_days_string = variations::GetVariationParamValueByFeature( + ntp_snippets::kBookmarkSuggestionsFeature, kMaxBookmarkAgeInDaysParamName); + int age_in_days = 0; + if (!base::StringToInt(age_in_days_string, &age_in_days)) + age_in_days = kMaxBookmarkAgeInDays; + + return base::Time::Now() - base::TimeDelta::FromDays(age_in_days); +} + +int GetMaxCount() { + std::string max_count_string = variations::GetVariationParamValueByFeature( + ntp_snippets::kBookmarkSuggestionsFeature, kMaxBookmarksParamName); + int max_count = 0; + if (base::StringToInt(max_count_string, &max_count)) + return max_count; + + return kMaxBookmarks; } } // namespace @@ -61,13 +85,21 @@ CategoryStatus BookmarkSuggestionsProvider::GetCategoryStatus( Category category) { + DCHECK_EQ(category, provided_category_); return category_status_; } +CategoryInfo BookmarkSuggestionsProvider::GetCategoryInfo(Category category) { + return CategoryInfo( + l10n_util::GetStringUTF16(IDS_NTP_BOOKMARK_SUGGESTIONS_SECTION_HEADER), + ContentSuggestionsCardLayout::MINIMAL_CARD); +} + void BookmarkSuggestionsProvider::DismissSuggestion( const std::string& suggestion_id) { - // TODO(jkrcal): Implement blacklisting bookmarks until they are next visited. - // Then also implement ClearDismissedSuggestionsForDebugging. + DCHECK(bookmark_model_->loaded()); + GURL url(GetWithinCategoryIDFromUniqueID(suggestion_id)); + MarkBookmarksDismissed(bookmark_model_, url); } void BookmarkSuggestionsProvider::FetchSuggestionImage( @@ -77,12 +109,31 @@ FROM_HERE, base::Bind(callback, suggestion_id, gfx::Image())); } -void BookmarkSuggestionsProvider::ClearCachedSuggestionsForDebugging() { +void BookmarkSuggestionsProvider::ClearCachedSuggestionsForDebugging( + Category category) { + DCHECK_EQ(category, provided_category_); // Ignored. } -void BookmarkSuggestionsProvider::ClearDismissedSuggestionsForDebugging() { - // TODO(jkrcal): Implement when discarded suggestions are supported. +std::vector<ContentSuggestion> +BookmarkSuggestionsProvider::GetDismissedSuggestionsForDebugging( + Category category) { + DCHECK_EQ(category, provided_category_); + std::vector<const BookmarkNode*> bookmarks = + GetDismissedBookmarksForDebugging(bookmark_model_); + + std::vector<ContentSuggestion> suggestions; + for (const BookmarkNode* bookmark : bookmarks) + suggestions.emplace_back(ConvertBookmark(bookmark)); + return suggestions; +} + +void BookmarkSuggestionsProvider::ClearDismissedSuggestionsForDebugging( + Category category) { + DCHECK_EQ(category, provided_category_); + if (!bookmark_model_->loaded()) + return; + MarkAllBookmarksUndismissed(bookmark_model_); } void BookmarkSuggestionsProvider::BookmarkModelLoaded( @@ -115,29 +166,34 @@ FetchBookmarks(); } +ContentSuggestion BookmarkSuggestionsProvider::ConvertBookmark( + const BookmarkNode* bookmark) { + ContentSuggestion suggestion( + MakeUniqueID(provided_category_, bookmark->url().spec()), + bookmark->url()); + + suggestion.set_title(bookmark->GetTitle()); + suggestion.set_snippet_text(base::string16()); + suggestion.set_publish_date(GetLastVisitDateForBookmark(bookmark)); + suggestion.set_publisher_name(base::UTF8ToUTF16(bookmark->url().host())); + return suggestion; +} + void BookmarkSuggestionsProvider::FetchBookmarksInternal() { DCHECK(bookmark_model_->loaded()); NotifyStatusChanged(CategoryStatus::AVAILABLE); + base::Time threshold_time = GetThresholdTime(); std::vector<const BookmarkNode*> bookmarks = GetRecentlyVisitedBookmarks( - bookmark_model_, kMaxBookmarks, GetThresholdTime()); + bookmark_model_, GetMaxCount(), threshold_time); std::vector<ContentSuggestion> suggestions; - for (const BookmarkNode* bookmark : bookmarks) { - ContentSuggestion suggestion( - MakeUniqueID(provided_category_, bookmark->url().spec()), - bookmark->url()); - - suggestion.set_title(bookmark->GetTitle()); - suggestion.set_snippet_text(base::string16()); - suggestion.set_publish_date(GetLastVisitDateForBookmark(bookmark)); - suggestion.set_publisher_name(base::UTF8ToUTF16(bookmark->url().host())); - suggestions.emplace_back(std::move(suggestion)); - } + for (const BookmarkNode* bookmark : bookmarks) + suggestions.emplace_back(ConvertBookmark(bookmark)); if (suggestions.empty()) - end_of_list_last_visit_date_ = GetThresholdTime(); + end_of_list_last_visit_date_ = threshold_time; else end_of_list_last_visit_date_ = suggestions.back().publish_date();
diff --git a/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h b/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h index 667dad6..79b723e 100644 --- a/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h +++ b/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h
@@ -33,11 +33,14 @@ // ContentSuggestionsProvider implementation. std::vector<Category> GetProvidedCategories() override; CategoryStatus GetCategoryStatus(Category category) override; + CategoryInfo GetCategoryInfo(Category category) override; void DismissSuggestion(const std::string& suggestion_id) override; void FetchSuggestionImage(const std::string& suggestion_id, const ImageFetchedCallback& callback) override; - void ClearCachedSuggestionsForDebugging() override; - void ClearDismissedSuggestionsForDebugging() override; + void ClearCachedSuggestionsForDebugging(Category category) override; + std::vector<ContentSuggestion> GetDismissedSuggestionsForDebugging( + Category category) override; + void ClearDismissedSuggestionsForDebugging(Category category) override; // bookmarks::BookmarkModelObserver implementation. void BookmarkModelLoaded(bookmarks::BookmarkModel* model, @@ -74,6 +77,8 @@ bookmarks::BookmarkModel* model, const std::set<GURL>& removed_urls) override {} + ContentSuggestion ConvertBookmark(const bookmarks::BookmarkNode* bookmark); + // The actual method to fetch bookmarks - follows each call to FetchBookmarks // but not sooner than the BookmarkModel gets loaded. void FetchBookmarksInternal();
diff --git a/components/ntp_snippets/category_info.cc b/components/ntp_snippets/category_info.cc new file mode 100644 index 0000000..213b2fa --- /dev/null +++ b/components/ntp_snippets/category_info.cc
@@ -0,0 +1,15 @@ +// 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 "components/ntp_snippets/category_info.h" + +namespace ntp_snippets { + +CategoryInfo::CategoryInfo(const base::string16& title, + ContentSuggestionsCardLayout card_layout) + : title_(title), card_layout_(card_layout) {} + +CategoryInfo::~CategoryInfo() {} + +} // namespace ntp_snippets
diff --git a/components/ntp_snippets/category_info.h b/components/ntp_snippets/category_info.h new file mode 100644 index 0000000..8ae272e --- /dev/null +++ b/components/ntp_snippets/category_info.h
@@ -0,0 +1,48 @@ +// 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 COMPONENTS_NTP_SNIPPETS_CATEGORY_INFO_H_ +#define COMPONENTS_NTP_SNIPPETS_CATEGORY_INFO_H_ + +#include "base/macros.h" +#include "base/strings/string16.h" + +namespace ntp_snippets { + +// On Android builds, a Java counterpart will be generated for this enum. +// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.ntp.snippets +enum class ContentSuggestionsCardLayout { + // Uses all fields. + FULL_CARD, + + // No snippet_text and no thumbnail image. + MINIMAL_CARD +}; + +// Contains static meta information about a Category. +class CategoryInfo { + public: + CategoryInfo(const base::string16& title, + ContentSuggestionsCardLayout card_layout); + CategoryInfo(CategoryInfo&&) = default; + CategoryInfo& operator=(CategoryInfo&&) = default; + + ~CategoryInfo(); + + // Localized title of the category. + const base::string16& title() const { return title_; } + + // Layout of the cards to be used to display suggestions in this category. + ContentSuggestionsCardLayout card_layout() const { return card_layout_; } + + private: + base::string16 title_; + ContentSuggestionsCardLayout card_layout_; + + DISALLOW_COPY_AND_ASSIGN(CategoryInfo); +}; + +} // namespace ntp_snippets + +#endif // COMPONENTS_NTP_SNIPPETS_CATEGORY_INFO_H_
diff --git a/components/ntp_snippets/content_suggestions_provider.h b/components/ntp_snippets/content_suggestions_provider.h index 066ea1e..2f343a4 100644 --- a/components/ntp_snippets/content_suggestions_provider.h +++ b/components/ntp_snippets/content_suggestions_provider.h
@@ -10,6 +10,7 @@ #include "base/callback_forward.h" #include "components/ntp_snippets/category.h" +#include "components/ntp_snippets/category_info.h" #include "components/ntp_snippets/category_status.h" #include "components/ntp_snippets/content_suggestion.h" @@ -77,6 +78,9 @@ // Determines the status of the given |category|, see CategoryStatus. virtual CategoryStatus GetCategoryStatus(Category category) = 0; + // Returns the meta information for the given |category|. + virtual CategoryInfo GetCategoryInfo(Category category) = 0; + // Dismisses the suggestion with the given ID. A provider needs to ensure that // a once-dismissed suggestion is never delivered again (through the // Observer). The provider must not call Observer::OnSuggestionsChanged if the @@ -86,19 +90,28 @@ // Fetches the image for the suggestion with the given ID and returns it // through the callback. This fetch may occur locally or from the internet. // If that suggestion doesn't exist, doesn't have an image or if the fetch - // fails, the callback gets a null image. + // fails, the callback gets a null image. The callback will not be called + // synchronously. virtual void FetchSuggestionImage(const std::string& suggestion_id, const ImageFetchedCallback& callback) = 0; - // Used only for debugging purposes. Clears all caches so that the next - // fetch starts from scratch. - virtual void ClearCachedSuggestionsForDebugging() = 0; + // Used only for debugging purposes. Clears all caches for the given category, + // so that the next fetch starts from scratch. + virtual void ClearCachedSuggestionsForDebugging(Category category) = 0; + + // Used only for debugging purposes. Retrieves suggestions for the given + // |category| that have previously been dismissed and are still stored in the + // provider. If the provider doesn't store dismissed suggestions for the given + // |category|, it always returns an empty vector. + virtual std::vector<ContentSuggestion> GetDismissedSuggestionsForDebugging( + Category category) = 0; // Used only for debugging purposes. Clears the cache of dismissed - // suggestions, if present, so that no suggestions are suppressed. This does - // not necessarily make previously dismissed suggestions reappear, as they may - // have been permanently deleted, depending on the provider implementation. - virtual void ClearDismissedSuggestionsForDebugging() = 0; + // suggestions for the given |category|, if present, so that no suggestions + // are suppressed. This does not necessarily make previously dismissed + // suggestions reappear, as they may have been permanently deleted, depending + // on the provider implementation. + virtual void ClearDismissedSuggestionsForDebugging(Category category) = 0; protected: ContentSuggestionsProvider(Observer* observer,
diff --git a/components/ntp_snippets/content_suggestions_service.cc b/components/ntp_snippets/content_suggestions_service.cc index 43ee91e..3311d45 100644 --- a/components/ntp_snippets/content_suggestions_service.cc +++ b/components/ntp_snippets/content_suggestions_service.cc
@@ -50,6 +50,14 @@ return iterator->second->GetCategoryStatus(category); } +base::Optional<CategoryInfo> ContentSuggestionsService::GetCategoryInfo( + Category category) const { + auto iterator = providers_by_category_.find(category); + if (iterator == providers_by_category_.end()) + return base::Optional<CategoryInfo>(); + return iterator->second->GetCategoryInfo(category); +} + const std::vector<ContentSuggestion>& ContentSuggestionsService::GetSuggestionsForCategory(Category category) const { auto iterator = suggestions_by_category_.find(category); @@ -79,19 +87,43 @@ callback); } -void ContentSuggestionsService::ClearCachedSuggestionsForDebugging() { +void ContentSuggestionsService::ClearAllCachedSuggestionsForDebugging() { suggestions_by_category_.clear(); id_category_map_.clear(); - for (auto& category_provider_pair : providers_by_category_) { - category_provider_pair.second->ClearCachedSuggestionsForDebugging(); + for (const auto& category_provider_pair : providers_by_category_) { + category_provider_pair.second->ClearCachedSuggestionsForDebugging( + category_provider_pair.first); + FOR_EACH_OBSERVER(Observer, observers_, + OnNewSuggestions(category_provider_pair.first)); } - FOR_EACH_OBSERVER(Observer, observers_, OnNewSuggestions()); } -void ContentSuggestionsService::ClearDismissedSuggestionsForDebugging() { - for (auto& category_provider_pair : providers_by_category_) { - category_provider_pair.second->ClearDismissedSuggestionsForDebugging(); +void ContentSuggestionsService::ClearCachedSuggestionsForDebugging( + Category category) { + for (const ContentSuggestion& suggestion : + suggestions_by_category_[category]) { + id_category_map_.erase(suggestion.id()); } + suggestions_by_category_[category].clear(); + auto iterator = providers_by_category_.find(category); + if (iterator != providers_by_category_.end()) + iterator->second->ClearCachedSuggestionsForDebugging(category); +} + +std::vector<ContentSuggestion> +ContentSuggestionsService::GetDismissedSuggestionsForDebugging( + Category category) { + auto iterator = providers_by_category_.find(category); + if (iterator == providers_by_category_.end()) + return std::vector<ContentSuggestion>(); + return iterator->second->GetDismissedSuggestionsForDebugging(category); +} + +void ContentSuggestionsService::ClearDismissedSuggestionsForDebugging( + Category category) { + auto iterator = providers_by_category_.find(category); + if (iterator != providers_by_category_.end()) + iterator->second->ClearDismissedSuggestionsForDebugging(category); } void ContentSuggestionsService::DismissSuggestion( @@ -166,7 +198,7 @@ suggestions_by_category_[category] = std::move(new_suggestions); - FOR_EACH_OBSERVER(Observer, observers_, OnNewSuggestions()); + FOR_EACH_OBSERVER(Observer, observers_, OnNewSuggestions(category)); } void ContentSuggestionsService::OnCategoryStatusChanged(
diff --git a/components/ntp_snippets/content_suggestions_service.h b/components/ntp_snippets/content_suggestions_service.h index 488aeab7..ad7f8a9 100644 --- a/components/ntp_snippets/content_suggestions_service.h +++ b/components/ntp_snippets/content_suggestions_service.h
@@ -12,6 +12,7 @@ #include "base/callback_forward.h" #include "base/observer_list.h" +#include "base/optional.h" #include "components/keyed_service/core/keyed_service.h" #include "components/ntp_snippets/category_factory.h" #include "components/ntp_snippets/category_status.h" @@ -35,11 +36,11 @@ class Observer { public: - // Fired every time the service receives a new set of data, replacing any - // previously available data (though in most cases there will be an overlap - // and only a few changes within the data). The new data is then available - // through the getters of the service. - virtual void OnNewSuggestions() = 0; + // Fired every time the service receives a new set of data for the given + // |category|, replacing any previously available data (though in most cases + // there will be an overlap and only a few changes within the data). The new + // data is then available through |GetSuggestionsForCategory(category)|. + virtual void OnNewSuggestions(Category category) = 0; // Fired when the status of a suggestions category changed. When the status // changes to an unavailable status, the suggestions of the respective @@ -78,6 +79,9 @@ // Gets the status of a category. CategoryStatus GetCategoryStatus(Category category) const; + // Gets the meta information of a category. + base::Optional<CategoryInfo> GetCategoryInfo(Category category) const; + // Gets the available suggestions for a category. The result is empty if the // category is available and empty, but also if the category is unavailable // for any reason, see |GetCategoryStatus()|. @@ -86,7 +90,8 @@ // Fetches the image for the suggestion with the given |suggestion_id| and // runs the |callback|. If that suggestion doesn't exist or the fetch fails, - // the callback gets an empty image. + // the callback gets an empty image. The callback will not be called + // synchronously. void FetchSuggestionImage(const std::string& suggestion_id, const ImageFetchedCallback& callback); @@ -105,17 +110,31 @@ // Only for debugging use through the internals page. // Removes all suggestions from all caches or internal stores in all - // providers. It does, however, not remove any suggestions from the provider's - // sources, so if their configuration hasn't changed, they should return the - // same results when they fetch the next time. In particular, calling this - // method will not mark any suggestions as dismissed. - void ClearCachedSuggestionsForDebugging(); + // providers. See |ClearCachedSuggestionsForDebugging|. + void ClearAllCachedSuggestionsForDebugging(); + + // Only for debugging use through the internals page. + // Removes all suggestions of the given |category| from all caches or internal + // stores in the service and the corresponding provider. It does, however, not + // remove any suggestions from the provider's sources, so if its configuration + // hasn't changed, it might return the same results when it fetches the next + // time. In particular, calling this method will not mark any suggestions as + // dismissed. + void ClearCachedSuggestionsForDebugging(Category category); + + // Only for debugging use through the internals page. + // Retrieves suggestions of the given |category| that have previously been + // dismissed and are still stored in the respective provider. If the + // provider doesn't store dismissed suggestions, this returns an empty vector. + std::vector<ContentSuggestion> GetDismissedSuggestionsForDebugging( + Category category); // Only for debugging use through the internals page. Some providers // internally store a list of dismissed suggestions to prevent them from - // reappearing. This function clears all such lists in all providers, making - // dismissed suggestions reappear (only for certain providers). - void ClearDismissedSuggestionsForDebugging(); + // reappearing. This function clears all suggestions of the given |category| + // from such lists, making dismissed suggestions reappear (if the provider + // supports it). + void ClearDismissedSuggestionsForDebugging(Category category); CategoryFactory* category_factory() { return &category_factory_; }
diff --git a/components/ntp_snippets/content_suggestions_service_unittest.cc b/components/ntp_snippets/content_suggestions_service_unittest.cc index 6943a36..064cd389 100644 --- a/components/ntp_snippets/content_suggestions_service_unittest.cc +++ b/components/ntp_snippets/content_suggestions_service_unittest.cc
@@ -13,6 +13,8 @@ #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/utf_string_conversions.h" +#include "components/ntp_snippets/category_info.h" #include "components/ntp_snippets/category_status.h" #include "components/ntp_snippets/content_suggestion.h" #include "components/ntp_snippets/content_suggestions_provider.h" @@ -71,6 +73,11 @@ return statuses_[category.id()]; } + CategoryInfo GetCategoryInfo(Category category) { + return CategoryInfo(base::ASCIIToUTF16("Section title"), + ContentSuggestionsCardLayout::FULL_CARD); + } + void FireSuggestionsChanged(Category category, std::vector<int> numbers) { observer()->OnNewSuggestions(this, category, CreateSuggestions(numbers)); } @@ -80,8 +87,10 @@ observer()->OnCategoryStatusChanged(this, category, new_status); } - MOCK_METHOD0(ClearCachedSuggestionsForDebugging, void()); - MOCK_METHOD0(ClearDismissedSuggestionsForDebugging, void()); + MOCK_METHOD1(ClearCachedSuggestionsForDebugging, void(Category category)); + MOCK_METHOD1(GetDismissedSuggestionsForDebugging, + std::vector<ContentSuggestion>(Category category)); + MOCK_METHOD1(ClearDismissedSuggestionsForDebugging, void(Category category)); MOCK_METHOD1(DismissSuggestion, void(const std::string& suggestion_id)); MOCK_METHOD2(FetchSuggestionImage, void(const std::string& suggestion_id, @@ -94,7 +103,7 @@ class MockServiceObserver : public ContentSuggestionsService::Observer { public: - MOCK_METHOD0(OnNewSuggestions, void()); + MOCK_METHOD1(OnNewSuggestions, void(Category category)); MOCK_METHOD2(OnCategoryStatusChanged, void(Category changed_category, CategoryStatus new_status)); MOCK_METHOD0(ContentSuggestionsServiceShutdown, void()); @@ -308,27 +317,27 @@ service()->AddObserver(&observer); // Send suggestions 1 and 2 - EXPECT_CALL(observer, OnNewSuggestions()).Times(1); + EXPECT_CALL(observer, OnNewSuggestions(articles_category)).Times(1); provider1->FireSuggestionsChanged(articles_category, {1, 2}); ExpectThatSuggestionsAre(articles_category, {1, 2}); Mock::VerifyAndClearExpectations(&observer); // Send them again, make sure they're not reported twice - EXPECT_CALL(observer, OnNewSuggestions()).Times(1); + EXPECT_CALL(observer, OnNewSuggestions(articles_category)).Times(1); provider1->FireSuggestionsChanged(articles_category, {1, 2}); ExpectThatSuggestionsAre(articles_category, {1, 2}); ExpectThatSuggestionsAre(offline_pages_category, std::vector<int>()); Mock::VerifyAndClearExpectations(&observer); // Send suggestions 13 and 14 - EXPECT_CALL(observer, OnNewSuggestions()).Times(1); + EXPECT_CALL(observer, OnNewSuggestions(offline_pages_category)).Times(1); provider2->FireSuggestionsChanged(offline_pages_category, {13, 14}); ExpectThatSuggestionsAre(articles_category, {1, 2}); ExpectThatSuggestionsAre(offline_pages_category, {13, 14}); Mock::VerifyAndClearExpectations(&observer); // Send suggestion 1 only - EXPECT_CALL(observer, OnNewSuggestions()).Times(1); + EXPECT_CALL(observer, OnNewSuggestions(articles_category)).Times(1); provider1->FireSuggestionsChanged(articles_category, {1}); ExpectThatSuggestionsAre(articles_category, {1}); ExpectThatSuggestionsAre(offline_pages_category, {13, 14});
diff --git a/components/ntp_snippets/features.cc b/components/ntp_snippets/features.cc index 3b5d056..9ed4735f 100644 --- a/components/ntp_snippets/features.cc +++ b/components/ntp_snippets/features.cc
@@ -6,9 +6,15 @@ namespace ntp_snippets { +const base::Feature kArticleSuggestionsFeature{ + "NTPArticleSuggestions", base::FEATURE_ENABLED_BY_DEFAULT}; + const base::Feature kBookmarkSuggestionsFeature{ "NTPBookmarkSuggestions", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kOfflinePageSuggestionsFeature{ + "NTPOfflinePageSuggestions", base::FEATURE_DISABLED_BY_DEFAULT}; + const base::Feature kContentSuggestionsFeature{ "NTPSnippets", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/components/ntp_snippets/features.h b/components/ntp_snippets/features.h index 66197878..130ed24 100644 --- a/components/ntp_snippets/features.h +++ b/components/ntp_snippets/features.h
@@ -9,7 +9,13 @@ namespace ntp_snippets { +// Features to turn individual providers on/off. +extern const base::Feature kArticleSuggestionsFeature; extern const base::Feature kBookmarkSuggestionsFeature; +extern const base::Feature kOfflinePageSuggestionsFeature; + +// Global toggle for the whole content suggestions feature. If this is set to +// false, all the per-provider features are ignored. extern const base::Feature kContentSuggestionsFeature; } // namespace ntp_snippets
diff --git a/components/ntp_snippets/ntp_snippets_fetcher.cc b/components/ntp_snippets/ntp_snippets_fetcher.cc index 4f595e76..d8ca5090 100644 --- a/components/ntp_snippets/ntp_snippets_fetcher.cc +++ b/components/ntp_snippets/ntp_snippets_fetcher.cc
@@ -259,62 +259,68 @@ std::string NTPSnippetsFetcher::RequestParams::BuildRequest() { auto request = base::MakeUnique<base::DictionaryValue>(); - if (fetch_api == CHROME_READER_API) { - auto content_params = base::MakeUnique<base::DictionaryValue>(); - content_params->SetBoolean("only_return_personalized_results", - only_return_personalized_results); + switch (fetch_api) { + case CHROME_READER_API: { + auto content_params = base::MakeUnique<base::DictionaryValue>(); + content_params->SetBoolean("only_return_personalized_results", + only_return_personalized_results); - auto content_restricts = base::MakeUnique<base::ListValue>(); - for (const auto* metadata : {"TITLE", "SNIPPET", "THUMBNAIL"}) { - auto entry = base::MakeUnique<base::DictionaryValue>(); - entry->SetString("type", "METADATA"); - entry->SetString("value", metadata); - content_restricts->Append(std::move(entry)); + auto content_restricts = base::MakeUnique<base::ListValue>(); + for (const auto* metadata : {"TITLE", "SNIPPET", "THUMBNAIL"}) { + auto entry = base::MakeUnique<base::DictionaryValue>(); + entry->SetString("type", "METADATA"); + entry->SetString("value", metadata); + content_restricts->Append(std::move(entry)); + } + + auto content_selectors = base::MakeUnique<base::ListValue>(); + for (const auto& host : host_restricts) { + auto entry = base::MakeUnique<base::DictionaryValue>(); + entry->SetString("type", "HOST_RESTRICT"); + entry->SetString("value", host); + content_selectors->Append(std::move(entry)); + } + + auto local_scoring_params = base::MakeUnique<base::DictionaryValue>(); + local_scoring_params->Set("content_params", std::move(content_params)); + local_scoring_params->Set("content_restricts", + std::move(content_restricts)); + local_scoring_params->Set("content_selectors", + std::move(content_selectors)); + + auto global_scoring_params = base::MakeUnique<base::DictionaryValue>(); + global_scoring_params->SetInteger("num_to_return", count_to_fetch); + global_scoring_params->SetInteger("sort_type", 1); + + auto advanced = base::MakeUnique<base::DictionaryValue>(); + advanced->Set("local_scoring_params", std::move(local_scoring_params)); + advanced->Set("global_scoring_params", std::move(global_scoring_params)); + + request->SetString("response_detail_level", "STANDARD"); + request->Set("advanced_options", std::move(advanced)); + if (!obfuscated_gaia_id.empty()) { + request->SetString("obfuscated_gaia_id", obfuscated_gaia_id); + } + if (!user_locale.empty()) { + request->SetString("user_locale", user_locale); + } + break; } - auto content_selectors = base::MakeUnique<base::ListValue>(); - for (const auto& host : host_restricts) { - auto entry = base::MakeUnique<base::DictionaryValue>(); - entry->SetString("type", "HOST_RESTRICT"); - entry->SetString("value", host); - content_selectors->Append(std::move(entry)); - } + case CHROME_CONTENT_SUGGESTIONS_API: { + if (!user_locale.empty()) { + request->SetString("uiLanguage", user_locale); + } + auto regular_hosts = base::MakeUnique<base::ListValue>(); + for (const auto& host : host_restricts) { + regular_hosts->AppendString(host); + } + request->Set("regularlyVisitedHostNames", std::move(regular_hosts)); - auto local_scoring_params = base::MakeUnique<base::DictionaryValue>(); - local_scoring_params->Set("content_params", std::move(content_params)); - local_scoring_params->Set("content_restricts", - std::move(content_restricts)); - local_scoring_params->Set("content_selectors", - std::move(content_selectors)); - - auto global_scoring_params = base::MakeUnique<base::DictionaryValue>(); - global_scoring_params->SetInteger("num_to_return", count_to_fetch); - global_scoring_params->SetInteger("sort_type", 1); - - auto advanced = base::MakeUnique<base::DictionaryValue>(); - advanced->Set("local_scoring_params", std::move(local_scoring_params)); - advanced->Set("global_scoring_params", std::move(global_scoring_params)); - - request->SetString("response_detail_level", "STANDARD"); - request->Set("advanced_options", std::move(advanced)); - if (!obfuscated_gaia_id.empty()) { - request->SetString("obfuscated_gaia_id", obfuscated_gaia_id); + // TODO(sfiera): support authentication and personalization + // TODO(sfiera): support count_to_fetch + break; } - if (!user_locale.empty()) { - request->SetString("user_locale", user_locale); - } - } else { - if (!user_locale.empty()) { - request->SetString("uiLanguage", user_locale); - } - auto regular_hosts = base::MakeUnique<base::ListValue>(); - for (const auto& host : host_restricts) { - regular_hosts->AppendString(host); - } - request->Set("regularlyVisitedHostNames", std::move(regular_hosts)); - - // TODO(sfiera): support authentication and personalization - // TODO(sfiera): support count_to_fetch } std::string request_json; @@ -494,31 +500,37 @@ return false; } - if (fetch_api_ == CHROME_READER_API) { - const base::ListValue* recos = nullptr; - return top_dict->GetList("recos", &recos) && - AddSnippetsFromListValue(/* content_suggestions_api = */ false, - *recos, snippets); - } else { - const base::ListValue* categories = nullptr; - if (!top_dict->GetList("categories", &categories)) { - return false; + switch (fetch_api_) { + case CHROME_READER_API: { + const base::ListValue* recos = nullptr; + return top_dict->GetList("recos", &recos) && + AddSnippetsFromListValue(/* content_suggestions_api = */ false, + *recos, snippets); } - // Merge all categories together, for now. - // TODO(sfiera): preserve categories from server. - for (const auto& v : *categories) { - const base::DictionaryValue* category = nullptr; - const base::ListValue* suggestions = nullptr; - if (!(v->GetAsDictionary(&category) && - category->GetList("suggestions", &suggestions) && - AddSnippetsFromListValue(/* content_suggestions_api = */ true, - *suggestions, snippets))) { + case CHROME_CONTENT_SUGGESTIONS_API: { + const base::ListValue* categories = nullptr; + if (!top_dict->GetList("categories", &categories)) { return false; } + + // Merge all categories together, for now. + // TODO(sfiera): preserve categories from server. + for (const auto& v : *categories) { + const base::DictionaryValue* category = nullptr; + const base::ListValue* suggestions = nullptr; + if (!(v->GetAsDictionary(&category) && + category->GetList("suggestions", &suggestions) && + AddSnippetsFromListValue(/* content_suggestions_api = */ true, + *suggestions, snippets))) { + return false; + } + } + return true; } - return true; } + NOTREACHED(); + return false; } void NTPSnippetsFetcher::OnJsonParsed(std::unique_ptr<base::Value> parsed) { @@ -548,8 +560,13 @@ DCHECK(result == FetchResult::SUCCESS || !snippets); last_status_ = FetchResultToString(result) + extra_message; - UMA_HISTOGRAM_TIMES("NewTabPage.Snippets.FetchTime", - tick_clock_->NowTicks() - fetch_start_time_); + // If the result is EMPTY_HOSTS or OAUTH_TOKEN_ERROR, we didn't actually send + // a network request, so don't record FetchTime in those cases. + if (result != FetchResult::EMPTY_HOSTS && + result != FetchResult::OAUTH_TOKEN_ERROR) { + UMA_HISTOGRAM_TIMES("NewTabPage.Snippets.FetchTime", + tick_clock_->NowTicks() - fetch_start_time_); + } UMA_HISTOGRAM_ENUMERATION("NewTabPage.Snippets.FetchResult", static_cast<int>(result), static_cast<int>(FetchResult::RESULT_MAX));
diff --git a/components/ntp_snippets/ntp_snippets_fetcher_unittest.cc b/components/ntp_snippets/ntp_snippets_fetcher_unittest.cc index c5ba65f6..9b6cfcc 100644 --- a/components/ntp_snippets/ntp_snippets_fetcher_unittest.cc +++ b/components/ntp_snippets/ntp_snippets_fetcher_unittest.cc
@@ -446,13 +446,13 @@ EXPECT_THAT( histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchResult"), ElementsAre(base::Bucket(/*min=*/1, /*count=*/1))); + // This particular error gets triggered prior to fetching, so no fetch time + // or response should get recorded. EXPECT_THAT(histogram_tester().GetAllSamples( "NewTabPage.Snippets.FetchHttpResponseOrErrorCode"), IsEmpty()); - // This particular error gets triggered prior to JSON parsing and hence tests - // observe no fetch latency. EXPECT_THAT(histogram_tester().GetAllSamples("NewTabPage.Snippets.FetchTime"), - ElementsAre(base::Bucket(/*min=*/0, /*count=*/1))); + IsEmpty()); } TEST_F(NTPSnippetsFetcherHostRestrictedTest, ShouldRestrictToHosts) {
diff --git a/components/ntp_snippets/ntp_snippets_service.cc b/components/ntp_snippets/ntp_snippets_service.cc index d906cbd..295acfb 100644 --- a/components/ntp_snippets/ntp_snippets_service.cc +++ b/components/ntp_snippets/ntp_snippets_service.cc
@@ -31,6 +31,8 @@ #include "components/prefs/pref_service.h" #include "components/suggestions/proto/suggestions.pb.h" #include "components/variations/variations_associated_data.h" +#include "grit/components_strings.h" +#include "ui/base/l10n/l10n_util.h" #include "ui/gfx/image/image.h" using image_fetcher::ImageDecoder; @@ -274,37 +276,15 @@ return std::vector<Category>({provided_category_}); } -void NTPSnippetsService::FetchSuggestionImage( - const std::string& suggestion_id, - const ImageFetchedCallback& callback) { - std::string snippet_id = GetWithinCategoryIDFromUniqueID(suggestion_id); - database_->LoadImage( - snippet_id, - base::Bind(&NTPSnippetsService::OnSnippetImageFetchedFromDatabase, - base::Unretained(this), snippet_id, callback)); +CategoryStatus NTPSnippetsService::GetCategoryStatus(Category category) { + DCHECK(category.IsKnownCategory(KnownCategories::ARTICLES)); + return category_status_; } -void NTPSnippetsService::ClearCachedSuggestionsForDebugging() { - if (!initialized()) - return; - - if (snippets_.empty()) - return; - - database_->DeleteSnippets(snippets_); - snippets_.clear(); - - NotifyNewSuggestions(); -} - -std::set<std::string> NTPSnippetsService::GetSuggestionsHosts() const { - // |suggestions_service_| can be null in tests. - if (!suggestions_service_) - return std::set<std::string>(); - - // TODO(treib): This should just call GetSnippetHostsFromPrefs. - return GetSuggestionsHostsImpl( - suggestions_service_->GetSuggestionsDataFromCache()); +CategoryInfo NTPSnippetsService::GetCategoryInfo(Category category) { + return CategoryInfo( + l10n_util::GetStringUTF16(IDS_NTP_ARTICLE_SUGGESTIONS_SECTION_HEADER), + ContentSuggestionsCardLayout::FULL_CARD); } void NTPSnippetsService::DismissSuggestion(const std::string& suggestion_id) { @@ -330,7 +310,55 @@ snippets_.erase(it); } -void NTPSnippetsService::ClearDismissedSuggestionsForDebugging() { +void NTPSnippetsService::FetchSuggestionImage( + const std::string& suggestion_id, + const ImageFetchedCallback& callback) { + std::string snippet_id = GetWithinCategoryIDFromUniqueID(suggestion_id); + database_->LoadImage( + snippet_id, + base::Bind(&NTPSnippetsService::OnSnippetImageFetchedFromDatabase, + base::Unretained(this), snippet_id, callback)); +} + +void NTPSnippetsService::ClearCachedSuggestionsForDebugging(Category category) { + DCHECK_EQ(category, provided_category_); + if (!initialized()) + return; + + if (snippets_.empty()) + return; + + database_->DeleteSnippets(snippets_); + snippets_.clear(); + + NotifyNewSuggestions(); +} + +std::vector<ContentSuggestion> +NTPSnippetsService::GetDismissedSuggestionsForDebugging(Category category) { + DCHECK_EQ(category, provided_category_); + std::vector<ContentSuggestion> result; + for (const std::unique_ptr<NTPSnippet>& snippet : dismissed_snippets_) { + if (!snippet->is_complete()) + continue; + ContentSuggestion suggestion( + MakeUniqueID(provided_category_, snippet->id()), + snippet->best_source().url); + suggestion.set_amp_url(snippet->best_source().amp_url); + suggestion.set_title(base::UTF8ToUTF16(snippet->title())); + suggestion.set_snippet_text(base::UTF8ToUTF16(snippet->snippet())); + suggestion.set_publish_date(snippet->publish_date()); + suggestion.set_publisher_name( + base::UTF8ToUTF16(snippet->best_source().publisher_name)); + suggestion.set_score(snippet->score()); + result.emplace_back(std::move(suggestion)); + } + return result; +} + +void NTPSnippetsService::ClearDismissedSuggestionsForDebugging( + Category category) { + DCHECK_EQ(category, provided_category_); if (!initialized()) return; @@ -341,9 +369,14 @@ dismissed_snippets_.clear(); } -CategoryStatus NTPSnippetsService::GetCategoryStatus(Category category) { - DCHECK(category.IsKnownCategory(KnownCategories::ARTICLES)); - return category_status_; +std::set<std::string> NTPSnippetsService::GetSuggestionsHosts() const { + // |suggestions_service_| can be null in tests. + if (!suggestions_service_) + return std::set<std::string>(); + + // TODO(treib): This should just call GetSnippetHostsFromPrefs. + return GetSuggestionsHostsImpl( + suggestions_service_->GetSuggestionsDataFromCache()); } // static @@ -664,8 +697,8 @@ } void NTPSnippetsService::EnterStateDisabled() { - ClearCachedSuggestionsForDebugging(); - ClearDismissedSuggestionsForDebugging(); + ClearCachedSuggestionsForDebugging(provided_category_); + ClearDismissedSuggestionsForDebugging(provided_category_); expiry_timer_.Stop(); suggestions_service_subscription_.reset();
diff --git a/components/ntp_snippets/ntp_snippets_service.h b/components/ntp_snippets/ntp_snippets_service.h index de27dac..43a27de 100644 --- a/components/ntp_snippets/ntp_snippets_service.h +++ b/components/ntp_snippets/ntp_snippets_service.h
@@ -109,15 +109,6 @@ void FetchSnippetsFromHosts(const std::set<std::string>& hosts, bool force_request); - // Available snippets. - const NTPSnippet::PtrVector& snippets() const { return snippets_; } - - // Returns the list of snippets previously dismissed by the user (that are - // not expired yet). - const NTPSnippet::PtrVector& dismissed_snippets() const { - return dismissed_snippets_; - } - const NTPSnippetsFetcher* snippets_fetcher() const { return snippets_fetcher_.get(); } @@ -133,15 +124,16 @@ void RescheduleFetching(); // ContentSuggestionsProvider implementation - // TODO(pke): At some point reorder the implementations in the .cc file - // accordingly. std::vector<Category> GetProvidedCategories() override; CategoryStatus GetCategoryStatus(Category category) override; + CategoryInfo GetCategoryInfo(Category category) override; void DismissSuggestion(const std::string& suggestion_id) override; void FetchSuggestionImage(const std::string& suggestion_id, const ImageFetchedCallback& callback) override; - void ClearCachedSuggestionsForDebugging() override; - void ClearDismissedSuggestionsForDebugging() override; + void ClearCachedSuggestionsForDebugging(Category category) override; + std::vector<ContentSuggestion> GetDismissedSuggestionsForDebugging( + Category category) override; + void ClearDismissedSuggestionsForDebugging(Category category) override; // Returns the lists of suggestion hosts the snippets are restricted to. std::set<std::string> GetSuggestionsHosts() const; @@ -149,6 +141,11 @@ // Returns the maximum number of snippets that will be shown at once. static int GetMaxSnippetCountForTesting(); + // Available snippets, only for unit tests. + const NTPSnippet::PtrVector& GetSnippetsForTesting() const { + return snippets_; + } + private: friend class NTPSnippetsServiceTest; FRIEND_TEST_ALL_PREFIXES(NTPSnippetsServiceTest, StatusChanges);
diff --git a/components/ntp_snippets/ntp_snippets_service_unittest.cc b/components/ntp_snippets/ntp_snippets_service_unittest.cc index 5a1afa9a..f826aea 100644 --- a/components/ntp_snippets/ntp_snippets_service_unittest.cc +++ b/components/ntp_snippets/ntp_snippets_service_unittest.cc
@@ -341,9 +341,11 @@ } std::string MakeUniqueID(const std::string& within_category_id) { - return service()->MakeUniqueID( - category_factory_.FromKnownCategory(KnownCategories::ARTICLES), - within_category_id); + return service()->MakeUniqueID(articles_category(), within_category_id); + } + + Category articles_category() { + return category_factory_.FromKnownCategory(KnownCategories::ARTICLES); } protected: @@ -394,8 +396,8 @@ std::string json_str(GetTestJson({GetSnippet()})); LoadFromJSONString(json_str); - ASSERT_THAT(service()->snippets(), SizeIs(1)); - const NTPSnippet& snippet = *service()->snippets().front(); + ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); + const NTPSnippet& snippet = *service()->GetSnippetsForTesting().front(); EXPECT_EQ(snippet.id(), kSnippetUrl); EXPECT_EQ(snippet.title(), kSnippetTitle); @@ -410,21 +412,22 @@ std::string json_str(GetTestJson({GetSnippet()})); LoadFromJSONString(json_str); - EXPECT_THAT(service()->snippets(), SizeIs(1)); + EXPECT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); - service()->ClearCachedSuggestionsForDebugging(); - EXPECT_THAT(service()->snippets(), IsEmpty()); + service()->ClearCachedSuggestionsForDebugging(articles_category()); + EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty()); } TEST_F(NTPSnippetsServiceTest, InsertAtFront) { std::string first("http://first"); LoadFromJSONString(GetTestJson({GetSnippetWithUrl(first)})); - EXPECT_THAT(service()->snippets(), ElementsAre(IdEq(first))); + EXPECT_THAT(service()->GetSnippetsForTesting(), ElementsAre(IdEq(first))); std::string second("http://second"); LoadFromJSONString(GetTestJson({GetSnippetWithUrl(second)})); // The snippet loaded last should be at the first position in the list now. - EXPECT_THAT(service()->snippets(), ElementsAre(IdEq(second), IdEq(first))); + EXPECT_THAT(service()->GetSnippetsForTesting(), + ElementsAre(IdEq(second), IdEq(first))); } TEST_F(NTPSnippetsServiceTest, LimitNumSnippets) { @@ -441,47 +444,47 @@ } LoadFromJSONString(GetTestJson(snippets1)); - ASSERT_THAT(service()->snippets(), SizeIs(snippets1.size())); + ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(snippets1.size())); LoadFromJSONString(GetTestJson(snippets2)); - EXPECT_THAT(service()->snippets(), SizeIs(max_snippet_count)); + EXPECT_THAT(service()->GetSnippetsForTesting(), SizeIs(max_snippet_count)); } TEST_F(NTPSnippetsServiceTest, LoadInvalidJson) { LoadFromJSONString(GetTestJson({GetInvalidSnippet()})); EXPECT_THAT(service()->snippets_fetcher()->last_status(), StartsWith("Received invalid JSON")); - EXPECT_THAT(service()->snippets(), IsEmpty()); + EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty()); } TEST_F(NTPSnippetsServiceTest, LoadInvalidJsonWithExistingSnippets) { LoadFromJSONString(GetTestJson({GetSnippet()})); - ASSERT_THAT(service()->snippets(), SizeIs(1)); + ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); ASSERT_EQ("OK", service()->snippets_fetcher()->last_status()); LoadFromJSONString(GetTestJson({GetInvalidSnippet()})); EXPECT_THAT(service()->snippets_fetcher()->last_status(), StartsWith("Received invalid JSON")); // This should not have changed the existing snippets. - EXPECT_THAT(service()->snippets(), SizeIs(1)); + EXPECT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); } TEST_F(NTPSnippetsServiceTest, LoadIncompleteJson) { LoadFromJSONString(GetTestJson({GetIncompleteSnippet()})); EXPECT_EQ("Invalid / empty list.", service()->snippets_fetcher()->last_status()); - EXPECT_THAT(service()->snippets(), IsEmpty()); + EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty()); } TEST_F(NTPSnippetsServiceTest, LoadIncompleteJsonWithExistingSnippets) { LoadFromJSONString(GetTestJson({GetSnippet()})); - ASSERT_THAT(service()->snippets(), SizeIs(1)); + ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); LoadFromJSONString(GetTestJson({GetIncompleteSnippet()})); EXPECT_EQ("Invalid / empty list.", service()->snippets_fetcher()->last_status()); // This should not have changed the existing snippets. - EXPECT_THAT(service()->snippets(), SizeIs(1)); + EXPECT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); } TEST_F(NTPSnippetsServiceTest, Dismiss) { @@ -494,45 +497,48 @@ LoadFromJSONString(json_str); - ASSERT_THAT(service()->snippets(), SizeIs(1)); + ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); // Dismissing a non-existent snippet shouldn't do anything. service()->DismissSuggestion(MakeUniqueID("http://othersite.com")); - EXPECT_THAT(service()->snippets(), SizeIs(1)); + EXPECT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); // Dismiss the snippet. service()->DismissSuggestion(MakeUniqueID(kSnippetUrl)); - EXPECT_THAT(service()->snippets(), IsEmpty()); + EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty()); // Make sure that fetching the same snippet again does not re-add it. LoadFromJSONString(json_str); - EXPECT_THAT(service()->snippets(), IsEmpty()); + EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty()); // The snippet should stay dismissed even after re-creating the service. RecreateSnippetsService(); LoadFromJSONString(json_str); - EXPECT_THAT(service()->snippets(), IsEmpty()); + EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty()); // The snippet can be added again after clearing dismissed snippets. - service()->ClearDismissedSuggestionsForDebugging(); - EXPECT_THAT(service()->snippets(), IsEmpty()); + service()->ClearDismissedSuggestionsForDebugging(articles_category()); + EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty()); LoadFromJSONString(json_str); - EXPECT_THAT(service()->snippets(), SizeIs(1)); + EXPECT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); } TEST_F(NTPSnippetsServiceTest, GetDismissed) { LoadFromJSONString(GetTestJson({GetSnippet()})); service()->DismissSuggestion(MakeUniqueID(kSnippetUrl)); - const NTPSnippet::PtrVector& snippets = service()->dismissed_snippets(); - EXPECT_EQ(1u, snippets.size()); - for (auto& snippet : snippets) { - EXPECT_EQ(kSnippetUrl, snippet->id()); + std::vector<ContentSuggestion> suggestions = + service()->GetDismissedSuggestionsForDebugging(articles_category()); + EXPECT_EQ(1u, suggestions.size()); + for (auto& suggestion : suggestions) { + EXPECT_EQ(MakeUniqueID(kSnippetUrl), suggestion.id()); } // There should be no dismissed snippet after clearing the list. - service()->ClearDismissedSuggestionsForDebugging(); - EXPECT_EQ(0u, service()->dismissed_snippets().size()); + service()->ClearDismissedSuggestionsForDebugging(articles_category()); + EXPECT_EQ(0u, service() + ->GetDismissedSuggestionsForDebugging(articles_category()) + .size()); } TEST_F(NTPSnippetsServiceTest, CreationTimestampParseFail) { @@ -541,8 +547,8 @@ NTPSnippet::TimeToJsonString(GetDefaultExpirationTime()))})); LoadFromJSONString(json_str); - ASSERT_THAT(service()->snippets(), SizeIs(1)); - const NTPSnippet& snippet = *service()->snippets().front(); + ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); + const NTPSnippet& snippet = *service()->GetSnippetsForTesting().front(); EXPECT_EQ(snippet.id(), kSnippetUrl); EXPECT_EQ(snippet.title(), kSnippetTitle); EXPECT_EQ(snippet.snippet(), kSnippetText); @@ -553,7 +559,7 @@ std::string json_str(GetTestJson({GetExpiredSnippet()})); LoadFromJSONString(json_str); - EXPECT_THAT(service()->snippets(), IsEmpty()); + EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty()); } TEST_F(NTPSnippetsServiceTest, TestSingleSource) { @@ -565,8 +571,8 @@ GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)})); LoadFromJSONString(json_str); - ASSERT_THAT(service()->snippets(), SizeIs(1)); - const NTPSnippet& snippet = *service()->snippets().front(); + ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); + const NTPSnippet& snippet = *service()->GetSnippetsForTesting().front(); EXPECT_EQ(snippet.sources().size(), 1u); EXPECT_EQ(snippet.id(), kSnippetUrl); EXPECT_EQ(snippet.best_source().url, GURL("http://source1.com")); @@ -583,7 +589,7 @@ GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)})); LoadFromJSONString(json_str); - EXPECT_THAT(service()->snippets(), IsEmpty()); + EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty()); } TEST_F(NTPSnippetsServiceTest, TestSingleSourceWithMissingData) { @@ -595,7 +601,7 @@ GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)})); LoadFromJSONString(json_str); - EXPECT_THAT(service()->snippets(), IsEmpty()); + EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty()); } TEST_F(NTPSnippetsServiceTest, TestMultipleSources) { @@ -610,8 +616,8 @@ GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)})); LoadFromJSONString(json_str); - ASSERT_THAT(service()->snippets(), SizeIs(1)); - const NTPSnippet& snippet = *service()->snippets().front(); + ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); + const NTPSnippet& snippet = *service()->GetSnippetsForTesting().front(); // Expect the first source to be chosen EXPECT_EQ(snippet.sources().size(), 2u); EXPECT_EQ(snippet.id(), kSnippetUrl); @@ -634,9 +640,9 @@ GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)})); LoadFromJSONString(json_str); - ASSERT_THAT(service()->snippets(), SizeIs(1)); + ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); { - const NTPSnippet& snippet = *service()->snippets().front(); + const NTPSnippet& snippet = *service()->GetSnippetsForTesting().front(); EXPECT_EQ(snippet.sources().size(), 2u); EXPECT_EQ(snippet.id(), kSnippetUrl); EXPECT_EQ(snippet.best_source().url, GURL("http://source2.com")); @@ -644,7 +650,7 @@ EXPECT_EQ(snippet.best_source().amp_url, GURL()); } - service()->ClearCachedSuggestionsForDebugging(); + service()->ClearCachedSuggestionsForDebugging(articles_category()); // Set Source 1 to have no AMP url, and Source 2 to have no publisher name // Source 1 should win in this case since we prefer publisher name to AMP url source_urls.clear(); @@ -660,9 +666,9 @@ GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)}); LoadFromJSONString(json_str); - ASSERT_THAT(service()->snippets(), SizeIs(1)); + ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); { - const NTPSnippet& snippet = *service()->snippets().front(); + const NTPSnippet& snippet = *service()->GetSnippetsForTesting().front(); EXPECT_EQ(snippet.sources().size(), 2u); EXPECT_EQ(snippet.id(), kSnippetUrl); EXPECT_EQ(snippet.best_source().url, GURL("http://source1.com")); @@ -670,7 +676,7 @@ EXPECT_EQ(snippet.best_source().amp_url, GURL()); } - service()->ClearCachedSuggestionsForDebugging(); + service()->ClearCachedSuggestionsForDebugging(articles_category()); // Set source 1 to have no AMP url and no source, and source 2 to only have // amp url. There should be no snippets since we only add sources we consider // complete @@ -687,7 +693,7 @@ GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)}); LoadFromJSONString(json_str); - EXPECT_THAT(service()->snippets(), IsEmpty()); + EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty()); } TEST_F(NTPSnippetsServiceTest, TestMultipleCompleteSources) { @@ -706,9 +712,9 @@ GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)})); LoadFromJSONString(json_str); - ASSERT_THAT(service()->snippets(), SizeIs(1)); + ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); { - const NTPSnippet& snippet = *service()->snippets().front(); + const NTPSnippet& snippet = *service()->GetSnippetsForTesting().front(); EXPECT_EQ(snippet.sources().size(), 3u); EXPECT_EQ(snippet.id(), kSnippetUrl); EXPECT_EQ(snippet.best_source().url, GURL("http://source1.com")); @@ -717,7 +723,7 @@ } // Test 2 complete sources, we should choose the first complete source - service()->ClearCachedSuggestionsForDebugging(); + service()->ClearCachedSuggestionsForDebugging(articles_category()); source_urls.clear(); source_urls.push_back(std::string("http://source1.com")); source_urls.push_back(std::string("http://source2.com")); @@ -734,9 +740,9 @@ GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)}); LoadFromJSONString(json_str); - ASSERT_THAT(service()->snippets(), SizeIs(1)); + ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); { - const NTPSnippet& snippet = *service()->snippets().front(); + const NTPSnippet& snippet = *service()->GetSnippetsForTesting().front(); EXPECT_EQ(snippet.sources().size(), 3u); EXPECT_EQ(snippet.id(), kSnippetUrl); EXPECT_EQ(snippet.best_source().url, GURL("http://source2.com")); @@ -745,7 +751,7 @@ } // Test 3 complete sources, we should choose the first complete source - service()->ClearCachedSuggestionsForDebugging(); + service()->ClearCachedSuggestionsForDebugging(articles_category()); source_urls.clear(); source_urls.push_back(std::string("http://source1.com")); source_urls.push_back(std::string("http://source2.com")); @@ -762,9 +768,9 @@ GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)}); LoadFromJSONString(json_str); - ASSERT_THAT(service()->snippets(), SizeIs(1)); + ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); { - const NTPSnippet& snippet = *service()->snippets().front(); + const NTPSnippet& snippet = *service()->GetSnippetsForTesting().front(); EXPECT_EQ(snippet.sources().size(), 3u); EXPECT_EQ(snippet.id(), kSnippetUrl); EXPECT_EQ(snippet.best_source().url, GURL("http://source2.com")); @@ -845,15 +851,15 @@ // Add the snippet from the mashable domain. LoadFromJSONString(GetTestJson({GetSnippetWithUrlAndTimesAndSources( source_urls[0], creation, expiry, source_urls, publishers, amp_urls)})); - ASSERT_THAT(service()->snippets(), SizeIs(1)); + ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); // Dismiss the snippet via the mashable source corpus ID. service()->DismissSuggestion(MakeUniqueID(source_urls[0])); - EXPECT_THAT(service()->snippets(), IsEmpty()); + EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty()); // The same article from the AOL domain should now be detected as dismissed. LoadFromJSONString(GetTestJson({GetSnippetWithUrlAndTimesAndSources( source_urls[1], creation, expiry, source_urls, publishers, amp_urls)})); - ASSERT_THAT(service()->snippets(), IsEmpty()); + ASSERT_THAT(service()->GetSnippetsForTesting(), IsEmpty()); } TEST_F(NTPSnippetsServiceTest, StatusChanges) { @@ -864,7 +870,8 @@ service()->OnDisabledReasonChanged(DisabledReason::SIGNED_OUT); base::RunLoop().RunUntilIdle(); EXPECT_EQ(NTPSnippetsService::State::DISABLED, service()->state_); - EXPECT_THAT(service()->snippets(), IsEmpty()); // No fetch should be made. + EXPECT_THAT(service()->GetSnippetsForTesting(), + IsEmpty()); // No fetch should be made. // Simulate user sign in. The service should be ready again and load snippets. SetUpFetchResponse(GetTestJson({GetSnippet()})); @@ -876,7 +883,7 @@ OnCategoryStatusChanged(_, _, CategoryStatus::AVAILABLE)); base::RunLoop().RunUntilIdle(); EXPECT_EQ(NTPSnippetsService::State::READY, service()->state_); - EXPECT_FALSE(service()->snippets().empty()); + EXPECT_FALSE(service()->GetSnippetsForTesting().empty()); } } // namespace ntp_snippets
diff --git a/components/ntp_snippets/offline_pages/offline_page_suggestions_provider.cc b/components/ntp_snippets/offline_pages/offline_page_suggestions_provider.cc index 2d262ec..ee8a254 100644 --- a/components/ntp_snippets/offline_pages/offline_page_suggestions_provider.cc +++ b/components/ntp_snippets/offline_pages/offline_page_suggestions_provider.cc
@@ -49,9 +49,17 @@ CategoryStatus OfflinePageSuggestionsProvider::GetCategoryStatus( Category category) { + DCHECK_EQ(category, provided_category_); return category_status_; } +CategoryInfo OfflinePageSuggestionsProvider::GetCategoryInfo( + Category category) { + // TODO(pke): Use the proper string once it's agreed on. + return CategoryInfo(base::ASCIIToUTF16("Offline pages"), + ContentSuggestionsCardLayout::MINIMAL_CARD); +} + void OfflinePageSuggestionsProvider::DismissSuggestion( const std::string& suggestion_id) { // TODO(pke): Implement some "dont show on NTP anymore" behaviour, @@ -67,11 +75,23 @@ FROM_HERE, base::Bind(callback, suggestion_id, gfx::Image())); } -void OfflinePageSuggestionsProvider::ClearCachedSuggestionsForDebugging() { +void OfflinePageSuggestionsProvider::ClearCachedSuggestionsForDebugging( + Category category) { + DCHECK_EQ(category, provided_category_); // Ignored. } -void OfflinePageSuggestionsProvider::ClearDismissedSuggestionsForDebugging() { +std::vector<ContentSuggestion> +OfflinePageSuggestionsProvider::GetDismissedSuggestionsForDebugging( + Category category) { + DCHECK_EQ(category, provided_category_); + // TODO(pke): Implement when dismissed suggestions are supported. + return std::vector<ContentSuggestion>(); +} + +void OfflinePageSuggestionsProvider::ClearDismissedSuggestionsForDebugging( + Category category) { + DCHECK_EQ(category, provided_category_); // TODO(pke): Implement when dismissed suggestions are supported. }
diff --git a/components/ntp_snippets/offline_pages/offline_page_suggestions_provider.h b/components/ntp_snippets/offline_pages/offline_page_suggestions_provider.h index 8ceac15fc..6266256f 100644 --- a/components/ntp_snippets/offline_pages/offline_page_suggestions_provider.h +++ b/components/ntp_snippets/offline_pages/offline_page_suggestions_provider.h
@@ -40,11 +40,14 @@ // ContentSuggestionsProvider implementation. std::vector<Category> GetProvidedCategories() override; CategoryStatus GetCategoryStatus(Category category) override; + CategoryInfo GetCategoryInfo(Category category) override; void DismissSuggestion(const std::string& suggestion_id) override; void FetchSuggestionImage(const std::string& suggestion_id, const ImageFetchedCallback& callback) override; - void ClearCachedSuggestionsForDebugging() override; - void ClearDismissedSuggestionsForDebugging() override; + void ClearCachedSuggestionsForDebugging(Category category) override; + std::vector<ContentSuggestion> GetDismissedSuggestionsForDebugging( + Category category) override; + void ClearDismissedSuggestionsForDebugging(Category category) override; // OfflinePageModel::Observer implementation. void OfflinePageModelLoaded(offline_pages::OfflinePageModel* model) override;
diff --git a/components/ntp_snippets_strings.grdp b/components/ntp_snippets_strings.grdp index b4407fde..f83018d 100644 --- a/components/ntp_snippets_strings.grdp +++ b/components/ntp_snippets_strings.grdp
@@ -2,12 +2,20 @@ <grit-part> <if expr="is_android"> - <message name="IDS_SNIPPETS_DISABLED_SIGNED_OUT_INSTRUCTIONS" desc="Body of the card explaining the status of the NTP suggested content, when the user is signed out." formatter_data="android_java"> + <message name="IDS_SNIPPETS_DISABLED_SIGNED_OUT_INSTRUCTIONS" desc="Body of the card explaining the status of the content suggestions on the New Tab Page, when the user is signed out." formatter_data="android_java"> To get personalized content suggested by Google, sign in to Chrome. </message> - <message name="IDS_SNIPPETS_DISABLED_GENERIC_PROMPT" desc="Title of the card explaining what action the user can take to get suggested content on the NTP." formatter_data="android_java"> + <message name="IDS_SNIPPETS_DISABLED_GENERIC_PROMPT" desc="Title of the card explaining what action the user can take to get content suggestions on the New Tab Page." formatter_data="android_java"> Get suggested content </message> </if> + <message name="IDS_NTP_ARTICLE_SUGGESTIONS_SECTION_HEADER" desc="Header of the articles section, which is a list of news articles displayed as cards on the New Tab Page."> + Articles for you + </message> + + <message name="IDS_NTP_BOOKMARK_SUGGESTIONS_SECTION_HEADER" desc="Header of the bookmarks section, which is a list of the user's most recently used bookmarks displayed as cards on the New Tab Page."> + Recent bookmarks + </message> + </grit-part>
diff --git a/components/offline_pages/background/request_coordinator.cc b/components/offline_pages/background/request_coordinator.cc index 20f2e745..cde6ced 100644 --- a/components/offline_pages/background/request_coordinator.cc +++ b/components/offline_pages/background/request_coordinator.cc
@@ -69,7 +69,7 @@ RequestCoordinator::~RequestCoordinator() {} bool RequestCoordinator::SavePageLater( - const GURL& url, const ClientId& client_id, bool was_user_requested) { + const GURL& url, const ClientId& client_id, bool user_requested) { DVLOG(2) << "URL is " << url << " " << __func__; if (!OfflinePageModel::CanSaveURL(url)) { @@ -82,7 +82,7 @@ // Build a SavePageRequest. offline_pages::SavePageRequest request( - id++, url, client_id, base::Time::Now(), was_user_requested); + id++, url, client_id, base::Time::Now(), user_requested); // Put the request on the request queue. queue_->AddRequest(request,
diff --git a/components/offline_pages/background/save_page_request.cc b/components/offline_pages/background/save_page_request.cc index 3d59444..91b3d4eb 100644 --- a/components/offline_pages/background/save_page_request.cc +++ b/components/offline_pages/background/save_page_request.cc
@@ -10,7 +10,7 @@ const GURL& url, const ClientId& client_id, const base::Time& creation_time, - const bool was_user_requested) + const bool user_requested) : request_id_(request_id), url_(url), client_id_(client_id), @@ -18,7 +18,7 @@ activation_time_(creation_time), started_attempt_count_(0), completed_attempt_count_(0), - user_requested_(was_user_requested), + user_requested_(user_requested), state_(RequestState::AVAILABLE) {} SavePageRequest::SavePageRequest(int64_t request_id,
diff --git a/components/offline_pages/client_namespace_constants.cc b/components/offline_pages/client_namespace_constants.cc index 6b391de..d2f11bef 100644 --- a/components/offline_pages/client_namespace_constants.cc +++ b/components/offline_pages/client_namespace_constants.cc
@@ -11,6 +11,7 @@ const char kAsyncNamespace[] = "async_loading"; const char kCCTNamespace[] = "custom_tabs"; const char kDownloadNamespace[] = "download"; +const char kNTPSuggestionsNamespace[] = "ntp_suggestions"; const char kDefaultNamespace[] = "default";
diff --git a/components/offline_pages/client_namespace_constants.h b/components/offline_pages/client_namespace_constants.h index 28057d6..823af09c 100644 --- a/components/offline_pages/client_namespace_constants.h +++ b/components/offline_pages/client_namespace_constants.h
@@ -16,6 +16,7 @@ extern const char kAsyncNamespace[]; extern const char kCCTNamespace[]; extern const char kDownloadNamespace[]; +extern const char kNTPSuggestionsNamespace[]; // Currently used for fallbacks like tests. extern const char kDefaultNamespace[];
diff --git a/components/offline_pages/client_policy_controller.cc b/components/offline_pages/client_policy_controller.cc index 2d03bec..6546946c 100644 --- a/components/offline_pages/client_policy_controller.cc +++ b/components/offline_pages/client_policy_controller.cc
@@ -39,6 +39,12 @@ base::TimeDelta::FromDays(0), kUnlimitedPages, kUnlimitedPages))); + policies_.insert(std::make_pair( + kNTPSuggestionsNamespace, MakePolicy(kNTPSuggestionsNamespace, + LifetimeType::PERSISTENT, + base::TimeDelta::FromDays(0), + kUnlimitedPages, + kUnlimitedPages))); // Fallback policy. policies_.insert(std::make_pair(
diff --git a/components/offline_pages/client_policy_controller_unittest.cc b/components/offline_pages/client_policy_controller_unittest.cc index 735d7a38..392b198 100644 --- a/components/offline_pages/client_policy_controller_unittest.cc +++ b/components/offline_pages/client_policy_controller_unittest.cc
@@ -77,4 +77,11 @@ EXPECT_FALSE(isTemporary(policy)); } +TEST_F(ClientPolicyControllerTest, CheckNTPSuggestionsDefined) { + OfflinePageClientPolicy policy = + controller()->GetPolicy(kNTPSuggestionsNamespace); + EXPECT_EQ(policy.name_space, kNTPSuggestionsNamespace); + EXPECT_FALSE(isTemporary(policy)); +} + } // namespace offline_pages
diff --git a/components/offline_pages/offline_page_model_impl_unittest.cc b/components/offline_pages/offline_page_model_impl_unittest.cc index eb6c721..b8d70c13 100644 --- a/components/offline_pages/offline_page_model_impl_unittest.cc +++ b/components/offline_pages/offline_page_model_impl_unittest.cc
@@ -1078,6 +1078,15 @@ static_cast<int>(SavePageResult::SUCCESS), 1); } +TEST_F(OfflinePageModelImplTest, NewTabPageNamespace) { + SavePage(kTestUrl, ClientId(kNTPSuggestionsNamespace, "123")); + std::string histogram_name = "OfflinePages.SavePageResult."; + histogram_name += kNTPSuggestionsNamespace; + + histograms().ExpectUniqueSample(histogram_name, + static_cast<int>(SavePageResult::SUCCESS), 1); +} + TEST(CommandLineFlagsTest, OfflineBookmarks) { // Disabled by default. EXPECT_FALSE(offline_pages::IsOfflineBookmarksEnabled());
diff --git a/components/password_manager/core/browser/credentials_filter.h b/components/password_manager/core/browser/credentials_filter.h index 2b336de..0658121 100644 --- a/components/password_manager/core/browser/credentials_filter.h +++ b/components/password_manager/core/browser/credentials_filter.h
@@ -11,6 +11,8 @@ namespace password_manager { +class PasswordFormManager; + // This interface is used to filter credentials during saving, retrieval from // PasswordStore, etc. class CredentialsFilter { @@ -26,9 +28,10 @@ // Should |form| be offered to be saved? virtual bool ShouldSave(const autofill::PasswordForm& form) const = 0; - // Call this if |form| was filled, and the subsequent sign-in looked like a - // success. Calling is optional, used only for statistics. - virtual void ReportFormUsed(const autofill::PasswordForm& form) const {} + // Call this if the form associated with |form_manager| was filled, and the + // subsequent sign-in looked like a success. + virtual void ReportFormLoginSuccess( + const PasswordFormManager& form_manager) const {} private: DISALLOW_COPY_AND_ASSIGN(CredentialsFilter);
diff --git a/components/password_manager/core/browser/password_form_manager.cc b/components/password_manager/core/browser/password_form_manager.cc index cb39586bb8..0cfc92c 100644 --- a/components/password_manager/core/browser/password_form_manager.cc +++ b/components/password_manager/core/browser/password_form_manager.cc
@@ -685,7 +685,8 @@ UpdateMetadataForUsage(&pending_credentials_); - client_->GetStoreResultFilter()->ReportFormUsed(pending_credentials_); + base::RecordAction( + base::UserMetricsAction("PasswordManager_LoginFollowingAutofill")); // Check to see if this form is a candidate for password generation. // Do not send votes on change password forms, since they were already sent in
diff --git a/components/password_manager/core/browser/password_form_manager_unittest.cc b/components/password_manager/core/browser/password_form_manager_unittest.cc index 54a021a..a250707 100644 --- a/components/password_manager/core/browser/password_form_manager_unittest.cc +++ b/components/password_manager/core/browser/password_form_manager_unittest.cc
@@ -15,6 +15,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/test/histogram_tester.h" #include "base/test/scoped_feature_list.h" +#include "base/test/user_action_tester.h" #include "build/build_config.h" #include "components/autofill/core/browser/autofill_manager.h" #include "components/autofill/core/browser/proto/server.pb.h" @@ -3022,4 +3023,23 @@ SimulateMatchingPhase(form_manager(), RESULT_SAVED_MATCH); } +// Check that PasswordFormManager records +// PasswordManager_LoginFollowingAutofill as part of processing a credential +// update. +TEST_F(PasswordFormManagerTest, ReportProcessingUpdate) { + SimulateMatchingPhase(form_manager(), RESULT_SAVED_MATCH); + PasswordForm pending = *observed_form(); + pending.username_value = saved_match()->username_value; + pending.password_value = saved_match()->password_value; + form_manager()->ProvisionallySave( + pending, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES); + + EXPECT_FALSE(form_manager()->IsNewLogin()); + + base::UserActionTester tester; + EXPECT_EQ(0, tester.GetActionCount("PasswordManager_LoginFollowingAutofill")); + form_manager()->Update(*saved_match()); + EXPECT_EQ(1, tester.GetActionCount("PasswordManager_LoginFollowingAutofill")); +} + } // namespace password_manager
diff --git a/components/password_manager/core/browser/password_manager.cc b/components/password_manager/core/browser/password_manager.cc index ce50418..e3cc09f 100644 --- a/components/password_manager/core/browser/password_manager.cc +++ b/components/password_manager/core/browser/password_manager.cc
@@ -570,7 +570,9 @@ provisional_save_manager_->retry_password_form_password_update() || (provisional_save_manager_->password_overridden() && client_->IsUpdatePasswordUIEnabled())) && - !provisional_save_manager_->has_generated_password() && + !(provisional_save_manager_->has_generated_password() && + (provisional_save_manager_->IsNewLogin() || + !client_->IsUpdatePasswordUIEnabled())) && !provisional_save_manager_->IsPendingCredentialsPublicSuffixMatch(); } @@ -676,6 +678,9 @@ logger->LogMessage(Logger::STRING_ON_ASK_USER_OR_SAVE_PASSWORD); } + client_->GetStoreResultFilter()->ReportFormLoginSuccess( + *provisional_save_manager_); + if (base::FeatureList::IsEnabled(features::kDropSyncCredential) && !client_->GetStoreResultFilter()->ShouldSave( provisional_save_manager_->pending_credentials())) {
diff --git a/components/password_manager/core/browser/password_manager_unittest.cc b/components/password_manager/core/browser/password_manager_unittest.cc index 8c367193..f28aa0a 100644 --- a/components/password_manager/core/browser/password_manager_unittest.cc +++ b/components/password_manager/core/browser/password_manager_unittest.cc
@@ -44,6 +44,8 @@ MOCK_CONST_METHOD1(FilterResultsPtr, void(ScopedVector<autofill::PasswordForm>* results)); MOCK_CONST_METHOD1(ShouldSave, bool(const autofill::PasswordForm& form)); + MOCK_CONST_METHOD1(ReportFormLoginSuccess, + void(const PasswordFormManager& form_manager)); // GMock cannot handle move-only arguments. ScopedVector<autofill::PasswordForm> FilterResults( @@ -78,7 +80,7 @@ MOCK_METHOD0(GetPrefs, PrefService*()); MOCK_METHOD0(GetDriver, PasswordManagerDriver*()); MOCK_CONST_METHOD0(IsUpdatePasswordUIEnabled, bool()); - MOCK_CONST_METHOD0(GetStoreResultFilter, const CredentialsFilter*()); + MOCK_CONST_METHOD0(GetStoreResultFilter, const MockStoreResultFilter*()); // Workaround for std::unique_ptr<> lacking a copy constructor. bool PromptUserToSaveOrUpdatePassword( @@ -240,7 +242,7 @@ base::MessageLoop message_loop_; scoped_refptr<MockPasswordStore> store_; - MockPasswordManagerClient client_; + testing::NiceMock<MockPasswordManagerClient> client_; MockPasswordManagerDriver driver_; std::unique_ptr<PasswordAutofillManager> password_autofill_manager_; std::unique_ptr<PasswordManager> manager_; @@ -597,6 +599,35 @@ manager()->OnPasswordFormsRendered(&driver_, observed, true); } +// On a successful login with an updated password, +// CredentialsFilter::ReportFormLoginSuccess should be called. +TEST_F(PasswordManagerTest, ReportFormLoginSuccessCalled) { + PasswordForm form(MakeSimpleForm()); + + std::vector<PasswordForm> observed; + observed.push_back(form); + EXPECT_CALL(driver_, FillPasswordForm(_)).Times(2); + // Simulate that |form| is already in the store, making this an update. + EXPECT_CALL(*store_, GetLogins(_, _)) + .WillRepeatedly(WithArg<1>(InvokeConsumer(form))); + manager()->OnPasswordFormsParsed(&driver_, observed); + manager()->OnPasswordFormsRendered(&driver_, observed, true); + + // Submit form and finish navigation. + EXPECT_CALL(client_, IsSavingAndFillingEnabledForCurrentPage()) + .WillRepeatedly(Return(true)); + EXPECT_CALL(client_, GetPrefs()).WillRepeatedly(Return(nullptr)); + manager()->ProvisionallySavePassword(form); + + // Chrome should recognise the successful login and call + // ReportFormLoginSuccess. + EXPECT_CALL(*client_.GetStoreResultFilter(), ReportFormLoginSuccess(_)); + EXPECT_CALL(*store_, UpdateLogin(_)); + observed.clear(); + manager()->OnPasswordFormsParsed(&driver_, observed); + manager()->OnPasswordFormsRendered(&driver_, observed, true); +} + // When there is a sync password saved, and the user successfully uses the // stored version of it, PasswordManager should not drop that password. TEST_F(PasswordManagerTest, SyncCredentialsNotDroppedIfUpToDate) { @@ -1288,24 +1319,32 @@ EXPECT_CALL(client_, IsSavingAndFillingEnabledForCurrentPage()) .WillRepeatedly(Return(true)); const bool kFalseTrue[] = {false, true}; - for (bool foundMatchedLoginsInStore : kFalseTrue) { - SCOPED_TRACE(testing::Message("foundMatchedLoginsInStore = ") - << foundMatchedLoginsInStore); + for (bool found_matched_logins_in_store : kFalseTrue) { + SCOPED_TRACE(testing::Message("found_matched_logins_in_store = ") + << found_matched_logins_in_store); std::vector<PasswordForm> observed; PasswordForm form(MakeFormWithOnlyNewPasswordField()); observed.push_back(form); - if (foundMatchedLoginsInStore) { + if (found_matched_logins_in_store) { EXPECT_CALL(*store_, GetLogins(_, _)) .WillRepeatedly(WithArg<1>(InvokeConsumer(form))); EXPECT_CALL(driver_, FillPasswordForm(_)).Times(2); - EXPECT_CALL(client_, NotifySuccessfulLoginWithExistingPassword(_)) - .Times(1); } else { EXPECT_CALL(*store_, GetLogins(_, _)) .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms())); } - EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_, _)).Times(0); - EXPECT_CALL(client_, AutomaticPasswordSaveIndicator()).Times(1); + std::unique_ptr<PasswordFormManager> form_manager; + if (found_matched_logins_in_store) { + EXPECT_CALL( + client_, + PromptUserToSaveOrUpdatePasswordPtr( + _, CredentialSourceType::CREDENTIAL_SOURCE_PASSWORD_MANAGER)) + .WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager))); + } else { + EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_, _)).Times(0); + } + EXPECT_CALL(client_, AutomaticPasswordSaveIndicator()) + .Times(found_matched_logins_in_store ? 0 : 1); manager()->OnPasswordFormsParsed(&driver_, observed); manager()->OnPasswordFormsRendered(&driver_, observed, true); @@ -1315,11 +1354,20 @@ manager()->SetHasGeneratedPasswordForForm(&driver_, form, true); ::testing::Mock::VerifyAndClearExpectations(store_.get()); - EXPECT_CALL(*store_, UpdateLoginWithPrimaryKey(_, form)).WillOnce(Return()); + if (!found_matched_logins_in_store) + EXPECT_CALL(*store_, UpdateLoginWithPrimaryKey(_, form)); OnPasswordFormSubmitted(form); observed.clear(); manager()->OnPasswordFormsParsed(&driver_, observed); manager()->OnPasswordFormsRendered(&driver_, observed, true); + + ::testing::Mock::VerifyAndClearExpectations(store_.get()); + if (found_matched_logins_in_store) { + // Credentials should be updated only when the user explicitly chooses. + ASSERT_TRUE(form_manager); + EXPECT_CALL(*store_, UpdateLoginWithPrimaryKey(_, form)); + form_manager->Update(form_manager->pending_credentials()); + } } }
diff --git a/components/password_manager/sync/browser/password_sync_util.cc b/components/password_manager/sync/browser/password_sync_util.cc index 19292c5..9eadfdf 100644 --- a/components/password_manager/sync/browser/password_sync_util.cc +++ b/components/password_manager/sync/browser/password_sync_util.cc
@@ -39,6 +39,12 @@ return false; } + // The empty username can mean that Chrome did not detect it correctly. For + // reasons described in http://crbug.com/636292#c1, the username is suspected + // to be the sync username unless proven otherwise. + if (form.username_value.empty()) + return true; + return gaia::AreEmailsSame( base::UTF16ToUTF8(form.username_value), GetSyncUsernameIfSyncingPasswords(sync_service, signin_manager));
diff --git a/components/password_manager/sync/browser/password_sync_util_unittest.cc b/components/password_manager/sync/browser/password_sync_util_unittest.cc index d1bfc448..5c21a83 100644 --- a/components/password_manager/sync/browser/password_sync_util_unittest.cc +++ b/components/password_manager/sync/browser/password_sync_util_unittest.cc
@@ -66,6 +66,8 @@ false}, {SimpleNonGaiaForm("sync_user@example.org"), "sync_user@example.org", false}, + {SimpleGaiaForm(""), "sync_user@example.org", true}, + {SimpleNonGaiaForm(""), "sync_user@example.org", false}, }; for (size_t i = 0; i < arraysize(kTestCases); ++i) {
diff --git a/components/password_manager/sync/browser/sync_credentials_filter.cc b/components/password_manager/sync/browser/sync_credentials_filter.cc index 5632331d..48bdf7d 100644 --- a/components/password_manager/sync/browser/sync_credentials_filter.cc +++ b/components/password_manager/sync/browser/sync_credentials_filter.cc
@@ -10,6 +10,7 @@ #include "base/metrics/field_trial.h" #include "base/metrics/histogram_macros.h" #include "base/metrics/user_metrics.h" +#include "components/password_manager/core/browser/password_form_manager.h" #include "components/password_manager/core/browser/password_manager_util.h" #include "components/password_manager/core/common/password_manager_features.h" #include "components/password_manager/sync/browser/password_sync_util.h" @@ -79,10 +80,16 @@ signin_manager_factory_function_.Run()); } -void SyncCredentialsFilter::ReportFormUsed( - const autofill::PasswordForm& form) const { - base::RecordAction( - base::UserMetricsAction("PasswordManager_SyncCredentialUsed")); +void SyncCredentialsFilter::ReportFormLoginSuccess( + const PasswordFormManager& form_manager) const { + if (!form_manager.IsNewLogin() && + sync_util::IsSyncAccountCredential( + form_manager.pending_credentials(), + sync_service_factory_function_.Run(), + signin_manager_factory_function_.Run())) { + base::RecordAction(base::UserMetricsAction( + "PasswordManager_SyncCredentialFilledAndLoginSuccessfull")); + } } // static
diff --git a/components/password_manager/sync/browser/sync_credentials_filter.h b/components/password_manager/sync/browser/sync_credentials_filter.h index 019a28c2..4ad64f3 100644 --- a/components/password_manager/sync/browser/sync_credentials_filter.h +++ b/components/password_manager/sync/browser/sync_credentials_filter.h
@@ -41,7 +41,8 @@ ScopedVector<autofill::PasswordForm> FilterResults( ScopedVector<autofill::PasswordForm> results) const override; bool ShouldSave(const autofill::PasswordForm& form) const override; - void ReportFormUsed(const autofill::PasswordForm& form) const override; + void ReportFormLoginSuccess( + const PasswordFormManager& form_manager) const override; private: enum AutofillForSyncCredentialsState {
diff --git a/components/password_manager/sync/browser/sync_credentials_filter_unittest.cc b/components/password_manager/sync/browser/sync_credentials_filter_unittest.cc index c4eca618..5f26c17 100644 --- a/components/password_manager/sync/browser/sync_credentials_filter_unittest.cc +++ b/components/password_manager/sync/browser/sync_credentials_filter_unittest.cc
@@ -5,20 +5,30 @@ #include "components/password_manager/sync/browser/sync_credentials_filter.h" #include <stddef.h> + +#include <memory> #include <utility> #include <vector> #include "base/bind.h" #include "base/bind_helpers.h" #include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "base/memory/scoped_vector.h" +#include "base/message_loop/message_loop.h" #include "base/test/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "base/test/user_action_tester.h" #include "components/autofill/core/common/password_form.h" +#include "components/password_manager/core/browser/mock_password_store.h" +#include "components/password_manager/core/browser/password_manager.h" #include "components/password_manager/core/browser/password_manager_test_utils.h" +#include "components/password_manager/core/browser/stub_form_saver.h" #include "components/password_manager/core/browser/stub_password_manager_client.h" +#include "components/password_manager/core/browser/stub_password_manager_driver.h" #include "components/password_manager/core/common/password_manager_features.h" #include "components/password_manager/sync/browser/sync_username_test_base.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" using autofill::PasswordForm; @@ -27,20 +37,36 @@ namespace { +const char kFilledAndLoginActionName[] = + "PasswordManager_SyncCredentialFilledAndLoginSuccessfull"; + class FakePasswordManagerClient : public StubPasswordManagerClient { public: - ~FakePasswordManagerClient() override {} + FakePasswordManagerClient() + : password_store_(new testing::NiceMock<MockPasswordStore>) {} + + ~FakePasswordManagerClient() override { + password_store_->ShutdownOnUIThread(); + } // PasswordManagerClient: const GURL& GetLastCommittedEntryURL() const override { return last_committed_entry_url_; } + MockPasswordStore* GetPasswordStore() const override { + return password_store_.get(); + } void set_last_committed_entry_url(const char* url_spec) { last_committed_entry_url_ = GURL(url_spec); } + private: + base::MessageLoop message_loop_; // For |password_store_|. GURL last_committed_entry_url_; + scoped_refptr<testing::NiceMock<MockPasswordStore>> password_store_; + + DISALLOW_COPY_AND_ASSIGN(FakePasswordManagerClient); }; bool IsFormFiltered(const CredentialsFilter* filter, const PasswordForm& form) { @@ -63,8 +89,12 @@ enum { NO_HISTOGRAM, HISTOGRAM_REPORTED } histogram_reported; }; + // Flag for creating a PasswordFormManager, deciding its IsNewLogin() value. + enum class LoginState { NEW, EXISTING }; + CredentialsFilterTest() - : filter_(&client_, + : password_manager_(&client_), + filter_(&client_, base::Bind(&SyncUsernameTestBase::sync_service, base::Unretained(this)), base::Bind(&SyncUsernameTestBase::signin_manager, @@ -88,12 +118,37 @@ FakeSignout(); } + // Creates a PasswordFormManager for the |pending| form and provisionally + // saves it. Ensures that the created manager's IsNewLogin responds according + // to |login_state|. + std::unique_ptr<PasswordFormManager> CreateFormManager( + LoginState login_state, + const PasswordForm& pending) { + auto form_manager = base::WrapUnique(new PasswordFormManager( + &password_manager_, &client_, driver_.AsWeakPtr(), pending, + base::WrapUnique(new StubFormSaver))); + + form_manager->FetchDataFromPasswordStore(); + ScopedVector<PasswordForm> saved_forms; + if (login_state == LoginState::EXISTING) { + saved_forms.push_back(new PasswordForm(pending)); + } + form_manager->OnGetPasswordStoreResults(std::move(saved_forms)); + + form_manager->ProvisionallySave( + pending, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES); + + return form_manager; + } + SyncCredentialsFilter* filter() { return &filter_; } FakePasswordManagerClient* client() { return &client_; } private: FakePasswordManagerClient client_; + PasswordManager password_manager_; + StubPasswordManagerDriver driver_; SyncCredentialsFilter filter_; }; @@ -225,11 +280,59 @@ } } -TEST_F(CredentialsFilterTest, ReportFormUsed) { +TEST_F(CredentialsFilterTest, ReportFormLoginSuccess_ExistingSyncCredentials) { + PasswordForm pending = SimpleGaiaForm("user@gmail.com"); + FakeSigninAs("user@gmail.com"); + SetSyncingPasswords(true); + base::UserActionTester tester; - ASSERT_EQ(0, tester.GetActionCount("PasswordManager_SyncCredentialUsed")); - filter()->ReportFormUsed(PasswordForm()); - EXPECT_EQ(1, tester.GetActionCount("PasswordManager_SyncCredentialUsed")); + auto form_manager = CreateFormManager(LoginState::EXISTING, pending); + filter()->ReportFormLoginSuccess(*form_manager); + EXPECT_EQ(1, tester.GetActionCount(kFilledAndLoginActionName)); +} + +TEST_F(CredentialsFilterTest, ReportFormLoginSuccess_NewSyncCredentials) { + PasswordForm pending = SimpleGaiaForm("user@gmail.com"); + FakeSigninAs("user@gmail.com"); + SetSyncingPasswords(true); + + base::UserActionTester tester; + auto form_manager = CreateFormManager(LoginState::NEW, pending); + filter()->ReportFormLoginSuccess(*form_manager); + EXPECT_EQ(0, tester.GetActionCount(kFilledAndLoginActionName)); +} + +TEST_F(CredentialsFilterTest, ReportFormLoginSuccess_GAIANotSyncCredentials) { + PasswordForm pending = SimpleGaiaForm("user@gmail.com"); + FakeSigninAs("other_user@gmail.com"); + SetSyncingPasswords(true); + + base::UserActionTester tester; + auto form_manager = CreateFormManager(LoginState::EXISTING, pending); + filter()->ReportFormLoginSuccess(*form_manager); + EXPECT_EQ(0, tester.GetActionCount(kFilledAndLoginActionName)); +} + +TEST_F(CredentialsFilterTest, ReportFormLoginSuccess_NotGAIACredentials) { + PasswordForm pending = SimpleNonGaiaForm("user@gmail.com"); + FakeSigninAs("user@gmail.com"); + SetSyncingPasswords(true); + + base::UserActionTester tester; + auto form_manager = CreateFormManager(LoginState::EXISTING, pending); + filter()->ReportFormLoginSuccess(*form_manager); + EXPECT_EQ(0, tester.GetActionCount(kFilledAndLoginActionName)); +} + +TEST_F(CredentialsFilterTest, ReportFormLoginSuccess_NotSyncing) { + PasswordForm pending = SimpleGaiaForm("user@gmail.com"); + FakeSigninAs("user@gmail.com"); + SetSyncingPasswords(false); + + base::UserActionTester tester; + auto form_manager = CreateFormManager(LoginState::EXISTING, pending); + filter()->ReportFormLoginSuccess(*form_manager); + EXPECT_EQ(0, tester.GetActionCount(kFilledAndLoginActionName)); } TEST_F(CredentialsFilterTest, ShouldSave_NotSyncCredential) {
diff --git a/components/physical_web.gypi b/components/physical_web.gypi new file mode 100644 index 0000000..d462fa1 --- /dev/null +++ b/components/physical_web.gypi
@@ -0,0 +1,23 @@ +# 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. + +{ + 'targets': [ + { + # GN version: //components/physical_web/data_source + 'target_name': 'physical_web_data_source', + 'type': 'static_library', + 'dependencies': [ + '../base/base.gyp:base', + ], + 'include_dirs': [ + '..', + ], + 'sources': [ + # Note: sources list duplicated in GN build. + 'physical_web/data_source/physical_web_data_source.h', + ], + }, + ], +}
diff --git a/components/physical_web/OWNERS b/components/physical_web/OWNERS new file mode 100644 index 0000000..2f1afa4 --- /dev/null +++ b/components/physical_web/OWNERS
@@ -0,0 +1,2 @@ +mattreynolds@chromium.org +olivierrobin@chromium.org
diff --git a/components/physical_web/data_source/BUILD.gn b/components/physical_web/data_source/BUILD.gn new file mode 100644 index 0000000..5e38526d --- /dev/null +++ b/components/physical_web/data_source/BUILD.gn
@@ -0,0 +1,13 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +source_set("data_source") { + sources = [ + "physical_web_data_source.h", + ] + + deps = [ + "//base", + ] +}
diff --git a/components/physical_web/data_source/physical_web_data_source.h b/components/physical_web/data_source/physical_web_data_source.h new file mode 100644 index 0000000..1fa11407 --- /dev/null +++ b/components/physical_web/data_source/physical_web_data_source.h
@@ -0,0 +1,40 @@ +// 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 COMPONENTS_PHYSICAL_WEB_DATA_SOURCE_PHYSICAL_WEB_DATA_SOURCE_H_ +#define COMPONENTS_PHYSICAL_WEB_DATA_SOURCE_PHYSICAL_WEB_DATA_SOURCE_H_ + +#include <memory> + +namespace base { +class ListValue; +} + +// Helper class for accessing Physical Web metadata and controlling the scanner. +class PhysicalWebDataSource { + public: + virtual ~PhysicalWebDataSource() {} + + // Starts scanning for Physical Web URLs. If |network_request_enabled| is + // true, discovered URLs will be sent to a resolution service. + virtual void StartDiscovery(bool network_request_enabled) = 0; + + // Stops scanning for Physical Web URLs and clears cached URL content. + virtual void StopDiscovery() = 0; + + // Returns a list of resolved URLs and associated page metadata. If network + // requests are disabled or if discovery is not active, the list will be + // empty. The method can be called at any time to receive the current metadata + // list. + virtual std::unique_ptr<base::ListValue> GetMetadata() = 0; + + // Returns boolean |true| if network requests are disabled and there are one + // or more discovered URLs that have not been sent to the resolution service. + // The method can be called at any time to check for unresolved discoveries. + // If discovery is inactive or network requests are enabled, it will always + // return false. + virtual bool HasUnresolvedDiscoveries() = 0; +}; + +#endif // COMPONENTS_PHYSICAL_WEB_DATA_SOURCE_PHYSICAL_WEB_DATA_SOURCE_H_
diff --git a/components/plugins/renderer/loadable_plugin_placeholder.cc b/components/plugins/renderer/loadable_plugin_placeholder.cc index a8c6d71..d0263d3e 100644 --- a/components/plugins/renderer/loadable_plugin_placeholder.cc +++ b/components/plugins/renderer/loadable_plugin_placeholder.cc
@@ -32,6 +32,7 @@ using base::UserMetricsAction; using content::PluginInstanceThrottler; +using content::RenderFrame; using content::RenderThread; namespace plugins { @@ -51,15 +52,17 @@ content::PluginInstanceThrottler* throttler) { DCHECK(throttler); DCHECK(!premade_throttler_); + heuristic_run_before_ = true; premade_throttler_ = throttler; } LoadablePluginPlaceholder::LoadablePluginPlaceholder( - content::RenderFrame* render_frame, + RenderFrame* render_frame, blink::WebLocalFrame* frame, const blink::WebPluginParams& params, const std::string& html_data) : PluginPlaceholderBase(render_frame, frame, params, html_data), + heuristic_run_before_(false), is_blocked_for_tinyness_(false), is_blocked_for_background_tab_(false), is_blocked_for_prerendering_(false), @@ -68,7 +71,6 @@ premade_throttler_(nullptr), allow_loading_(false), finished_loading_(false), - heuristic_run_before_(premade_throttler_ != nullptr), weak_factory_(this) {} LoadablePluginPlaceholder::~LoadablePluginPlaceholder() { @@ -199,27 +201,27 @@ // On a size update check if we now qualify as a essential plugin. url::Origin content_origin = url::Origin(GetPluginParams().url); - content::RenderFrame::PeripheralContentStatus status = + RenderFrame::PeripheralContentStatus status = render_frame()->GetPeripheralContentStatus( render_frame()->GetWebFrame()->top()->getSecurityOrigin(), - content_origin, gfx::Size(width, height)); + content_origin, gfx::Size(width, height), + heuristic_run_before_ ? RenderFrame::DONT_RECORD_DECISION + : RenderFrame::RECORD_DECISION); bool plugin_is_tiny_and_blocked = is_blocked_for_tinyness_ && - status == - content::RenderFrame::CONTENT_STATUS_ESSENTIAL_CROSS_ORIGIN_TINY; + status == RenderFrame::CONTENT_STATUS_ESSENTIAL_CROSS_ORIGIN_TINY; // Early exit for plugins that we've discovered to be essential. if (!plugin_is_tiny_and_blocked && - status != content::RenderFrame::CONTENT_STATUS_PERIPHERAL) { + status != RenderFrame::CONTENT_STATUS_PERIPHERAL) { MarkPluginEssential( heuristic_run_before_ ? PluginInstanceThrottler::UNTHROTTLE_METHOD_BY_SIZE_CHANGE : PluginInstanceThrottler::UNTHROTTLE_METHOD_DO_NOT_RECORD); if (!heuristic_run_before_ && - status == - content::RenderFrame::CONTENT_STATUS_ESSENTIAL_CROSS_ORIGIN_BIG) { + status == RenderFrame::CONTENT_STATUS_ESSENTIAL_CROSS_ORIGIN_BIG) { render_frame()->WhitelistContentOrigin(content_origin); }
diff --git a/components/plugins/renderer/loadable_plugin_placeholder.h b/components/plugins/renderer/loadable_plugin_placeholder.h index 0d7d8d9..ea52ae9e 100644 --- a/components/plugins/renderer/loadable_plugin_placeholder.h +++ b/components/plugins/renderer/loadable_plugin_placeholder.h
@@ -82,6 +82,9 @@ void DidFinishLoadingCallback(); void DidFinishIconRepositionForTestingCallback(); + // True if the power saver heuristic has already been run on this content. + bool heuristic_run_before_; + private: // WebViewPlugin::Delegate methods: void PluginDestroyed() override; @@ -135,9 +138,6 @@ gfx::Rect unobscured_rect_; - // True if the power saver heuristic has already been run on this content. - bool heuristic_run_before_; - base::WeakPtrFactory<LoadablePluginPlaceholder> weak_factory_; DISALLOW_COPY_AND_ASSIGN(LoadablePluginPlaceholder);
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json index 2751eff..6bd1a9d 100644 --- a/components/policy/resources/policy_templates.json +++ b/components/policy/resources/policy_templates.json
@@ -397,7 +397,7 @@ 'id': 7, 'caption': '''Enable network prediction''', 'tags': [], - 'desc': '''This policy is deprecated in M48 in favor of NetworkPredictionOptions, and removed in M54. + 'desc': '''This policy is deprecated in M48 in favor of <ph name="NETWORKPREDICTIONOPTIONS_POLICY_NAME">NetworkPredictionOptions</ph>, and removed in M54. Enables network prediction in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> and prevents users from changing this setting.
diff --git a/components/printing/test/print_web_view_helper_browsertest.cc b/components/printing/test/print_web_view_helper_browsertest.cc index 5fbfacc..f047776 100644 --- a/components/printing/test/print_web_view_helper_browsertest.cc +++ b/components/printing/test/print_web_view_helper_browsertest.cc
@@ -897,8 +897,7 @@ // Test to verify that preview generated only for one page. TEST_F(MAYBE_PrintWebViewHelperPreviewTest, OnPrintPreviewForSelectedText) { LoadHTML(kMultipageHTML); - GetMainFrame()->selectRange( - blink::WebRange::fromDocumentRange(GetMainFrame(), 1, 3)); + GetMainFrame()->selectRange(blink::WebRange(1, 3)); // Fill in some dummy values. base::DictionaryValue dict;
diff --git a/components/scheduler/BUILD.gn b/components/scheduler/BUILD.gn deleted file mode 100644 index 035feb1..0000000 --- a/components/scheduler/BUILD.gn +++ /dev/null
@@ -1,187 +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. - -# GYP version: components/scheduler.gypi:scheduler -component("scheduler") { - sources = [ - "base/cancelable_closure_holder.cc", - "base/cancelable_closure_holder.h", - "base/enqueue_order.cc", - "base/enqueue_order.h", - "base/lazy_now.cc", - "base/lazy_now.h", - "base/long_task_tracker.cc", - "base/long_task_tracker.h", - "base/pollable_thread_safe_flag.cc", - "base/pollable_thread_safe_flag.h", - "base/queueing_time_estimator.cc", - "base/queueing_time_estimator.h", - "base/real_time_domain.cc", - "base/real_time_domain.h", - "base/task_queue.h", - "base/task_queue_impl.cc", - "base/task_queue_impl.h", - "base/task_queue_manager.cc", - "base/task_queue_manager.h", - "base/task_queue_manager_delegate.h", - "base/task_queue_selector.cc", - "base/task_queue_selector.h", - "base/task_time_tracker.h", - "base/time_domain.cc", - "base/time_domain.h", - "base/virtual_time_domain.cc", - "base/virtual_time_domain.h", - "base/work_queue.cc", - "base/work_queue.h", - "base/work_queue_sets.cc", - "base/work_queue_sets.h", - "child/child_scheduler.h", - "child/compositor_worker_scheduler.cc", - "child/compositor_worker_scheduler.h", - "child/idle_helper.cc", - "child/idle_helper.h", - "child/scheduler_helper.cc", - "child/scheduler_helper.h", - "child/scheduler_tqm_delegate.h", - "child/scheduler_tqm_delegate_impl.cc", - "child/scheduler_tqm_delegate_impl.h", - "child/single_thread_idle_task_runner.cc", - "child/single_thread_idle_task_runner.h", - "child/web_scheduler_impl.cc", - "child/web_scheduler_impl.h", - "child/web_task_runner_impl.cc", - "child/web_task_runner_impl.h", - "child/webthread_base.cc", - "child/webthread_base.h", - "child/webthread_impl_for_worker_scheduler.cc", - "child/webthread_impl_for_worker_scheduler.h", - "child/worker_scheduler.cc", - "child/worker_scheduler.h", - "child/worker_scheduler_impl.cc", - "child/worker_scheduler_impl.h", - "renderer/auto_advancing_virtual_time_domain.cc", - "renderer/auto_advancing_virtual_time_domain.h", - "renderer/deadline_task_runner.cc", - "renderer/deadline_task_runner.h", - "renderer/idle_time_estimator.cc", - "renderer/idle_time_estimator.h", - "renderer/render_widget_scheduling_state.cc", - "renderer/render_widget_scheduling_state.h", - "renderer/render_widget_signals.cc", - "renderer/render_widget_signals.h", - "renderer/renderer_scheduler.cc", - "renderer/renderer_scheduler.h", - "renderer/renderer_scheduler_impl.cc", - "renderer/renderer_scheduler_impl.h", - "renderer/renderer_web_scheduler_impl.cc", - "renderer/renderer_web_scheduler_impl.h", - "renderer/task_cost_estimator.cc", - "renderer/task_cost_estimator.h", - "renderer/throttled_time_domain.cc", - "renderer/throttled_time_domain.h", - "renderer/throttling_helper.cc", - "renderer/throttling_helper.h", - "renderer/user_model.cc", - "renderer/user_model.h", - "renderer/web_frame_scheduler_impl.cc", - "renderer/web_frame_scheduler_impl.h", - "renderer/web_view_scheduler_impl.cc", - "renderer/web_view_scheduler_impl.h", - "renderer/webthread_impl_for_renderer_scheduler.cc", - "renderer/webthread_impl_for_renderer_scheduler.h", - "scheduler_export.h", - ] - - defines = [ "SCHEDULER_IMPLEMENTATION" ] - - # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. - configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] - - deps = [ - ":common", - "//base", - "//cc:cc", - "//third_party/WebKit/public:blink", - "//ui/gfx:gfx", - ] - - public_deps = [ - "//third_party/WebKit/public:blink", - "//v8", - ] -} - -# GYP version: components/scheduler.gypi:scheduler_common -static_library("common") { - sources = [ - "common/scheduler_switches.cc", - "common/scheduler_switches.h", - ] -} - -source_set("unit_tests") { - testonly = true - - sources = [ - "base/long_task_tracker_unittest.cc", - "base/queueing_time_estimator_unittest.cc", - "base/task_queue_manager_delegate_for_test.cc", - "base/task_queue_manager_delegate_for_test.h", - "base/task_queue_manager_unittest.cc", - "base/task_queue_selector_unittest.cc", - "base/test_count_uses_time_source.cc", - "base/test_count_uses_time_source.h", - "base/test_task_time_tracker.h", - "base/test_time_source.cc", - "base/test_time_source.h", - "base/time_domain_unittest.cc", - "base/work_queue_sets_unittest.cc", - "child/idle_helper_unittest.cc", - "child/scheduler_helper_unittest.cc", - "child/scheduler_tqm_delegate_for_test.cc", - "child/scheduler_tqm_delegate_for_test.h", - "child/scheduler_tqm_delegate_impl_unittest.cc", - "child/webthread_impl_for_worker_scheduler_unittest.cc", - "child/worker_scheduler_impl_unittest.cc", - "renderer/auto_advancing_virtual_time_domain_unittest.cc", - "renderer/deadline_task_runner_unittest.cc", - "renderer/idle_time_estimator_unittest.cc", - "renderer/render_widget_signals_unittest.cpp", - "renderer/renderer_scheduler_impl_unittest.cc", - "renderer/task_cost_estimator_unittest.cc", - "renderer/throttling_helper_unittest.cc", - "renderer/user_model_unittest.cc", - "renderer/web_view_scheduler_impl_unittest.cc", - "renderer/webthread_impl_for_renderer_scheduler_unittest.cc", - ] - - deps = [ - ":scheduler", - "//base/test:test_support", - "//cc:test_support", - "//testing/gmock", - "//testing/gtest", - ] -} - -# GYP version: components/scheduler.gypi:scheduler_test_support -static_library("test_support") { - testonly = true - - sources = [ - "test/lazy_scheduler_message_loop_delegate_for_tests.cc", - "test/lazy_scheduler_message_loop_delegate_for_tests.h", - "test/renderer_scheduler_test_support.cc", - "test/renderer_scheduler_test_support.h", - ] - - deps = [ - "//third_party/WebKit/public:blink", - ] - - public_deps = [ - ":scheduler", - "//base", - ] -}
diff --git a/components/scheduler/DEPS b/components/scheduler/DEPS deleted file mode 100644 index a70514277..0000000 --- a/components/scheduler/DEPS +++ /dev/null
@@ -1,4 +0,0 @@ -include_rules = [ - "-components/scheduler", - "+components/scheduler/common", -]
diff --git a/components/scheduler/base/DEPS b/components/scheduler/base/DEPS deleted file mode 100644 index 5d86a1b..0000000 --- a/components/scheduler/base/DEPS +++ /dev/null
@@ -1,9 +0,0 @@ -include_rules = [ - "+components/scheduler/scheduler_export.h", -] - -specific_include_rules = { - "(test_time_source|.*test)\.cc": [ - "+cc/test", - ], -}
diff --git a/components/scheduler/base/cancelable_closure_holder.cc b/components/scheduler/base/cancelable_closure_holder.cc deleted file mode 100644 index 54c1462..0000000 --- a/components/scheduler/base/cancelable_closure_holder.cc +++ /dev/null
@@ -1,28 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/base/cancelable_closure_holder.h" - -namespace scheduler { - -CancelableClosureHolder::CancelableClosureHolder() {} - -CancelableClosureHolder::~CancelableClosureHolder() {} - -void CancelableClosureHolder::Reset(const base::Closure& callback) { - callback_ = callback; - cancelable_callback_.Reset(callback_); -} - -void CancelableClosureHolder::Cancel() { - DCHECK(!callback_.is_null()); - cancelable_callback_.Reset(callback_); -} - -const base::Closure& CancelableClosureHolder::callback() const { - DCHECK(!callback_.is_null()); - return cancelable_callback_.callback(); -} - -} // namespace scheduler
diff --git a/components/scheduler/base/cancelable_closure_holder.h b/components/scheduler/base/cancelable_closure_holder.h deleted file mode 100644 index 5254cd4..0000000 --- a/components/scheduler/base/cancelable_closure_holder.h +++ /dev/null
@@ -1,40 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_BASE_CANCELABLE_CLOSURE_HOLDER_H_ -#define COMPONENTS_SCHEDULER_BASE_CANCELABLE_CLOSURE_HOLDER_H_ - -#include "base/cancelable_callback.h" -#include "base/macros.h" - -namespace scheduler { - -// A CancelableClosureHolder is a CancelableCallback which resets its wrapped -// callback with a cached closure whenever it is canceled. -class CancelableClosureHolder { - public: - CancelableClosureHolder(); - ~CancelableClosureHolder(); - - // Resets the closure to be wrapped by the cancelable callback. Cancels any - // outstanding callbacks. - void Reset(const base::Closure& callback); - - // Cancels any outstanding closures returned by callback(). - void Cancel(); - - // Returns a callback that will be disabled by calling Cancel(). Callback - // must have been set using Reset() before calling this function. - const base::Closure& callback() const; - - private: - base::Closure callback_; - base::CancelableClosure cancelable_callback_; - - DISALLOW_COPY_AND_ASSIGN(CancelableClosureHolder); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_BASE_CANCELABLE_CLOSURE_HOLDER_H_
diff --git a/components/scheduler/base/enqueue_order.cc b/components/scheduler/base/enqueue_order.cc deleted file mode 100644 index dd04bbd..0000000 --- a/components/scheduler/base/enqueue_order.cc +++ /dev/null
@@ -1,20 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/base/enqueue_order.h" - -namespace scheduler { -namespace internal { - -EnqueueOrderGenerator::EnqueueOrderGenerator() : enqueue_order_(0) {} - -EnqueueOrderGenerator::~EnqueueOrderGenerator() {} - -EnqueueOrder EnqueueOrderGenerator::GenerateNext() { - base::AutoLock lock(lock_); - return enqueue_order_++; -} - -} // namespace internal -} // namespace scheduler
diff --git a/components/scheduler/base/enqueue_order.h b/components/scheduler/base/enqueue_order.h deleted file mode 100644 index 21001ff..0000000 --- a/components/scheduler/base/enqueue_order.h +++ /dev/null
@@ -1,32 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_BASE_ENQUEUE_ORDER_H_ -#define COMPONENTS_SCHEDULER_BASE_ENQUEUE_ORDER_H_ - -#include <stdint.h> - -#include "base/synchronization/lock.h" - -namespace scheduler { -namespace internal { - -using EnqueueOrder = uint64_t; - -class EnqueueOrderGenerator { - public: - EnqueueOrderGenerator(); - ~EnqueueOrderGenerator(); - - EnqueueOrder GenerateNext(); - - private: - base::Lock lock_; - EnqueueOrder enqueue_order_; -}; - -} // namespace internal -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_BASE_ENQUEUE_ORDER_H_
diff --git a/components/scheduler/base/lazy_now.cc b/components/scheduler/base/lazy_now.cc deleted file mode 100644 index 3492ca67..0000000 --- a/components/scheduler/base/lazy_now.cc +++ /dev/null
@@ -1,17 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/base/lazy_now.h" - -#include "base/time/tick_clock.h" -#include "components/scheduler/base/task_queue_manager.h" - -namespace scheduler { -base::TimeTicks LazyNow::Now() { - if (now_.is_null()) - now_ = tick_clock_->NowTicks(); - return now_; -} - -} // namespace scheduler
diff --git a/components/scheduler/base/lazy_now.h b/components/scheduler/base/lazy_now.h deleted file mode 100644 index 959a245..0000000 --- a/components/scheduler/base/lazy_now.h +++ /dev/null
@@ -1,36 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_BASE_LAZY_NOW_H_ -#define COMPONENTS_SCHEDULER_BASE_LAZY_NOW_H_ - -#include "base/time/time.h" -#include "components/scheduler/scheduler_export.h" - -namespace base { -class TickClock; -} - -namespace scheduler { - -// Now() is somewhat expensive so it makes sense not to call Now() unless we -// really need to. -class SCHEDULER_EXPORT LazyNow { - public: - explicit LazyNow(base::TimeTicks now) : tick_clock_(nullptr), now_(now) { - DCHECK(!now.is_null()); - } - - explicit LazyNow(base::TickClock* tick_clock) : tick_clock_(tick_clock) {} - - base::TimeTicks Now(); - - private: - base::TickClock* tick_clock_; // NOT OWNED - base::TimeTicks now_; -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_BASE_LAZY_NOW_H_
diff --git a/components/scheduler/base/long_task_tracker.cc b/components/scheduler/base/long_task_tracker.cc deleted file mode 100644 index e3d6a39..0000000 --- a/components/scheduler/base/long_task_tracker.cc +++ /dev/null
@@ -1,28 +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 "components/scheduler/base/long_task_tracker.h" - -namespace scheduler { - -namespace { -int kLongTaskThresholdMillis = 50; -} - -LongTaskTracker::LongTaskTracker() {} - -LongTaskTracker::~LongTaskTracker() {} - -void LongTaskTracker::RecordLongTask(base::TimeTicks startTime, - base::TimeDelta duration) { - if (duration.InMilliseconds() > kLongTaskThresholdMillis) { - long_task_times_.push_back(std::make_pair(startTime, duration)); - } -} - -LongTaskTracker::LongTaskTiming LongTaskTracker::GetLongTaskTiming() { - return std::move(long_task_times_); -} - -} // namespace scheduler
diff --git a/components/scheduler/base/long_task_tracker.h b/components/scheduler/base/long_task_tracker.h deleted file mode 100644 index af10f6f..0000000 --- a/components/scheduler/base/long_task_tracker.h +++ /dev/null
@@ -1,40 +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 COMPONENTS_SCHEDULER_BASE_LONG_TASK_TRACKER_H_ -#define COMPONENTS_SCHEDULER_BASE_LONG_TASK_TRACKER_H_ - -#include <vector> - -#include "base/macros.h" -#include "base/time/time.h" -#include "components/scheduler/scheduler_export.h" - -namespace scheduler { - -// Records and reports long task times, above the threshold. -// The threshold is set to 50ms in the implementation. -class SCHEDULER_EXPORT LongTaskTracker { - public: - using LongTaskTiming = - std::vector<std::pair<base::TimeTicks, base::TimeDelta>>; - - LongTaskTracker(); - ~LongTaskTracker(); - - LongTaskTiming GetLongTaskTiming(); - void RecordLongTask(base::TimeTicks startTime, - base::TimeDelta duration); - - private: - friend class LongTaskTrackerTest; - - LongTaskTiming long_task_times_; - - DISALLOW_COPY_AND_ASSIGN(LongTaskTracker); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_BASE_LONG_TASK_TRACKER_H_
diff --git a/components/scheduler/base/long_task_tracker_unittest.cc b/components/scheduler/base/long_task_tracker_unittest.cc deleted file mode 100644 index 8d11c9b4..0000000 --- a/components/scheduler/base/long_task_tracker_unittest.cc +++ /dev/null
@@ -1,53 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/base/long_task_tracker.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace scheduler { - -class LongTaskTrackerTest : public ::testing::Test { - protected: - LongTaskTracker long_task_tracker_; - - size_t NumLongTasks() { - return long_task_tracker_.long_task_times_.size(); - } -}; - -TEST_F(LongTaskTrackerTest, RecordAndReport) { - EXPECT_EQ(0U, NumLongTasks()); - - // Add long tasks above 50ms threshold - long_task_tracker_.RecordLongTask( - base::TimeTicks() + base::TimeDelta::FromMilliseconds(4500), - base::TimeDelta::FromMilliseconds(51)); - EXPECT_EQ(1U, NumLongTasks()); - - long_task_tracker_.RecordLongTask( - base::TimeTicks() + base::TimeDelta::FromMilliseconds(5500), - base::TimeDelta::FromMilliseconds(75)); - EXPECT_EQ(2U, NumLongTasks()); - - // Add task below 50ms threshold - long_task_tracker_.RecordLongTask( - base::TimeTicks() + base::TimeDelta::FromMilliseconds(6500), - base::TimeDelta::FromMilliseconds(49)); - EXPECT_EQ(2U, NumLongTasks()); - - LongTaskTracker::LongTaskTiming long_task_times = - long_task_tracker_.GetLongTaskTiming(); - // GetLongTaskTiming clears the internal vector - EXPECT_EQ(0U, NumLongTasks()); - // Validate recorded contents - EXPECT_EQ(2U, long_task_times.size()); - EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromMilliseconds(4500), - long_task_times[0].first); - EXPECT_EQ(51, long_task_times[0].second.InMilliseconds()); - EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromMilliseconds(5500), - long_task_times[1].first); - EXPECT_EQ(75, long_task_times[1].second.InMilliseconds()); -} - -}
diff --git a/components/scheduler/base/pollable_thread_safe_flag.cc b/components/scheduler/base/pollable_thread_safe_flag.cc deleted file mode 100644 index 13d5b6f..0000000 --- a/components/scheduler/base/pollable_thread_safe_flag.cc +++ /dev/null
@@ -1,19 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/base/pollable_thread_safe_flag.h" - -PollableThreadSafeFlag::PollableThreadSafeFlag(base::Lock* write_lock_) - : flag_(false), write_lock_(write_lock_) {} - -PollableThreadSafeFlag::~PollableThreadSafeFlag() {} - -void PollableThreadSafeFlag::SetWhileLocked(bool value) { - write_lock_->AssertAcquired(); - base::subtle::Release_Store(&flag_, value); -} - -bool PollableThreadSafeFlag::IsSet() const { - return base::subtle::Acquire_Load(&flag_) != false; -}
diff --git a/components/scheduler/base/pollable_thread_safe_flag.h b/components/scheduler/base/pollable_thread_safe_flag.h deleted file mode 100644 index 8e37b69..0000000 --- a/components/scheduler/base/pollable_thread_safe_flag.h +++ /dev/null
@@ -1,36 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_BASE_POLLABLE_THREAD_SAFE_FLAG_H_ -#define COMPONENTS_SCHEDULER_BASE_POLLABLE_THREAD_SAFE_FLAG_H_ - -#include "base/atomicops.h" -#include "base/macros.h" -#include "base/synchronization/lock.h" - -// A PollableThreadSafeFlag can be polled without requiring a lock, but can only -// be updated if a lock is held. This enables lock-free checking as to whether a -// condition has changed, while protecting operations which update the condition -// with a lock. You must ensure that the flag is only updated within the same -// lock-protected critical section as any other variables on which the condition -// depends. -class PollableThreadSafeFlag { - public: - explicit PollableThreadSafeFlag(base::Lock* write_lock); - ~PollableThreadSafeFlag(); - - // Set the flag. May only be called if |write_lock| is held. - void SetWhileLocked(bool value); - - // Returns true iff the flag is set to true. - bool IsSet() const; - - private: - base::subtle::Atomic32 flag_; - base::Lock* write_lock_; // Not owned. - - DISALLOW_COPY_AND_ASSIGN(PollableThreadSafeFlag); -}; - -#endif // COMPONENTS_SCHEDULER_BASE_POLLABLE_THREAD_SAFE_FLAG_H_
diff --git a/components/scheduler/base/queueing_time_estimator.cc b/components/scheduler/base/queueing_time_estimator.cc deleted file mode 100644 index 1402380..0000000 --- a/components/scheduler/base/queueing_time_estimator.cc +++ /dev/null
@@ -1,87 +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 "components/scheduler/base/queueing_time_estimator.h" - -#include "base/time/default_tick_clock.h" - -namespace scheduler { - -namespace { - -// This method computes the expected queueing time of a randomly distributed -// task R within a window containing a single task T. Let T' be the time range -// for which T overlaps the window. We first compute the probability that R will -// start within T'. We then compute the expected queueing duration if R does -// start within this range. Since the start time of R is uniformly distributed -// within the window, this is equal to the average of the queueing times if R -// started at the beginning or end of T'. The expected queueing time of T is the -// probability that R will start within T', multiplied by the expected queueing -// duration if R does fall in this range. -base::TimeDelta ExpectedQueueingTimeFromTask(base::TimeTicks task_start, - base::TimeTicks task_end, - base::TimeTicks window_start, - base::TimeTicks window_end) { - DCHECK(task_start <= task_end); - DCHECK(task_start <= window_end); - DCHECK(window_start < window_end); - DCHECK(task_end >= window_start); - base::TimeTicks task_in_window_start_time = - std::max(task_start, window_start); - base::TimeTicks task_in_window_end_time = - std::min(task_end, window_end); - DCHECK(task_in_window_end_time <= task_in_window_end_time); - - double probability_of_this_task = - static_cast<double>((task_in_window_end_time - task_in_window_start_time) - .InMicroseconds()) / - (window_end - window_start).InMicroseconds(); - - base::TimeDelta expected_queueing_duration_within_task = - ((task_end - task_in_window_start_time) + - (task_end - task_in_window_end_time)) / - 2; - - return base::TimeDelta::FromMillisecondsD( - probability_of_this_task * - expected_queueing_duration_within_task.InMillisecondsF()); -} - -} // namespace - -QueueingTimeEstimator::QueueingTimeEstimator( - QueueingTimeEstimator::Client* client, - base::TimeDelta window_duration) - : client_(client), - window_duration_(window_duration), - window_start_time_() {} - -void QueueingTimeEstimator::OnToplevelTaskCompleted( - base::TimeTicks task_start_time, - base::TimeTicks task_end_time) { - if (window_start_time_.is_null()) - window_start_time_ = task_start_time; - - while (TimePastWindowEnd(task_end_time)) { - if (!TimePastWindowEnd(task_start_time)) { - // Include the current task in this window. - current_expected_queueing_time_ += ExpectedQueueingTimeFromTask( - task_start_time, task_end_time, window_start_time_, - window_start_time_ + window_duration_); - } - client_->OnQueueingTimeForWindowEstimated(current_expected_queueing_time_); - window_start_time_ += window_duration_; - current_expected_queueing_time_ = base::TimeDelta(); - } - - current_expected_queueing_time_ += ExpectedQueueingTimeFromTask( - task_start_time, task_end_time, window_start_time_, - window_start_time_ + window_duration_); -} - -bool QueueingTimeEstimator::TimePastWindowEnd(base::TimeTicks time) { - return time > window_start_time_ + window_duration_; -} - -} // namespace scheduler
diff --git a/components/scheduler/base/queueing_time_estimator.h b/components/scheduler/base/queueing_time_estimator.h deleted file mode 100644 index 2d302ea..0000000 --- a/components/scheduler/base/queueing_time_estimator.h +++ /dev/null
@@ -1,53 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_RENDERER_QUEUEING_TIME_ESTIMATOR_H_ -#define COMPONENTS_SCHEDULER_RENDERER_QUEUEING_TIME_ESTIMATOR_H_ - -#include "base/macros.h" -#include "base/message_loop/message_loop.h" -#include "base/time/time.h" -#include "components/scheduler/scheduler_export.h" - -namespace base { -class TickClock; -} - -namespace scheduler { - -// Records the expected queueing time for a high priority task occurring -// randomly during each interval of length |window_duration|. -class SCHEDULER_EXPORT QueueingTimeEstimator { - public: - class SCHEDULER_EXPORT Client { - public: - virtual void OnQueueingTimeForWindowEstimated( - base::TimeDelta queueing_time) = 0; - Client() {} - virtual ~Client() {} - - private: - DISALLOW_COPY_AND_ASSIGN(Client); - }; - - QueueingTimeEstimator(Client* client, - base::TimeDelta window_duration); - - void OnToplevelTaskCompleted(base::TimeTicks task_start_time, - base::TimeTicks task_end_time); - - private: - bool TimePastWindowEnd(base::TimeTicks task_end_time); - Client* client_; // NOT OWNED. - - base::TimeDelta current_expected_queueing_time_; - base::TimeDelta window_duration_; - base::TimeTicks window_start_time_; - - DISALLOW_COPY_AND_ASSIGN(QueueingTimeEstimator); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_RENDERER_QUEUEING_TIME_ESTIMATOR_H_
diff --git a/components/scheduler/base/queueing_time_estimator_unittest.cc b/components/scheduler/base/queueing_time_estimator_unittest.cc deleted file mode 100644 index c9df20b29..0000000 --- a/components/scheduler/base/queueing_time_estimator_unittest.cc +++ /dev/null
@@ -1,94 +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 "components/scheduler/base/queueing_time_estimator.h" -#include "components/scheduler/base/test_time_source.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace scheduler { - -using QueueingTimeEstimatorTest = testing::Test; - -class TestQueueingTimeEstimatorClient - : public QueueingTimeEstimator::Client { - public: - void OnQueueingTimeForWindowEstimated( - base::TimeDelta queueing_time) override { - expected_queueing_times_.push_back(queueing_time); - } - const std::vector<base::TimeDelta>& expected_queueing_times() { - return expected_queueing_times_; - } - - private: - std::vector<base::TimeDelta> expected_queueing_times_; -}; - -class QueueingTimeEstimatorForTest : public QueueingTimeEstimator { - public: - QueueingTimeEstimatorForTest(TestQueueingTimeEstimatorClient* client, - base::TimeDelta window_duration) - : QueueingTimeEstimator(client, window_duration) {} -}; - -// Three tasks of one second each, all within a 5 second window. Expected -// queueing time is the probability of falling into one of these tasks (3/5), -// multiplied by the expected queueing time within a task (0.5 seconds). Thus we -// expect a queueing time of 0.3 seconds. -TEST_F(QueueingTimeEstimatorTest, AllTasksWithinWindow) { - base::TimeTicks time; - TestQueueingTimeEstimatorClient client; - QueueingTimeEstimatorForTest estimator(&client, - base::TimeDelta::FromSeconds(5)); - for (int i = 0; i < 3; ++i) { - estimator.OnToplevelTaskCompleted( - time, time + base::TimeDelta::FromMilliseconds(1000)); - time += base::TimeDelta::FromMilliseconds(1500); - } - - // Flush the data by adding a task in the next window. - time += base::TimeDelta::FromMilliseconds(5000); - estimator.OnToplevelTaskCompleted( - time, time + base::TimeDelta::FromMilliseconds(500)); - - EXPECT_THAT(client.expected_queueing_times(), - testing::ElementsAre(base::TimeDelta::FromMilliseconds(300))); -} - -// One 20 second long task, starting 3 seconds into the first window. -// Window 1: Probability of being within task = 2/5. Expected delay within task: -// avg(20, 18). Total expected queueing time = 7.6s. -// Window 2: Probability of being within task = 1. Expected delay within task: -// avg(18, 13). Total expected queueing time = 15.5s. -// Window 5: Probability of being within task = 3/5. Expected delay within task: -// avg(3, 0). Total expected queueing time = 0.9s. -TEST_F(QueueingTimeEstimatorTest, MultiWindowTask) { - TestQueueingTimeEstimatorClient client; - QueueingTimeEstimatorForTest estimator(&client, - base::TimeDelta::FromSeconds(5)); - base::TimeTicks time; - time += base::TimeDelta::FromMilliseconds(5000); - estimator.OnToplevelTaskCompleted(time, time); - - time += base::TimeDelta::FromMilliseconds(3000); - - estimator.OnToplevelTaskCompleted( - time, time + base::TimeDelta::FromMilliseconds(20000)); - - // Flush the data by adding a task in the next window. - time += base::TimeDelta::FromMilliseconds(25000); - - estimator.OnToplevelTaskCompleted( - time, time + base::TimeDelta::FromMilliseconds(500)); - - EXPECT_THAT(client.expected_queueing_times(), - testing::ElementsAre(base::TimeDelta::FromMilliseconds(7600), - base::TimeDelta::FromMilliseconds(15500), - base::TimeDelta::FromMilliseconds(10500), - base::TimeDelta::FromMilliseconds(5500), - base::TimeDelta::FromMilliseconds(900))); -} - -} // namespace scheduler
diff --git a/components/scheduler/base/real_time_domain.cc b/components/scheduler/base/real_time_domain.cc deleted file mode 100644 index a452b97..0000000 --- a/components/scheduler/base/real_time_domain.cc +++ /dev/null
@@ -1,73 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/base/real_time_domain.h" - -#include "base/bind.h" -#include "components/scheduler/base/task_queue_impl.h" -#include "components/scheduler/base/task_queue_manager.h" -#include "components/scheduler/base/task_queue_manager_delegate.h" - -namespace scheduler { - -RealTimeDomain::RealTimeDomain(const char* tracing_category) - : TimeDomain(nullptr), - tracing_category_(tracing_category), - task_queue_manager_(nullptr) {} - -RealTimeDomain::RealTimeDomain(TimeDomain::Observer* observer, - const char* tracing_category) - : TimeDomain(observer), - tracing_category_(tracing_category), - task_queue_manager_(nullptr) {} - -RealTimeDomain::~RealTimeDomain() {} - -void RealTimeDomain::OnRegisterWithTaskQueueManager( - TaskQueueManager* task_queue_manager) { - task_queue_manager_ = task_queue_manager; - DCHECK(task_queue_manager_); -} - -LazyNow RealTimeDomain::CreateLazyNow() const { - return task_queue_manager_->CreateLazyNow(); -} - -base::TimeTicks RealTimeDomain::Now() const { - return task_queue_manager_->delegate()->NowTicks(); -} - -void RealTimeDomain::RequestWakeup(base::TimeTicks now, base::TimeDelta delay) { - // NOTE this is only called if the scheduled runtime is sooner than any - // previously scheduled runtime, or there is no (outstanding) previously - // scheduled runtime. - task_queue_manager_->MaybeScheduleDelayedWork(FROM_HERE, now, delay); -} - -bool RealTimeDomain::MaybeAdvanceTime() { - base::TimeTicks next_run_time; - if (!NextScheduledRunTime(&next_run_time)) - return false; - - base::TimeTicks now = Now(); - if (now >= next_run_time) - return true; // Causes DoWork to post a continuation. - - base::TimeDelta delay = next_run_time - now; - TRACE_EVENT1(tracing_category_, "RealTimeDomain::MaybeAdvanceTime", - "delay_ms", delay.InMillisecondsF()); - - // The next task is sometime in the future, make sure we schedule a DoWork to - // run it. - task_queue_manager_->MaybeScheduleDelayedWork(FROM_HERE, now, delay); - return false; -} - -void RealTimeDomain::AsValueIntoInternal( - base::trace_event::TracedValue* state) const {} - -const char* RealTimeDomain::GetName() const { - return "RealTimeDomain"; -} -} // namespace scheduler
diff --git a/components/scheduler/base/real_time_domain.h b/components/scheduler/base/real_time_domain.h deleted file mode 100644 index fa20ba7..0000000 --- a/components/scheduler/base/real_time_domain.h +++ /dev/null
@@ -1,44 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_BASE_REAL_TIME_DOMAIN_H_ -#define COMPONENTS_SCHEDULER_BASE_REAL_TIME_DOMAIN_H_ - -#include <set> - -#include "base/macros.h" -#include "components/scheduler/base/time_domain.h" -#include "components/scheduler/scheduler_export.h" - -namespace scheduler { - -class SCHEDULER_EXPORT RealTimeDomain : public TimeDomain { - public: - explicit RealTimeDomain(const char* tracing_category); - RealTimeDomain(TimeDomain::Observer* observer, const char* tracing_category); - ~RealTimeDomain() override; - - // TimeDomain implementation: - LazyNow CreateLazyNow() const override; - base::TimeTicks Now() const override; - bool MaybeAdvanceTime() override; - const char* GetName() const override; - - protected: - void OnRegisterWithTaskQueueManager( - TaskQueueManager* task_queue_manager) override; - void RequestWakeup(base::TimeTicks now, base::TimeDelta delay) override; - void AsValueIntoInternal( - base::trace_event::TracedValue* state) const override; - - private: - const char* tracing_category_; // NOT OWNED - TaskQueueManager* task_queue_manager_; // NOT OWNED - - DISALLOW_COPY_AND_ASSIGN(RealTimeDomain); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_BASE_REAL_TIME_DOMAIN_H_
diff --git a/components/scheduler/base/task_queue.h b/components/scheduler/base/task_queue.h deleted file mode 100644 index b3a3163..0000000 --- a/components/scheduler/base/task_queue.h +++ /dev/null
@@ -1,216 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_BASE_TASK_QUEUE_H_ -#define COMPONENTS_SCHEDULER_BASE_TASK_QUEUE_H_ - -#include "base/macros.h" -#include "base/message_loop/message_loop.h" -#include "base/single_thread_task_runner.h" -#include "base/trace_event/trace_event.h" -#include "components/scheduler/scheduler_export.h" - -namespace base { -namespace trace_event { -class BlameContext; -} -} - -namespace scheduler { -class LazyNow; -class TimeDomain; - -class SCHEDULER_EXPORT TaskQueue : public base::SingleThreadTaskRunner { - public: - TaskQueue() {} - - // Unregisters the task queue after which no tasks posted to it will run and - // the TaskQueueManager's reference to it will be released soon. - virtual void UnregisterTaskQueue() = 0; - - enum QueuePriority { - // Queues with control priority will run before any other queue, and will - // explicitly starve other queues. Typically this should only be used for - // private queues which perform control operations. - CONTROL_PRIORITY, - // Queues with high priority will be selected preferentially over normal or - // best effort queues. The selector will ensure that high priority queues - // cannot completely starve normal priority queues. - HIGH_PRIORITY, - // Queues with normal priority are the default. - NORMAL_PRIORITY, - // Queues with best effort priority will only be run if all other queues are - // empty. They can be starved by the other queues. - BEST_EFFORT_PRIORITY, - // Must be the last entry. - QUEUE_PRIORITY_COUNT, - FIRST_QUEUE_PRIORITY = CONTROL_PRIORITY, - }; - - // Keep TaskQueue::PumpPolicyToString in sync with this enum. - enum class PumpPolicy { - // Tasks posted to an incoming queue with an AUTO pump policy will be - // automatically scheduled for execution or transferred to the work queue - // automatically. - AUTO, - // Tasks posted to an incoming queue with an AFTER_WAKEUP pump policy - // will be scheduled for execution or transferred to the work queue - // automatically but only after another queue has executed a task. - AFTER_WAKEUP, - // Tasks posted to an incoming queue with a MANUAL will not be - // automatically scheduled for execution or transferred to the work queue. - // Instead, the selector should call PumpQueue() when necessary to bring - // in new tasks for execution. - MANUAL, - // Must be last entry. - PUMP_POLICY_COUNT, - FIRST_PUMP_POLICY = AUTO, - }; - - // Keep TaskQueue::WakeupPolicyToString in sync with this enum. - enum class WakeupPolicy { - // Tasks run on a queue with CAN_WAKE_OTHER_QUEUES wakeup policy can - // cause queues with the AFTER_WAKEUP PumpPolicy to be woken up. - CAN_WAKE_OTHER_QUEUES, - // Tasks run on a queue with DONT_WAKE_OTHER_QUEUES won't cause queues - // with the AFTER_WAKEUP PumpPolicy to be woken up. - DONT_WAKE_OTHER_QUEUES, - // Must be last entry. - WAKEUP_POLICY_COUNT, - FIRST_WAKEUP_POLICY = CAN_WAKE_OTHER_QUEUES, - }; - - // Options for constructing a TaskQueue. Once set the |name|, - // |should_monitor_quiescence| and |wakeup_policy| are immutable. The - // |pump_policy| can be mutated with |SetPumpPolicy()|. - struct Spec { - // Note |name| must have application lifetime. - explicit Spec(const char* name) - : name(name), - should_monitor_quiescence(false), - pump_policy(TaskQueue::PumpPolicy::AUTO), - wakeup_policy(TaskQueue::WakeupPolicy::CAN_WAKE_OTHER_QUEUES), - time_domain(nullptr), - should_notify_observers(true), - should_report_when_execution_blocked(false) {} - - Spec SetShouldMonitorQuiescence(bool should_monitor) { - should_monitor_quiescence = should_monitor; - return *this; - } - - Spec SetPumpPolicy(PumpPolicy policy) { - pump_policy = policy; - return *this; - } - - Spec SetWakeupPolicy(WakeupPolicy policy) { - wakeup_policy = policy; - return *this; - } - - Spec SetShouldNotifyObservers(bool run_observers) { - should_notify_observers = run_observers; - return *this; - } - - Spec SetTimeDomain(TimeDomain* domain) { - time_domain = domain; - return *this; - } - - // See TaskQueueManager::Observer::OnTriedToExecuteBlockedTask. - Spec SetShouldReportWhenExecutionBlocked(bool should_report) { - should_report_when_execution_blocked = should_report; - return *this; - } - - const char* name; - bool should_monitor_quiescence; - TaskQueue::PumpPolicy pump_policy; - TaskQueue::WakeupPolicy wakeup_policy; - TimeDomain* time_domain; - bool should_notify_observers; - bool should_report_when_execution_blocked; - }; - - // Enable or disable task execution for this queue. NOTE this must be called - // on the thread this TaskQueue was created by. - virtual void SetQueueEnabled(bool enabled) = 0; - - // NOTE this must be called on the thread this TaskQueue was created by. - virtual bool IsQueueEnabled() const = 0; - - // Returns true if the queue is completely empty. - virtual bool IsEmpty() const = 0; - - // Returns true if the queue has work that's ready to execute now, or if it - // would have if the queue was pumped. NOTE this must be called on the thread - // this TaskQueue was created by. - virtual bool HasPendingImmediateWork() const = 0; - - // Returns true if tasks can't run now but could if the queue was pumped. - virtual bool NeedsPumping() const = 0; - - // Can be called on any thread. - virtual const char* GetName() const = 0; - - // Set the priority of the queue to |priority|. NOTE this must be called on - // the thread this TaskQueue was created by. - virtual void SetQueuePriority(QueuePriority priority) = 0; - - // Returns the current queue priority. - virtual QueuePriority GetQueuePriority() const = 0; - - // Set the pumping policy of the queue to |pump_policy|. NOTE this must be - // called on the thread this TaskQueue was created by. - virtual void SetPumpPolicy(PumpPolicy pump_policy) = 0; - - // Returns the current PumpPolicy. NOTE this must be called on the thread this - // TaskQueue was created by. - virtual PumpPolicy GetPumpPolicy() const = 0; - - // Reloads new tasks from the incoming queue into the work queue, regardless - // of whether the work queue is empty or not. After this, the function ensures - // that the tasks in the work queue, if any, are scheduled for execution. - // - // This function only needs to be called if automatic pumping is disabled. - // By default automatic pumping is enabled for all queues. NOTE this must be - // called on the thread this TaskQueue was created by. - // - // The |may_post_dowork| parameter controls whether or not PumpQueue calls - // TaskQueueManager::MaybeScheduleImmediateWork. - // TODO(alexclarke): Add a base::RunLoop observer so we can get rid of - // |may_post_dowork|. - virtual void PumpQueue(LazyNow* lazy_now, bool may_post_dowork) = 0; - - // These functions can only be called on the same thread that the task queue - // manager executes its tasks on. - virtual void AddTaskObserver( - base::MessageLoop::TaskObserver* task_observer) = 0; - virtual void RemoveTaskObserver( - base::MessageLoop::TaskObserver* task_observer) = 0; - - // Set the blame context which is entered and left while executing tasks from - // this task queue. |blame_context| must be null or outlive this task queue. - // Must be called on the thread this TaskQueue was created by. - virtual void SetBlameContext( - base::trace_event::BlameContext* blame_context) = 0; - - // Removes the task queue from the previous TimeDomain and adds it to - // |domain|. This is a moderately expensive operation. - virtual void SetTimeDomain(TimeDomain* domain) = 0; - - // Returns the queue's current TimeDomain. Can be called from any thread. - virtual TimeDomain* GetTimeDomain() const = 0; - - protected: - ~TaskQueue() override {} - - DISALLOW_COPY_AND_ASSIGN(TaskQueue); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_BASE_TASK_QUEUE_H_
diff --git a/components/scheduler/base/task_queue_impl.cc b/components/scheduler/base/task_queue_impl.cc deleted file mode 100644 index 7d684fb..0000000 --- a/components/scheduler/base/task_queue_impl.cc +++ /dev/null
@@ -1,717 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/base/task_queue_impl.h" - -#include "base/trace_event/blame_context.h" -#include "components/scheduler/base/task_queue_manager.h" -#include "components/scheduler/base/task_queue_manager_delegate.h" -#include "components/scheduler/base/time_domain.h" -#include "components/scheduler/base/work_queue.h" - -namespace scheduler { -namespace internal { - -TaskQueueImpl::TaskQueueImpl( - TaskQueueManager* task_queue_manager, - TimeDomain* time_domain, - const Spec& spec, - const char* disabled_by_default_tracing_category, - const char* disabled_by_default_verbose_tracing_category) - : thread_id_(base::PlatformThread::CurrentId()), - any_thread_(task_queue_manager, spec.pump_policy, time_domain), - name_(spec.name), - disabled_by_default_tracing_category_( - disabled_by_default_tracing_category), - disabled_by_default_verbose_tracing_category_( - disabled_by_default_verbose_tracing_category), - main_thread_only_(task_queue_manager, - spec.pump_policy, - this, - time_domain), - wakeup_policy_(spec.wakeup_policy), - should_monitor_quiescence_(spec.should_monitor_quiescence), - should_notify_observers_(spec.should_notify_observers), - should_report_when_execution_blocked_( - spec.should_report_when_execution_blocked) { - DCHECK(time_domain); - time_domain->RegisterQueue(this); -} - -TaskQueueImpl::~TaskQueueImpl() { -#if DCHECK_IS_ON() - base::AutoLock lock(any_thread_lock_); - // NOTE this check shouldn't fire because |TaskQueueManager::queues_| - // contains a strong reference to this TaskQueueImpl and the TaskQueueManager - // destructor calls UnregisterTaskQueue on all task queues. - DCHECK(any_thread().task_queue_manager == nullptr) - << "UnregisterTaskQueue must be called first!"; - -#endif -} - -TaskQueueImpl::Task::Task() - : PendingTask(tracked_objects::Location(), - base::Closure(), - base::TimeTicks(), - true), -#ifndef NDEBUG - enqueue_order_set_(false), -#endif - enqueue_order_(0) { - sequence_num = 0; -} - -TaskQueueImpl::Task::Task(const tracked_objects::Location& posted_from, - const base::Closure& task, - base::TimeTicks desired_run_time, - EnqueueOrder sequence_number, - bool nestable) - : PendingTask(posted_from, task, desired_run_time, nestable), -#ifndef NDEBUG - enqueue_order_set_(false), -#endif - enqueue_order_(0) { - sequence_num = sequence_number; -} - -TaskQueueImpl::Task::Task(const tracked_objects::Location& posted_from, - const base::Closure& task, - base::TimeTicks desired_run_time, - EnqueueOrder sequence_number, - bool nestable, - EnqueueOrder enqueue_order) - : PendingTask(posted_from, task, desired_run_time, nestable), -#ifndef NDEBUG - enqueue_order_set_(true), -#endif - enqueue_order_(enqueue_order) { - sequence_num = sequence_number; -} - -TaskQueueImpl::AnyThread::AnyThread(TaskQueueManager* task_queue_manager, - PumpPolicy pump_policy, - TimeDomain* time_domain) - : task_queue_manager(task_queue_manager), - pump_policy(pump_policy), - time_domain(time_domain) {} - -TaskQueueImpl::AnyThread::~AnyThread() {} - -TaskQueueImpl::MainThreadOnly::MainThreadOnly( - TaskQueueManager* task_queue_manager, - PumpPolicy pump_policy, - TaskQueueImpl* task_queue, - TimeDomain* time_domain) - : task_queue_manager(task_queue_manager), - pump_policy(pump_policy), - time_domain(time_domain), - delayed_work_queue(new WorkQueue(task_queue, "delayed")), - immediate_work_queue(new WorkQueue(task_queue, "immediate")), - set_index(0), - is_enabled(true), - blame_context(nullptr) {} - -TaskQueueImpl::MainThreadOnly::~MainThreadOnly() {} - -void TaskQueueImpl::UnregisterTaskQueue() { - base::AutoLock lock(any_thread_lock_); - if (main_thread_only().time_domain) - main_thread_only().time_domain->UnregisterQueue(this); - if (!any_thread().task_queue_manager) - return; - any_thread().time_domain = nullptr; - main_thread_only().time_domain = nullptr; - any_thread().task_queue_manager->UnregisterTaskQueue(this); - - any_thread().task_queue_manager = nullptr; - main_thread_only().task_queue_manager = nullptr; - main_thread_only().delayed_incoming_queue = std::priority_queue<Task>(); - any_thread().immediate_incoming_queue = std::queue<Task>(); - main_thread_only().immediate_work_queue.reset(); - main_thread_only().delayed_work_queue.reset(); -} - -bool TaskQueueImpl::RunsTasksOnCurrentThread() const { - base::AutoLock lock(any_thread_lock_); - return base::PlatformThread::CurrentId() == thread_id_; -} - -bool TaskQueueImpl::PostDelayedTask(const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) { - if (delay.is_zero()) - return PostImmediateTaskImpl(from_here, task, TaskType::NORMAL); - - return PostDelayedTaskImpl(from_here, task, delay, TaskType::NORMAL); -} - -bool TaskQueueImpl::PostNonNestableDelayedTask( - const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) { - if (delay.is_zero()) - return PostImmediateTaskImpl(from_here, task, TaskType::NON_NESTABLE); - - return PostDelayedTaskImpl(from_here, task, delay, TaskType::NON_NESTABLE); -} - -bool TaskQueueImpl::PostImmediateTaskImpl( - const tracked_objects::Location& from_here, - const base::Closure& task, - TaskType task_type) { - base::AutoLock lock(any_thread_lock_); - if (!any_thread().task_queue_manager) - return false; - - EnqueueOrder sequence_number = - any_thread().task_queue_manager->GetNextSequenceNumber(); - - PushOntoImmediateIncomingQueueLocked( - Task(from_here, task, base::TimeTicks(), sequence_number, - task_type != TaskType::NON_NESTABLE, sequence_number)); - return true; -} - -bool TaskQueueImpl::PostDelayedTaskImpl( - const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay, - TaskType task_type) { - DCHECK_GT(delay, base::TimeDelta()); - if (base::PlatformThread::CurrentId() == thread_id_) { - // Lock-free fast path for delayed tasks posted from the main thread. - if (!main_thread_only().task_queue_manager) - return false; - - EnqueueOrder sequence_number = - main_thread_only().task_queue_manager->GetNextSequenceNumber(); - - base::TimeTicks time_domain_now = main_thread_only().time_domain->Now(); - base::TimeTicks time_domain_delayed_run_time = time_domain_now + delay; - PushOntoDelayedIncomingQueueFromMainThread( - Task(from_here, task, time_domain_delayed_run_time, sequence_number, - task_type != TaskType::NON_NESTABLE), - time_domain_now); - } else { - // NOTE posting a delayed task from a different thread is not expected to - // be common. This pathway is less optimal than perhaps it could be - // because it causes two main thread tasks to be run. Should this - // assumption prove to be false in future, we may need to revisit this. - base::AutoLock lock(any_thread_lock_); - if (!any_thread().task_queue_manager) - return false; - - EnqueueOrder sequence_number = - any_thread().task_queue_manager->GetNextSequenceNumber(); - - base::TimeTicks time_domain_now = any_thread().time_domain->Now(); - base::TimeTicks time_domain_delayed_run_time = time_domain_now + delay; - PushOntoDelayedIncomingQueueLocked( - Task(from_here, task, time_domain_delayed_run_time, sequence_number, - task_type != TaskType::NON_NESTABLE)); - } - return true; -} - -void TaskQueueImpl::PushOntoDelayedIncomingQueueFromMainThread( - Task pending_task, - base::TimeTicks now) { - main_thread_only().task_queue_manager->DidQueueTask(pending_task); - - // Schedule a later call to MoveReadyDelayedTasksToDelayedWorkQueue. - base::TimeTicks delayed_run_time = pending_task.delayed_run_time; - main_thread_only().delayed_incoming_queue.push(std::move(pending_task)); - main_thread_only().time_domain->ScheduleDelayedWork( - this, delayed_run_time, now); - TraceQueueSize(false); -} - -void TaskQueueImpl::PushOntoDelayedIncomingQueueLocked(Task pending_task) { - any_thread().task_queue_manager->DidQueueTask(pending_task); - - int thread_hop_task_sequence_number = - any_thread().task_queue_manager->GetNextSequenceNumber(); - PushOntoImmediateIncomingQueueLocked(Task( - FROM_HERE, - base::Bind(&TaskQueueImpl::ScheduleDelayedWorkTask, this, - base::Passed(&pending_task)), - base::TimeTicks(), thread_hop_task_sequence_number, false, - thread_hop_task_sequence_number)); -} - -void TaskQueueImpl::PushOntoImmediateIncomingQueueLocked(Task pending_task) { - if (any_thread().immediate_incoming_queue.empty()) - any_thread().time_domain->RegisterAsUpdatableTaskQueue(this); - if (any_thread().pump_policy == PumpPolicy::AUTO && - any_thread().immediate_incoming_queue.empty()) { - any_thread().task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE); - } - any_thread().task_queue_manager->DidQueueTask(pending_task); - any_thread().immediate_incoming_queue.push(std::move(pending_task)); - TraceQueueSize(true); -} - -void TaskQueueImpl::ScheduleDelayedWorkTask(Task pending_task) { - DCHECK(main_thread_checker_.CalledOnValidThread()); - base::TimeTicks delayed_run_time = pending_task.delayed_run_time; - main_thread_only().delayed_incoming_queue.push(std::move(pending_task)); - main_thread_only().time_domain->ScheduleDelayedWork( - this, delayed_run_time, - main_thread_only().time_domain->Now()); -} - -void TaskQueueImpl::SetQueueEnabled(bool enabled) { - if (main_thread_only().is_enabled == enabled) - return; - main_thread_only().is_enabled = enabled; - if (!main_thread_only().task_queue_manager) - return; - if (enabled) { - main_thread_only().task_queue_manager->selector_.EnableQueue(this); - } else { - main_thread_only().task_queue_manager->selector_.DisableQueue(this); - } -} - -bool TaskQueueImpl::IsQueueEnabled() const { - return main_thread_only().is_enabled; -} - -bool TaskQueueImpl::IsEmpty() const { - if (!main_thread_only().delayed_work_queue->Empty() || - !main_thread_only().immediate_work_queue->Empty()) { - return false; - } - - base::AutoLock lock(any_thread_lock_); - return any_thread().immediate_incoming_queue.empty() && - main_thread_only().delayed_incoming_queue.empty(); -} - -bool TaskQueueImpl::HasPendingImmediateWork() const { - if (!main_thread_only().delayed_work_queue->Empty() || - !main_thread_only().immediate_work_queue->Empty()) { - return true; - } - - return NeedsPumping(); -} - -bool TaskQueueImpl::NeedsPumping() const { - if (!main_thread_only().immediate_work_queue->Empty()) - return false; - - base::AutoLock lock(any_thread_lock_); - if (!any_thread().immediate_incoming_queue.empty()) - return true; - - // If there's no immediate Incoming work then we only need pumping if there - // is a delayed task that should be running now. - if (main_thread_only().delayed_incoming_queue.empty()) - return false; - - return main_thread_only().delayed_incoming_queue.top().delayed_run_time <= - main_thread_only().time_domain->CreateLazyNow().Now(); -} - -bool TaskQueueImpl::TaskIsOlderThanQueuedImmediateTasksLocked( - const Task* task) { - // A null task is passed when UpdateQueue is called before any task is run. - // In this case we don't want to pump an after_wakeup queue, so return true - // here. - if (!task) - return true; - - // Return false if task is newer than the oldest immediate task. - if (!any_thread().immediate_incoming_queue.empty() && - task->enqueue_order() > - any_thread().immediate_incoming_queue.front().enqueue_order()) { - return false; - } - return true; -} - -bool TaskQueueImpl::TaskIsOlderThanQueuedDelayedTasks(const Task* task) { - DCHECK(main_thread_checker_.CalledOnValidThread()); - // A null task is passed when UpdateQueue is called before any task is run. - // In this case we don't want to pump an after_wakeup queue, so return true - // here. - if (!task) - return true; - - EnqueueOrder enqueue_order; - if (!main_thread_only().delayed_work_queue->GetFrontTaskEnqueueOrder( - &enqueue_order)) { - return true; - } - - return task->enqueue_order() < enqueue_order; -} - -bool TaskQueueImpl::ShouldAutoPumpImmediateQueueLocked( - bool should_trigger_wakeup, - const Task* previous_task) { - if (main_thread_only().pump_policy == PumpPolicy::MANUAL) - return false; - if (main_thread_only().pump_policy == PumpPolicy::AFTER_WAKEUP && - (!should_trigger_wakeup || - TaskIsOlderThanQueuedImmediateTasksLocked(previous_task))) - return false; - return true; -} - -bool TaskQueueImpl::ShouldAutoPumpDelayedQueue(bool should_trigger_wakeup, - const Task* previous_task) { - if (main_thread_only().pump_policy == PumpPolicy::MANUAL) - return false; - if (main_thread_only().pump_policy == PumpPolicy::AFTER_WAKEUP && - (!should_trigger_wakeup || - TaskIsOlderThanQueuedDelayedTasks(previous_task))) - return false; - return true; -} - -void TaskQueueImpl::MoveReadyDelayedTasksToDelayedWorkQueue(LazyNow* lazy_now) { - // Enqueue all delayed tasks that should be running now. - while (!main_thread_only().delayed_incoming_queue.empty() && - main_thread_only().delayed_incoming_queue.top().delayed_run_time <= - lazy_now->Now()) { - // Note: the const_cast is needed because there is no direct way to move - // elements out of a priority queue. The queue must not be modified between - // the top() and the pop(). - main_thread_only().delayed_work_queue->PushAndSetEnqueueOrder( - std::move( - const_cast<Task&>(main_thread_only().delayed_incoming_queue.top())), - main_thread_only().task_queue_manager->GetNextSequenceNumber()); - main_thread_only().delayed_incoming_queue.pop(); - } -} - -void TaskQueueImpl::UpdateDelayedWorkQueue(LazyNow* lazy_now, - bool should_trigger_wakeup, - const Task* previous_task) { - if (!main_thread_only().task_queue_manager) - return; - if (!ShouldAutoPumpDelayedQueue(should_trigger_wakeup, previous_task)) - return; - MoveReadyDelayedTasksToDelayedWorkQueue(lazy_now); - TraceQueueSize(false); -} - -void TaskQueueImpl::UpdateImmediateWorkQueue(bool should_trigger_wakeup, - const Task* previous_task) { - DCHECK(main_thread_only().immediate_work_queue->Empty()); - base::AutoLock lock(any_thread_lock_); - if (!main_thread_only().task_queue_manager) - return; - if (!ShouldAutoPumpImmediateQueueLocked(should_trigger_wakeup, previous_task)) - return; - - main_thread_only().immediate_work_queue->SwapLocked( - any_thread().immediate_incoming_queue); - - // |any_thread().immediate_incoming_queue| is now empty so - // TimeDomain::UpdateQueues no longer needs to consider this queue for - // reloading. - main_thread_only().time_domain->UnregisterAsUpdatableTaskQueue(this); -} - -void TaskQueueImpl::TraceQueueSize(bool is_locked) const { - bool is_tracing; - TRACE_EVENT_CATEGORY_GROUP_ENABLED(disabled_by_default_tracing_category_, - &is_tracing); - if (!is_tracing) - return; - - // It's only safe to access the work queues from the main thread. - // TODO(alexclarke): We should find another way of tracing this - if (base::PlatformThread::CurrentId() != thread_id_) - return; - - if (!is_locked) - any_thread_lock_.Acquire(); - else - any_thread_lock_.AssertAcquired(); - TRACE_COUNTER1(disabled_by_default_tracing_category_, GetName(), - any_thread().immediate_incoming_queue.size() + - main_thread_only().immediate_work_queue->Size() + - main_thread_only().delayed_work_queue->Size() + - main_thread_only().delayed_incoming_queue.size()); - if (!is_locked) - any_thread_lock_.Release(); -} - -void TaskQueueImpl::SetPumpPolicy(PumpPolicy pump_policy) { - base::AutoLock lock(any_thread_lock_); - if (pump_policy == PumpPolicy::AUTO && - any_thread().pump_policy != PumpPolicy::AUTO) { - LazyNow lazy_now(main_thread_only().time_domain->CreateLazyNow()); - PumpQueueLocked(&lazy_now, true); - } - any_thread().pump_policy = pump_policy; - main_thread_only().pump_policy = pump_policy; -} - -TaskQueue::PumpPolicy TaskQueueImpl::GetPumpPolicy() const { - return main_thread_only().pump_policy; -} - -void TaskQueueImpl::PumpQueueLocked(LazyNow* lazy_now, bool may_post_dowork) { - TRACE_EVENT1(disabled_by_default_tracing_category_, - "TaskQueueImpl::PumpQueueLocked", "queue", name_); - TaskQueueManager* task_queue_manager = any_thread().task_queue_manager; - if (!task_queue_manager) - return; - - MoveReadyDelayedTasksToDelayedWorkQueue(lazy_now); - - while (!any_thread().immediate_incoming_queue.empty()) { - main_thread_only().immediate_work_queue->Push( - std::move(any_thread().immediate_incoming_queue.front())); - any_thread().immediate_incoming_queue.pop(); - } - - // |immediate_incoming_queue| is now empty so TimeDomain::UpdateQueues no - // longer needs to consider this queue for reloading. - main_thread_only().time_domain->UnregisterAsUpdatableTaskQueue(this); - - if (main_thread_only().immediate_work_queue->Empty() && - main_thread_only().delayed_work_queue->Empty()) { - return; - } - - if (may_post_dowork) - task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE); -} - -void TaskQueueImpl::PumpQueue(LazyNow* lazy_now, bool may_post_dowork) { - base::AutoLock lock(any_thread_lock_); - PumpQueueLocked(lazy_now, may_post_dowork); -} - -const char* TaskQueueImpl::GetName() const { - return name_; -} - -void TaskQueueImpl::SetQueuePriority(QueuePriority priority) { - if (!main_thread_only().task_queue_manager || priority == GetQueuePriority()) - return; - main_thread_only().task_queue_manager->selector_.SetQueuePriority(this, - priority); -} - -TaskQueueImpl::QueuePriority TaskQueueImpl::GetQueuePriority() const { - size_t set_index = immediate_work_queue()->work_queue_set_index(); - DCHECK_EQ(set_index, delayed_work_queue()->work_queue_set_index()); - return static_cast<TaskQueue::QueuePriority>(set_index); -} - -// static -const char* TaskQueueImpl::PumpPolicyToString( - TaskQueue::PumpPolicy pump_policy) { - switch (pump_policy) { - case TaskQueue::PumpPolicy::AUTO: - return "auto"; - case TaskQueue::PumpPolicy::AFTER_WAKEUP: - return "after_wakeup"; - case TaskQueue::PumpPolicy::MANUAL: - return "manual"; - default: - NOTREACHED(); - return nullptr; - } -} - -// static -const char* TaskQueueImpl::WakeupPolicyToString( - TaskQueue::WakeupPolicy wakeup_policy) { - switch (wakeup_policy) { - case TaskQueue::WakeupPolicy::CAN_WAKE_OTHER_QUEUES: - return "can_wake_other_queues"; - case TaskQueue::WakeupPolicy::DONT_WAKE_OTHER_QUEUES: - return "dont_wake_other_queues"; - default: - NOTREACHED(); - return nullptr; - } -} - -// static -const char* TaskQueueImpl::PriorityToString(QueuePriority priority) { - switch (priority) { - case CONTROL_PRIORITY: - return "control"; - case HIGH_PRIORITY: - return "high"; - case NORMAL_PRIORITY: - return "normal"; - case BEST_EFFORT_PRIORITY: - return "best_effort"; - default: - NOTREACHED(); - return nullptr; - } -} - -void TaskQueueImpl::AsValueInto(base::trace_event::TracedValue* state) const { - base::AutoLock lock(any_thread_lock_); - state->BeginDictionary(); - state->SetString("name", GetName()); - state->SetBoolean("enabled", main_thread_only().is_enabled); - state->SetString("time_domain_name", - main_thread_only().time_domain->GetName()); - state->SetString("pump_policy", PumpPolicyToString(any_thread().pump_policy)); - state->SetString("wakeup_policy", WakeupPolicyToString(wakeup_policy_)); - bool verbose_tracing_enabled = false; - TRACE_EVENT_CATEGORY_GROUP_ENABLED( - disabled_by_default_verbose_tracing_category_, &verbose_tracing_enabled); - state->SetInteger("immediate_incoming_queue_size", - any_thread().immediate_incoming_queue.size()); - state->SetInteger("delayed_incoming_queue_size", - main_thread_only().delayed_incoming_queue.size()); - state->SetInteger("immediate_work_queue_size", - main_thread_only().immediate_work_queue->Size()); - state->SetInteger("delayed_work_queue_size", - main_thread_only().delayed_work_queue->Size()); - if (!main_thread_only().delayed_incoming_queue.empty()) { - base::TimeDelta delay_to_next_task = - (main_thread_only().delayed_incoming_queue.top().delayed_run_time - - main_thread_only().time_domain->CreateLazyNow().Now()); - state->SetDouble("delay_to_next_task_ms", - delay_to_next_task.InMillisecondsF()); - } - if (verbose_tracing_enabled) { - state->BeginArray("immediate_incoming_queue"); - QueueAsValueInto(any_thread().immediate_incoming_queue, state); - state->EndArray(); - state->BeginArray("delayed_work_queue"); - main_thread_only().delayed_work_queue->AsValueInto(state); - state->EndArray(); - state->BeginArray("immediate_work_queue"); - main_thread_only().immediate_work_queue->AsValueInto(state); - state->EndArray(); - state->BeginArray("delayed_incoming_queue"); - QueueAsValueInto(main_thread_only().delayed_incoming_queue, state); - state->EndArray(); - } - state->SetString("priority", PriorityToString(GetQueuePriority())); - state->EndDictionary(); -} - -void TaskQueueImpl::AddTaskObserver( - base::MessageLoop::TaskObserver* task_observer) { - main_thread_only().task_observers.AddObserver(task_observer); -} - -void TaskQueueImpl::RemoveTaskObserver( - base::MessageLoop::TaskObserver* task_observer) { - main_thread_only().task_observers.RemoveObserver(task_observer); -} - -void TaskQueueImpl::NotifyWillProcessTask( - const base::PendingTask& pending_task) { - DCHECK(should_notify_observers_); - if (main_thread_only().blame_context) - main_thread_only().blame_context->Enter(); - FOR_EACH_OBSERVER(base::MessageLoop::TaskObserver, - main_thread_only().task_observers, - WillProcessTask(pending_task)); -} - -void TaskQueueImpl::NotifyDidProcessTask( - const base::PendingTask& pending_task) { - DCHECK(should_notify_observers_); - FOR_EACH_OBSERVER(base::MessageLoop::TaskObserver, - main_thread_only().task_observers, - DidProcessTask(pending_task)); - if (main_thread_only().blame_context) - main_thread_only().blame_context->Leave(); -} - -void TaskQueueImpl::SetTimeDomain(TimeDomain* time_domain) { - base::AutoLock lock(any_thread_lock_); - DCHECK(time_domain); - // NOTE this is similar to checking |any_thread().task_queue_manager| but the - // TaskQueueSelectorTests constructs TaskQueueImpl directly with a null - // task_queue_manager. Instead we check |any_thread().time_domain| which is - // another way of asserting that UnregisterTaskQueue has not been called. - DCHECK(any_thread().time_domain); - if (!any_thread().time_domain) - return; - DCHECK(main_thread_checker_.CalledOnValidThread()); - if (time_domain == main_thread_only().time_domain) - return; - - main_thread_only().time_domain->MigrateQueue(this, time_domain); - main_thread_only().time_domain = time_domain; - any_thread().time_domain = time_domain; -} - -TimeDomain* TaskQueueImpl::GetTimeDomain() const { - if (base::PlatformThread::CurrentId() == thread_id_) - return main_thread_only().time_domain; - - base::AutoLock lock(any_thread_lock_); - return any_thread().time_domain; -} - -void TaskQueueImpl::SetBlameContext( - base::trace_event::BlameContext* blame_context) { - main_thread_only().blame_context = blame_context; -} - -// static -void TaskQueueImpl::QueueAsValueInto(const std::queue<Task>& queue, - base::trace_event::TracedValue* state) { - // Remove const to search |queue| in the destructive manner. Restore the - // content from |visited| later. - std::queue<Task>* mutable_queue = const_cast<std::queue<Task>*>(&queue); - std::queue<Task> visited; - while (!mutable_queue->empty()) { - TaskAsValueInto(mutable_queue->front(), state); - visited.push(std::move(mutable_queue->front())); - mutable_queue->pop(); - } - *mutable_queue = std::move(visited); -} - -// static -void TaskQueueImpl::QueueAsValueInto(const std::priority_queue<Task>& queue, - base::trace_event::TracedValue* state) { - // Remove const to search |queue| in the destructive manner. Restore the - // content from |visited| later. - std::priority_queue<Task>* mutable_queue = - const_cast<std::priority_queue<Task>*>(&queue); - std::priority_queue<Task> visited; - while (!mutable_queue->empty()) { - TaskAsValueInto(mutable_queue->top(), state); - visited.push(std::move(const_cast<Task&>(mutable_queue->top()))); - mutable_queue->pop(); - } - *mutable_queue = std::move(visited); -} - -// static -void TaskQueueImpl::TaskAsValueInto(const Task& task, - base::trace_event::TracedValue* state) { - state->BeginDictionary(); - state->SetString("posted_from", task.posted_from.ToString()); -#ifndef NDEBUG - if (task.enqueue_order_set()) - state->SetInteger("enqueue_order", task.enqueue_order()); -#else - state->SetInteger("enqueue_order", task.enqueue_order()); -#endif - state->SetInteger("sequence_num", task.sequence_num); - state->SetBoolean("nestable", task.nestable); - state->SetBoolean("is_high_res", task.is_high_res); - state->SetDouble( - "delayed_run_time", - (task.delayed_run_time - base::TimeTicks()).InMicroseconds() / 1000.0L); - state->EndDictionary(); -} - -} // namespace internal -} // namespace scheduler
diff --git a/components/scheduler/base/task_queue_impl.h b/components/scheduler/base/task_queue_impl.h deleted file mode 100644 index 327cbd2..0000000 --- a/components/scheduler/base/task_queue_impl.h +++ /dev/null
@@ -1,309 +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 CONTENT_RENDERER_SCHEDULER_BASE_TASK_QUEUE_IMPL_H_ -#define CONTENT_RENDERER_SCHEDULER_BASE_TASK_QUEUE_IMPL_H_ - -#include <stddef.h> - -#include <memory> -#include <set> - -#include "base/macros.h" -#include "base/pending_task.h" -#include "base/threading/thread_checker.h" -#include "base/trace_event/trace_event.h" -#include "base/trace_event/trace_event_argument.h" -#include "components/scheduler/base/enqueue_order.h" -#include "components/scheduler/base/task_queue.h" -#include "components/scheduler/scheduler_export.h" - -namespace scheduler { -class LazyNow; -class TimeDomain; -class TaskQueueManager; - -namespace internal { -class WorkQueue; -class WorkQueueSets; - -class SCHEDULER_EXPORT TaskQueueImpl final : public TaskQueue { - public: - TaskQueueImpl(TaskQueueManager* task_queue_manager, - TimeDomain* time_domain, - const Spec& spec, - const char* disabled_by_default_tracing_category, - const char* disabled_by_default_verbose_tracing_category); - - class SCHEDULER_EXPORT Task : public base::PendingTask { - public: - Task(); - Task(const tracked_objects::Location& posted_from, - const base::Closure& task, - base::TimeTicks desired_run_time, - EnqueueOrder sequence_number, - bool nestable); - - Task(const tracked_objects::Location& posted_from, - const base::Closure& task, - base::TimeTicks desired_run_time, - EnqueueOrder sequence_number, - bool nestable, - EnqueueOrder enqueue_order); - - EnqueueOrder enqueue_order() const { -#ifndef NDEBUG - DCHECK(enqueue_order_set_); -#endif - return enqueue_order_; - } - - void set_enqueue_order(EnqueueOrder enqueue_order) { -#ifndef NDEBUG - DCHECK(!enqueue_order_set_); - enqueue_order_set_ = true; -#endif - enqueue_order_ = enqueue_order; - } - -#ifndef NDEBUG - bool enqueue_order_set() const { return enqueue_order_set_; } -#endif - - private: -#ifndef NDEBUG - bool enqueue_order_set_; -#endif - // Similar to sequence number, but the |enqueue_order| is set by - // EnqueueTasksLocked and is not initially defined for delayed tasks until - // they are enqueued on the |immediate_incoming_queue_|. - EnqueueOrder enqueue_order_; - }; - - // TaskQueue implementation. - void UnregisterTaskQueue() override; - bool RunsTasksOnCurrentThread() const override; - bool PostDelayedTask(const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) override; - bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) override; - - void SetQueueEnabled(bool enabled) override; - bool IsQueueEnabled() const override; - bool IsEmpty() const override; - bool HasPendingImmediateWork() const override; - bool NeedsPumping() const override; - void SetQueuePriority(QueuePriority priority) override; - QueuePriority GetQueuePriority() const override; - void PumpQueue(LazyNow* lazy_now, bool may_post_dowork) override; - void SetPumpPolicy(PumpPolicy pump_policy) override; - PumpPolicy GetPumpPolicy() const override; - void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer) override; - void RemoveTaskObserver( - base::MessageLoop::TaskObserver* task_observer) override; - void SetTimeDomain(TimeDomain* time_domain) override; - TimeDomain* GetTimeDomain() const override; - void SetBlameContext(base::trace_event::BlameContext* blame_context) override; - - void UpdateImmediateWorkQueue(bool should_trigger_wakeup, - const Task* previous_task); - void UpdateDelayedWorkQueue(LazyNow* lazy_now, - bool should_trigger_wakeup, - const Task* previous_task); - - WakeupPolicy wakeup_policy() const { - DCHECK(main_thread_checker_.CalledOnValidThread()); - return wakeup_policy_; - } - - const char* GetName() const override; - - void AsValueInto(base::trace_event::TracedValue* state) const; - - bool GetQuiescenceMonitored() const { return should_monitor_quiescence_; } - bool GetShouldNotifyObservers() const { - return should_notify_observers_; - } - - void NotifyWillProcessTask(const base::PendingTask& pending_task); - void NotifyDidProcessTask(const base::PendingTask& pending_task); - - // Can be called on any thread. - static const char* PumpPolicyToString(TaskQueue::PumpPolicy pump_policy); - - // Can be called on any thread. - static const char* WakeupPolicyToString( - TaskQueue::WakeupPolicy wakeup_policy); - - // Can be called on any thread. - static const char* PriorityToString(TaskQueue::QueuePriority priority); - - WorkQueue* delayed_work_queue() { - return main_thread_only().delayed_work_queue.get(); - } - - const WorkQueue* delayed_work_queue() const { - return main_thread_only().delayed_work_queue.get(); - } - - WorkQueue* immediate_work_queue() { - return main_thread_only().immediate_work_queue.get(); - } - - const WorkQueue* immediate_work_queue() const { - return main_thread_only().immediate_work_queue.get(); - } - - bool should_report_when_execution_blocked() const { - return should_report_when_execution_blocked_; - } - - private: - friend class WorkQueue; - - enum class TaskType { - NORMAL, - NON_NESTABLE, - }; - - struct AnyThread { - AnyThread(TaskQueueManager* task_queue_manager, - PumpPolicy pump_policy, - TimeDomain* time_domain); - ~AnyThread(); - - // TaskQueueManager, PumpPolicy and TimeDomain are maintained in two copies: - // inside AnyThread and inside MainThreadOnly. They can be changed only from - // main thread, so it should be locked before accessing from other threads. - TaskQueueManager* task_queue_manager; - PumpPolicy pump_policy; - TimeDomain* time_domain; - - std::queue<Task> immediate_incoming_queue; - }; - - struct MainThreadOnly { - MainThreadOnly(TaskQueueManager* task_queue_manager, - PumpPolicy pump_policy, - TaskQueueImpl* task_queue, - TimeDomain* time_domain); - ~MainThreadOnly(); - - // Another copy of TaskQueueManager, PumpPolicy and TimeDomain for lock-free - // access from the main thread. See description inside struct AnyThread for - // details. - TaskQueueManager* task_queue_manager; - PumpPolicy pump_policy; - TimeDomain* time_domain; - - std::unique_ptr<WorkQueue> delayed_work_queue; - std::unique_ptr<WorkQueue> immediate_work_queue; - std::priority_queue<Task> delayed_incoming_queue; - base::ObserverList<base::MessageLoop::TaskObserver> task_observers; - size_t set_index; - bool is_enabled; - base::trace_event::BlameContext* blame_context; // Not owned. - }; - - ~TaskQueueImpl() override; - - bool PostImmediateTaskImpl(const tracked_objects::Location& from_here, - const base::Closure& task, - TaskType task_type); - bool PostDelayedTaskImpl(const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay, - TaskType task_type); - - // Push the task onto the |delayed_incoming_queue|. Lock-free main thread - // only fast path. - void PushOntoDelayedIncomingQueueFromMainThread(Task pending_task, - base::TimeTicks now); - - // Push the task onto the |delayed_incoming_queue|. Slow path from other - // threads. - void PushOntoDelayedIncomingQueueLocked(Task pending_task); - - void ScheduleDelayedWorkTask(Task pending_task); - - // Enqueues any delayed tasks which should be run now on the - // |delayed_work_queue|. Must be called from the main thread. - void MoveReadyDelayedTasksToDelayedWorkQueue(LazyNow* lazy_now); - - void MoveReadyImmediateTasksToImmediateWorkQueueLocked(); - - // Note this does nothing if its not called from the main thread. - void PumpQueueLocked(LazyNow* lazy_now, bool may_post_dowork); - - // Returns true if |task| is older than the oldest incoming immediate task. - // NOTE |any_thread_lock_| must be locked. - bool TaskIsOlderThanQueuedImmediateTasksLocked(const Task* task); - - // Returns true if |task| is older than the oldest delayed task. Must be - // called from the main thread. - bool TaskIsOlderThanQueuedDelayedTasks(const Task* task); - - // NOTE |any_thread_lock_| must be locked. - bool ShouldAutoPumpImmediateQueueLocked(bool should_trigger_wakeup, - const Task* previous_task); - - // Must be called from the main thread. - bool ShouldAutoPumpDelayedQueue(bool should_trigger_wakeup, - const Task* previous_task); - - // Push the task onto the |immediate_incoming_queue| and for auto pumped - // queues it calls MaybePostDoWorkOnMainRunner if the Incoming queue was - // empty. - void PushOntoImmediateIncomingQueueLocked(Task pending_task); - - void TraceQueueSize(bool is_locked) const; - static void QueueAsValueInto(const std::queue<Task>& queue, - base::trace_event::TracedValue* state); - static void QueueAsValueInto(const std::priority_queue<Task>& queue, - base::trace_event::TracedValue* state); - static void TaskAsValueInto(const Task& task, - base::trace_event::TracedValue* state); - - const base::PlatformThreadId thread_id_; - - mutable base::Lock any_thread_lock_; - AnyThread any_thread_; - struct AnyThread& any_thread() { - any_thread_lock_.AssertAcquired(); - return any_thread_; - } - const struct AnyThread& any_thread() const { - any_thread_lock_.AssertAcquired(); - return any_thread_; - } - - const char* name_; - const char* disabled_by_default_tracing_category_; - const char* disabled_by_default_verbose_tracing_category_; - - base::ThreadChecker main_thread_checker_; - MainThreadOnly main_thread_only_; - MainThreadOnly& main_thread_only() { - DCHECK(main_thread_checker_.CalledOnValidThread()); - return main_thread_only_; - } - const MainThreadOnly& main_thread_only() const { - DCHECK(main_thread_checker_.CalledOnValidThread()); - return main_thread_only_; - } - - const WakeupPolicy wakeup_policy_; - const bool should_monitor_quiescence_; - const bool should_notify_observers_; - const bool should_report_when_execution_blocked_; - - DISALLOW_COPY_AND_ASSIGN(TaskQueueImpl); -}; - -} // namespace internal -} // namespace scheduler - -#endif // CONTENT_RENDERER_SCHEDULER_BASE_TASK_QUEUE_IMPL_H_
diff --git a/components/scheduler/base/task_queue_manager.cc b/components/scheduler/base/task_queue_manager.cc deleted file mode 100644 index 08eb782..0000000 --- a/components/scheduler/base/task_queue_manager.cc +++ /dev/null
@@ -1,442 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/base/task_queue_manager.h" - -#include <queue> -#include <set> - -#include "base/bind.h" -#include "base/metrics/histogram_macros.h" -#include "base/trace_event/trace_event.h" -#include "components/scheduler/base/real_time_domain.h" -#include "components/scheduler/base/task_queue_impl.h" -#include "components/scheduler/base/task_queue_manager_delegate.h" -#include "components/scheduler/base/task_queue_selector.h" -#include "components/scheduler/base/task_time_tracker.h" -#include "components/scheduler/base/work_queue.h" -#include "components/scheduler/base/work_queue_sets.h" - -namespace scheduler { - -namespace { -const size_t kRecordRecordTaskDelayHistogramsEveryNTasks = 10; - -void RecordDelayedTaskLateness(base::TimeDelta lateness) { - UMA_HISTOGRAM_TIMES("RendererScheduler.TaskQueueManager.DelayedTaskLateness", - lateness); -} - -void RecordImmediateTaskQueueingDuration(tracked_objects::Duration duration) { - UMA_HISTOGRAM_TIMES( - "RendererScheduler.TaskQueueManager.ImmediateTaskQueueingDuration", - base::TimeDelta::FromMilliseconds(duration.InMilliseconds())); -} -} - -TaskQueueManager::TaskQueueManager( - scoped_refptr<TaskQueueManagerDelegate> delegate, - const char* tracing_category, - const char* disabled_by_default_tracing_category, - const char* disabled_by_default_verbose_tracing_category) - : real_time_domain_(new RealTimeDomain(tracing_category)), - delegate_(delegate), - task_was_run_on_quiescence_monitored_queue_(false), - work_batch_size_(1), - task_count_(0), - task_time_tracker_(nullptr), - tracing_category_(tracing_category), - disabled_by_default_tracing_category_( - disabled_by_default_tracing_category), - disabled_by_default_verbose_tracing_category_( - disabled_by_default_verbose_tracing_category), - currently_executing_task_queue_(nullptr), - observer_(nullptr), - deletion_sentinel_(new DeletionSentinel()), - weak_factory_(this) { - DCHECK(delegate->RunsTasksOnCurrentThread()); - TRACE_EVENT_OBJECT_CREATED_WITH_ID(disabled_by_default_tracing_category, - "TaskQueueManager", this); - selector_.SetTaskQueueSelectorObserver(this); - - from_main_thread_immediate_do_work_closure_ = - base::Bind(&TaskQueueManager::DoWork, weak_factory_.GetWeakPtr(), - base::TimeTicks(), true); - from_other_thread_immediate_do_work_closure_ = - base::Bind(&TaskQueueManager::DoWork, weak_factory_.GetWeakPtr(), - base::TimeTicks(), false); - - // TODO(alexclarke): Change this to be a parameter that's passed in. - RegisterTimeDomain(real_time_domain_.get()); -} - -TaskQueueManager::~TaskQueueManager() { - TRACE_EVENT_OBJECT_DELETED_WITH_ID(disabled_by_default_tracing_category_, - "TaskQueueManager", this); - - while (!queues_.empty()) - (*queues_.begin())->UnregisterTaskQueue(); - - selector_.SetTaskQueueSelectorObserver(nullptr); -} - -void TaskQueueManager::RegisterTimeDomain(TimeDomain* time_domain) { - time_domains_.insert(time_domain); - time_domain->OnRegisterWithTaskQueueManager(this); -} - -void TaskQueueManager::UnregisterTimeDomain(TimeDomain* time_domain) { - time_domains_.erase(time_domain); -} - -scoped_refptr<internal::TaskQueueImpl> TaskQueueManager::NewTaskQueue( - const TaskQueue::Spec& spec) { - TRACE_EVENT1(tracing_category_, - "TaskQueueManager::NewTaskQueue", "queue_name", spec.name); - DCHECK(main_thread_checker_.CalledOnValidThread()); - TimeDomain* time_domain = - spec.time_domain ? spec.time_domain : real_time_domain_.get(); - DCHECK(time_domains_.find(time_domain) != time_domains_.end()); - scoped_refptr<internal::TaskQueueImpl> queue( - make_scoped_refptr(new internal::TaskQueueImpl( - this, time_domain, spec, disabled_by_default_tracing_category_, - disabled_by_default_verbose_tracing_category_))); - queues_.insert(queue); - selector_.AddQueue(queue.get()); - return queue; -} - -void TaskQueueManager::SetObserver(Observer* observer) { - DCHECK(main_thread_checker_.CalledOnValidThread()); - observer_ = observer; -} - -void TaskQueueManager::UnregisterTaskQueue( - scoped_refptr<internal::TaskQueueImpl> task_queue) { - TRACE_EVENT1(tracing_category_, - "TaskQueueManager::UnregisterTaskQueue", "queue_name", - task_queue->GetName()); - DCHECK(main_thread_checker_.CalledOnValidThread()); - if (observer_) - observer_->OnUnregisterTaskQueue(task_queue); - - // Add |task_queue| to |queues_to_delete_| so we can prevent it from being - // freed while any of our structures hold hold a raw pointer to it. - queues_to_delete_.insert(task_queue); - queues_.erase(task_queue); - selector_.RemoveQueue(task_queue.get()); -} - -void TaskQueueManager::UpdateWorkQueues( - bool should_trigger_wakeup, - const internal::TaskQueueImpl::Task* previous_task, - LazyNow lazy_now) { - TRACE_EVENT0(disabled_by_default_tracing_category_, - "TaskQueueManager::UpdateWorkQueues"); - - for (TimeDomain* time_domain : time_domains_) { - LazyNow lazy_now_in_domain = time_domain == real_time_domain_.get() - ? lazy_now - : time_domain->CreateLazyNow(); - time_domain->UpdateWorkQueues(should_trigger_wakeup, previous_task, - lazy_now_in_domain); - } -} - -void TaskQueueManager::MaybeScheduleImmediateWork( - const tracked_objects::Location& from_here) { - bool on_main_thread = delegate_->BelongsToCurrentThread(); - // De-duplicate DoWork posts. - if (on_main_thread) { - if (!main_thread_pending_wakeups_.insert(base::TimeTicks()).second) { - return; - } - delegate_->PostTask(from_here, from_main_thread_immediate_do_work_closure_); - } else { - { - base::AutoLock lock(other_thread_lock_); - if (!other_thread_pending_wakeups_.insert(base::TimeTicks()).second) - return; - } - delegate_->PostTask(from_here, - from_other_thread_immediate_do_work_closure_); - } -} - -void TaskQueueManager::MaybeScheduleDelayedWork( - const tracked_objects::Location& from_here, - base::TimeTicks now, - base::TimeDelta delay) { - DCHECK(main_thread_checker_.CalledOnValidThread()); - DCHECK_GE(delay, base::TimeDelta()); - base::TimeTicks run_time = now + delay; - // De-duplicate DoWork posts. - if (!main_thread_pending_wakeups_.insert(run_time).second) - return; - delegate_->PostDelayedTask( - from_here, base::Bind(&TaskQueueManager::DoWork, - weak_factory_.GetWeakPtr(), run_time, true), - delay); -} - -void TaskQueueManager::DoWork(base::TimeTicks run_time, bool from_main_thread) { - DCHECK(main_thread_checker_.CalledOnValidThread()); - TRACE_EVENT1(tracing_category_, "TaskQueueManager::DoWork", - "from_main_thread", from_main_thread); - if (from_main_thread) { - main_thread_pending_wakeups_.erase(run_time); - } else { - base::AutoLock lock(other_thread_lock_); - other_thread_pending_wakeups_.erase(run_time); - } - - if (!delegate_->IsNested()) - queues_to_delete_.clear(); - - LazyNow lazy_now(real_time_domain()->CreateLazyNow()); - base::TimeTicks task_start_time; - - if (!delegate_->IsNested() && task_time_tracker_) - task_start_time = lazy_now.Now(); - - // Pass false and nullptr to UpdateWorkQueues here to prevent waking up a - // pump-after-wakeup queue. - UpdateWorkQueues(false, nullptr, lazy_now); - - internal::TaskQueueImpl::Task previous_task; - - for (int i = 0; i < work_batch_size_; i++) { - internal::WorkQueue* work_queue; - if (!SelectWorkQueueToService(&work_queue)) { - break; - } - - bool should_trigger_wakeup = work_queue->task_queue()->wakeup_policy() == - TaskQueue::WakeupPolicy::CAN_WAKE_OTHER_QUEUES; - - switch (ProcessTaskFromWorkQueue(work_queue, &previous_task)) { - case ProcessTaskResult::DEFERRED: - // If a task was deferred, try again with another task. Note that this - // means deferred tasks (i.e. non-nestable tasks) will never trigger - // queue wake-ups. - continue; - case ProcessTaskResult::EXECUTED: - break; - case ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED: - return; // The TaskQueueManager got deleted, we must bail out. - } - - lazy_now = real_time_domain()->CreateLazyNow(); - if (!delegate_->IsNested() && task_time_tracker_) { - // Only report top level task durations. - base::TimeTicks task_end_time = lazy_now.Now(); - task_time_tracker_->ReportTaskTime(task_start_time, task_end_time); - task_start_time = task_end_time; - } - - work_queue = nullptr; // The queue may have been unregistered. - - UpdateWorkQueues(should_trigger_wakeup, &previous_task, lazy_now); - - // Only run a single task per batch in nested run loops so that we can - // properly exit the nested loop when someone calls RunLoop::Quit(). - if (delegate_->IsNested()) - break; - } - - // TODO(alexclarke): Consider refactoring the above loop to terminate only - // when there's no more work left to be done, rather than posting a - // continuation task. - if (!selector_.EnabledWorkQueuesEmpty() || TryAdvanceTimeDomains()) - MaybeScheduleImmediateWork(FROM_HERE); -} - -bool TaskQueueManager::TryAdvanceTimeDomains() { - bool can_advance = false; - for (TimeDomain* time_domain : time_domains_) { - can_advance |= time_domain->MaybeAdvanceTime(); - } - return can_advance; -} - -bool TaskQueueManager::SelectWorkQueueToService( - internal::WorkQueue** out_work_queue) { - bool should_run = selector_.SelectWorkQueueToService(out_work_queue); - TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( - disabled_by_default_tracing_category_, "TaskQueueManager", this, - AsValueWithSelectorResult(should_run, *out_work_queue)); - return should_run; -} - -void TaskQueueManager::DidQueueTask( - const internal::TaskQueueImpl::Task& pending_task) { - task_annotator_.DidQueueTask("TaskQueueManager::PostTask", pending_task); -} - -TaskQueueManager::ProcessTaskResult TaskQueueManager::ProcessTaskFromWorkQueue( - internal::WorkQueue* work_queue, - internal::TaskQueueImpl::Task* out_previous_task) { - DCHECK(main_thread_checker_.CalledOnValidThread()); - scoped_refptr<DeletionSentinel> protect(deletion_sentinel_); - internal::TaskQueueImpl* queue = work_queue->task_queue(); - - if (queue->GetQuiescenceMonitored()) - task_was_run_on_quiescence_monitored_queue_ = true; - - internal::TaskQueueImpl::Task pending_task = - work_queue->TakeTaskFromWorkQueue(); - if (!pending_task.nestable && delegate_->IsNested()) { - // Defer non-nestable work to the main task runner. NOTE these tasks can be - // arbitrarily delayed so the additional delay should not be a problem. - // TODO(skyostil): Figure out a way to not forget which task queue the - // task is associated with. See http://crbug.com/522843. - delegate_->PostNonNestableTask(pending_task.posted_from, pending_task.task); - return ProcessTaskResult::DEFERRED; - } - - MaybeRecordTaskDelayHistograms(pending_task, queue); - - TRACE_TASK_EXECUTION("TaskQueueManager::ProcessTaskFromWorkQueue", - pending_task); - if (queue->GetShouldNotifyObservers()) { - FOR_EACH_OBSERVER(base::MessageLoop::TaskObserver, task_observers_, - WillProcessTask(pending_task)); - queue->NotifyWillProcessTask(pending_task); - } - TRACE_EVENT1(tracing_category_, - "TaskQueueManager::RunTask", "queue", queue->GetName()); - // NOTE when TaskQueues get unregistered a reference ends up getting retained - // by |queues_to_delete_| which is cleared at the top of |DoWork|. This means - // we are OK to use raw pointers here. - internal::TaskQueueImpl* prev_executing_task_queue = - currently_executing_task_queue_; - currently_executing_task_queue_ = queue; - task_annotator_.RunTask("TaskQueueManager::PostTask", pending_task); - - // Detect if the TaskQueueManager just got deleted. If this happens we must - // not access any member variables after this point. - if (protect->HasOneRef()) - return ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED; - - currently_executing_task_queue_ = prev_executing_task_queue; - - if (queue->GetShouldNotifyObservers()) { - FOR_EACH_OBSERVER(base::MessageLoop::TaskObserver, task_observers_, - DidProcessTask(pending_task)); - queue->NotifyDidProcessTask(pending_task); - } - - pending_task.task.Reset(); - *out_previous_task = std::move(pending_task); - return ProcessTaskResult::EXECUTED; -} - -void TaskQueueManager::MaybeRecordTaskDelayHistograms( - const internal::TaskQueueImpl::Task& pending_task, - const internal::TaskQueueImpl* queue) { - if ((task_count_++ % kRecordRecordTaskDelayHistogramsEveryNTasks) != 0) - return; - - // Record delayed task lateness and immediate task queueing durations, but - // only for auto-pumped queues. Manually pumped and after wakeup queues can - // have arbitarially large delayes, which would cloud any analysis. - if (queue->GetPumpPolicy() == TaskQueue::PumpPolicy::AUTO) { - if (!pending_task.delayed_run_time.is_null()) { - RecordDelayedTaskLateness(delegate_->NowTicks() - - pending_task.delayed_run_time); - } else if (!pending_task.time_posted.is_null()) { - RecordImmediateTaskQueueingDuration(tracked_objects::TrackedTime::Now() - - pending_task.time_posted); - } - } -} - -bool TaskQueueManager::RunsTasksOnCurrentThread() const { - return delegate_->RunsTasksOnCurrentThread(); -} - -void TaskQueueManager::SetWorkBatchSize(int work_batch_size) { - DCHECK(main_thread_checker_.CalledOnValidThread()); - DCHECK_GE(work_batch_size, 1); - work_batch_size_ = work_batch_size; -} - -void TaskQueueManager::AddTaskObserver( - base::MessageLoop::TaskObserver* task_observer) { - DCHECK(main_thread_checker_.CalledOnValidThread()); - task_observers_.AddObserver(task_observer); -} - -void TaskQueueManager::RemoveTaskObserver( - base::MessageLoop::TaskObserver* task_observer) { - DCHECK(main_thread_checker_.CalledOnValidThread()); - task_observers_.RemoveObserver(task_observer); -} - -bool TaskQueueManager::GetAndClearSystemIsQuiescentBit() { - bool task_was_run = task_was_run_on_quiescence_monitored_queue_; - task_was_run_on_quiescence_monitored_queue_ = false; - return !task_was_run; -} - -const scoped_refptr<TaskQueueManagerDelegate>& TaskQueueManager::delegate() - const { - return delegate_; -} - -internal::EnqueueOrder TaskQueueManager::GetNextSequenceNumber() { - return enqueue_order_generator_.GenerateNext(); -} - -LazyNow TaskQueueManager::CreateLazyNow() const { - return LazyNow(delegate_.get()); -} - -std::unique_ptr<base::trace_event::ConvertableToTraceFormat> -TaskQueueManager::AsValueWithSelectorResult( - bool should_run, - internal::WorkQueue* selected_work_queue) const { - DCHECK(main_thread_checker_.CalledOnValidThread()); - std::unique_ptr<base::trace_event::TracedValue> state( - new base::trace_event::TracedValue()); - state->BeginArray("queues"); - for (auto& queue : queues_) - queue->AsValueInto(state.get()); - state->EndArray(); - state->BeginDictionary("selector"); - selector_.AsValueInto(state.get()); - state->EndDictionary(); - if (should_run) { - state->SetString("selected_queue", - selected_work_queue->task_queue()->GetName()); - state->SetString("work_queue_name", selected_work_queue->name()); - } - - state->BeginArray("time_domains"); - for (auto* time_domain : time_domains_) - time_domain->AsValueInto(state.get()); - state->EndArray(); - return std::move(state); -} - -void TaskQueueManager::OnTaskQueueEnabled(internal::TaskQueueImpl* queue) { - DCHECK(main_thread_checker_.CalledOnValidThread()); - // Only schedule DoWork if there's something to do. - if (!queue->immediate_work_queue()->Empty() || - !queue->delayed_work_queue()->Empty()) { - MaybeScheduleImmediateWork(FROM_HERE); - } -} - -void TaskQueueManager::OnTriedToSelectBlockedWorkQueue( - internal::WorkQueue* work_queue) { - DCHECK(main_thread_checker_.CalledOnValidThread()); - DCHECK(!work_queue->Empty()); - if (observer_) { - observer_->OnTriedToExecuteBlockedTask(*work_queue->task_queue(), - *work_queue->GetFrontTask()); - } -} - -} // namespace scheduler
diff --git a/components/scheduler/base/task_queue_manager.h b/components/scheduler/base/task_queue_manager.h deleted file mode 100644 index bb938ad..0000000 --- a/components/scheduler/base/task_queue_manager.h +++ /dev/null
@@ -1,268 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_RENDERER_SCHEDULER_BASE_TASK_QUEUE_MANAGER_H_ -#define CONTENT_RENDERER_SCHEDULER_BASE_TASK_QUEUE_MANAGER_H_ - -#include <map> - -#include "base/atomic_sequence_num.h" -#include "base/debug/task_annotator.h" -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "base/message_loop/message_loop.h" -#include "base/pending_task.h" -#include "base/synchronization/lock.h" -#include "base/threading/thread_checker.h" -#include "components/scheduler/base/enqueue_order.h" -#include "components/scheduler/base/task_queue_impl.h" -#include "components/scheduler/base/task_queue_selector.h" -#include "components/scheduler/scheduler_export.h" - -namespace base { -class TickClock; - -namespace trace_event { -class ConvertableToTraceFormat; -class TracedValue; -} // namespace trace_event -} // namespace base - -namespace scheduler { -namespace internal { -class TaskQueueImpl; -} // namespace internal - -class LazyNow; -class RealTimeDomain; -class TimeDomain; -class TaskQueueManagerDelegate; -class TaskTimeTracker; - -// The task queue manager provides N task queues and a selector interface for -// choosing which task queue to service next. Each task queue consists of two -// sub queues: -// -// 1. Incoming task queue. Tasks that are posted get immediately appended here. -// When a task is appended into an empty incoming queue, the task manager -// work function (DoWork) is scheduled to run on the main task runner. -// -// 2. Work queue. If a work queue is empty when DoWork() is entered, tasks from -// the incoming task queue (if any) are moved here. The work queues are -// registered with the selector as input to the scheduling decision. -// -class SCHEDULER_EXPORT TaskQueueManager - : public internal::TaskQueueSelector::Observer { - public: - // Create a task queue manager where |delegate| identifies the thread - // on which where the tasks are eventually run. Category strings must have - // application lifetime (statics or literals). They may not include " chars. - TaskQueueManager(scoped_refptr<TaskQueueManagerDelegate> delegate, - const char* tracing_category, - const char* disabled_by_default_tracing_category, - const char* disabled_by_default_verbose_tracing_category); - ~TaskQueueManager() override; - - // Requests that a task to process work is posted on the main task runner. - // These tasks are de-duplicated in two buckets: main-thread and all other - // threads. This distinction is done to reduce the overehead from locks, we - // assume the main-thread path will be hot. - void MaybeScheduleImmediateWork(const tracked_objects::Location& from_here); - - // Requests that a delayed task to process work is posted on the main task - // runner. These delayed tasks are de-duplicated. Must be called on the thread - // this class was created on. - void MaybeScheduleDelayedWork(const tracked_objects::Location& from_here, - base::TimeTicks now, - base::TimeDelta delay); - - // Set the number of tasks executed in a single invocation of the task queue - // manager. Increasing the batch size can reduce the overhead of yielding - // back to the main message loop -- at the cost of potentially delaying other - // tasks posted to the main loop. The batch size is 1 by default. - void SetWorkBatchSize(int work_batch_size); - - // When given a non-null TaskTimeTracker, the TaskQueueManager calls its - // ReportTaskTime method for every top level task. The task_time_tracker must - // outlive this object, or be removed via SetTaskTimeTracker(nullptr). - void SetTaskTimeTracker(TaskTimeTracker* task_time_tracker) { - task_time_tracker_ = task_time_tracker; - } - - // These functions can only be called on the same thread that the task queue - // manager executes its tasks on. - void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer); - void RemoveTaskObserver(base::MessageLoop::TaskObserver* task_observer); - - // Returns true if any task from a monitored task queue was was run since the - // last call to GetAndClearSystemIsQuiescentBit. - bool GetAndClearSystemIsQuiescentBit(); - - // Creates a task queue with the given |spec|. Must be called on the thread - // this class was created on. - scoped_refptr<internal::TaskQueueImpl> NewTaskQueue( - const TaskQueue::Spec& spec); - - class SCHEDULER_EXPORT Observer { - public: - virtual ~Observer() {} - - // Called when |queue| is unregistered. - virtual void OnUnregisterTaskQueue( - const scoped_refptr<TaskQueue>& queue) = 0; - - // Called when the manager tried to execute a task from a disabled - // queue. See TaskQueue::Spec::SetShouldReportWhenExecutionBlocked. - virtual void OnTriedToExecuteBlockedTask(const TaskQueue& queue, - const base::PendingTask& task) = 0; - }; - - // Called once to set the Observer. This function is called on the main - // thread. If |observer| is null, then no callbacks will occur. - // Note |observer| is expected to outlive the SchedulerHelper. - void SetObserver(Observer* observer); - - // Returns the delegate used by the TaskQueueManager. - const scoped_refptr<TaskQueueManagerDelegate>& delegate() const; - - // Time domains must be registered for the task queues to get updated. - void RegisterTimeDomain(TimeDomain* time_domain); - void UnregisterTimeDomain(TimeDomain* time_domain); - - RealTimeDomain* real_time_domain() const { return real_time_domain_.get(); } - - LazyNow CreateLazyNow() const; - - // Returns the currently executing TaskQueue if any. Must be called on the - // thread this class was created on. - TaskQueue* currently_executing_task_queue() const { - DCHECK(main_thread_checker_.CalledOnValidThread()); - return currently_executing_task_queue_; - } - - private: - friend class LazyNow; - friend class internal::TaskQueueImpl; - friend class TaskQueueManagerTest; - - class DeletionSentinel : public base::RefCounted<DeletionSentinel> { - private: - friend class base::RefCounted<DeletionSentinel>; - ~DeletionSentinel() {} - }; - - // Unregisters a TaskQueue previously created by |NewTaskQueue()|. - // NOTE we have to flush the queue from |newly_updatable_| which means as a - // side effect MoveNewlyUpdatableQueuesIntoUpdatableQueueSet is called by this - // function. - void UnregisterTaskQueue(scoped_refptr<internal::TaskQueueImpl> task_queue); - - // TaskQueueSelector::Observer implementation: - void OnTaskQueueEnabled(internal::TaskQueueImpl* queue) override; - void OnTriedToSelectBlockedWorkQueue( - internal::WorkQueue* work_queue) override; - - // Called by the task queue to register a new pending task. - void DidQueueTask(const internal::TaskQueueImpl::Task& pending_task); - - // Use the selector to choose a pending task and run it. - void DoWork(base::TimeTicks run_time, bool from_main_thread); - - // Delayed Tasks with run_times <= Now() are enqueued onto the work queue. - // Reloads any empty work queues which have automatic pumping enabled and - // which are eligible to be auto pumped based on the |previous_task| which was - // run and |should_trigger_wakeup|. Call with an empty |previous_task| if no - // task was just run. - void UpdateWorkQueues(bool should_trigger_wakeup, - const internal::TaskQueueImpl::Task* previous_task, - LazyNow lazy_now); - - // Chooses the next work queue to service. Returns true if |out_queue| - // indicates the queue from which the next task should be run, false to - // avoid running any tasks. - bool SelectWorkQueueToService(internal::WorkQueue** out_work_queue); - - // Runs a single nestable task from the |queue|. On exit, |out_task| will - // contain the task which was executed. Non-nestable task are reposted on the - // run loop. The queue must not be empty. - enum class ProcessTaskResult { - DEFERRED, - EXECUTED, - TASK_QUEUE_MANAGER_DELETED - }; - ProcessTaskResult ProcessTaskFromWorkQueue( - internal::WorkQueue* work_queue, - internal::TaskQueueImpl::Task* out_previous_task); - - bool RunsTasksOnCurrentThread() const; - bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay); - - internal::EnqueueOrder GetNextSequenceNumber(); - - // Calls MaybeAdvanceTime on all time domains and returns true if one of them - // was able to advance. - bool TryAdvanceTimeDomains(); - - void MaybeRecordTaskDelayHistograms( - const internal::TaskQueueImpl::Task& pending_task, - const internal::TaskQueueImpl* queue); - - std::unique_ptr<base::trace_event::ConvertableToTraceFormat> - AsValueWithSelectorResult(bool should_run, - internal::WorkQueue* selected_work_queue) const; - - std::set<TimeDomain*> time_domains_; - std::unique_ptr<RealTimeDomain> real_time_domain_; - - std::set<scoped_refptr<internal::TaskQueueImpl>> queues_; - - // We have to be careful when deleting a queue because some of the code uses - // raw pointers and doesn't expect the rug to be pulled out from underneath. - std::set<scoped_refptr<internal::TaskQueueImpl>> queues_to_delete_; - - internal::EnqueueOrderGenerator enqueue_order_generator_; - base::debug::TaskAnnotator task_annotator_; - - base::ThreadChecker main_thread_checker_; - scoped_refptr<TaskQueueManagerDelegate> delegate_; - internal::TaskQueueSelector selector_; - - base::Closure from_main_thread_immediate_do_work_closure_; - base::Closure from_other_thread_immediate_do_work_closure_; - - bool task_was_run_on_quiescence_monitored_queue_; - - // To reduce locking overhead we track pending calls to DoWork separately for - // the main thread and other threads. - std::set<base::TimeTicks> main_thread_pending_wakeups_; - - // Protects |other_thread_pending_wakeups_|. - mutable base::Lock other_thread_lock_; - std::set<base::TimeTicks> other_thread_pending_wakeups_; - - int work_batch_size_; - size_t task_count_; - - base::ObserverList<base::MessageLoop::TaskObserver> task_observers_; - - TaskTimeTracker* task_time_tracker_; // NOT OWNED - - const char* tracing_category_; - const char* disabled_by_default_tracing_category_; - const char* disabled_by_default_verbose_tracing_category_; - - internal::TaskQueueImpl* currently_executing_task_queue_; // NOT OWNED - - Observer* observer_; // NOT OWNED - scoped_refptr<DeletionSentinel> deletion_sentinel_; - base::WeakPtrFactory<TaskQueueManager> weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(TaskQueueManager); -}; - -} // namespace scheduler - -#endif // CONTENT_RENDERER_SCHEDULER_BASE_TASK_QUEUE_MANAGER_H_
diff --git a/components/scheduler/base/task_queue_manager_delegate.h b/components/scheduler/base/task_queue_manager_delegate.h deleted file mode 100644 index 1bb40501..0000000 --- a/components/scheduler/base/task_queue_manager_delegate.h +++ /dev/null
@@ -1,34 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_BASE_TASK_QUEUE_MANAGER_DELEGATE_H_ -#define COMPONENTS_SCHEDULER_BASE_TASK_QUEUE_MANAGER_DELEGATE_H_ - -#include "base/callback.h" -#include "base/macros.h" -#include "base/message_loop/message_loop.h" -#include "base/time/tick_clock.h" -#include "components/scheduler/scheduler_export.h" - -namespace scheduler { - -class SCHEDULER_EXPORT TaskQueueManagerDelegate - : public base::SingleThreadTaskRunner, - public base::TickClock { - public: - TaskQueueManagerDelegate() {} - - // Returns true if the task runner is nested (i.e., running a run loop within - // a nested task). - virtual bool IsNested() const = 0; - - protected: - ~TaskQueueManagerDelegate() override {} - - DISALLOW_COPY_AND_ASSIGN(TaskQueueManagerDelegate); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_BASE_TASK_QUEUE_MANAGER_DELEGATE_H_
diff --git a/components/scheduler/base/task_queue_manager_delegate_for_test.cc b/components/scheduler/base/task_queue_manager_delegate_for_test.cc deleted file mode 100644 index 56380307d..0000000 --- a/components/scheduler/base/task_queue_manager_delegate_for_test.cc +++ /dev/null
@@ -1,56 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/base/task_queue_manager_delegate_for_test.h" - -#include <utility> - -#include "base/bind.h" -#include "base/bind_helpers.h" - -namespace scheduler { - -// static -scoped_refptr<TaskQueueManagerDelegateForTest> -TaskQueueManagerDelegateForTest::Create( - scoped_refptr<base::SingleThreadTaskRunner> task_runner, - std::unique_ptr<base::TickClock> time_source) { - return make_scoped_refptr( - new TaskQueueManagerDelegateForTest(task_runner, std::move(time_source))); -} - -TaskQueueManagerDelegateForTest::TaskQueueManagerDelegateForTest( - scoped_refptr<base::SingleThreadTaskRunner> task_runner, - std::unique_ptr<base::TickClock> time_source) - : task_runner_(task_runner), time_source_(std::move(time_source)) {} - -TaskQueueManagerDelegateForTest::~TaskQueueManagerDelegateForTest() {} - -bool TaskQueueManagerDelegateForTest::PostDelayedTask( - const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) { - return task_runner_->PostDelayedTask(from_here, task, delay); -} - -bool TaskQueueManagerDelegateForTest::PostNonNestableDelayedTask( - const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) { - return task_runner_->PostNonNestableDelayedTask(from_here, task, delay); -} - -bool TaskQueueManagerDelegateForTest::RunsTasksOnCurrentThread() const { - return task_runner_->RunsTasksOnCurrentThread(); -} - -bool TaskQueueManagerDelegateForTest::IsNested() const { - return false; -} - -base::TimeTicks TaskQueueManagerDelegateForTest::NowTicks() { - return time_source_->NowTicks(); -} - -} // namespace scheduler
diff --git a/components/scheduler/base/task_queue_manager_delegate_for_test.h b/components/scheduler/base/task_queue_manager_delegate_for_test.h deleted file mode 100644 index cb97e474..0000000 --- a/components/scheduler/base/task_queue_manager_delegate_for_test.h +++ /dev/null
@@ -1,48 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_BASE_TASK_QUEUE_MANAGER_DELEGATE_FOR_TEST_H_ -#define COMPONENTS_SCHEDULER_BASE_TASK_QUEUE_MANAGER_DELEGATE_FOR_TEST_H_ - -#include <memory> - -#include "base/macros.h" -#include "base/time/tick_clock.h" -#include "components/scheduler/base/task_queue_manager_delegate.h" - -namespace scheduler { - -class TaskQueueManagerDelegateForTest : public TaskQueueManagerDelegate { - public: - static scoped_refptr<TaskQueueManagerDelegateForTest> Create( - scoped_refptr<base::SingleThreadTaskRunner> task_runner, - std::unique_ptr<base::TickClock> time_source); - - // NestableSingleThreadTaskRunner implementation - bool PostDelayedTask(const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) override; - bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) override; - bool RunsTasksOnCurrentThread() const override; - bool IsNested() const override; - base::TimeTicks NowTicks() override; - - protected: - ~TaskQueueManagerDelegateForTest() override; - TaskQueueManagerDelegateForTest( - scoped_refptr<base::SingleThreadTaskRunner> task_runner, - std::unique_ptr<base::TickClock> time_source); - - private: - scoped_refptr<base::SingleThreadTaskRunner> task_runner_; - std::unique_ptr<base::TickClock> time_source_; - - DISALLOW_COPY_AND_ASSIGN(TaskQueueManagerDelegateForTest); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_BASE_TASK_QUEUE_MANAGER_DELEGATE_FOR_TEST_H_
diff --git a/components/scheduler/base/task_queue_manager_perftest.cc b/components/scheduler/base/task_queue_manager_perftest.cc deleted file mode 100644 index 3283c567..0000000 --- a/components/scheduler/base/task_queue_manager_perftest.cc +++ /dev/null
@@ -1,171 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/base/task_queue_manager.h" - -#include <stddef.h> - -#include "base/bind.h" -#include "base/memory/ptr_util.h" -#include "base/run_loop.h" -#include "base/threading/thread.h" -#include "base/time/default_tick_clock.h" -#include "components/scheduler/base/task_queue_impl.h" -#include "components/scheduler/base/task_queue_manager_delegate_for_test.h" -#include "components/scheduler/base/task_queue_selector.h" -#include "components/scheduler/base/test_task_time_tracker.h" -#include "components/scheduler/base/work_queue_sets.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/perf/perf_test.h" - -namespace scheduler { - -class TaskQueueManagerPerfTest : public testing::Test { - public: - TaskQueueManagerPerfTest() - : num_queues_(0), - max_tasks_in_flight_(0), - num_tasks_in_flight_(0), - num_tasks_to_post_(0), - num_tasks_to_run_(0) {} - - void SetUp() override { - if (base::ThreadTicks::IsSupported()) - base::ThreadTicks::WaitUntilInitialized(); - } - - void Initialize(size_t num_queues) { - num_queues_ = num_queues; - message_loop_.reset(new base::MessageLoop()); - run_loop_.reset(new base::RunLoop()); - manager_ = base::WrapUnique(new TaskQueueManager( - TaskQueueManagerDelegateForTest::Create( - message_loop_->task_runner(), - base::WrapUnique(new base::DefaultTickClock())), - "fake.category", "fake.category", "fake.category.debug")); - manager_->SetTaskTimeTracker(&test_task_time_tracker_); - for (size_t i = 0; i < num_queues; i++) - queues_.push_back(manager_->NewTaskQueue(TaskQueue::Spec("test"))); - } - - void TestDelayedTask() { - if (--num_tasks_to_run_ == 0) { - run_loop_->QuitWhenIdle(); - } - - num_tasks_in_flight_--; - // NOTE there are only up to max_tasks_in_flight_ pending delayed tasks at - // any one time. Thanks to the lower_num_tasks_to_post going to zero if - // there are a lot of tasks in flight, the total number of task in flight at - // any one time is very variable. - unsigned int lower_num_tasks_to_post = - num_tasks_in_flight_ < (max_tasks_in_flight_ / 2) ? 1 : 0; - unsigned int max_tasks_to_post = - num_tasks_to_post_ % 2 ? lower_num_tasks_to_post : 10; - for (unsigned int i = 0; - i < max_tasks_to_post && num_tasks_in_flight_ < max_tasks_in_flight_ && - num_tasks_to_post_ > 0; - i++) { - // Choose a queue weighted towards queue 0. - unsigned int queue = num_tasks_to_post_ % (num_queues_ + 1); - if (queue == num_queues_) { - queue = 0; - } - // Simulate a mix of short and longer delays. - unsigned int delay = - num_tasks_to_post_ % 2 ? 1 : (10 + num_tasks_to_post_ % 10); - queues_[queue]->PostDelayedTask( - FROM_HERE, base::Bind(&TaskQueueManagerPerfTest::TestDelayedTask, - base::Unretained(this)), - base::TimeDelta::FromMicroseconds(delay)); - num_tasks_in_flight_++; - num_tasks_to_post_--; - } - } - - void ResetAndCallTestDelayedTask(unsigned int num_tasks_to_run) { - num_tasks_in_flight_ = 1; - num_tasks_to_post_ = num_tasks_to_run; - num_tasks_to_run_ = num_tasks_to_run; - TestDelayedTask(); - } - - void Benchmark(const std::string& trace, const base::Closure& test_task) { - base::ThreadTicks start = base::ThreadTicks::Now(); - base::ThreadTicks now; - unsigned long long num_iterations = 0; - do { - test_task.Run(); - run_loop_->Run(); - now = base::ThreadTicks::Now(); - num_iterations++; - } while (now - start < base::TimeDelta::FromSeconds(5)); - perf_test::PrintResult( - "task", "", trace, - (now - start).InMicroseconds() / static_cast<double>(num_iterations), - "us/run", true); - } - - size_t num_queues_; - unsigned int max_tasks_in_flight_; - unsigned int num_tasks_in_flight_; - unsigned int num_tasks_to_post_; - unsigned int num_tasks_to_run_; - std::unique_ptr<TaskQueueManager> manager_; - std::unique_ptr<base::MessageLoop> message_loop_; - std::unique_ptr<base::RunLoop> run_loop_; - std::vector<scoped_refptr<base::SingleThreadTaskRunner>> queues_; - // TODO(alexclarke): parameterize so we can measure with and without a - // TaskTimeTracker. - TestTaskTimeTracker test_task_time_tracker_; -}; - -TEST_F(TaskQueueManagerPerfTest, RunTenThousandDelayedTasks_OneQueue) { - if (!base::ThreadTicks::IsSupported()) - return; - Initialize(1u); - - max_tasks_in_flight_ = 200; - Benchmark("run 10000 delayed tasks with one queue", - base::Bind(&TaskQueueManagerPerfTest::ResetAndCallTestDelayedTask, - base::Unretained(this), 10000)); -} - -TEST_F(TaskQueueManagerPerfTest, RunTenThousandDelayedTasks_FourQueues) { - if (!base::ThreadTicks::IsSupported()) - return; - Initialize(4u); - - max_tasks_in_flight_ = 200; - Benchmark("run 10000 delayed tasks with four queues", - base::Bind(&TaskQueueManagerPerfTest::ResetAndCallTestDelayedTask, - base::Unretained(this), 10000)); -} - -TEST_F(TaskQueueManagerPerfTest, RunTenThousandDelayedTasks_EightQueues) { - if (!base::ThreadTicks::IsSupported()) - return; - Initialize(8u); - - max_tasks_in_flight_ = 200; - Benchmark("run 10000 delayed tasks with eight queues", - base::Bind(&TaskQueueManagerPerfTest::ResetAndCallTestDelayedTask, - base::Unretained(this), 10000)); -} - -TEST_F(TaskQueueManagerPerfTest, RunTenThousandDelayedTasks_ThirtyTwoQueues) { - if (!base::ThreadTicks::IsSupported()) - return; - Initialize(32u); - - max_tasks_in_flight_ = 200; - Benchmark("run 10000 delayed tasks with eight queues", - base::Bind(&TaskQueueManagerPerfTest::ResetAndCallTestDelayedTask, - base::Unretained(this), 10000)); -} - -// TODO(alexclarke): Add additional tests with different mixes of non-delayed vs -// delayed tasks. - -} // namespace scheduler
diff --git a/components/scheduler/base/task_queue_manager_unittest.cc b/components/scheduler/base/task_queue_manager_unittest.cc deleted file mode 100644 index 8f37a1f0..0000000 --- a/components/scheduler/base/task_queue_manager_unittest.cc +++ /dev/null
@@ -1,2008 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/base/task_queue_manager.h" - -#include <stddef.h> - -#include <utility> - -#include "base/location.h" -#include "base/memory/ptr_util.h" -#include "base/memory/ref_counted_memory.h" -#include "base/run_loop.h" -#include "base/single_thread_task_runner.h" -#include "base/test/simple_test_tick_clock.h" -#include "base/test/trace_event_analyzer.h" -#include "base/threading/thread.h" -#include "base/trace_event/blame_context.h" -#include "base/trace_event/trace_buffer.h" -#include "cc/test/ordered_simple_task_runner.h" -#include "components/scheduler/base/real_time_domain.h" -#include "components/scheduler/base/task_queue_impl.h" -#include "components/scheduler/base/task_queue_manager_delegate_for_test.h" -#include "components/scheduler/base/task_queue_selector.h" -#include "components/scheduler/base/test_count_uses_time_source.h" -#include "components/scheduler/base/test_task_time_tracker.h" -#include "components/scheduler/base/test_time_source.h" -#include "components/scheduler/base/virtual_time_domain.h" -#include "components/scheduler/base/work_queue.h" -#include "components/scheduler/base/work_queue_sets.h" -#include "testing/gmock/include/gmock/gmock.h" - -using testing::ElementsAre; -using testing::ElementsAreArray; -using testing::_; -using scheduler::internal::EnqueueOrder; - -namespace scheduler { - -class MessageLoopTaskRunner : public TaskQueueManagerDelegateForTest { - public: - static scoped_refptr<MessageLoopTaskRunner> Create( - std::unique_ptr<base::TickClock> tick_clock) { - return make_scoped_refptr(new MessageLoopTaskRunner(std::move(tick_clock))); - } - - // NestableTaskRunner implementation. - bool IsNested() const override { - return base::MessageLoop::current()->IsNested(); - } - - private: - explicit MessageLoopTaskRunner(std::unique_ptr<base::TickClock> tick_clock) - : TaskQueueManagerDelegateForTest( - base::MessageLoop::current()->task_runner(), - std::move(tick_clock)) {} - ~MessageLoopTaskRunner() override {} -}; - -class TaskQueueManagerTest : public testing::Test { - public: - TaskQueueManagerTest() {} - void DeleteTaskQueueManager() { manager_.reset(); } - - protected: - void InitializeWithClock(size_t num_queues, - std::unique_ptr<base::TickClock> test_time_source) { - test_task_runner_ = make_scoped_refptr( - new cc::OrderedSimpleTaskRunner(now_src_.get(), false)); - main_task_runner_ = TaskQueueManagerDelegateForTest::Create( - test_task_runner_.get(), - base::WrapUnique(new TestTimeSource(now_src_.get()))); - - manager_ = base::WrapUnique(new TaskQueueManager( - main_task_runner_, "test.scheduler", "test.scheduler", - "test.scheduler.debug")); - manager_->SetTaskTimeTracker(&test_task_time_tracker_); - - for (size_t i = 0; i < num_queues; i++) - runners_.push_back(manager_->NewTaskQueue(TaskQueue::Spec("test_queue"))); - } - - void Initialize(size_t num_queues) { - now_src_.reset(new base::SimpleTestTickClock()); - now_src_->Advance(base::TimeDelta::FromMicroseconds(1000)); - InitializeWithClock(num_queues, - base::WrapUnique(new TestTimeSource(now_src_.get()))); - } - - void InitializeWithRealMessageLoop(size_t num_queues) { - now_src_.reset(new base::SimpleTestTickClock()); - message_loop_.reset(new base::MessageLoop()); - // A null clock triggers some assertions. - now_src_->Advance(base::TimeDelta::FromMicroseconds(1000)); - manager_ = base::WrapUnique(new TaskQueueManager( - MessageLoopTaskRunner::Create( - base::WrapUnique(new TestTimeSource(now_src_.get()))), - "test.scheduler", "test.scheduler", "test.scheduler.debug")); - manager_->SetTaskTimeTracker(&test_task_time_tracker_); - - for (size_t i = 0; i < num_queues; i++) - runners_.push_back(manager_->NewTaskQueue(TaskQueue::Spec("test_queue"))); - } - - std::unique_ptr<base::MessageLoop> message_loop_; - std::unique_ptr<base::SimpleTestTickClock> now_src_; - scoped_refptr<TaskQueueManagerDelegateForTest> main_task_runner_; - scoped_refptr<cc::OrderedSimpleTaskRunner> test_task_runner_; - std::unique_ptr<TaskQueueManager> manager_; - std::vector<scoped_refptr<internal::TaskQueueImpl>> runners_; - TestTaskTimeTracker test_task_time_tracker_; -}; - -void PostFromNestedRunloop(base::MessageLoop* message_loop, - base::SingleThreadTaskRunner* runner, - std::vector<std::pair<base::Closure, bool>>* tasks) { - base::MessageLoop::ScopedNestableTaskAllower allow(message_loop); - for (std::pair<base::Closure, bool>& pair : *tasks) { - if (pair.second) { - runner->PostTask(FROM_HERE, pair.first); - } else { - runner->PostNonNestableTask(FROM_HERE, pair.first); - } - } - base::RunLoop().RunUntilIdle(); -} - -void NopTask() {} - -TEST_F(TaskQueueManagerTest, - NowCalledMinimumNumberOfTimesToComputeTaskDurations) { - message_loop_.reset(new base::MessageLoop()); - // This memory is managed by the TaskQueueManager, but we need to hold a - // pointer to this object to read out how many times Now was called. - TestCountUsesTimeSource* test_count_uses_time_source = - new TestCountUsesTimeSource(); - - manager_ = base::WrapUnique(new TaskQueueManager( - MessageLoopTaskRunner::Create( - base::WrapUnique(test_count_uses_time_source)), - "test.scheduler", "test.scheduler", "test.scheduler.debug")); - manager_->SetWorkBatchSize(6); - manager_->SetTaskTimeTracker(&test_task_time_tracker_); - - for (size_t i = 0; i < 3; i++) - runners_.push_back(manager_->NewTaskQueue(TaskQueue::Spec("test_queue"))); - - runners_[0]->PostTask(FROM_HERE, base::Bind(&NopTask)); - runners_[0]->PostTask(FROM_HERE, base::Bind(&NopTask)); - runners_[1]->PostTask(FROM_HERE, base::Bind(&NopTask)); - runners_[1]->PostTask(FROM_HERE, base::Bind(&NopTask)); - runners_[2]->PostTask(FROM_HERE, base::Bind(&NopTask)); - runners_[2]->PostTask(FROM_HERE, base::Bind(&NopTask)); - - base::RunLoop().RunUntilIdle(); - // We need to call Now for the beginning of the first task, and then the end - // of every task after. We reuse the end time of one task for the start time - // of the next task. In this case, there were 6 tasks, so we expect 7 calls to - // Now. - EXPECT_EQ(7, test_count_uses_time_source->now_calls_count()); -} - -TEST_F(TaskQueueManagerTest, - NowNotCalledForNestedTasks) { - message_loop_.reset(new base::MessageLoop()); - // This memory is managed by the TaskQueueManager, but we need to hold a - // pointer to this object to read out how many times Now was called. - TestCountUsesTimeSource* test_count_uses_time_source = - new TestCountUsesTimeSource(); - - manager_ = base::WrapUnique(new TaskQueueManager( - MessageLoopTaskRunner::Create( - base::WrapUnique(test_count_uses_time_source)), - "test.scheduler", "test.scheduler", "test.scheduler.debug")); - manager_->SetTaskTimeTracker(&test_task_time_tracker_); - - runners_.push_back(manager_->NewTaskQueue(TaskQueue::Spec("test_queue"))); - - std::vector<std::pair<base::Closure, bool>> tasks_to_post_from_nested_loop; - for (int i = 0; i <= 6; ++i) { - tasks_to_post_from_nested_loop.push_back( - std::make_pair(base::Bind(&NopTask), true)); - } - - runners_[0]->PostTask( - FROM_HERE, base::Bind(&PostFromNestedRunloop, message_loop_.get(), - base::RetainedRef(runners_[0]), - base::Unretained(&tasks_to_post_from_nested_loop))); - - base::RunLoop().RunUntilIdle(); - // We need to call Now twice, to measure the start and end of the outermost - // task. We shouldn't call it for any of the nested tasks. - EXPECT_EQ(2, test_count_uses_time_source->now_calls_count()); -} - -void NullTask() {} - -void TestTask(EnqueueOrder value, std::vector<EnqueueOrder>* out_result) { - out_result->push_back(value); -} - -TEST_F(TaskQueueManagerTest, SingleQueuePosting) { - Initialize(1u); - - std::vector<EnqueueOrder> run_order; - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order)); - - test_task_runner_->RunUntilIdle(); - EXPECT_THAT(run_order, ElementsAre(1, 2, 3)); -} - -TEST_F(TaskQueueManagerTest, MultiQueuePosting) { - Initialize(3u); - - std::vector<EnqueueOrder> run_order; - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); - runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order)); - runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 4, &run_order)); - runners_[2]->PostTask(FROM_HERE, base::Bind(&TestTask, 5, &run_order)); - runners_[2]->PostTask(FROM_HERE, base::Bind(&TestTask, 6, &run_order)); - - test_task_runner_->RunUntilIdle(); - EXPECT_THAT(run_order, ElementsAre(1, 2, 3, 4, 5, 6)); -} - -TEST_F(TaskQueueManagerTest, NonNestableTaskPosting) { - InitializeWithRealMessageLoop(1u); - - std::vector<EnqueueOrder> run_order; - runners_[0]->PostNonNestableTask(FROM_HERE, - base::Bind(&TestTask, 1, &run_order)); - - base::RunLoop().RunUntilIdle(); - EXPECT_THAT(run_order, ElementsAre(1)); -} - -TEST_F(TaskQueueManagerTest, NonNestableTaskExecutesInExpectedOrder) { - InitializeWithRealMessageLoop(1u); - - std::vector<EnqueueOrder> run_order; - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order)); - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 4, &run_order)); - runners_[0]->PostNonNestableTask(FROM_HERE, - base::Bind(&TestTask, 5, &run_order)); - - base::RunLoop().RunUntilIdle(); - EXPECT_THAT(run_order, ElementsAre(1, 2, 3, 4, 5)); -} - -TEST_F(TaskQueueManagerTest, NonNestableTaskDoesntExecuteInNestedLoop) { - InitializeWithRealMessageLoop(1u); - - std::vector<EnqueueOrder> run_order; - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); - - std::vector<std::pair<base::Closure, bool>> tasks_to_post_from_nested_loop; - tasks_to_post_from_nested_loop.push_back( - std::make_pair(base::Bind(&TestTask, 3, &run_order), false)); - tasks_to_post_from_nested_loop.push_back( - std::make_pair(base::Bind(&TestTask, 4, &run_order), true)); - tasks_to_post_from_nested_loop.push_back( - std::make_pair(base::Bind(&TestTask, 5, &run_order), true)); - - runners_[0]->PostTask( - FROM_HERE, base::Bind(&PostFromNestedRunloop, message_loop_.get(), - base::RetainedRef(runners_[0]), - base::Unretained(&tasks_to_post_from_nested_loop))); - - base::RunLoop().RunUntilIdle(); - // Note we expect task 3 to run last because it's non-nestable. - EXPECT_THAT(run_order, ElementsAre(1, 2, 4, 5, 3)); -} - -TEST_F(TaskQueueManagerTest, QueuePolling) { - Initialize(1u); - - std::vector<EnqueueOrder> run_order; - EXPECT_FALSE(runners_[0]->HasPendingImmediateWork()); - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); - EXPECT_TRUE(runners_[0]->HasPendingImmediateWork()); - - test_task_runner_->RunUntilIdle(); - EXPECT_FALSE(runners_[0]->HasPendingImmediateWork()); -} - -TEST_F(TaskQueueManagerTest, DelayedTaskPosting) { - Initialize(1u); - - std::vector<EnqueueOrder> run_order; - base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10)); - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order), - delay); - EXPECT_EQ(delay, test_task_runner_->DelayToNextTaskTime()); - EXPECT_FALSE(runners_[0]->HasPendingImmediateWork()); - EXPECT_TRUE(run_order.empty()); - - // The task doesn't run before the delay has completed. - test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(9)); - EXPECT_TRUE(run_order.empty()); - - // After the delay has completed, the task runs normally. - test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(1)); - EXPECT_THAT(run_order, ElementsAre(1)); - EXPECT_FALSE(runners_[0]->HasPendingImmediateWork()); -} - -bool MessageLoopTaskCounter(size_t* count) { - *count = *count + 1; - return true; -} - -TEST_F(TaskQueueManagerTest, DelayedTaskExecutedInOneMessageLoopTask) { - Initialize(1u); - - base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10)); - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), delay); - - size_t task_count = 0; - test_task_runner_->RunTasksWhile( - base::Bind(&MessageLoopTaskCounter, &task_count)); - EXPECT_EQ(1u, task_count); -} - -TEST_F(TaskQueueManagerTest, DelayedTaskPosting_MultipleTasks_DecendingOrder) { - Initialize(1u); - - std::vector<EnqueueOrder> run_order; - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order), - base::TimeDelta::FromMilliseconds(10)); - - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order), - base::TimeDelta::FromMilliseconds(8)); - - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order), - base::TimeDelta::FromMilliseconds(5)); - - EXPECT_EQ(base::TimeDelta::FromMilliseconds(5), - test_task_runner_->DelayToNextTaskTime()); - - test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(5)); - EXPECT_THAT(run_order, ElementsAre(3)); - EXPECT_EQ(base::TimeDelta::FromMilliseconds(3), - test_task_runner_->DelayToNextTaskTime()); - - test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(3)); - EXPECT_THAT(run_order, ElementsAre(3, 2)); - EXPECT_EQ(base::TimeDelta::FromMilliseconds(2), - test_task_runner_->DelayToNextTaskTime()); - - test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(2)); - EXPECT_THAT(run_order, ElementsAre(3, 2, 1)); -} - -TEST_F(TaskQueueManagerTest, DelayedTaskPosting_MultipleTasks_AscendingOrder) { - Initialize(1u); - - std::vector<EnqueueOrder> run_order; - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order), - base::TimeDelta::FromMilliseconds(1)); - - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order), - base::TimeDelta::FromMilliseconds(5)); - - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order), - base::TimeDelta::FromMilliseconds(10)); - - EXPECT_EQ(base::TimeDelta::FromMilliseconds(1), - test_task_runner_->DelayToNextTaskTime()); - - test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(1)); - EXPECT_THAT(run_order, ElementsAre(1)); - EXPECT_EQ(base::TimeDelta::FromMilliseconds(4), - test_task_runner_->DelayToNextTaskTime()); - - test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(4)); - EXPECT_THAT(run_order, ElementsAre(1, 2)); - EXPECT_EQ(base::TimeDelta::FromMilliseconds(5), - test_task_runner_->DelayToNextTaskTime()); - - test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(5)); - EXPECT_THAT(run_order, ElementsAre(1, 2, 3)); -} - -TEST_F(TaskQueueManagerTest, PostDelayedTask_SharesUnderlyingDelayedTasks) { - Initialize(1u); - - std::vector<EnqueueOrder> run_order; - base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10)); - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order), - delay); - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order), - delay); - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order), - delay); - - EXPECT_EQ(1u, test_task_runner_->NumPendingTasks()); -} - -class TestObject { - public: - ~TestObject() { destructor_count_++; } - - void Run() { FAIL() << "TestObject::Run should not be called"; } - - static int destructor_count_; -}; - -int TestObject::destructor_count_ = 0; - -TEST_F(TaskQueueManagerTest, PendingDelayedTasksRemovedOnShutdown) { - Initialize(1u); - - TestObject::destructor_count_ = 0; - - base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10)); - runners_[0]->PostDelayedTask( - FROM_HERE, base::Bind(&TestObject::Run, base::Owned(new TestObject())), - delay); - runners_[0]->PostTask( - FROM_HERE, base::Bind(&TestObject::Run, base::Owned(new TestObject()))); - - manager_.reset(); - - EXPECT_EQ(2, TestObject::destructor_count_); -} - -TEST_F(TaskQueueManagerTest, ManualPumping) { - Initialize(1u); - runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL); - - std::vector<EnqueueOrder> run_order; - // Posting a task when pumping is disabled doesn't result in work getting - // posted. - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); - EXPECT_FALSE(test_task_runner_->HasPendingTasks()); - - // However polling still works. - EXPECT_TRUE(runners_[0]->HasPendingImmediateWork()); - - // After pumping the task runs normally. - LazyNow lazy_now(now_src_.get()); - runners_[0]->PumpQueue(&lazy_now, true); - EXPECT_TRUE(test_task_runner_->HasPendingTasks()); - test_task_runner_->RunUntilIdle(); - EXPECT_THAT(run_order, ElementsAre(1)); -} - -TEST_F(TaskQueueManagerTest, ManualPumpingToggle) { - Initialize(1u); - runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL); - - std::vector<EnqueueOrder> run_order; - // Posting a task when pumping is disabled doesn't result in work getting - // posted. - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); - EXPECT_FALSE(test_task_runner_->HasPendingTasks()); - - // When pumping is enabled the task runs normally. - runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::AUTO); - EXPECT_TRUE(test_task_runner_->HasPendingTasks()); - test_task_runner_->RunUntilIdle(); - EXPECT_THAT(run_order, ElementsAre(1)); -} - -TEST_F(TaskQueueManagerTest, DenyRunning_BeforePosting) { - Initialize(1u); - - std::vector<EnqueueOrder> run_order; - runners_[0]->SetQueueEnabled(false); - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); - - test_task_runner_->RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); - - runners_[0]->SetQueueEnabled(true); - test_task_runner_->RunUntilIdle(); - EXPECT_THAT(run_order, ElementsAre(1)); -} - -TEST_F(TaskQueueManagerTest, DenyRunning_AfterPosting) { - Initialize(1u); - - std::vector<EnqueueOrder> run_order; - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); - runners_[0]->SetQueueEnabled(false); - - test_task_runner_->RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); - - runners_[0]->SetQueueEnabled(true); - test_task_runner_->RunUntilIdle(); - EXPECT_THAT(run_order, ElementsAre(1)); -} - -TEST_F(TaskQueueManagerTest, DenyRunning_ManuallyPumpedTransitionsToAuto) { - Initialize(1u); - - std::vector<EnqueueOrder> run_order; - runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL); - runners_[0]->SetQueueEnabled(false); - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); - - test_task_runner_->RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); - - runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::AUTO); - runners_[0]->SetQueueEnabled(true); - test_task_runner_->RunUntilIdle(); - EXPECT_THAT(run_order, ElementsAre(1)); -} - -TEST_F(TaskQueueManagerTest, ManualPumpingWithDelayedTask) { - Initialize(1u); - runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL); - - std::vector<EnqueueOrder> run_order; - // Posting a delayed task when pumping will apply the delay, but won't cause - // work to executed afterwards. - base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10)); - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order), - delay); - - // After pumping but before the delay period has expired, task does not run. - LazyNow lazy_now1(now_src_.get()); - runners_[0]->PumpQueue(&lazy_now1, true); - test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(5)); - EXPECT_TRUE(run_order.empty()); - - // Once the delay has expired, pumping causes the task to run. - now_src_->Advance(base::TimeDelta::FromMilliseconds(5)); - LazyNow lazy_now2(now_src_.get()); - runners_[0]->PumpQueue(&lazy_now2, true); - EXPECT_TRUE(test_task_runner_->HasPendingTasks()); - test_task_runner_->RunPendingTasks(); - EXPECT_THAT(run_order, ElementsAre(1)); -} - -TEST_F(TaskQueueManagerTest, ManualPumpingWithMultipleDelayedTasks) { - Initialize(1u); - runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL); - - std::vector<EnqueueOrder> run_order; - // Posting a delayed task when pumping will apply the delay, but won't cause - // work to executed afterwards. - base::TimeDelta delay1(base::TimeDelta::FromMilliseconds(1)); - base::TimeDelta delay2(base::TimeDelta::FromMilliseconds(10)); - base::TimeDelta delay3(base::TimeDelta::FromMilliseconds(20)); - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order), - delay1); - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order), - delay2); - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order), - delay3); - - now_src_->Advance(base::TimeDelta::FromMilliseconds(15)); - test_task_runner_->RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); - - // Once the delay has expired, pumping causes the task to run. - LazyNow lazy_now(now_src_.get()); - runners_[0]->PumpQueue(&lazy_now, true); - test_task_runner_->RunUntilIdle(); - EXPECT_THAT(run_order, ElementsAre(1, 2)); -} - -TEST_F(TaskQueueManagerTest, DelayedTasksDontAutoRunWithManualPumping) { - Initialize(1u); - runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL); - - std::vector<EnqueueOrder> run_order; - base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10)); - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order), - delay); - - test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(10)); - EXPECT_TRUE(run_order.empty()); -} - -TEST_F(TaskQueueManagerTest, ManualPumpingWithNonEmptyWorkQueue) { - Initialize(1u); - runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL); - - std::vector<EnqueueOrder> run_order; - // Posting two tasks and pumping twice should result in two tasks in the work - // queue. - LazyNow lazy_now(now_src_.get()); - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); - runners_[0]->PumpQueue(&lazy_now, true); - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); - runners_[0]->PumpQueue(&lazy_now, true); - - EXPECT_EQ(2u, runners_[0]->immediate_work_queue()->Size()); -} - -void ReentrantTestTask(scoped_refptr<base::SingleThreadTaskRunner> runner, - int countdown, - std::vector<EnqueueOrder>* out_result) { - out_result->push_back(countdown); - if (--countdown) { - runner->PostTask(FROM_HERE, - Bind(&ReentrantTestTask, runner, countdown, out_result)); - } -} - -TEST_F(TaskQueueManagerTest, ReentrantPosting) { - Initialize(1u); - - std::vector<EnqueueOrder> run_order; - runners_[0]->PostTask(FROM_HERE, - Bind(&ReentrantTestTask, runners_[0], 3, &run_order)); - - test_task_runner_->RunUntilIdle(); - EXPECT_THAT(run_order, ElementsAre(3, 2, 1)); -} - -TEST_F(TaskQueueManagerTest, NoTasksAfterShutdown) { - Initialize(1u); - - std::vector<EnqueueOrder> run_order; - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); - manager_.reset(); - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); - - test_task_runner_->RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); -} - -void PostTaskToRunner(scoped_refptr<base::SingleThreadTaskRunner> runner, - std::vector<EnqueueOrder>* run_order) { - runner->PostTask(FROM_HERE, base::Bind(&TestTask, 1, run_order)); -} - -TEST_F(TaskQueueManagerTest, PostFromThread) { - InitializeWithRealMessageLoop(1u); - - std::vector<EnqueueOrder> run_order; - base::Thread thread("TestThread"); - thread.Start(); - thread.task_runner()->PostTask( - FROM_HERE, base::Bind(&PostTaskToRunner, runners_[0], &run_order)); - thread.Stop(); - - base::RunLoop().RunUntilIdle(); - EXPECT_THAT(run_order, ElementsAre(1)); -} - -void RePostingTestTask(scoped_refptr<base::SingleThreadTaskRunner> runner, - int* run_count) { - (*run_count)++; - runner->PostTask(FROM_HERE, Bind(&RePostingTestTask, - base::Unretained(runner.get()), run_count)); -} - -TEST_F(TaskQueueManagerTest, DoWorkCantPostItselfMultipleTimes) { - Initialize(1u); - - int run_count = 0; - runners_[0]->PostTask( - FROM_HERE, base::Bind(&RePostingTestTask, runners_[0], &run_count)); - - test_task_runner_->RunPendingTasks(); - // NOTE without the executing_task_ check in MaybeScheduleDoWork there - // will be two tasks here. - EXPECT_EQ(1u, test_task_runner_->NumPendingTasks()); - EXPECT_EQ(1, run_count); -} - -TEST_F(TaskQueueManagerTest, PostFromNestedRunloop) { - InitializeWithRealMessageLoop(1u); - - std::vector<EnqueueOrder> run_order; - std::vector<std::pair<base::Closure, bool>> tasks_to_post_from_nested_loop; - tasks_to_post_from_nested_loop.push_back( - std::make_pair(base::Bind(&TestTask, 1, &run_order), true)); - - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 0, &run_order)); - runners_[0]->PostTask( - FROM_HERE, base::Bind(&PostFromNestedRunloop, message_loop_.get(), - base::RetainedRef(runners_[0]), - base::Unretained(&tasks_to_post_from_nested_loop))); - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); - - base::RunLoop().RunUntilIdle(); - - EXPECT_THAT(run_order, ElementsAre(0, 2, 1)); -} - -TEST_F(TaskQueueManagerTest, WorkBatching) { - Initialize(1u); - - manager_->SetWorkBatchSize(2); - - std::vector<EnqueueOrder> run_order; - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order)); - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 4, &run_order)); - - // Running one task in the host message loop should cause two posted tasks to - // get executed. - EXPECT_EQ(test_task_runner_->NumPendingTasks(), 1u); - test_task_runner_->RunPendingTasks(); - EXPECT_THAT(run_order, ElementsAre(1, 2)); - - // The second task runs the remaining two posted tasks. - EXPECT_EQ(test_task_runner_->NumPendingTasks(), 1u); - test_task_runner_->RunPendingTasks(); - EXPECT_THAT(run_order, ElementsAre(1, 2, 3, 4)); -} - -TEST_F(TaskQueueManagerTest, AutoPumpAfterWakeup) { - Initialize(2u); - runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP); - - std::vector<EnqueueOrder> run_order; - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); - test_task_runner_->RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); // Shouldn't run - no other task to wake TQM. - - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); - test_task_runner_->RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); // Still shouldn't wake TQM. - - runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order)); - test_task_runner_->RunUntilIdle(); - // Executing a task on an auto pumped queue should wake the TQM. - EXPECT_THAT(run_order, ElementsAre(3, 1, 2)); -} - -TEST_F(TaskQueueManagerTest, AutoPumpAfterWakeupWhenAlreadyAwake) { - Initialize(2u); - runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP); - - std::vector<EnqueueOrder> run_order; - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); - runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); - test_task_runner_->RunUntilIdle(); - EXPECT_THAT(run_order, ElementsAre(2, 1)); // TQM was already awake. -} - -TEST_F(TaskQueueManagerTest, - AutoPumpAfterWakeupTriggeredByManuallyPumpedQueue) { - Initialize(2u); - runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP); - runners_[1]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL); - - std::vector<EnqueueOrder> run_order; - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); - test_task_runner_->RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); // Shouldn't run - no other task to wake TQM. - - runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); - test_task_runner_->RunUntilIdle(); - // This still shouldn't wake TQM as manual queue was not pumped. - EXPECT_TRUE(run_order.empty()); - - LazyNow lazy_now(now_src_.get()); - runners_[1]->PumpQueue(&lazy_now, true); - test_task_runner_->RunUntilIdle(); - // Executing a task on an auto pumped queue should wake the TQM. - EXPECT_THAT(run_order, ElementsAre(2, 1)); -} - -void TestPostingTask(scoped_refptr<base::SingleThreadTaskRunner> task_runner, - base::Closure task) { - task_runner->PostTask(FROM_HERE, task); -} - -TEST_F(TaskQueueManagerTest, AutoPumpAfterWakeupFromTask) { - Initialize(2u); - runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP); - - std::vector<EnqueueOrder> run_order; - // Check that a task which posts a task to an auto pump after wakeup queue - // doesn't cause the queue to wake up. - base::Closure after_wakeup_task = base::Bind(&TestTask, 1, &run_order); - runners_[1]->PostTask( - FROM_HERE, base::Bind(&TestPostingTask, runners_[0], after_wakeup_task)); - test_task_runner_->RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); - - // Wake up the queue. - runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); - test_task_runner_->RunUntilIdle(); - EXPECT_THAT(run_order, ElementsAre(2, 1)); -} - -TEST_F(TaskQueueManagerTest, AutoPumpAfterWakeupFromMultipleTasks) { - Initialize(2u); - runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP); - - std::vector<EnqueueOrder> run_order; - // Check that a task which posts a task to an auto pump after wakeup queue - // doesn't cause the queue to wake up. - base::Closure after_wakeup_task_1 = base::Bind(&TestTask, 1, &run_order); - base::Closure after_wakeup_task_2 = base::Bind(&TestTask, 2, &run_order); - runners_[1]->PostTask(FROM_HERE, base::Bind(&TestPostingTask, runners_[0], - after_wakeup_task_1)); - runners_[1]->PostTask(FROM_HERE, base::Bind(&TestPostingTask, runners_[0], - after_wakeup_task_2)); - test_task_runner_->RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); - - // Wake up the queue. - runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order)); - test_task_runner_->RunUntilIdle(); - EXPECT_THAT(run_order, ElementsAre(3, 1, 2)); -} - -TEST_F(TaskQueueManagerTest, AutoPumpAfterWakeupBecomesQuiescent) { - Initialize(2u); - runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP); - - int run_count = 0; - // Check that if multiple tasks reposts themselves onto a pump-after-wakeup - // queue they don't wake each other and will eventually stop when no other - // tasks execute. - runners_[0]->PostTask( - FROM_HERE, base::Bind(&RePostingTestTask, runners_[0], &run_count)); - runners_[0]->PostTask( - FROM_HERE, base::Bind(&RePostingTestTask, runners_[0], &run_count)); - runners_[1]->PostTask(FROM_HERE, base::Bind(&NopTask)); - test_task_runner_->RunUntilIdle(); - // The reposting tasks posted to the after wakeup queue shouldn't have woken - // each other up. - EXPECT_EQ(2, run_count); -} - -TEST_F(TaskQueueManagerTest, AutoPumpAfterWakeupWithDontWakeQueue) { - Initialize(1u); - - scoped_refptr<internal::TaskQueueImpl> queue0 = manager_->NewTaskQueue( - TaskQueue::Spec("test_queue 0") - .SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP)); - scoped_refptr<internal::TaskQueueImpl> queue1 = manager_->NewTaskQueue( - TaskQueue::Spec("test_queue 0") - .SetWakeupPolicy(TaskQueue::WakeupPolicy::DONT_WAKE_OTHER_QUEUES)); - scoped_refptr<internal::TaskQueueImpl> queue2 = runners_[0]; - - std::vector<EnqueueOrder> run_order; - queue0->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); - queue1->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); - test_task_runner_->RunUntilIdle(); - // Executing a DONT_WAKE_OTHER_QUEUES queue shouldn't wake the autopump after - // wakeup queue. - EXPECT_THAT(run_order, ElementsAre(2)); - - queue2->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order)); - test_task_runner_->RunUntilIdle(); - // Executing a CAN_WAKE_OTHER_QUEUES queue should wake the autopump after - // wakeup queue. - EXPECT_THAT(run_order, ElementsAre(2, 3, 1)); -} - -class MockTaskObserver : public base::MessageLoop::TaskObserver { - public: - MOCK_METHOD1(DidProcessTask, void(const base::PendingTask& task)); - MOCK_METHOD1(WillProcessTask, void(const base::PendingTask& task)); -}; - -TEST_F(TaskQueueManagerTest, TaskObserverAdding) { - InitializeWithRealMessageLoop(1u); - MockTaskObserver observer; - - manager_->SetWorkBatchSize(2); - manager_->AddTaskObserver(&observer); - - std::vector<EnqueueOrder> run_order; - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); - - EXPECT_CALL(observer, WillProcessTask(_)).Times(2); - EXPECT_CALL(observer, DidProcessTask(_)).Times(2); - base::RunLoop().RunUntilIdle(); -} - -TEST_F(TaskQueueManagerTest, TaskObserverRemoving) { - InitializeWithRealMessageLoop(1u); - MockTaskObserver observer; - manager_->SetWorkBatchSize(2); - manager_->AddTaskObserver(&observer); - manager_->RemoveTaskObserver(&observer); - - std::vector<EnqueueOrder> run_order; - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); - - EXPECT_CALL(observer, WillProcessTask(_)).Times(0); - EXPECT_CALL(observer, DidProcessTask(_)).Times(0); - - base::RunLoop().RunUntilIdle(); -} - -void RemoveObserverTask(TaskQueueManager* manager, - base::MessageLoop::TaskObserver* observer) { - manager->RemoveTaskObserver(observer); -} - -TEST_F(TaskQueueManagerTest, TaskObserverRemovingInsideTask) { - InitializeWithRealMessageLoop(1u); - MockTaskObserver observer; - manager_->SetWorkBatchSize(3); - manager_->AddTaskObserver(&observer); - - runners_[0]->PostTask( - FROM_HERE, base::Bind(&RemoveObserverTask, manager_.get(), &observer)); - - EXPECT_CALL(observer, WillProcessTask(_)).Times(1); - EXPECT_CALL(observer, DidProcessTask(_)).Times(0); - base::RunLoop().RunUntilIdle(); -} - -TEST_F(TaskQueueManagerTest, QueueTaskObserverAdding) { - InitializeWithRealMessageLoop(2u); - MockTaskObserver observer; - - manager_->SetWorkBatchSize(2); - runners_[0]->AddTaskObserver(&observer); - - std::vector<EnqueueOrder> run_order; - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); - runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); - - EXPECT_CALL(observer, WillProcessTask(_)).Times(1); - EXPECT_CALL(observer, DidProcessTask(_)).Times(1); - base::RunLoop().RunUntilIdle(); -} - -TEST_F(TaskQueueManagerTest, QueueTaskObserverRemoving) { - InitializeWithRealMessageLoop(1u); - MockTaskObserver observer; - manager_->SetWorkBatchSize(2); - runners_[0]->AddTaskObserver(&observer); - runners_[0]->RemoveTaskObserver(&observer); - - std::vector<EnqueueOrder> run_order; - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); - - EXPECT_CALL(observer, WillProcessTask(_)).Times(0); - EXPECT_CALL(observer, DidProcessTask(_)).Times(0); - - base::RunLoop().RunUntilIdle(); -} - -void RemoveQueueObserverTask(scoped_refptr<TaskQueue> queue, - base::MessageLoop::TaskObserver* observer) { - queue->RemoveTaskObserver(observer); -} - -TEST_F(TaskQueueManagerTest, QueueTaskObserverRemovingInsideTask) { - InitializeWithRealMessageLoop(1u); - MockTaskObserver observer; - runners_[0]->AddTaskObserver(&observer); - - runners_[0]->PostTask( - FROM_HERE, base::Bind(&RemoveQueueObserverTask, runners_[0], &observer)); - - EXPECT_CALL(observer, WillProcessTask(_)).Times(1); - EXPECT_CALL(observer, DidProcessTask(_)).Times(0); - base::RunLoop().RunUntilIdle(); -} - -TEST_F(TaskQueueManagerTest, ThreadCheckAfterTermination) { - Initialize(1u); - EXPECT_TRUE(runners_[0]->RunsTasksOnCurrentThread()); - manager_.reset(); - EXPECT_TRUE(runners_[0]->RunsTasksOnCurrentThread()); -} - -TEST_F(TaskQueueManagerTest, TimeDomain_NextScheduledRunTime) { - Initialize(2u); - now_src_->Advance(base::TimeDelta::FromMicroseconds(10000)); - - // With no delayed tasks. - base::TimeTicks run_time; - EXPECT_FALSE(manager_->real_time_domain()->NextScheduledRunTime(&run_time)); - - // With a non-delayed task. - runners_[0]->PostTask(FROM_HERE, base::Bind(&NopTask)); - EXPECT_FALSE(manager_->real_time_domain()->NextScheduledRunTime(&run_time)); - - // With a delayed task. - base::TimeDelta expected_delay = base::TimeDelta::FromMilliseconds(50); - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), expected_delay); - EXPECT_TRUE(manager_->real_time_domain()->NextScheduledRunTime(&run_time)); - EXPECT_EQ(now_src_->NowTicks() + expected_delay, run_time); - - // With another delayed task in the same queue with a longer delay. - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), - base::TimeDelta::FromMilliseconds(100)); - EXPECT_TRUE(manager_->real_time_domain()->NextScheduledRunTime(&run_time)); - EXPECT_EQ(now_src_->NowTicks() + expected_delay, run_time); - - // With another delayed task in the same queue with a shorter delay. - expected_delay = base::TimeDelta::FromMilliseconds(20); - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), expected_delay); - EXPECT_TRUE(manager_->real_time_domain()->NextScheduledRunTime(&run_time)); - EXPECT_EQ(now_src_->NowTicks() + expected_delay, run_time); - - // With another delayed task in a different queue with a shorter delay. - expected_delay = base::TimeDelta::FromMilliseconds(10); - runners_[1]->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), expected_delay); - EXPECT_TRUE(manager_->real_time_domain()->NextScheduledRunTime(&run_time)); - EXPECT_EQ(now_src_->NowTicks() + expected_delay, run_time); - - // Test it updates as time progresses - now_src_->Advance(expected_delay); - EXPECT_TRUE(manager_->real_time_domain()->NextScheduledRunTime(&run_time)); - EXPECT_EQ(now_src_->NowTicks(), run_time); -} - -TEST_F(TaskQueueManagerTest, TimeDomain_NextScheduledRunTime_MultipleQueues) { - Initialize(3u); - - base::TimeDelta delay1 = base::TimeDelta::FromMilliseconds(50); - base::TimeDelta delay2 = base::TimeDelta::FromMilliseconds(5); - base::TimeDelta delay3 = base::TimeDelta::FromMilliseconds(10); - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), delay1); - runners_[1]->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), delay2); - runners_[2]->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), delay3); - runners_[0]->PostTask(FROM_HERE, base::Bind(&NopTask)); - - base::TimeTicks run_time; - EXPECT_TRUE(manager_->real_time_domain()->NextScheduledRunTime(&run_time)); - EXPECT_EQ(now_src_->NowTicks() + delay2, run_time); -} - -TEST_F(TaskQueueManagerTest, DeleteTaskQueueManagerInsideATask) { - Initialize(1u); - - runners_[0]->PostTask( - FROM_HERE, base::Bind(&TaskQueueManagerTest::DeleteTaskQueueManager, - base::Unretained(this))); - - // This should not crash, assuming DoWork detects the TaskQueueManager has - // been deleted. - test_task_runner_->RunUntilIdle(); -} - -TEST_F(TaskQueueManagerTest, GetAndClearSystemIsQuiescentBit) { - Initialize(3u); - - scoped_refptr<internal::TaskQueueImpl> queue0 = manager_->NewTaskQueue( - TaskQueue::Spec("test_queue 0").SetShouldMonitorQuiescence(true)); - scoped_refptr<internal::TaskQueueImpl> queue1 = manager_->NewTaskQueue( - TaskQueue::Spec("test_queue 1").SetShouldMonitorQuiescence(true)); - scoped_refptr<internal::TaskQueueImpl> queue2 = manager_->NewTaskQueue( - TaskQueue::Spec("test_queue 2").SetShouldMonitorQuiescence(false)); - - EXPECT_TRUE(manager_->GetAndClearSystemIsQuiescentBit()); - - queue0->PostTask(FROM_HERE, base::Bind(&NopTask)); - test_task_runner_->RunUntilIdle(); - EXPECT_FALSE(manager_->GetAndClearSystemIsQuiescentBit()); - EXPECT_TRUE(manager_->GetAndClearSystemIsQuiescentBit()); - - queue1->PostTask(FROM_HERE, base::Bind(&NopTask)); - test_task_runner_->RunUntilIdle(); - EXPECT_FALSE(manager_->GetAndClearSystemIsQuiescentBit()); - EXPECT_TRUE(manager_->GetAndClearSystemIsQuiescentBit()); - - queue2->PostTask(FROM_HERE, base::Bind(&NopTask)); - test_task_runner_->RunUntilIdle(); - EXPECT_TRUE(manager_->GetAndClearSystemIsQuiescentBit()); - - queue0->PostTask(FROM_HERE, base::Bind(&NopTask)); - queue1->PostTask(FROM_HERE, base::Bind(&NopTask)); - test_task_runner_->RunUntilIdle(); - EXPECT_FALSE(manager_->GetAndClearSystemIsQuiescentBit()); - EXPECT_TRUE(manager_->GetAndClearSystemIsQuiescentBit()); -} - -TEST_F(TaskQueueManagerTest, HasPendingImmediateWork) { - Initialize(2u); - internal::TaskQueueImpl* queue0 = runners_[0].get(); - internal::TaskQueueImpl* queue1 = runners_[1].get(); - queue0->SetPumpPolicy(TaskQueue::PumpPolicy::AUTO); - queue1->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL); - - EXPECT_FALSE(queue0->HasPendingImmediateWork()); - EXPECT_FALSE(queue1->HasPendingImmediateWork()); - - queue0->PostTask(FROM_HERE, base::Bind(NullTask)); - queue1->PostTask(FROM_HERE, base::Bind(NullTask)); - EXPECT_TRUE(queue0->HasPendingImmediateWork()); - EXPECT_TRUE(queue1->HasPendingImmediateWork()); - - test_task_runner_->RunUntilIdle(); - EXPECT_FALSE(queue0->HasPendingImmediateWork()); - EXPECT_TRUE(queue1->HasPendingImmediateWork()); - - LazyNow lazy_now(now_src_.get()); - queue1->PumpQueue(&lazy_now, true); - EXPECT_FALSE(queue0->HasPendingImmediateWork()); - EXPECT_TRUE(queue1->HasPendingImmediateWork()); - - test_task_runner_->RunUntilIdle(); - EXPECT_FALSE(queue0->HasPendingImmediateWork()); - EXPECT_FALSE(queue1->HasPendingImmediateWork()); -} - -TEST_F(TaskQueueManagerTest, HasPendingImmediateWorkAndNeedsPumping) { - Initialize(2u); - internal::TaskQueueImpl* queue0 = runners_[0].get(); - internal::TaskQueueImpl* queue1 = runners_[1].get(); - queue0->SetPumpPolicy(TaskQueue::PumpPolicy::AUTO); - queue1->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL); - - EXPECT_FALSE(queue0->HasPendingImmediateWork()); - EXPECT_FALSE(queue0->NeedsPumping()); - EXPECT_FALSE(queue1->HasPendingImmediateWork()); - EXPECT_FALSE(queue1->NeedsPumping()); - - queue0->PostTask(FROM_HERE, base::Bind(NullTask)); - queue0->PostTask(FROM_HERE, base::Bind(NullTask)); - queue1->PostTask(FROM_HERE, base::Bind(NullTask)); - EXPECT_TRUE(queue0->HasPendingImmediateWork()); - EXPECT_TRUE(queue0->NeedsPumping()); - EXPECT_TRUE(queue1->HasPendingImmediateWork()); - EXPECT_TRUE(queue1->NeedsPumping()); - - test_task_runner_->SetRunTaskLimit(1); - test_task_runner_->RunPendingTasks(); - EXPECT_TRUE(queue0->HasPendingImmediateWork()); - EXPECT_FALSE(queue0->NeedsPumping()); - EXPECT_TRUE(queue1->HasPendingImmediateWork()); - EXPECT_TRUE(queue1->NeedsPumping()); - - test_task_runner_->ClearRunTaskLimit(); - test_task_runner_->RunUntilIdle(); - EXPECT_FALSE(queue0->HasPendingImmediateWork()); - EXPECT_FALSE(queue0->NeedsPumping()); - EXPECT_TRUE(queue1->HasPendingImmediateWork()); - EXPECT_TRUE(queue1->NeedsPumping()); - - LazyNow lazy_now(now_src_.get()); - queue1->PumpQueue(&lazy_now, true); - EXPECT_FALSE(queue0->HasPendingImmediateWork()); - EXPECT_FALSE(queue0->NeedsPumping()); - EXPECT_TRUE(queue1->HasPendingImmediateWork()); - EXPECT_FALSE(queue1->NeedsPumping()); - - test_task_runner_->RunUntilIdle(); - EXPECT_FALSE(queue0->HasPendingImmediateWork()); - EXPECT_FALSE(queue0->NeedsPumping()); - EXPECT_FALSE(queue1->HasPendingImmediateWork()); - EXPECT_FALSE(queue1->NeedsPumping()); -} - -void ExpensiveTestTask(int value, - base::SimpleTestTickClock* clock, - std::vector<EnqueueOrder>* out_result) { - out_result->push_back(value); - clock->Advance(base::TimeDelta::FromMilliseconds(1)); -} - -TEST_F(TaskQueueManagerTest, ImmediateAndDelayedTaskInterleaving) { - Initialize(1u); - - std::vector<EnqueueOrder> run_order; - base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10); - for (int i = 10; i < 19; i++) { - runners_[0]->PostDelayedTask( - FROM_HERE, - base::Bind(&ExpensiveTestTask, i, now_src_.get(), &run_order), - delay); - } - - test_task_runner_->RunForPeriod(delay); - - for (int i = 0; i < 9; i++) { - runners_[0]->PostTask( - FROM_HERE, - base::Bind(&ExpensiveTestTask, i, now_src_.get(), &run_order)); - } - - test_task_runner_->SetAutoAdvanceNowToPendingTasks(true); - test_task_runner_->RunUntilIdle(); - - // Delayed tasks are not allowed to starve out immediate work which is why - // some of the immediate tasks run out of order. - int expected_run_order[] = { - 10, 11, 12, 13, 0, 14, 15, 16, 1, 17, 18, 2, 3, 4, 5, 6, 7, 8 - }; - EXPECT_THAT(run_order, ElementsAreArray(expected_run_order)); -} - -TEST_F(TaskQueueManagerTest, - DelayedTaskDoesNotSkipAHeadOfNonDelayedTask_SameQueue) { - Initialize(1u); - - std::vector<EnqueueOrder> run_order; - base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10); - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order)); - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order), - delay); - - now_src_->Advance(delay * 2); - test_task_runner_->RunUntilIdle(); - - EXPECT_THAT(run_order, ElementsAre(2, 3, 1)); -} - -TEST_F(TaskQueueManagerTest, - DelayedTaskDoesNotSkipAHeadOfNonDelayedTask_DifferentQueues) { - Initialize(2u); - - std::vector<EnqueueOrder> run_order; - base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10); - runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); - runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order)); - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order), - delay); - - now_src_->Advance(delay * 2); - test_task_runner_->RunUntilIdle(); - - EXPECT_THAT(run_order, ElementsAre(2, 3, 1)); -} - -TEST_F(TaskQueueManagerTest, DelayedTaskDoesNotSkipAHeadOfShorterDelayedTask) { - Initialize(2u); - - std::vector<EnqueueOrder> run_order; - base::TimeDelta delay1 = base::TimeDelta::FromMilliseconds(10); - base::TimeDelta delay2 = base::TimeDelta::FromMilliseconds(5); - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order), - delay1); - runners_[1]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order), - delay2); - - now_src_->Advance(delay1 * 2); - test_task_runner_->RunUntilIdle(); - - EXPECT_THAT(run_order, ElementsAre(2, 1)); -} - -void CheckIsNested(bool* is_nested) { - *is_nested = base::MessageLoop::current()->IsNested(); -} - -void PostAndQuitFromNestedRunloop(base::RunLoop* run_loop, - base::SingleThreadTaskRunner* runner, - bool* was_nested) { - base::MessageLoop::ScopedNestableTaskAllower allow( - base::MessageLoop::current()); - runner->PostTask(FROM_HERE, run_loop->QuitClosure()); - runner->PostTask(FROM_HERE, base::Bind(&CheckIsNested, was_nested)); - run_loop->Run(); -} - -TEST_F(TaskQueueManagerTest, QuitWhileNested) { - // This test makes sure we don't continue running a work batch after a nested - // run loop has been exited in the middle of the batch. - InitializeWithRealMessageLoop(1u); - manager_->SetWorkBatchSize(2); - - bool was_nested = true; - base::RunLoop run_loop; - runners_[0]->PostTask(FROM_HERE, base::Bind(&PostAndQuitFromNestedRunloop, - base::Unretained(&run_loop), - base::RetainedRef(runners_[0]), - base::Unretained(&was_nested))); - - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(was_nested); -} - -class SequenceNumberCapturingTaskObserver - : public base::MessageLoop::TaskObserver { - public: - // MessageLoop::TaskObserver overrides. - void WillProcessTask(const base::PendingTask& pending_task) override {} - void DidProcessTask(const base::PendingTask& pending_task) override { - sequence_numbers_.push_back(pending_task.sequence_num); - } - - const std::vector<EnqueueOrder>& sequence_numbers() const { - return sequence_numbers_; - } - - private: - std::vector<EnqueueOrder> sequence_numbers_; -}; - -TEST_F(TaskQueueManagerTest, SequenceNumSetWhenTaskIsPosted) { - Initialize(1u); - - SequenceNumberCapturingTaskObserver observer; - manager_->AddTaskObserver(&observer); - - // Register four tasks that will run in reverse order. - std::vector<EnqueueOrder> run_order; - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order), - base::TimeDelta::FromMilliseconds(30)); - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order), - base::TimeDelta::FromMilliseconds(20)); - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order), - base::TimeDelta::FromMilliseconds(10)); - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 4, &run_order)); - - test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(40)); - ASSERT_THAT(run_order, ElementsAre(4, 3, 2, 1)); - - // The sequence numbers are a zero-based monotonically incrememting counter - // which should be set when the task is posted rather than when it's enqueued - // onto the Incoming queue. - EXPECT_THAT(observer.sequence_numbers(), ElementsAre(3, 2, 1, 0)); - - manager_->RemoveTaskObserver(&observer); -} - -TEST_F(TaskQueueManagerTest, NewTaskQueues) { - Initialize(1u); - - scoped_refptr<internal::TaskQueueImpl> queue1 = - manager_->NewTaskQueue(TaskQueue::Spec("foo")); - scoped_refptr<internal::TaskQueueImpl> queue2 = - manager_->NewTaskQueue(TaskQueue::Spec("bar")); - scoped_refptr<internal::TaskQueueImpl> queue3 = - manager_->NewTaskQueue(TaskQueue::Spec("baz")); - - ASSERT_NE(queue1, queue2); - ASSERT_NE(queue1, queue3); - ASSERT_NE(queue2, queue3); - - std::vector<EnqueueOrder> run_order; - queue1->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); - queue2->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); - queue3->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order)); - test_task_runner_->RunUntilIdle(); - - EXPECT_THAT(run_order, ElementsAre(1, 2, 3)); -} - -TEST_F(TaskQueueManagerTest, UnregisterTaskQueue) { - Initialize(1u); - - scoped_refptr<internal::TaskQueueImpl> queue1 = - manager_->NewTaskQueue(TaskQueue::Spec("foo")); - scoped_refptr<internal::TaskQueueImpl> queue2 = - manager_->NewTaskQueue(TaskQueue::Spec("bar")); - scoped_refptr<internal::TaskQueueImpl> queue3 = - manager_->NewTaskQueue(TaskQueue::Spec("baz")); - - ASSERT_NE(queue1, queue2); - ASSERT_NE(queue1, queue3); - ASSERT_NE(queue2, queue3); - - std::vector<EnqueueOrder> run_order; - queue1->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); - queue2->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); - queue3->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order)); - - queue2->UnregisterTaskQueue(); - test_task_runner_->RunUntilIdle(); - - EXPECT_THAT(run_order, ElementsAre(1, 3)); -} - -TEST_F(TaskQueueManagerTest, UnregisterTaskQueue_WithDelayedTasks) { - Initialize(2u); - - // Register three delayed tasks - std::vector<EnqueueOrder> run_order; - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order), - base::TimeDelta::FromMilliseconds(10)); - runners_[1]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order), - base::TimeDelta::FromMilliseconds(20)); - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order), - base::TimeDelta::FromMilliseconds(30)); - - runners_[1]->UnregisterTaskQueue(); - test_task_runner_->RunUntilIdle(); - - test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(40)); - ASSERT_THAT(run_order, ElementsAre(1, 3)); -} - -namespace { -void UnregisterQueue(scoped_refptr<internal::TaskQueueImpl> queue) { - queue->UnregisterTaskQueue(); -} -} - -TEST_F(TaskQueueManagerTest, UnregisterTaskQueue_InTasks) { - Initialize(3u); - - std::vector<EnqueueOrder> run_order; - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); - runners_[0]->PostTask(FROM_HERE, base::Bind(&UnregisterQueue, runners_[1])); - runners_[0]->PostTask(FROM_HERE, base::Bind(&UnregisterQueue, runners_[2])); - runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); - runners_[2]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order)); - - test_task_runner_->RunUntilIdle(); - ASSERT_THAT(run_order, ElementsAre(1)); -} - -void PostTestTasksFromNestedMessageLoop( - base::MessageLoop* message_loop, - scoped_refptr<base::SingleThreadTaskRunner> main_runner, - scoped_refptr<base::SingleThreadTaskRunner> wake_up_runner, - std::vector<EnqueueOrder>* run_order) { - base::MessageLoop::ScopedNestableTaskAllower allow(message_loop); - main_runner->PostNonNestableTask(FROM_HERE, - base::Bind(&TestTask, 1, run_order)); - // The following should never get executed. - wake_up_runner->PostTask(FROM_HERE, base::Bind(&TestTask, 2, run_order)); - base::RunLoop().RunUntilIdle(); -} - -TEST_F(TaskQueueManagerTest, DeferredNonNestableTaskDoesNotTriggerWakeUp) { - // This test checks that running (i.e., deferring) a non-nestable task in a - // nested run loop does not trigger the pumping of an on-wakeup queue. - InitializeWithRealMessageLoop(2u); - runners_[1]->SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP); - - std::vector<EnqueueOrder> run_order; - runners_[0]->PostTask( - FROM_HERE, - base::Bind(&PostTestTasksFromNestedMessageLoop, message_loop_.get(), - runners_[0], runners_[1], base::Unretained(&run_order))); - - base::RunLoop().RunUntilIdle(); - ASSERT_THAT(run_order, ElementsAre(1)); -} - -namespace { - -class MockObserver : public TaskQueueManager::Observer { - public: - MOCK_METHOD1(OnUnregisterTaskQueue, - void(const scoped_refptr<TaskQueue>& queue)); - MOCK_METHOD2(OnTriedToExecuteBlockedTask, - void(const TaskQueue& queue, const base::PendingTask& task)); -}; - -} // namespace - -TEST_F(TaskQueueManagerTest, OnUnregisterTaskQueue) { - Initialize(0u); - - MockObserver observer; - manager_->SetObserver(&observer); - - scoped_refptr<internal::TaskQueueImpl> task_queue = - manager_->NewTaskQueue(TaskQueue::Spec("test_queue")); - - EXPECT_CALL(observer, OnUnregisterTaskQueue(_)).Times(1); - task_queue->UnregisterTaskQueue(); - - manager_->SetObserver(nullptr); -} - -TEST_F(TaskQueueManagerTest, OnTriedToExecuteBlockedTask) { - Initialize(0u); - - MockObserver observer; - manager_->SetObserver(&observer); - - scoped_refptr<internal::TaskQueueImpl> task_queue = manager_->NewTaskQueue( - TaskQueue::Spec("test_queue").SetShouldReportWhenExecutionBlocked(true)); - task_queue->SetQueueEnabled(false); - task_queue->PostTask(FROM_HERE, base::Bind(&NopTask)); - - EXPECT_CALL(observer, OnTriedToExecuteBlockedTask(_, _)).Times(1); - test_task_runner_->RunPendingTasks(); - - manager_->SetObserver(nullptr); -} - -TEST_F(TaskQueueManagerTest, ExecutedNonBlockedTask) { - Initialize(0u); - - MockObserver observer; - manager_->SetObserver(&observer); - - scoped_refptr<internal::TaskQueueImpl> task_queue = manager_->NewTaskQueue( - TaskQueue::Spec("test_queue").SetShouldReportWhenExecutionBlocked(true)); - task_queue->PostTask(FROM_HERE, base::Bind(&NopTask)); - - EXPECT_CALL(observer, OnTriedToExecuteBlockedTask(_, _)).Times(0); - test_task_runner_->RunPendingTasks(); - - manager_->SetObserver(nullptr); -} - -void HasOneRefTask(std::vector<bool>* log, internal::TaskQueueImpl* tq) { - log->push_back(tq->HasOneRef()); -} - -TEST_F(TaskQueueManagerTest, UnregisterTaskQueueInNestedLoop) { - InitializeWithRealMessageLoop(1u); - - // We retain a reference to the task queue even when the manager has deleted - // its reference. - scoped_refptr<internal::TaskQueueImpl> task_queue = - manager_->NewTaskQueue(TaskQueue::Spec("test_queue")); - - std::vector<bool> log; - std::vector<std::pair<base::Closure, bool>> tasks_to_post_from_nested_loop; - - // Inside a nested run loop, call task_queue->UnregisterTaskQueue, bookended - // by calls to HasOneRefTask to make sure the manager doesn't release its - // reference until the nested run loop exits. - // NB: This first HasOneRefTask is a sanity check. - tasks_to_post_from_nested_loop.push_back( - std::make_pair(base::Bind(&HasOneRefTask, base::Unretained(&log), - base::Unretained(task_queue.get())), - true)); - tasks_to_post_from_nested_loop.push_back(std::make_pair( - base::Bind(&internal::TaskQueueImpl::UnregisterTaskQueue, - base::Unretained(task_queue.get())), true)); - tasks_to_post_from_nested_loop.push_back( - std::make_pair(base::Bind(&HasOneRefTask, base::Unretained(&log), - base::Unretained(task_queue.get())), - true)); - runners_[0]->PostTask( - FROM_HERE, base::Bind(&PostFromNestedRunloop, message_loop_.get(), - base::RetainedRef(runners_[0]), - base::Unretained(&tasks_to_post_from_nested_loop))); - base::RunLoop().RunUntilIdle(); - - // Add a final call to HasOneRefTask. This gives the manager a chance to - // release its reference, and checks that it has. - runners_[0]->PostTask(FROM_HERE, - base::Bind(&HasOneRefTask, base::Unretained(&log), - base::Unretained(task_queue.get()))); - base::RunLoop().RunUntilIdle(); - - EXPECT_THAT(log, ElementsAre(false, false, true)); -} - -TEST_F(TaskQueueManagerTest, TimeDomainsAreIndependant) { - Initialize(2u); - - base::TimeTicks start_time = manager_->delegate()->NowTicks(); - std::unique_ptr<VirtualTimeDomain> domain_a( - new VirtualTimeDomain(nullptr, start_time)); - std::unique_ptr<VirtualTimeDomain> domain_b( - new VirtualTimeDomain(nullptr, start_time)); - manager_->RegisterTimeDomain(domain_a.get()); - manager_->RegisterTimeDomain(domain_b.get()); - runners_[0]->SetTimeDomain(domain_a.get()); - runners_[1]->SetTimeDomain(domain_b.get()); - - std::vector<EnqueueOrder> run_order; - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order), - base::TimeDelta::FromMilliseconds(10)); - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order), - base::TimeDelta::FromMilliseconds(20)); - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order), - base::TimeDelta::FromMilliseconds(30)); - - runners_[1]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 4, &run_order), - base::TimeDelta::FromMilliseconds(10)); - runners_[1]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 5, &run_order), - base::TimeDelta::FromMilliseconds(20)); - runners_[1]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 6, &run_order), - base::TimeDelta::FromMilliseconds(30)); - - domain_b->AdvanceTo(start_time + base::TimeDelta::FromMilliseconds(50)); - manager_->MaybeScheduleImmediateWork(FROM_HERE); - - test_task_runner_->RunUntilIdle(); - EXPECT_THAT(run_order, ElementsAre(4, 5, 6)); - - domain_a->AdvanceTo(start_time + base::TimeDelta::FromMilliseconds(50)); - manager_->MaybeScheduleImmediateWork(FROM_HERE); - - test_task_runner_->RunUntilIdle(); - EXPECT_THAT(run_order, ElementsAre(4, 5, 6, 1, 2, 3)); - - runners_[0]->UnregisterTaskQueue(); - runners_[1]->UnregisterTaskQueue(); - - manager_->UnregisterTimeDomain(domain_a.get()); - manager_->UnregisterTimeDomain(domain_b.get()); -} - -TEST_F(TaskQueueManagerTest, TimeDomainMigration) { - Initialize(1u); - - base::TimeTicks start_time = manager_->delegate()->NowTicks(); - std::unique_ptr<VirtualTimeDomain> domain_a( - new VirtualTimeDomain(nullptr, start_time)); - manager_->RegisterTimeDomain(domain_a.get()); - runners_[0]->SetTimeDomain(domain_a.get()); - - std::vector<EnqueueOrder> run_order; - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order), - base::TimeDelta::FromMilliseconds(10)); - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order), - base::TimeDelta::FromMilliseconds(20)); - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order), - base::TimeDelta::FromMilliseconds(30)); - runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 4, &run_order), - base::TimeDelta::FromMilliseconds(40)); - - domain_a->AdvanceTo(start_time + base::TimeDelta::FromMilliseconds(20)); - manager_->MaybeScheduleImmediateWork(FROM_HERE); - test_task_runner_->RunUntilIdle(); - EXPECT_THAT(run_order, ElementsAre(1, 2)); - - std::unique_ptr<VirtualTimeDomain> domain_b( - new VirtualTimeDomain(nullptr, start_time)); - manager_->RegisterTimeDomain(domain_b.get()); - runners_[0]->SetTimeDomain(domain_b.get()); - - domain_b->AdvanceTo(start_time + base::TimeDelta::FromMilliseconds(50)); - manager_->MaybeScheduleImmediateWork(FROM_HERE); - - test_task_runner_->RunUntilIdle(); - EXPECT_THAT(run_order, ElementsAre(1, 2, 3, 4)); - - runners_[0]->UnregisterTaskQueue(); - - manager_->UnregisterTimeDomain(domain_a.get()); - manager_->UnregisterTimeDomain(domain_b.get()); -} - -TEST_F(TaskQueueManagerTest, TimeDomainMigrationWithIncomingImmediateTasks) { - Initialize(1u); - - base::TimeTicks start_time = manager_->delegate()->NowTicks(); - std::unique_ptr<VirtualTimeDomain> domain_a( - new VirtualTimeDomain(nullptr, start_time)); - std::unique_ptr<VirtualTimeDomain> domain_b( - new VirtualTimeDomain(nullptr, start_time)); - manager_->RegisterTimeDomain(domain_a.get()); - manager_->RegisterTimeDomain(domain_b.get()); - - runners_[0]->SetTimeDomain(domain_a.get()); - std::vector<EnqueueOrder> run_order; - runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); - runners_[0]->SetTimeDomain(domain_b.get()); - - test_task_runner_->RunUntilIdle(); - EXPECT_THAT(run_order, ElementsAre(1)); - - runners_[0]->UnregisterTaskQueue(); - - manager_->UnregisterTimeDomain(domain_a.get()); - manager_->UnregisterTimeDomain(domain_b.get()); -} - -namespace { -void ChromiumRunloopInspectionTask( - scoped_refptr<cc::OrderedSimpleTaskRunner> test_task_runner) { - EXPECT_EQ(1u, test_task_runner->NumPendingTasks()); -} -} // namespace - -TEST_F(TaskQueueManagerTest, NumberOfPendingTasksOnChromiumRunLoop) { - Initialize(1u); - - // NOTE because tasks posted to the chromiumrun loop are not cancellable, we - // will end up with a lot more tasks posted if the delayed tasks were posted - // in the reverse order. - // TODO(alexclarke): Consider talking to the message pump directly. - test_task_runner_->SetAutoAdvanceNowToPendingTasks(true); - for (int i = 1; i < 100; i++) { - runners_[0]->PostDelayedTask( - FROM_HERE, - base::Bind(&ChromiumRunloopInspectionTask, test_task_runner_), - base::TimeDelta::FromMilliseconds(i)); - } - test_task_runner_->RunUntilIdle(); -} - -namespace { - -class QuadraticTask { - public: - QuadraticTask(scoped_refptr<internal::TaskQueueImpl> task_queue, - base::TimeDelta delay, - base::SimpleTestTickClock* now_src) - : count_(0), task_queue_(task_queue), delay_(delay), now_src_(now_src) {} - - void SetShouldExit(base::Callback<bool()> should_exit) { - should_exit_ = should_exit; - } - - void Run() { - if (should_exit_.Run()) - return; - count_++; - task_queue_->PostDelayedTask( - FROM_HERE, base::Bind(&QuadraticTask::Run, base::Unretained(this)), - delay_); - task_queue_->PostDelayedTask( - FROM_HERE, base::Bind(&QuadraticTask::Run, base::Unretained(this)), - delay_); - now_src_->Advance(base::TimeDelta::FromMilliseconds(5)); - } - - int count() const { return count_; } - - private: - int count_; - scoped_refptr<internal::TaskQueueImpl> task_queue_; - base::TimeDelta delay_; - base::Callback<bool()> should_exit_; - base::SimpleTestTickClock* now_src_; -}; - -class LinearTask { - public: - LinearTask(scoped_refptr<internal::TaskQueueImpl> task_queue, - base::TimeDelta delay, - base::SimpleTestTickClock* now_src) - : count_(0), task_queue_(task_queue), delay_(delay), now_src_(now_src) {} - - void SetShouldExit(base::Callback<bool()> should_exit) { - should_exit_ = should_exit; - } - - void Run() { - if (should_exit_.Run()) - return; - count_++; - task_queue_->PostDelayedTask( - FROM_HERE, base::Bind(&LinearTask::Run, base::Unretained(this)), - delay_); - now_src_->Advance(base::TimeDelta::FromMilliseconds(5)); - } - - int count() const { return count_; } - - private: - int count_; - scoped_refptr<internal::TaskQueueImpl> task_queue_; - base::TimeDelta delay_; - base::Callback<bool()> should_exit_; - base::SimpleTestTickClock* now_src_; -}; - -bool ShouldExit(QuadraticTask* quadratic_task, LinearTask* linear_task) { - return quadratic_task->count() == 1000 || linear_task->count() == 1000; -} - -} // namespace - -TEST_F(TaskQueueManagerTest, - DelayedTasksDontBadlyStarveNonDelayedWork_SameQueue) { - Initialize(1u); - - QuadraticTask quadratic_delayed_task( - runners_[0], base::TimeDelta::FromMilliseconds(10), now_src_.get()); - LinearTask linear_immediate_task(runners_[0], base::TimeDelta(), - now_src_.get()); - base::Callback<bool()> should_exit = - base::Bind(ShouldExit, &quadratic_delayed_task, &linear_immediate_task); - quadratic_delayed_task.SetShouldExit(should_exit); - linear_immediate_task.SetShouldExit(should_exit); - - quadratic_delayed_task.Run(); - linear_immediate_task.Run(); - - test_task_runner_->SetAutoAdvanceNowToPendingTasks(true); - test_task_runner_->RunUntilIdle(); - - double ratio = static_cast<double>(linear_immediate_task.count()) / - static_cast<double>(quadratic_delayed_task.count()); - - EXPECT_GT(ratio, 0.333); - EXPECT_LT(ratio, 1.1); -} - -TEST_F(TaskQueueManagerTest, ImmediateWorkCanStarveDelayedTasks_SameQueue) { - Initialize(1u); - - QuadraticTask quadratic_immediate_task(runners_[0], base::TimeDelta(), - now_src_.get()); - LinearTask linear_delayed_task( - runners_[0], base::TimeDelta::FromMilliseconds(10), now_src_.get()); - base::Callback<bool()> should_exit = - base::Bind(&ShouldExit, &quadratic_immediate_task, &linear_delayed_task); - - quadratic_immediate_task.SetShouldExit(should_exit); - linear_delayed_task.SetShouldExit(should_exit); - - quadratic_immediate_task.Run(); - linear_delayed_task.Run(); - - test_task_runner_->SetAutoAdvanceNowToPendingTasks(true); - test_task_runner_->RunUntilIdle(); - - double ratio = static_cast<double>(linear_delayed_task.count()) / - static_cast<double>(quadratic_immediate_task.count()); - - // This is by design, we want to enforce a strict ordering in task execution - // where by delayed tasks can not skip ahead of non-delayed work. - EXPECT_GT(ratio, 0.0); - EXPECT_LT(ratio, 0.1); -} - -TEST_F(TaskQueueManagerTest, - DelayedTasksDontBadlyStarveNonDelayedWork_DifferentQueue) { - Initialize(2u); - - QuadraticTask quadratic_delayed_task( - runners_[0], base::TimeDelta::FromMilliseconds(10), now_src_.get()); - LinearTask linear_immediate_task(runners_[1], base::TimeDelta(), - now_src_.get()); - base::Callback<bool()> should_exit = - base::Bind(ShouldExit, &quadratic_delayed_task, &linear_immediate_task); - quadratic_delayed_task.SetShouldExit(should_exit); - linear_immediate_task.SetShouldExit(should_exit); - - quadratic_delayed_task.Run(); - linear_immediate_task.Run(); - - test_task_runner_->SetAutoAdvanceNowToPendingTasks(true); - test_task_runner_->RunUntilIdle(); - - double ratio = static_cast<double>(linear_immediate_task.count()) / - static_cast<double>(quadratic_delayed_task.count()); - - EXPECT_GT(ratio, 0.333); - EXPECT_LT(ratio, 1.1); -} - -TEST_F(TaskQueueManagerTest, - ImmediateWorkCanStarveDelayedTasks_DifferentQueue) { - Initialize(2u); - - QuadraticTask quadratic_immediate_task(runners_[0], base::TimeDelta(), - now_src_.get()); - LinearTask linear_delayed_task( - runners_[1], base::TimeDelta::FromMilliseconds(10), now_src_.get()); - base::Callback<bool()> should_exit = - base::Bind(&ShouldExit, &quadratic_immediate_task, &linear_delayed_task); - - quadratic_immediate_task.SetShouldExit(should_exit); - linear_delayed_task.SetShouldExit(should_exit); - - quadratic_immediate_task.Run(); - linear_delayed_task.Run(); - - test_task_runner_->SetAutoAdvanceNowToPendingTasks(true); - test_task_runner_->RunUntilIdle(); - - double ratio = static_cast<double>(linear_delayed_task.count()) / - static_cast<double>(quadratic_immediate_task.count()); - - // This is by design, we want to enforce a strict ordering in task execution - // where by delayed tasks can not skip ahead of non-delayed work. - EXPECT_GT(ratio, 0.0); - EXPECT_LT(ratio, 0.1); -} - -TEST_F(TaskQueueManagerTest, CurrentlyExecutingTaskQueue_NoTaskRunning) { - Initialize(1u); - - EXPECT_EQ(nullptr, manager_->currently_executing_task_queue()); -} - -namespace { -void CurrentlyExecutingTaskQueueTestTask(TaskQueueManager* task_queue_manager, - std::vector<TaskQueue*>* task_sources) { - task_sources->push_back(task_queue_manager->currently_executing_task_queue()); -} -} - -TEST_F(TaskQueueManagerTest, CurrentlyExecutingTaskQueue_TaskRunning) { - Initialize(2u); - - internal::TaskQueueImpl* queue0 = runners_[0].get(); - internal::TaskQueueImpl* queue1 = runners_[1].get(); - - std::vector<TaskQueue*> task_sources; - queue0->PostTask(FROM_HERE, base::Bind(&CurrentlyExecutingTaskQueueTestTask, - manager_.get(), &task_sources)); - queue1->PostTask(FROM_HERE, base::Bind(&CurrentlyExecutingTaskQueueTestTask, - manager_.get(), &task_sources)); - test_task_runner_->RunUntilIdle(); - - EXPECT_THAT(task_sources, ElementsAre(queue0, queue1)); - EXPECT_EQ(nullptr, manager_->currently_executing_task_queue()); -} - -namespace { -void RunloopCurrentlyExecutingTaskQueueTestTask( - base::MessageLoop* message_loop, - TaskQueueManager* task_queue_manager, - std::vector<TaskQueue*>* task_sources, - std::vector<std::pair<base::Closure, TaskQueue*>>* tasks) { - base::MessageLoop::ScopedNestableTaskAllower allow(message_loop); - task_sources->push_back(task_queue_manager->currently_executing_task_queue()); - - for (std::pair<base::Closure, TaskQueue*>& pair : *tasks) { - pair.second->PostTask(FROM_HERE, pair.first); - } - - base::RunLoop().RunUntilIdle(); - task_sources->push_back(task_queue_manager->currently_executing_task_queue()); -} -} - -TEST_F(TaskQueueManagerTest, CurrentlyExecutingTaskQueue_NestedLoop) { - InitializeWithRealMessageLoop(3u); - - TaskQueue* queue0 = runners_[0].get(); - TaskQueue* queue1 = runners_[1].get(); - TaskQueue* queue2 = runners_[2].get(); - - std::vector<TaskQueue*> task_sources; - std::vector<std::pair<base::Closure, TaskQueue*>> - tasks_to_post_from_nested_loop; - tasks_to_post_from_nested_loop.push_back( - std::make_pair(base::Bind(&CurrentlyExecutingTaskQueueTestTask, - manager_.get(), &task_sources), - queue1)); - tasks_to_post_from_nested_loop.push_back( - std::make_pair(base::Bind(&CurrentlyExecutingTaskQueueTestTask, - manager_.get(), &task_sources), - queue2)); - - queue0->PostTask( - FROM_HERE, base::Bind(&RunloopCurrentlyExecutingTaskQueueTestTask, - message_loop_.get(), manager_.get(), &task_sources, - &tasks_to_post_from_nested_loop)); - - base::RunLoop().RunUntilIdle(); - EXPECT_THAT(task_sources, ElementsAre(queue0, queue1, queue2, queue0)); - EXPECT_EQ(nullptr, manager_->currently_executing_task_queue()); -} - -void OnTraceDataCollected(base::Closure quit_closure, - base::trace_event::TraceResultBuffer* buffer, - const scoped_refptr<base::RefCountedString>& json, - bool has_more_events) { - buffer->AddFragment(json->data()); - if (!has_more_events) - quit_closure.Run(); -} - -class TaskQueueManagerTestWithTracing : public TaskQueueManagerTest { - public: - void StartTracing(); - void StopTracing(); - std::unique_ptr<trace_analyzer::TraceAnalyzer> CreateTraceAnalyzer(); -}; - -void TaskQueueManagerTestWithTracing::StartTracing() { - base::trace_event::TraceLog::GetInstance()->SetEnabled( - base::trace_event::TraceConfig("*"), - base::trace_event::TraceLog::RECORDING_MODE); -} - -void TaskQueueManagerTestWithTracing::StopTracing() { - base::trace_event::TraceLog::GetInstance()->SetDisabled(); -} - -std::unique_ptr<trace_analyzer::TraceAnalyzer> -TaskQueueManagerTestWithTracing::CreateTraceAnalyzer() { - base::trace_event::TraceResultBuffer buffer; - base::trace_event::TraceResultBuffer::SimpleOutput trace_output; - buffer.SetOutputCallback(trace_output.GetCallback()); - base::RunLoop run_loop; - buffer.Start(); - base::trace_event::TraceLog::GetInstance()->Flush( - Bind(&OnTraceDataCollected, run_loop.QuitClosure(), - base::Unretained(&buffer))); - run_loop.Run(); - buffer.Finish(); - - return base::WrapUnique( - trace_analyzer::TraceAnalyzer::Create(trace_output.json_output)); -} - -TEST_F(TaskQueueManagerTestWithTracing, BlameContextAttribution) { - using trace_analyzer::Query; - - InitializeWithRealMessageLoop(1u); - TaskQueue* queue = runners_[0].get(); - - StartTracing(); - { - base::trace_event::BlameContext blame_context("cat", "name", "type", - "scope", 0, nullptr); - blame_context.Initialize(); - queue->SetBlameContext(&blame_context); - queue->PostTask(FROM_HERE, base::Bind(&NopTask)); - base::RunLoop().RunUntilIdle(); - } - StopTracing(); - std::unique_ptr<trace_analyzer::TraceAnalyzer> analyzer = - CreateTraceAnalyzer(); - - trace_analyzer::TraceEventVector events; - Query q = Query::EventPhaseIs(TRACE_EVENT_PHASE_ENTER_CONTEXT) || - Query::EventPhaseIs(TRACE_EVENT_PHASE_LEAVE_CONTEXT); - analyzer->FindEvents(q, &events); - - EXPECT_EQ(2u, events.size()); -} - -} // namespace scheduler
diff --git a/components/scheduler/base/task_queue_selector.cc b/components/scheduler/base/task_queue_selector.cc deleted file mode 100644 index 9db8ab9..0000000 --- a/components/scheduler/base/task_queue_selector.cc +++ /dev/null
@@ -1,380 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/base/task_queue_selector.h" - -#include "base/logging.h" -#include "base/trace_event/trace_event_argument.h" -#include "components/scheduler/base/task_queue_impl.h" -#include "components/scheduler/base/work_queue.h" - -namespace scheduler { -namespace internal { - -TaskQueueSelector::TaskQueueSelector() - : enabled_selector_(this, "enabled"), - blocked_selector_(this, "blocked"), - immediate_starvation_count_(0), - high_priority_starvation_count_(0), - num_blocked_queues_to_report_(0), - task_queue_selector_observer_(nullptr) {} - -TaskQueueSelector::~TaskQueueSelector() {} - -void TaskQueueSelector::AddQueue(internal::TaskQueueImpl* queue) { - DCHECK(main_thread_checker_.CalledOnValidThread()); - DCHECK(queue->IsQueueEnabled()); - enabled_selector_.AddQueue(queue, TaskQueue::NORMAL_PRIORITY); -} - -void TaskQueueSelector::RemoveQueue(internal::TaskQueueImpl* queue) { - DCHECK(main_thread_checker_.CalledOnValidThread()); - if (queue->IsQueueEnabled()) { - enabled_selector_.RemoveQueue(queue); -// The #if DCHECK_IS_ON() shouldn't be necessary but this doesn't compile on -// chromeos bots without it :( -#if DCHECK_IS_ON() - DCHECK(!blocked_selector_.CheckContainsQueueForTest(queue)); -#endif - } else if (queue->should_report_when_execution_blocked()) { - DCHECK_GT(num_blocked_queues_to_report_, 0u); - num_blocked_queues_to_report_--; - blocked_selector_.RemoveQueue(queue); -#if DCHECK_IS_ON() - DCHECK(!enabled_selector_.CheckContainsQueueForTest(queue)); -#endif - } -} - -void TaskQueueSelector::EnableQueue(internal::TaskQueueImpl* queue) { - DCHECK(main_thread_checker_.CalledOnValidThread()); - DCHECK(queue->IsQueueEnabled()); - if (queue->should_report_when_execution_blocked()) { - DCHECK_GT(num_blocked_queues_to_report_, 0u); - num_blocked_queues_to_report_--; - blocked_selector_.RemoveQueue(queue); - } - enabled_selector_.AddQueue(queue, queue->GetQueuePriority()); - if (task_queue_selector_observer_) - task_queue_selector_observer_->OnTaskQueueEnabled(queue); -} - -void TaskQueueSelector::DisableQueue(internal::TaskQueueImpl* queue) { - DCHECK(main_thread_checker_.CalledOnValidThread()); - DCHECK(!queue->IsQueueEnabled()); - enabled_selector_.RemoveQueue(queue); - if (queue->should_report_when_execution_blocked()) { - blocked_selector_.AddQueue(queue, queue->GetQueuePriority()); - num_blocked_queues_to_report_++; - } -} - -void TaskQueueSelector::SetQueuePriority(internal::TaskQueueImpl* queue, - TaskQueue::QueuePriority priority) { - DCHECK_LT(priority, TaskQueue::QUEUE_PRIORITY_COUNT); - DCHECK(main_thread_checker_.CalledOnValidThread()); - if (queue->IsQueueEnabled()) { - enabled_selector_.ChangeSetIndex(queue, priority); - } else if (queue->should_report_when_execution_blocked()) { - blocked_selector_.ChangeSetIndex(queue, priority); - } else { - // Normally blocked_selector_.ChangeSetIndex would assign the queue's - // priority, however if |queue->should_report_when_execution_blocked()| is - // false then the disabled queue is not in any set so we need to do it here. - queue->delayed_work_queue()->AssignSetIndex(priority); - queue->immediate_work_queue()->AssignSetIndex(priority); - } - DCHECK_EQ(priority, queue->GetQueuePriority()); -} - -TaskQueue::QueuePriority TaskQueueSelector::NextPriority( - TaskQueue::QueuePriority priority) { - DCHECK(priority < TaskQueue::QUEUE_PRIORITY_COUNT); - return static_cast<TaskQueue::QueuePriority>(static_cast<int>(priority) + 1); -} - -TaskQueueSelector::PrioritizingSelector::PrioritizingSelector( - TaskQueueSelector* task_queue_selector, - const char* name) - : task_queue_selector_(task_queue_selector), - delayed_work_queue_sets_(TaskQueue::QUEUE_PRIORITY_COUNT, name), - immediate_work_queue_sets_(TaskQueue::QUEUE_PRIORITY_COUNT, name) {} - -void TaskQueueSelector::PrioritizingSelector::AddQueue( - internal::TaskQueueImpl* queue, - TaskQueue::QueuePriority priority) { -#if DCHECK_IS_ON() - DCHECK(!CheckContainsQueueForTest(queue)); -#endif - delayed_work_queue_sets_.AddQueue(queue->delayed_work_queue(), priority); - immediate_work_queue_sets_.AddQueue(queue->immediate_work_queue(), priority); -#if DCHECK_IS_ON() - DCHECK(CheckContainsQueueForTest(queue)); -#endif -} - -void TaskQueueSelector::PrioritizingSelector::ChangeSetIndex( - internal::TaskQueueImpl* queue, - TaskQueue::QueuePriority priority) { -#if DCHECK_IS_ON() - DCHECK(CheckContainsQueueForTest(queue)); -#endif - delayed_work_queue_sets_.ChangeSetIndex(queue->delayed_work_queue(), - priority); - immediate_work_queue_sets_.ChangeSetIndex(queue->immediate_work_queue(), - priority); -#if DCHECK_IS_ON() - DCHECK(CheckContainsQueueForTest(queue)); -#endif -} - -void TaskQueueSelector::PrioritizingSelector::RemoveQueue( - internal::TaskQueueImpl* queue) { -#if DCHECK_IS_ON() - DCHECK(CheckContainsQueueForTest(queue)); -#endif - delayed_work_queue_sets_.RemoveQueue(queue->delayed_work_queue()); - immediate_work_queue_sets_.RemoveQueue(queue->immediate_work_queue()); - -#if DCHECK_IS_ON() - DCHECK(!CheckContainsQueueForTest(queue)); -#endif -} - -bool TaskQueueSelector::PrioritizingSelector:: - ChooseOldestImmediateTaskWithPriority(TaskQueue::QueuePriority priority, - WorkQueue** out_work_queue) const { - return immediate_work_queue_sets_.GetOldestQueueInSet(priority, - out_work_queue); -} - -bool TaskQueueSelector::PrioritizingSelector:: - ChooseOldestDelayedTaskWithPriority(TaskQueue::QueuePriority priority, - WorkQueue** out_work_queue) const { - return delayed_work_queue_sets_.GetOldestQueueInSet(priority, out_work_queue); -} - -bool TaskQueueSelector::PrioritizingSelector:: - ChooseOldestImmediateOrDelayedTaskWithPriority( - TaskQueue::QueuePriority priority, - bool* out_chose_delayed_over_immediate, - WorkQueue** out_work_queue) const { - WorkQueue* immediate_queue; - DCHECK_EQ(*out_chose_delayed_over_immediate, false); - if (immediate_work_queue_sets_.GetOldestQueueInSet(priority, - &immediate_queue)) { - WorkQueue* delayed_queue; - if (delayed_work_queue_sets_.GetOldestQueueInSet(priority, - &delayed_queue)) { - if (immediate_queue->ShouldRunBefore(delayed_queue)) { - *out_work_queue = immediate_queue; - } else { - *out_chose_delayed_over_immediate = true; - *out_work_queue = delayed_queue; - } - } else { - *out_work_queue = immediate_queue; - } - return true; - } - return delayed_work_queue_sets_.GetOldestQueueInSet(priority, out_work_queue); -} - -bool TaskQueueSelector::PrioritizingSelector::ChooseOldestWithPriority( - TaskQueue::QueuePriority priority, - bool* out_chose_delayed_over_immediate, - WorkQueue** out_work_queue) const { - // Select an immediate work queue if we are starving immediate tasks. - if (task_queue_selector_->immediate_starvation_count_ >= - kMaxDelayedStarvationTasks) { - if (ChooseOldestImmediateTaskWithPriority(priority, out_work_queue)) { - return true; - } - if (ChooseOldestDelayedTaskWithPriority(priority, out_work_queue)) { - return true; - } - return false; - } - return ChooseOldestImmediateOrDelayedTaskWithPriority( - priority, out_chose_delayed_over_immediate, out_work_queue); -} - -bool TaskQueueSelector::PrioritizingSelector::SelectWorkQueueToService( - TaskQueue::QueuePriority max_priority, - WorkQueue** out_work_queue, - bool* out_chose_delayed_over_immediate) { - DCHECK(task_queue_selector_->main_thread_checker_.CalledOnValidThread()); - DCHECK_EQ(*out_chose_delayed_over_immediate, false); - - // Always service the control queue if it has any work. - if (max_priority > TaskQueue::CONTROL_PRIORITY && - ChooseOldestWithPriority(TaskQueue::CONTROL_PRIORITY, - out_chose_delayed_over_immediate, - out_work_queue)) { - return true; - } - - // Select from the normal priority queue if we are starving it. - if (max_priority > TaskQueue::NORMAL_PRIORITY && - task_queue_selector_->high_priority_starvation_count_ >= - kMaxHighPriorityStarvationTasks && - ChooseOldestWithPriority(TaskQueue::NORMAL_PRIORITY, - out_chose_delayed_over_immediate, - out_work_queue)) { - return true; - } - // Otherwise choose in priority order. - for (TaskQueue::QueuePriority priority = TaskQueue::HIGH_PRIORITY; - priority < max_priority; priority = NextPriority(priority)) { - if (ChooseOldestWithPriority(priority, out_chose_delayed_over_immediate, - out_work_queue)) { - return true; - } - } - return false; -} - -#if DCHECK_IS_ON() || !defined(NDEBUG) -bool -TaskQueueSelector::PrioritizingSelector::CheckContainsQueueForTest( - const internal::TaskQueueImpl* queue) const { - bool contains_delayed_work_queue = - delayed_work_queue_sets_.ContainsWorkQueueForTest( - queue->delayed_work_queue()); - - bool contains_immediate_work_queue = - immediate_work_queue_sets_.ContainsWorkQueueForTest( - queue->immediate_work_queue()); - - DCHECK_EQ(contains_delayed_work_queue, contains_immediate_work_queue); - return contains_delayed_work_queue; -} -#endif - -bool TaskQueueSelector::SelectWorkQueueToService(WorkQueue** out_work_queue) { - DCHECK(main_thread_checker_.CalledOnValidThread()); - bool chose_delayed_over_immediate = false; - bool found_queue = enabled_selector_.SelectWorkQueueToService( - TaskQueue::QUEUE_PRIORITY_COUNT, out_work_queue, - &chose_delayed_over_immediate); - if (!found_queue) { - TrySelectingBlockedQueue(); - return false; - } - - TrySelectingBlockedQueueOverEnabledQueue(**out_work_queue); - DidSelectQueueWithPriority( - (*out_work_queue)->task_queue()->GetQueuePriority(), - chose_delayed_over_immediate); - return true; -} - -void TaskQueueSelector::TrySelectingBlockedQueue() { - DCHECK(main_thread_checker_.CalledOnValidThread()); - if (!num_blocked_queues_to_report_ || !task_queue_selector_observer_) - return; - WorkQueue* chosen_blocked_queue; - bool chose_delayed_over_immediate = false; - // There was nothing unblocked to run, see if we could have run a blocked - // task. - if (blocked_selector_.SelectWorkQueueToService( - TaskQueue::QUEUE_PRIORITY_COUNT, &chosen_blocked_queue, - &chose_delayed_over_immediate)) { - task_queue_selector_observer_->OnTriedToSelectBlockedWorkQueue( - chosen_blocked_queue); - } -} - -void TaskQueueSelector::TrySelectingBlockedQueueOverEnabledQueue( - const WorkQueue& chosen_enabled_queue) { - DCHECK(main_thread_checker_.CalledOnValidThread()); - if (!num_blocked_queues_to_report_ || !task_queue_selector_observer_) - return; - - TaskQueue::QueuePriority max_priority = - NextPriority(chosen_enabled_queue.task_queue()->GetQueuePriority()); - - WorkQueue* chosen_blocked_queue; - bool chose_delayed_over_immediate = false; - bool found_queue = blocked_selector_.SelectWorkQueueToService( - max_priority, &chosen_blocked_queue, &chose_delayed_over_immediate); - if (!found_queue) - return; - - // Check if the chosen blocked queue has a lower numerical priority than the - // chosen enabled queue. If so we would have chosen the blocked queue (since - // zero is the highest priority). - if (chosen_blocked_queue->task_queue()->GetQueuePriority() < - chosen_enabled_queue.task_queue()->GetQueuePriority()) { - task_queue_selector_observer_->OnTriedToSelectBlockedWorkQueue( - chosen_blocked_queue); - return; - } - DCHECK_EQ(chosen_blocked_queue->task_queue()->GetQueuePriority(), - chosen_enabled_queue.task_queue()->GetQueuePriority()); - // Otherwise there was an enabled and a blocked task with the same priority. - // The one with the older enqueue order wins. - if (chosen_blocked_queue->ShouldRunBefore(&chosen_enabled_queue)) { - task_queue_selector_observer_->OnTriedToSelectBlockedWorkQueue( - chosen_blocked_queue); - } -} - -void TaskQueueSelector::DidSelectQueueWithPriority( - TaskQueue::QueuePriority priority, - bool chose_delayed_over_immediate) { - switch (priority) { - case TaskQueue::CONTROL_PRIORITY: - break; - case TaskQueue::HIGH_PRIORITY: - high_priority_starvation_count_++; - break; - case TaskQueue::NORMAL_PRIORITY: - case TaskQueue::BEST_EFFORT_PRIORITY: - high_priority_starvation_count_ = 0; - break; - default: - NOTREACHED(); - } - if (chose_delayed_over_immediate) { - immediate_starvation_count_++; - } else { - immediate_starvation_count_ = 0; - } -} - -void TaskQueueSelector::AsValueInto( - base::trace_event::TracedValue* state) const { - DCHECK(main_thread_checker_.CalledOnValidThread()); - state->SetInteger("high_priority_starvation_count", - high_priority_starvation_count_); - state->SetInteger("immediate_starvation_count", immediate_starvation_count_); - state->SetInteger("num_blocked_queues_to_report", - num_blocked_queues_to_report_); -} - -void TaskQueueSelector::SetTaskQueueSelectorObserver(Observer* observer) { - task_queue_selector_observer_ = observer; -} - -bool TaskQueueSelector::EnabledWorkQueuesEmpty() const { - DCHECK(main_thread_checker_.CalledOnValidThread()); - for (TaskQueue::QueuePriority priority = TaskQueue::CONTROL_PRIORITY; - priority < TaskQueue::QUEUE_PRIORITY_COUNT; - priority = NextPriority(priority)) { - if (!enabled_selector_.delayed_work_queue_sets()->IsSetEmpty(priority) || - !enabled_selector_.immediate_work_queue_sets()->IsSetEmpty(priority)) { - return false; - } - } - return true; -} - -void TaskQueueSelector::SetImmediateStarvationCountForTest( - size_t immediate_starvation_count) { - immediate_starvation_count_ = immediate_starvation_count; -} - -} // namespace internal -} // namespace scheduler
diff --git a/components/scheduler/base/task_queue_selector.h b/components/scheduler/base/task_queue_selector.h deleted file mode 100644 index 4a82adc..0000000 --- a/components/scheduler/base/task_queue_selector.h +++ /dev/null
@@ -1,206 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_BASE_TASK_QUEUE_SELECTOR_H_ -#define COMPONENTS_SCHEDULER_BASE_TASK_QUEUE_SELECTOR_H_ - -#include <stddef.h> - -#include <set> - -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "base/pending_task.h" -#include "base/threading/thread_checker.h" -#include "components/scheduler/base/work_queue_sets.h" -#include "components/scheduler/scheduler_export.h" - -namespace scheduler { -namespace internal { - -// TaskQueueSelector is used by the SchedulerHelper to enable prioritization -// of particular task queues. -class SCHEDULER_EXPORT TaskQueueSelector { - public: - TaskQueueSelector(); - ~TaskQueueSelector(); - - // Called to register a queue that can be selected. This function is called - // on the main thread. - void AddQueue(internal::TaskQueueImpl* queue); - - // The specified work will no longer be considered for selection. This - // function is called on the main thread. - void RemoveQueue(internal::TaskQueueImpl* queue); - - // Make |queue| eligible for selection. This function is called on the main - // thread. Must only be called if |queue| is disabled. - void EnableQueue(internal::TaskQueueImpl* queue); - - // Disable selection from |queue|. If task blocking is enabled for the queue, - // Observer::OnTriedToSelectBlockedWorkQueue will be emitted if the - // SelectWorkQueueToService tries to select this disabled queue for execution. - // Must only be called if |queue| is enabled. - void DisableQueue(internal::TaskQueueImpl* queue); - - // Called get or set the priority of |queue|. - void SetQueuePriority(internal::TaskQueueImpl* queue, - TaskQueue::QueuePriority priority); - - // Called to choose the work queue from which the next task should be taken - // and run. Return true if |out_work_queue| indicates the queue to service or - // false to avoid running any task. - // - // This function is called on the main thread. - bool SelectWorkQueueToService(WorkQueue** out_work_queue); - - // Serialize the selector state for tracing. - void AsValueInto(base::trace_event::TracedValue* state) const; - - class SCHEDULER_EXPORT Observer { - public: - virtual ~Observer() {} - - // Called when |queue| transitions from disabled to enabled. - virtual void OnTaskQueueEnabled(internal::TaskQueueImpl* queue) = 0; - - // Called when the selector tried to select a task from a disabled work - // queue. See TaskQueue::Spec::SetShouldReportWhenExecutionBlocked. A single - // call to SelectWorkQueueToService will only result in up to one - // blocking notification even if multiple disabled queues could have been - // selected. - virtual void OnTriedToSelectBlockedWorkQueue( - internal::WorkQueue* work_queue) = 0; - }; - - // Called once to set the Observer. This function is called - // on the main thread. If |observer| is null, then no callbacks will occur. - void SetTaskQueueSelectorObserver(Observer* observer); - - // Returns true if all the enabled work queues are empty. Returns false - // otherwise. - bool EnabledWorkQueuesEmpty() const; - - protected: - class SCHEDULER_EXPORT PrioritizingSelector { - public: - PrioritizingSelector(TaskQueueSelector* task_queue_selector, - const char* name); - - void ChangeSetIndex(internal::TaskQueueImpl* queue, - TaskQueue::QueuePriority priority); - void AddQueue(internal::TaskQueueImpl* queue, - TaskQueue::QueuePriority priority); - void RemoveQueue(internal::TaskQueueImpl* queue); - - bool SelectWorkQueueToService(TaskQueue::QueuePriority max_priority, - WorkQueue** out_work_queue, - bool* out_chose_delayed_over_immediate); - - WorkQueueSets* delayed_work_queue_sets() { - return &delayed_work_queue_sets_; - } - WorkQueueSets* immediate_work_queue_sets() { - return &immediate_work_queue_sets_; - } - - const WorkQueueSets* delayed_work_queue_sets() const { - return &delayed_work_queue_sets_; - } - const WorkQueueSets* immediate_work_queue_sets() const { - return &immediate_work_queue_sets_; - } - - bool ChooseOldestWithPriority(TaskQueue::QueuePriority priority, - bool* out_chose_delayed_over_immediate, - WorkQueue** out_work_queue) const; - -#if DCHECK_IS_ON() || !defined(NDEBUG) - bool CheckContainsQueueForTest(const internal::TaskQueueImpl* queue) const; -#endif - - private: - bool ChooseOldestImmediateTaskWithPriority( - TaskQueue::QueuePriority priority, - WorkQueue** out_work_queue) const; - - bool ChooseOldestDelayedTaskWithPriority(TaskQueue::QueuePriority priority, - WorkQueue** out_work_queue) const; - - // Return true if |out_queue| contains the queue with the oldest pending - // task from the set of queues of |priority|, or false if all queues of that - // priority are empty. In addition |out_chose_delayed_over_immediate| is set - // to true iff we chose a delayed work queue in favour of an immediate work - // queue. - bool ChooseOldestImmediateOrDelayedTaskWithPriority( - TaskQueue::QueuePriority priority, - bool* out_chose_delayed_over_immediate, - WorkQueue** out_work_queue) const; - - const TaskQueueSelector* task_queue_selector_; - WorkQueueSets delayed_work_queue_sets_; - WorkQueueSets immediate_work_queue_sets_; - - DISALLOW_COPY_AND_ASSIGN(PrioritizingSelector); - }; - - // Return true if |out_queue| contains the queue with the oldest pending task - // from the set of queues of |priority|, or false if all queues of that - // priority are empty. In addition |out_chose_delayed_over_immediate| is set - // to true iff we chose a delayed work queue in favour of an immediate work - // queue. This method will force select an immediate task if those are being - // starved by delayed tasks. - void SetImmediateStarvationCountForTest(size_t immediate_starvation_count); - - PrioritizingSelector* enabled_selector_for_test() { - return &enabled_selector_; - } - - private: - // Returns the priority which is next after |priority|. - static TaskQueue::QueuePriority NextPriority( - TaskQueue::QueuePriority priority); - - bool SelectWorkQueueToServiceInternal(WorkQueue** out_work_queue); - - // Called whenever the selector chooses a task queue for execution with the - // priority |priority|. - void DidSelectQueueWithPriority(TaskQueue::QueuePriority priority, - bool chose_delayed_over_immediate); - - // No enabled queue could be selected, check if we could have chosen a - // disabled (blocked) work queue instead. - void TrySelectingBlockedQueue(); - - // Check if we could have chosen a disabled (blocked) work queue instead. - // |chosen_enabled_queue| is the enabled queue that got chosen. - void TrySelectingBlockedQueueOverEnabledQueue( - const WorkQueue& chosen_enabled_queue); - - // Number of high priority tasks which can be run before a normal priority - // task should be selected to prevent starvation. - // TODO(rmcilroy): Check if this is a good value. - static const size_t kMaxHighPriorityStarvationTasks = 5; - - // Maximum number of delayed tasks tasks which can be run while there's a - // waiting non-delayed task. - static const size_t kMaxDelayedStarvationTasks = 3; - - private: - base::ThreadChecker main_thread_checker_; - - PrioritizingSelector enabled_selector_; - PrioritizingSelector blocked_selector_; - size_t immediate_starvation_count_; - size_t high_priority_starvation_count_; - size_t num_blocked_queues_to_report_; - - Observer* task_queue_selector_observer_; // NOT OWNED - DISALLOW_COPY_AND_ASSIGN(TaskQueueSelector); -}; - -} // namespace internal -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_BASE_TASK_QUEUE_SELECTOR_H
diff --git a/components/scheduler/base/task_queue_selector_unittest.cc b/components/scheduler/base/task_queue_selector_unittest.cc deleted file mode 100644 index 1be477d..0000000 --- a/components/scheduler/base/task_queue_selector_unittest.cc +++ /dev/null
@@ -1,494 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/base/task_queue_selector.h" - -#include <stddef.h> - -#include <memory> - -#include "base/bind.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/pending_task.h" -#include "components/scheduler/base/task_queue_impl.h" -#include "components/scheduler/base/virtual_time_domain.h" -#include "components/scheduler/base/work_queue.h" -#include "components/scheduler/base/work_queue_sets.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using testing::_; - -namespace scheduler { -namespace internal { - -class MockObserver : public TaskQueueSelector::Observer { - public: - MockObserver() {} - virtual ~MockObserver() {} - - MOCK_METHOD1(OnTaskQueueEnabled, void(internal::TaskQueueImpl*)); - MOCK_METHOD1(OnTriedToSelectBlockedWorkQueue, void(internal::WorkQueue*)); - - private: - DISALLOW_COPY_AND_ASSIGN(MockObserver); -}; - -class TaskQueueSelectorForTest : public TaskQueueSelector { - public: - using TaskQueueSelector::SetImmediateStarvationCountForTest; - using TaskQueueSelector::PrioritizingSelector; - using TaskQueueSelector::enabled_selector_for_test; -}; - -class TaskQueueSelectorTest : public testing::Test { - public: - TaskQueueSelectorTest() - : test_closure_(base::Bind(&TaskQueueSelectorTest::TestFunction)) {} - ~TaskQueueSelectorTest() override {} - - TaskQueueSelectorForTest::PrioritizingSelector* enabled_selector() { - return selector_.enabled_selector_for_test(); - } - - WorkQueueSets* delayed_work_queue_sets() { - return enabled_selector()->delayed_work_queue_sets(); - } - WorkQueueSets* immediate_work_queue_sets() { - return enabled_selector()->immediate_work_queue_sets(); - } - - void PushTasks(const size_t queue_indices[], size_t num_tasks) { - std::set<size_t> changed_queue_set; - for (size_t i = 0; i < num_tasks; i++) { - changed_queue_set.insert(queue_indices[i]); - task_queues_[queue_indices[i]]->immediate_work_queue()->Push( - TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(), 0, - true, i)); - } - } - - void PushTasksWithEnqueueOrder(const size_t queue_indices[], - const size_t enqueue_orders[], - size_t num_tasks) { - std::set<size_t> changed_queue_set; - for (size_t i = 0; i < num_tasks; i++) { - changed_queue_set.insert(queue_indices[i]); - task_queues_[queue_indices[i]]->immediate_work_queue()->Push( - TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(), 0, - true, enqueue_orders[i])); - } - } - - std::vector<size_t> PopTasks() { - std::vector<size_t> order; - WorkQueue* chosen_work_queue; - while (selector_.SelectWorkQueueToService(&chosen_work_queue)) { - size_t chosen_queue_index = - queue_to_index_map_.find(chosen_work_queue->task_queue())->second; - order.push_back(chosen_queue_index); - chosen_work_queue->PopTaskForTest(); - immediate_work_queue_sets()->OnPopQueue(chosen_work_queue); - } - return order; - } - - static void TestFunction() {} - - void EnableQueue(TaskQueueImpl* queue) { - queue->SetQueueEnabled(true); - selector_.EnableQueue(queue); - } - - void DisableQueue(TaskQueueImpl* queue) { - queue->SetQueueEnabled(false); - selector_.DisableQueue(queue); - } - - protected: - void SetUp() final { - virtual_time_domain_ = base::WrapUnique<VirtualTimeDomain>( - new VirtualTimeDomain(nullptr, base::TimeTicks())); - for (size_t i = 0; i < kTaskQueueCount; i++) { - scoped_refptr<TaskQueueImpl> task_queue = make_scoped_refptr( - new TaskQueueImpl(nullptr, virtual_time_domain_.get(), - TaskQueue::Spec("test queue"), "test", "test")); - selector_.AddQueue(task_queue.get()); - task_queues_.push_back(task_queue); - } - for (size_t i = 0; i < kTaskQueueCount; i++) { - EXPECT_EQ(TaskQueue::NORMAL_PRIORITY, task_queues_[i]->GetQueuePriority()) - << i; - queue_to_index_map_.insert(std::make_pair(task_queues_[i].get(), i)); - } - } - - void TearDown() final { - for (scoped_refptr<TaskQueueImpl>& task_queue : task_queues_) { - task_queue->UnregisterTaskQueue(); - // Note since this test doesn't have a TaskQueueManager we need to - // manually remove |task_queue| from the |selector_|. Normally - // UnregisterTaskQueue would do that. - selector_.RemoveQueue(task_queue.get()); - } - } - - scoped_refptr<TaskQueueImpl> NewTaskQueueWithBlockReporting() { - return make_scoped_refptr(new TaskQueueImpl( - nullptr, virtual_time_domain_.get(), - TaskQueue::Spec("test queue").SetShouldReportWhenExecutionBlocked(true), - "test", "test")); - } - - const size_t kTaskQueueCount = 5; - base::Closure test_closure_; - TaskQueueSelectorForTest selector_; - std::unique_ptr<VirtualTimeDomain> virtual_time_domain_; - std::vector<scoped_refptr<TaskQueueImpl>> task_queues_; - std::map<TaskQueueImpl*, size_t> queue_to_index_map_; -}; - -TEST_F(TaskQueueSelectorTest, TestDefaultPriority) { - size_t queue_order[] = {4, 3, 2, 1, 0}; - PushTasks(queue_order, 5); - EXPECT_THAT(PopTasks(), testing::ElementsAre(4, 3, 2, 1, 0)); -} - -TEST_F(TaskQueueSelectorTest, TestHighPriority) { - size_t queue_order[] = {0, 1, 2, 3, 4}; - PushTasks(queue_order, 5); - selector_.SetQueuePriority(task_queues_[2].get(), TaskQueue::HIGH_PRIORITY); - EXPECT_THAT(PopTasks(), testing::ElementsAre(2, 0, 1, 3, 4)); -} - -TEST_F(TaskQueueSelectorTest, TestBestEffortPriority) { - size_t queue_order[] = {0, 1, 2, 3, 4}; - PushTasks(queue_order, 5); - selector_.SetQueuePriority(task_queues_[0].get(), - TaskQueue::BEST_EFFORT_PRIORITY); - selector_.SetQueuePriority(task_queues_[2].get(), TaskQueue::HIGH_PRIORITY); - EXPECT_THAT(PopTasks(), testing::ElementsAre(2, 1, 3, 4, 0)); -} - -TEST_F(TaskQueueSelectorTest, TestControlPriority) { - size_t queue_order[] = {0, 1, 2, 3, 4}; - PushTasks(queue_order, 5); - selector_.SetQueuePriority(task_queues_[4].get(), - TaskQueue::CONTROL_PRIORITY); - EXPECT_EQ(TaskQueue::CONTROL_PRIORITY, task_queues_[4]->GetQueuePriority()); - selector_.SetQueuePriority(task_queues_[2].get(), TaskQueue::HIGH_PRIORITY); - EXPECT_EQ(TaskQueue::HIGH_PRIORITY, task_queues_[2]->GetQueuePriority()); - EXPECT_THAT(PopTasks(), testing::ElementsAre(4, 2, 0, 1, 3)); -} - -TEST_F(TaskQueueSelectorTest, TestObserverWithEnabledQueue) { - DisableQueue(task_queues_[1].get()); - MockObserver mock_observer; - selector_.SetTaskQueueSelectorObserver(&mock_observer); - EXPECT_CALL(mock_observer, OnTaskQueueEnabled(_)).Times(1); - EnableQueue(task_queues_[1].get()); -} - -TEST_F(TaskQueueSelectorTest, - TestObserverWithSetQueuePriorityAndQueueAlreadyEnabled) { - selector_.SetQueuePriority(task_queues_[1].get(), TaskQueue::HIGH_PRIORITY); - MockObserver mock_observer; - selector_.SetTaskQueueSelectorObserver(&mock_observer); - EXPECT_CALL(mock_observer, OnTaskQueueEnabled(_)).Times(0); - selector_.SetQueuePriority(task_queues_[1].get(), TaskQueue::NORMAL_PRIORITY); -} - -TEST_F(TaskQueueSelectorTest, TestDisableEnable) { - MockObserver mock_observer; - selector_.SetTaskQueueSelectorObserver(&mock_observer); - - size_t queue_order[] = {0, 1, 2, 3, 4}; - PushTasks(queue_order, 5); - DisableQueue(task_queues_[2].get()); - DisableQueue(task_queues_[4].get()); - // Disabling a queue should not affect its priority. - EXPECT_EQ(TaskQueue::NORMAL_PRIORITY, task_queues_[2]->GetQueuePriority()); - EXPECT_EQ(TaskQueue::NORMAL_PRIORITY, task_queues_[4]->GetQueuePriority()); - EXPECT_THAT(PopTasks(), testing::ElementsAre(0, 1, 3)); - - EXPECT_CALL(mock_observer, OnTaskQueueEnabled(_)).Times(2); - EnableQueue(task_queues_[2].get()); - selector_.SetQueuePriority(task_queues_[2].get(), - TaskQueue::BEST_EFFORT_PRIORITY); - EXPECT_THAT(PopTasks(), testing::ElementsAre(2)); - EnableQueue(task_queues_[4].get()); - EXPECT_THAT(PopTasks(), testing::ElementsAre(4)); -} - -TEST_F(TaskQueueSelectorTest, TestDisableChangePriorityThenEnable) { - EXPECT_TRUE(task_queues_[2]->delayed_work_queue()->Empty()); - EXPECT_TRUE(task_queues_[2]->immediate_work_queue()->Empty()); - - DisableQueue(task_queues_[2].get()); - selector_.SetQueuePriority(task_queues_[2].get(), TaskQueue::HIGH_PRIORITY); - - size_t queue_order[] = {0, 1, 2, 3, 4}; - PushTasks(queue_order, 5); - - EXPECT_TRUE(task_queues_[2]->delayed_work_queue()->Empty()); - EXPECT_FALSE(task_queues_[2]->immediate_work_queue()->Empty()); - EnableQueue(task_queues_[2].get()); - - EXPECT_EQ(TaskQueue::HIGH_PRIORITY, task_queues_[2]->GetQueuePriority()); - EXPECT_THAT(PopTasks(), testing::ElementsAre(2, 0, 1, 3, 4)); -} - -TEST_F(TaskQueueSelectorTest, TestEmptyQueues) { - WorkQueue* chosen_work_queue = nullptr; - EXPECT_FALSE(selector_.SelectWorkQueueToService(&chosen_work_queue)); - - // Test only disabled queues. - size_t queue_order[] = {0}; - PushTasks(queue_order, 1); - task_queues_[0]->SetQueueEnabled(false); - selector_.DisableQueue(task_queues_[0].get()); - EXPECT_FALSE(selector_.SelectWorkQueueToService(&chosen_work_queue)); -} - -TEST_F(TaskQueueSelectorTest, TestAge) { - size_t enqueue_order[] = {10, 1, 2, 9, 4}; - size_t queue_order[] = {0, 1, 2, 3, 4}; - PushTasksWithEnqueueOrder(queue_order, enqueue_order, 5); - EXPECT_THAT(PopTasks(), testing::ElementsAre(1, 2, 4, 3, 0)); -} - -TEST_F(TaskQueueSelectorTest, TestControlStarvesOthers) { - size_t queue_order[] = {0, 1, 2, 3}; - PushTasks(queue_order, 4); - selector_.SetQueuePriority(task_queues_[3].get(), - TaskQueue::CONTROL_PRIORITY); - selector_.SetQueuePriority(task_queues_[2].get(), TaskQueue::HIGH_PRIORITY); - selector_.SetQueuePriority(task_queues_[1].get(), - TaskQueue::BEST_EFFORT_PRIORITY); - for (int i = 0; i < 100; i++) { - WorkQueue* chosen_work_queue = nullptr; - EXPECT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue)); - EXPECT_EQ(task_queues_[3].get(), chosen_work_queue->task_queue()); - // Don't remove task from queue to simulate all queues still being full. - } -} - -TEST_F(TaskQueueSelectorTest, TestHighPriorityDoesNotStarveNormal) { - size_t queue_order[] = {0, 1, 2}; - PushTasks(queue_order, 3); - selector_.SetQueuePriority(task_queues_[2].get(), TaskQueue::HIGH_PRIORITY); - selector_.SetQueuePriority(task_queues_[1].get(), - TaskQueue::BEST_EFFORT_PRIORITY); - size_t counts[] = {0, 0, 0}; - for (int i = 0; i < 100; i++) { - WorkQueue* chosen_work_queue = nullptr; - EXPECT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue)); - size_t chosen_queue_index = - queue_to_index_map_.find(chosen_work_queue->task_queue())->second; - counts[chosen_queue_index]++; - // Don't remove task from queue to simulate all queues still being full. - } - EXPECT_GT(counts[0], 0ul); // Check high doesn't starve normal. - EXPECT_GT(counts[2], counts[0]); // Check high gets more chance to run. - EXPECT_EQ(0ul, counts[1]); // Check best effort is starved. -} - -TEST_F(TaskQueueSelectorTest, TestBestEffortGetsStarved) { - size_t queue_order[] = {0, 1}; - PushTasks(queue_order, 2); - selector_.SetQueuePriority(task_queues_[0].get(), - TaskQueue::BEST_EFFORT_PRIORITY); - EXPECT_EQ(TaskQueue::NORMAL_PRIORITY, task_queues_[1]->GetQueuePriority()); - WorkQueue* chosen_work_queue = nullptr; - for (int i = 0; i < 100; i++) { - EXPECT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue)); - EXPECT_EQ(task_queues_[1].get(), chosen_work_queue->task_queue()); - // Don't remove task from queue to simulate all queues still being full. - } - selector_.SetQueuePriority(task_queues_[1].get(), TaskQueue::HIGH_PRIORITY); - for (int i = 0; i < 100; i++) { - EXPECT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue)); - EXPECT_EQ(task_queues_[1].get(), chosen_work_queue->task_queue()); - // Don't remove task from queue to simulate all queues still being full. - } - selector_.SetQueuePriority(task_queues_[1].get(), - TaskQueue::CONTROL_PRIORITY); - for (int i = 0; i < 100; i++) { - EXPECT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue)); - EXPECT_EQ(task_queues_[1].get(), chosen_work_queue->task_queue()); - // Don't remove task from queue to simulate all queues still being full. - } -} - -TEST_F(TaskQueueSelectorTest, EnabledWorkQueuesEmpty) { - EXPECT_TRUE(selector_.EnabledWorkQueuesEmpty()); - size_t queue_order[] = {0, 1}; - PushTasks(queue_order, 2); - - EXPECT_FALSE(selector_.EnabledWorkQueuesEmpty()); - PopTasks(); - EXPECT_TRUE(selector_.EnabledWorkQueuesEmpty()); -} - -TEST_F(TaskQueueSelectorTest, EnabledWorkQueuesEmpty_ControlPriority) { - size_t queue_order[] = {0}; - PushTasks(queue_order, 1); - - selector_.SetQueuePriority(task_queues_[0].get(), - TaskQueue::CONTROL_PRIORITY); - - EXPECT_FALSE(selector_.EnabledWorkQueuesEmpty()); -} - -TEST_F(TaskQueueSelectorTest, ChooseOldestWithPriority_Empty) { - WorkQueue* chosen_work_queue = nullptr; - bool chose_delayed_over_immediate = false; - EXPECT_FALSE(enabled_selector()->ChooseOldestWithPriority( - TaskQueue::NORMAL_PRIORITY, &chose_delayed_over_immediate, - &chosen_work_queue)); - EXPECT_FALSE(chose_delayed_over_immediate); -} - -TEST_F(TaskQueueSelectorTest, ChooseOldestWithPriority_OnlyDelayed) { - task_queues_[0]->delayed_work_queue()->Push(TaskQueueImpl::Task( - FROM_HERE, test_closure_, base::TimeTicks(), 0, true, 0)); - - WorkQueue* chosen_work_queue = nullptr; - bool chose_delayed_over_immediate = false; - EXPECT_TRUE(enabled_selector()->ChooseOldestWithPriority( - TaskQueue::NORMAL_PRIORITY, &chose_delayed_over_immediate, - &chosen_work_queue)); - EXPECT_EQ(chosen_work_queue, task_queues_[0]->delayed_work_queue()); - EXPECT_FALSE(chose_delayed_over_immediate); -} - -TEST_F(TaskQueueSelectorTest, ChooseOldestWithPriority_OnlyImmediate) { - task_queues_[0]->immediate_work_queue()->Push(TaskQueueImpl::Task( - FROM_HERE, test_closure_, base::TimeTicks(), 0, true, 0)); - - WorkQueue* chosen_work_queue = nullptr; - bool chose_delayed_over_immediate = false; - EXPECT_TRUE(enabled_selector()->ChooseOldestWithPriority( - TaskQueue::NORMAL_PRIORITY, &chose_delayed_over_immediate, - &chosen_work_queue)); - EXPECT_EQ(chosen_work_queue, task_queues_[0]->immediate_work_queue()); - EXPECT_FALSE(chose_delayed_over_immediate); -} - -TEST_F(TaskQueueSelectorTest, TestObserverWithOneBlockedQueue) { - TaskQueueSelectorForTest selector; - MockObserver mock_observer; - selector.SetTaskQueueSelectorObserver(&mock_observer); - - scoped_refptr<TaskQueueImpl> task_queue(NewTaskQueueWithBlockReporting()); - selector.AddQueue(task_queue.get()); - task_queue->SetQueueEnabled(false); - selector.DisableQueue(task_queue.get()); - - task_queue->immediate_work_queue()->PushAndSetEnqueueOrder( - TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(), 0, true), - 0); - - WorkQueue* chosen_work_queue; - EXPECT_CALL(mock_observer, OnTriedToSelectBlockedWorkQueue(_)).Times(1); - EXPECT_FALSE(selector.SelectWorkQueueToService(&chosen_work_queue)); - - task_queue->UnregisterTaskQueue(); - selector.RemoveQueue(task_queue.get()); -} - -TEST_F(TaskQueueSelectorTest, TestObserverWithTwoBlockedQueues) { - TaskQueueSelectorForTest selector; - MockObserver mock_observer; - selector.SetTaskQueueSelectorObserver(&mock_observer); - - scoped_refptr<TaskQueueImpl> task_queue(NewTaskQueueWithBlockReporting()); - scoped_refptr<TaskQueueImpl> task_queue2(NewTaskQueueWithBlockReporting()); - selector.AddQueue(task_queue.get()); - selector.AddQueue(task_queue2.get()); - task_queue->SetQueueEnabled(false); - task_queue2->SetQueueEnabled(false); - selector.DisableQueue(task_queue.get()); - selector.DisableQueue(task_queue2.get()); - selector.SetQueuePriority(task_queue2.get(), TaskQueue::CONTROL_PRIORITY); - - task_queue->immediate_work_queue()->PushAndSetEnqueueOrder( - TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(), 0, true), - 0); - task_queue2->immediate_work_queue()->PushAndSetEnqueueOrder( - TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(), 0, true), - 0); - - // Should still only see one call to OnTriedToSelectBlockedWorkQueue. - WorkQueue* chosen_work_queue; - EXPECT_CALL(mock_observer, OnTriedToSelectBlockedWorkQueue(_)).Times(1); - EXPECT_FALSE(selector.SelectWorkQueueToService(&chosen_work_queue)); - testing::Mock::VerifyAndClearExpectations(&mock_observer); - - // Removing the second queue and selecting again should result in another - // notification. - task_queue->UnregisterTaskQueue(); - selector.RemoveQueue(task_queue.get()); - EXPECT_CALL(mock_observer, OnTriedToSelectBlockedWorkQueue(_)).Times(1); - EXPECT_FALSE(selector.SelectWorkQueueToService(&chosen_work_queue)); - - task_queue2->UnregisterTaskQueue(); - selector.RemoveQueue(task_queue2.get()); -} - -struct ChooseOldestWithPriorityTestParam { - int delayed_task_enqueue_order; - int immediate_task_enqueue_order; - int immediate_starvation_count; - const char* expected_work_queue_name; - bool expected_did_starve_immediate_queue; -}; - -static const ChooseOldestWithPriorityTestParam - kChooseOldestWithPriorityTestCases[] = { - {1, 2, 0, "delayed", true}, - {1, 2, 1, "delayed", true}, - {1, 2, 2, "delayed", true}, - {1, 2, 3, "immediate", false}, - {1, 2, 4, "immediate", false}, - {2, 1, 4, "immediate", false}, - {2, 1, 4, "immediate", false}, -}; - -class ChooseOldestWithPriorityTest - : public TaskQueueSelectorTest, - public testing::WithParamInterface<ChooseOldestWithPriorityTestParam> {}; - -TEST_P(ChooseOldestWithPriorityTest, RoundRobinTest) { - task_queues_[0]->immediate_work_queue()->Push( - TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(), - GetParam().immediate_task_enqueue_order, true, - GetParam().immediate_task_enqueue_order)); - - task_queues_[0]->delayed_work_queue()->Push( - TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(), - GetParam().delayed_task_enqueue_order, true, - GetParam().delayed_task_enqueue_order)); - - selector_.SetImmediateStarvationCountForTest( - GetParam().immediate_starvation_count); - - WorkQueue* chosen_work_queue = nullptr; - bool chose_delayed_over_immediate = false; - EXPECT_TRUE(enabled_selector()->ChooseOldestWithPriority( - TaskQueue::NORMAL_PRIORITY, &chose_delayed_over_immediate, - &chosen_work_queue)); - EXPECT_EQ(chosen_work_queue->task_queue(), task_queues_[0].get()); - EXPECT_STREQ(chosen_work_queue->name(), GetParam().expected_work_queue_name); - EXPECT_EQ(chose_delayed_over_immediate, - GetParam().expected_did_starve_immediate_queue); -} - -INSTANTIATE_TEST_CASE_P(ChooseOldestWithPriorityTest, - ChooseOldestWithPriorityTest, - testing::ValuesIn(kChooseOldestWithPriorityTestCases)); - -} // namespace internal -} // namespace scheduler
diff --git a/components/scheduler/base/task_time_tracker.h b/components/scheduler/base/task_time_tracker.h deleted file mode 100644 index 8546229..0000000 --- a/components/scheduler/base/task_time_tracker.h +++ /dev/null
@@ -1,26 +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 CONTENT_RENDERER_SCHEDULER_BASE_TASK_TIME_TRACKER_H_ -#define CONTENT_RENDERER_SCHEDULER_BASE_TASK_TIME_TRACKER_H_ - -#include "base/time/time.h" -#include "components/scheduler/scheduler_export.h" - -namespace scheduler { - -class SCHEDULER_EXPORT TaskTimeTracker { - public: - TaskTimeTracker() {} - virtual ~TaskTimeTracker() {} - - virtual void ReportTaskTime(base::TimeTicks startTime, - base::TimeTicks endTime) = 0; - private: - DISALLOW_COPY_AND_ASSIGN(TaskTimeTracker); -}; - -} // namespace scheduler - -#endif // CONTENT_RENDERER_SCHEDULER_BASE_TASK_TIME_TRACKER_H_
diff --git a/components/scheduler/base/test_count_uses_time_source.cc b/components/scheduler/base/test_count_uses_time_source.cc deleted file mode 100644 index 4175d1aa2..0000000 --- a/components/scheduler/base/test_count_uses_time_source.cc +++ /dev/null
@@ -1,21 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/base/test_count_uses_time_source.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace scheduler { - -TestCountUsesTimeSource::TestCountUsesTimeSource() : now_calls_count_(0) {} - -TestCountUsesTimeSource::~TestCountUsesTimeSource() { -} - -base::TimeTicks TestCountUsesTimeSource::NowTicks() { - now_calls_count_++; - // Don't return 0, as it triggers some assertions. - return base::TimeTicks() + base::TimeDelta::FromSeconds(1); -} - -} // namespace scheduler
diff --git a/components/scheduler/base/test_count_uses_time_source.h b/components/scheduler/base/test_count_uses_time_source.h deleted file mode 100644 index 92dbc19..0000000 --- a/components/scheduler/base/test_count_uses_time_source.h +++ /dev/null
@@ -1,29 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_BASE_TEST_COUNT_USES_TIME_SOURCE_H_ -#define COMPONENTS_SCHEDULER_BASE_TEST_COUNT_USES_TIME_SOURCE_H_ - -#include "base/macros.h" -#include "base/time/tick_clock.h" - -namespace scheduler { - -class TestCountUsesTimeSource : public base::TickClock { - public: - explicit TestCountUsesTimeSource(); - ~TestCountUsesTimeSource() override; - - base::TimeTicks NowTicks() override; - int now_calls_count() { return now_calls_count_; } - - private: - DISALLOW_COPY_AND_ASSIGN(TestCountUsesTimeSource); - - int now_calls_count_; -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_BASE_TEST_COUNT_USES_TIME_SOURCE_H_
diff --git a/components/scheduler/base/test_task_time_tracker.h b/components/scheduler/base/test_task_time_tracker.h deleted file mode 100644 index 7703e8f..0000000 --- a/components/scheduler/base/test_task_time_tracker.h +++ /dev/null
@@ -1,21 +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 CONTENT_RENDERER_SCHEDULER_BASE_TEST_TASK_TIME_TRACKER_H_ -#define CONTENT_RENDERER_SCHEDULER_BASE_TEST_TASK_TIME_TRACKER_H_ - -#include "base/time/time.h" -#include "components/scheduler/base/task_time_tracker.h" - -namespace scheduler { - -class TestTaskTimeTracker : public TaskTimeTracker { - public: - void ReportTaskTime(base::TimeTicks startTime, - base::TimeTicks endTime) override {} -}; - -} // namespace scheduler - -#endif // CONTENT_RENDERER_SCHEDULER_BASE_TEST_TASK_TIME_TRACKER_H_
diff --git a/components/scheduler/base/test_time_source.cc b/components/scheduler/base/test_time_source.cc deleted file mode 100644 index 6bbe83ba..0000000 --- a/components/scheduler/base/test_time_source.cc +++ /dev/null
@@ -1,20 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/base/test_time_source.h" - -namespace scheduler { - -TestTimeSource::TestTimeSource(base::SimpleTestTickClock* time_source) - : time_source_(time_source) { - DCHECK(time_source_); -} - -TestTimeSource::~TestTimeSource() {} - -base::TimeTicks TestTimeSource::NowTicks() { - return time_source_->NowTicks(); -} - -} // namespace scheduler
diff --git a/components/scheduler/base/test_time_source.h b/components/scheduler/base/test_time_source.h deleted file mode 100644 index 9ff57f0..0000000 --- a/components/scheduler/base/test_time_source.h +++ /dev/null
@@ -1,31 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_BASE_TEST_TIME_SOURCE_H_ -#define COMPONENTS_SCHEDULER_BASE_TEST_TIME_SOURCE_H_ - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/test/simple_test_tick_clock.h" -#include "base/time/tick_clock.h" - -namespace scheduler { - -class TestTimeSource : public base::TickClock { - public: - explicit TestTimeSource(base::SimpleTestTickClock* time_source); - ~TestTimeSource() override; - - base::TimeTicks NowTicks() override; - - private: - // Not owned. - base::SimpleTestTickClock* time_source_; - - DISALLOW_COPY_AND_ASSIGN(TestTimeSource); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_BASE_TEST_TIME_SOURCE_H_
diff --git a/components/scheduler/base/time_domain.cc b/components/scheduler/base/time_domain.cc deleted file mode 100644 index 353a9576..0000000 --- a/components/scheduler/base/time_domain.cc +++ /dev/null
@@ -1,221 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/base/time_domain.h" - -#include <set> - -#include "components/scheduler/base/task_queue_impl.h" -#include "components/scheduler/base/task_queue_manager_delegate.h" -#include "components/scheduler/base/work_queue.h" -#include "components/scheduler/scheduler_export.h" - -namespace scheduler { - -TimeDomain::TimeDomain(Observer* observer) : observer_(observer) {} - -TimeDomain::~TimeDomain() { - DCHECK(main_thread_checker_.CalledOnValidThread()); -} - -void TimeDomain::RegisterQueue(internal::TaskQueueImpl* queue) { - DCHECK(main_thread_checker_.CalledOnValidThread()); - DCHECK_EQ(queue->GetTimeDomain(), this); -} - -void TimeDomain::UnregisterQueue(internal::TaskQueueImpl* queue) { - DCHECK(main_thread_checker_.CalledOnValidThread()); - DCHECK_EQ(queue->GetTimeDomain(), this); - UnregisterAsUpdatableTaskQueue(queue); - - // We need to remove |task_queue| from delayed_wakeup_multimap_ which is a - // little awkward since it's keyed by time. O(n) running time. - for (DelayedWakeupMultimap::iterator iter = delayed_wakeup_multimap_.begin(); - iter != delayed_wakeup_multimap_.end();) { - if (iter->second == queue) { - // O(1) amortized. - iter = delayed_wakeup_multimap_.erase(iter); - } else { - iter++; - } - } -} - -void TimeDomain::MigrateQueue(internal::TaskQueueImpl* queue, - TimeDomain* destination_time_domain) { - DCHECK(main_thread_checker_.CalledOnValidThread()); - DCHECK_EQ(queue->GetTimeDomain(), this); - DCHECK(destination_time_domain); - - // Make sure we remember to update |queue| if it's got incoming immediate - // work. - if (UnregisterAsUpdatableTaskQueue(queue)) - destination_time_domain->updatable_queue_set_.insert(queue); - - base::TimeTicks destination_now = destination_time_domain->Now(); - // We need to remove |task_queue| from delayed_wakeup_multimap_ which is a - // little awkward since it's keyed by time. O(n) running time. - for (DelayedWakeupMultimap::iterator iter = delayed_wakeup_multimap_.begin(); - iter != delayed_wakeup_multimap_.end();) { - if (iter->second == queue) { - destination_time_domain->ScheduleDelayedWork(queue, iter->first, - destination_now); - // O(1) amortized. - iter = delayed_wakeup_multimap_.erase(iter); - } else { - iter++; - } - } -} - -void TimeDomain::ScheduleDelayedWork(internal::TaskQueueImpl* queue, - base::TimeTicks delayed_run_time, - base::TimeTicks now) { - DCHECK(main_thread_checker_.CalledOnValidThread()); - if (delayed_wakeup_multimap_.empty() || - delayed_run_time < delayed_wakeup_multimap_.begin()->first) { - base::TimeDelta delay = std::max(base::TimeDelta(), delayed_run_time - now); - RequestWakeup(now, delay); - } - - delayed_wakeup_multimap_.insert(std::make_pair(delayed_run_time, queue)); - if (observer_) - observer_->OnTimeDomainHasDelayedWork(); -} - -void TimeDomain::RegisterAsUpdatableTaskQueue(internal::TaskQueueImpl* queue) { - { - base::AutoLock lock(newly_updatable_lock_); - newly_updatable_.push_back(queue); - } - if (observer_) - observer_->OnTimeDomainHasImmediateWork(); -} - -bool TimeDomain::UnregisterAsUpdatableTaskQueue( - internal::TaskQueueImpl* queue) { - DCHECK(main_thread_checker_.CalledOnValidThread()); - - bool was_updatable = updatable_queue_set_.erase(queue) != 0; - - base::AutoLock lock(newly_updatable_lock_); - // Remove all copies of |queue| from |newly_updatable_|. - for (size_t i = 0; i < newly_updatable_.size();) { - if (newly_updatable_[i] == queue) { - // Move last element into slot #i and then compact. - newly_updatable_[i] = newly_updatable_.back(); - newly_updatable_.pop_back(); - was_updatable = true; - } else { - i++; - } - } - return was_updatable; -} - -void TimeDomain::UpdateWorkQueues( - bool should_trigger_wakeup, - const internal::TaskQueueImpl::Task* previous_task, - LazyNow lazy_now) { - DCHECK(main_thread_checker_.CalledOnValidThread()); - - // Move any ready delayed tasks into the Incoming queues. - WakeupReadyDelayedQueues(&lazy_now, should_trigger_wakeup, previous_task); - - MoveNewlyUpdatableQueuesIntoUpdatableQueueSet(); - - auto iter = updatable_queue_set_.begin(); - while (iter != updatable_queue_set_.end()) { - internal::TaskQueueImpl* queue = *iter++; - // NOTE Update work queue may erase itself from |updatable_queue_set_|. - // This is fine, erasing an element won't invalidate any interator, as long - // as the iterator isn't the element being delated. - if (queue->immediate_work_queue()->Empty()) - queue->UpdateImmediateWorkQueue(should_trigger_wakeup, previous_task); - } -} - -void TimeDomain::MoveNewlyUpdatableQueuesIntoUpdatableQueueSet() { - DCHECK(main_thread_checker_.CalledOnValidThread()); - base::AutoLock lock(newly_updatable_lock_); - while (!newly_updatable_.empty()) { - updatable_queue_set_.insert(newly_updatable_.back()); - newly_updatable_.pop_back(); - } -} - -void TimeDomain::WakeupReadyDelayedQueues( - LazyNow* lazy_now, - bool should_trigger_wakeup, - const internal::TaskQueueImpl::Task* previous_task) { - DCHECK(main_thread_checker_.CalledOnValidThread()); - // Wake up any queues with pending delayed work. Note std::multipmap stores - // the elements sorted by key, so the begin() iterator points to the earliest - // queue to wakeup. - std::set<internal::TaskQueueImpl*> dedup_set; - while (!delayed_wakeup_multimap_.empty()) { - DelayedWakeupMultimap::iterator next_wakeup = - delayed_wakeup_multimap_.begin(); - if (next_wakeup->first > lazy_now->Now()) - break; - // A queue could have any number of delayed tasks pending so it's worthwhile - // deduping calls to UpdateDelayedWorkQueue since it takes a lock. - // NOTE the order in which these are called matters since the order - // in which EnqueueTaskLocks is called is respected when choosing which - // queue to execute a task from. - if (dedup_set.insert(next_wakeup->second).second) { - next_wakeup->second->UpdateDelayedWorkQueue( - lazy_now, should_trigger_wakeup, previous_task); - } - delayed_wakeup_multimap_.erase(next_wakeup); - } -} - -void TimeDomain::ClearExpiredWakeups() { - DCHECK(main_thread_checker_.CalledOnValidThread()); - LazyNow lazy_now(CreateLazyNow()); - while (!delayed_wakeup_multimap_.empty()) { - DelayedWakeupMultimap::iterator next_wakeup = - delayed_wakeup_multimap_.begin(); - if (next_wakeup->first > lazy_now.Now()) - break; - delayed_wakeup_multimap_.erase(next_wakeup); - } -} - -bool TimeDomain::NextScheduledRunTime(base::TimeTicks* out_time) const { - DCHECK(main_thread_checker_.CalledOnValidThread()); - if (delayed_wakeup_multimap_.empty()) - return false; - - *out_time = delayed_wakeup_multimap_.begin()->first; - return true; -} - -bool TimeDomain::NextScheduledTaskQueue(TaskQueue** out_task_queue) const { - DCHECK(main_thread_checker_.CalledOnValidThread()); - if (delayed_wakeup_multimap_.empty()) - return false; - - *out_task_queue = delayed_wakeup_multimap_.begin()->second; - return true; -} - -void TimeDomain::AsValueInto(base::trace_event::TracedValue* state) const { - state->BeginDictionary(); - state->SetString("name", GetName()); - state->BeginArray("updatable_queue_set"); - for (auto* queue : updatable_queue_set_) - state->AppendString(queue->GetName()); - state->EndArray(); - state->SetInteger("registered_delay_count", delayed_wakeup_multimap_.size()); - if (!delayed_wakeup_multimap_.empty()) { - base::TimeDelta delay = delayed_wakeup_multimap_.begin()->first - Now(); - state->SetDouble("next_delay_ms", delay.InMillisecondsF()); - } - AsValueIntoInternal(state); - state->EndDictionary(); -} - -} // namespace scheduler
diff --git a/components/scheduler/base/time_domain.h b/components/scheduler/base/time_domain.h deleted file mode 100644 index 506f02d..0000000 --- a/components/scheduler/base/time_domain.h +++ /dev/null
@@ -1,157 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_BASE_TIME_DOMAIN_H_ -#define COMPONENTS_SCHEDULER_BASE_TIME_DOMAIN_H_ - -#include <map> - -#include "base/callback.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/time/time.h" -#include "components/scheduler/base/lazy_now.h" -#include "components/scheduler/base/task_queue_impl.h" -#include "components/scheduler/scheduler_export.h" - -namespace scheduler { -namespace internal { -class TaskQueueImpl; -} // internal -class TaskQueueManager; -class TaskQueueManagerDelegate; - -class SCHEDULER_EXPORT TimeDomain { - public: - class SCHEDULER_EXPORT Observer { - public: - virtual ~Observer() {} - - // Called when an empty TaskQueue registered with this TimeDomain has a task - // enqueued. - virtual void OnTimeDomainHasImmediateWork() = 0; - - // Called when a TaskQueue registered with this TimeDomain has a delayed - // task enqueued. - virtual void OnTimeDomainHasDelayedWork() = 0; - }; - - explicit TimeDomain(Observer* observer); - virtual ~TimeDomain(); - - // Returns a LazyNow that evaluate this TimeDomain's Now. Can be called from - // any thread. - // TODO(alexclarke): Make this main thread only. - virtual LazyNow CreateLazyNow() const = 0; - - // Evaluate this TimeDomain's Now. Can be called from any thread. - virtual base::TimeTicks Now() const = 0; - - // Some TimeDomains support virtual time, this method tells us to advance time - // if possible and return true if time was advanced. - virtual bool MaybeAdvanceTime() = 0; - - // Returns the name of this time domain for tracing. - virtual const char* GetName() const = 0; - - // If there is a scheduled delayed task, |out_time| is set to the scheduled - // runtime for the next one and it returns true. Returns false otherwise. - bool NextScheduledRunTime(base::TimeTicks* out_time) const; - - protected: - friend class internal::TaskQueueImpl; - friend class TaskQueueManager; - - void AsValueInto(base::trace_event::TracedValue* state) const; - - // Migrates |queue| from this time domain to |destination_time_domain|. - void MigrateQueue(internal::TaskQueueImpl* queue, - TimeDomain* destination_time_domain); - - // If there is a scheduled delayed task, |out_task_queue| is set to the queue - // the next task was posted to and it returns true. Returns false otherwise. - bool NextScheduledTaskQueue(TaskQueue** out_task_queue) const; - - // Adds |queue| to the set of task queues that UpdateWorkQueues calls - // UpdateWorkQueue on. - void RegisterAsUpdatableTaskQueue(internal::TaskQueueImpl* queue); - - // Schedules a call to TaskQueueImpl::MoveReadyDelayedTasksToDelayedWorkQueue - // when this TimeDomain reaches |delayed_run_time|. - void ScheduleDelayedWork(internal::TaskQueueImpl* queue, - base::TimeTicks delayed_run_time, - base::TimeTicks now); - - // Registers the |queue|. - void RegisterQueue(internal::TaskQueueImpl* queue); - - // Removes |queue| from the set of task queues that UpdateWorkQueues calls - // UpdateWorkQueue on. Returns true if |queue| was updatable. - bool UnregisterAsUpdatableTaskQueue(internal::TaskQueueImpl* queue); - - // Removes |queue| from all internal data structures. - void UnregisterQueue(internal::TaskQueueImpl* queue); - - // Updates active queues associated with this TimeDomain. - void UpdateWorkQueues(bool should_trigger_wakeup, - const internal::TaskQueueImpl::Task* previous_task, - LazyNow lazy_now); - - // Called by the TaskQueueManager when the TimeDomain is registered. - virtual void OnRegisterWithTaskQueueManager( - TaskQueueManager* task_queue_manager) = 0; - - // The implementaion will secedule task processing to run with |delay| with - // respect to the TimeDomain's time source. Always called on the main thread. - // NOTE this is only called by ScheduleDelayedWork if the scheduled runtime - // is sooner than any previously sheduled work or if there is no other - // scheduled work. - virtual void RequestWakeup(base::TimeTicks now, base::TimeDelta delay) = 0; - - // For implementation specific tracing. - virtual void AsValueIntoInternal( - base::trace_event::TracedValue* state) const = 0; - - // Call TaskQueueImpl::UpdateDelayedWorkQueue for each queue where the delay - // has elapsed. - void WakeupReadyDelayedQueues( - LazyNow* lazy_now, - bool should_trigger_wakeup, - const internal::TaskQueueImpl::Task* previous_task); - - protected: - // Clears expired entries from |delayed_wakeup_multimap_|. Caution needs to be - // taken to ensure TaskQueueImpl::UpdateDelayedWorkQueue or - // TaskQueueImpl::Pump is called on the affected queues. - void ClearExpiredWakeups(); - - private: - void MoveNewlyUpdatableQueuesIntoUpdatableQueueSet(); - - typedef std::multimap<base::TimeTicks, internal::TaskQueueImpl*> - DelayedWakeupMultimap; - - DelayedWakeupMultimap delayed_wakeup_multimap_; - - // This lock guards only |newly_updatable_|. It's not expected to be heavily - // contended. - base::Lock newly_updatable_lock_; - std::vector<internal::TaskQueueImpl*> newly_updatable_; - - // Set of task queues with avaliable work on the incoming queue. This should - // only be accessed from the main thread. - std::set<internal::TaskQueueImpl*> updatable_queue_set_; - - Observer* observer_; // NOT OWNED. - - base::ThreadChecker main_thread_checker_; - - DISALLOW_COPY_AND_ASSIGN(TimeDomain); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_BASE_TIME_DOMAIN_H_
diff --git a/components/scheduler/base/time_domain_unittest.cc b/components/scheduler/base/time_domain_unittest.cc deleted file mode 100644 index cdbc744..0000000 --- a/components/scheduler/base/time_domain_unittest.cc +++ /dev/null
@@ -1,232 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/base/time_domain.h" - -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/test/simple_test_tick_clock.h" -#include "cc/test/ordered_simple_task_runner.h" -#include "components/scheduler/base/task_queue_impl.h" -#include "components/scheduler/base/task_queue_manager.h" -#include "components/scheduler/base/task_queue_manager_delegate_for_test.h" -#include "components/scheduler/base/test_time_source.h" -#include "components/scheduler/base/work_queue.h" -#include "testing/gmock/include/gmock/gmock.h" - -using testing::_; -using testing::AnyNumber; -using testing::Mock; - -namespace scheduler { - -class MockTimeDomain : public TimeDomain { - public: - explicit MockTimeDomain(TimeDomain::Observer* observer) - : TimeDomain(observer), - now_(base::TimeTicks() + base::TimeDelta::FromSeconds(1)) {} - - ~MockTimeDomain() override {} - - using TimeDomain::ClearExpiredWakeups; - using TimeDomain::NextScheduledRunTime; - using TimeDomain::NextScheduledTaskQueue; - using TimeDomain::ScheduleDelayedWork; - using TimeDomain::UnregisterQueue; - using TimeDomain::UpdateWorkQueues; - using TimeDomain::RegisterAsUpdatableTaskQueue; - - // TimeSource implementation: - LazyNow CreateLazyNow() const override { return LazyNow(now_); } - base::TimeTicks Now() const override { return now_; } - - void AsValueIntoInternal( - base::trace_event::TracedValue* state) const override {} - - bool MaybeAdvanceTime() override { return false; } - const char* GetName() const override { return "Test"; } - void OnRegisterWithTaskQueueManager( - TaskQueueManager* task_queue_manager) override {} - - MOCK_METHOD2(RequestWakeup, void(base::TimeTicks now, base::TimeDelta delay)); - - void SetNow(base::TimeTicks now) { now_ = now; } - - - private: - base::TimeTicks now_; - - DISALLOW_COPY_AND_ASSIGN(MockTimeDomain); -}; - -class TimeDomainTest : public testing::Test { - public: - void SetUp() final { - time_domain_ = base::WrapUnique(CreateMockTimeDomain()); - task_queue_ = make_scoped_refptr(new internal::TaskQueueImpl( - nullptr, time_domain_.get(), TaskQueue::Spec("test_queue"), - "test.category", "test.category")); - } - - void TearDown() final { - if (task_queue_) - task_queue_->UnregisterTaskQueue(); - } - - virtual MockTimeDomain* CreateMockTimeDomain() { - return new MockTimeDomain(nullptr); - } - - std::unique_ptr<MockTimeDomain> time_domain_; - scoped_refptr<internal::TaskQueueImpl> task_queue_; -}; - -TEST_F(TimeDomainTest, ScheduleDelayedWork) { - base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10); - base::TimeTicks delayed_runtime = time_domain_->Now() + delay; - EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, delay)); - base::TimeTicks now = time_domain_->Now(); - time_domain_->ScheduleDelayedWork(task_queue_.get(), now + delay, now); - - base::TimeTicks next_scheduled_runtime; - EXPECT_TRUE(time_domain_->NextScheduledRunTime(&next_scheduled_runtime)); - EXPECT_EQ(delayed_runtime, next_scheduled_runtime); - - TaskQueue* next_task_queue; - EXPECT_TRUE(time_domain_->NextScheduledTaskQueue(&next_task_queue)); - EXPECT_EQ(task_queue_.get(), next_task_queue); -} - -TEST_F(TimeDomainTest, RequestWakeup_OnlyCalledForEarlierTasks) { - base::TimeDelta delay1 = base::TimeDelta::FromMilliseconds(10); - base::TimeDelta delay2 = base::TimeDelta::FromMilliseconds(20); - base::TimeDelta delay3 = base::TimeDelta::FromMilliseconds(30); - base::TimeDelta delay4 = base::TimeDelta::FromMilliseconds(1); - - // RequestWakeup should always be called if there are no other wakeups. - EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, delay1)); - base::TimeTicks now = time_domain_->Now(); - time_domain_->ScheduleDelayedWork(task_queue_.get(), now + delay1, now); - - Mock::VerifyAndClearExpectations(time_domain_.get()); - - // RequestWakeup should not be called when scheduling later tasks. - EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, _)).Times(0); - time_domain_->ScheduleDelayedWork(task_queue_.get(), now + delay2, now); - time_domain_->ScheduleDelayedWork(task_queue_.get(), now + delay3, now); - - // RequestWakeup should be called when scheduling earlier tasks. - Mock::VerifyAndClearExpectations(time_domain_.get()); - EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, delay4)); - time_domain_->ScheduleDelayedWork(task_queue_.get(), now + delay4, now); -} - -TEST_F(TimeDomainTest, UnregisterQueue) { - scoped_refptr<internal::TaskQueueImpl> task_queue2_ = - make_scoped_refptr(new internal::TaskQueueImpl( - nullptr, time_domain_.get(), TaskQueue::Spec("test_queue2"), - "test.category", "test.category")); - - EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, _)).Times(1); - base::TimeTicks now = time_domain_->Now(); - time_domain_->ScheduleDelayedWork( - task_queue_.get(), now + base::TimeDelta::FromMilliseconds(10), now); - time_domain_->ScheduleDelayedWork( - task_queue2_.get(), now + base::TimeDelta::FromMilliseconds(100), now); - - TaskQueue* next_task_queue; - EXPECT_TRUE(time_domain_->NextScheduledTaskQueue(&next_task_queue)); - EXPECT_EQ(task_queue_.get(), next_task_queue); - - time_domain_->UnregisterQueue(task_queue_.get()); - task_queue_ = scoped_refptr<internal::TaskQueueImpl>(); - EXPECT_TRUE(time_domain_->NextScheduledTaskQueue(&next_task_queue)); - EXPECT_EQ(task_queue2_.get(), next_task_queue); - - time_domain_->UnregisterQueue(task_queue2_.get()); - EXPECT_FALSE(time_domain_->NextScheduledTaskQueue(&next_task_queue)); -} - -TEST_F(TimeDomainTest, UpdateWorkQueues) { - base::TimeDelta delay = base::TimeDelta::FromMilliseconds(50); - EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, delay)); - base::TimeTicks now = time_domain_->Now(); - base::TimeTicks delayed_runtime = now + delay; - time_domain_->ScheduleDelayedWork(task_queue_.get(), delayed_runtime, now); - - base::TimeTicks next_run_time; - ASSERT_TRUE(time_domain_->NextScheduledRunTime(&next_run_time)); - EXPECT_EQ(delayed_runtime, next_run_time); - - LazyNow lazy_now = time_domain_->CreateLazyNow(); - time_domain_->UpdateWorkQueues(false, nullptr, lazy_now); - ASSERT_TRUE(time_domain_->NextScheduledRunTime(&next_run_time)); - EXPECT_EQ(delayed_runtime, next_run_time); - - time_domain_->SetNow(delayed_runtime); - lazy_now = time_domain_->CreateLazyNow(); - time_domain_->UpdateWorkQueues(false, nullptr, lazy_now); - ASSERT_FALSE(time_domain_->NextScheduledRunTime(&next_run_time)); -} - -TEST_F(TimeDomainTest, ClearExpiredWakeups) { - base::TimeTicks now = time_domain_->Now(); - base::TimeDelta delay1 = base::TimeDelta::FromMilliseconds(10); - base::TimeDelta delay2 = base::TimeDelta::FromMilliseconds(20); - base::TimeTicks run_time1 = now + delay1; - base::TimeTicks run_time2 = now + delay2; - - EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, _)).Times(AnyNumber()); - time_domain_->ScheduleDelayedWork(task_queue_.get(), run_time1, now); - time_domain_->ScheduleDelayedWork(task_queue_.get(), run_time2, now); - - base::TimeTicks next_run_time; - ASSERT_TRUE(time_domain_->NextScheduledRunTime(&next_run_time)); - EXPECT_EQ(run_time1, next_run_time); - - time_domain_->SetNow(run_time1); - time_domain_->ClearExpiredWakeups(); - - ASSERT_TRUE(time_domain_->NextScheduledRunTime(&next_run_time)); - EXPECT_EQ(run_time2, next_run_time); - - time_domain_->SetNow(run_time2); - time_domain_->ClearExpiredWakeups(); - ASSERT_FALSE(time_domain_->NextScheduledRunTime(&next_run_time)); -} - -namespace { -class MockObserver : public TimeDomain::Observer { - public: - ~MockObserver() override {} - - MOCK_METHOD0(OnTimeDomainHasImmediateWork, void()); - MOCK_METHOD0(OnTimeDomainHasDelayedWork, void()); -}; -} // namespace - -class TimeDomainWithObserverTest : public TimeDomainTest { - public: - MockTimeDomain* CreateMockTimeDomain() override { - observer_.reset(new MockObserver()); - return new MockTimeDomain(observer_.get()); - } - - std::unique_ptr<MockObserver> observer_; -}; - -TEST_F(TimeDomainWithObserverTest, OnTimeDomainHasImmediateWork) { - EXPECT_CALL(*observer_, OnTimeDomainHasImmediateWork()); - time_domain_->RegisterAsUpdatableTaskQueue(task_queue_.get()); -} - -TEST_F(TimeDomainWithObserverTest, OnTimeDomainHasDelayedWork) { - EXPECT_CALL(*observer_, OnTimeDomainHasDelayedWork()); - EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, _)); - base::TimeTicks now = time_domain_->Now(); - time_domain_->ScheduleDelayedWork( - task_queue_.get(), now + base::TimeDelta::FromMilliseconds(10), now); -} - -} // namespace scheduler
diff --git a/components/scheduler/base/virtual_time_domain.cc b/components/scheduler/base/virtual_time_domain.cc deleted file mode 100644 index db9c403..0000000 --- a/components/scheduler/base/virtual_time_domain.cc +++ /dev/null
@@ -1,64 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/base/virtual_time_domain.h" - -#include "base/bind.h" -#include "components/scheduler/base/task_queue_impl.h" -#include "components/scheduler/base/task_queue_manager.h" -#include "components/scheduler/base/task_queue_manager_delegate.h" - -namespace scheduler { - -VirtualTimeDomain::VirtualTimeDomain(TimeDomain::Observer* observer, - base::TimeTicks initial_time) - : TimeDomain(observer), now_(initial_time), task_queue_manager_(nullptr) {} - -VirtualTimeDomain::~VirtualTimeDomain() {} - -void VirtualTimeDomain::OnRegisterWithTaskQueueManager( - TaskQueueManager* task_queue_manager) { - task_queue_manager_ = task_queue_manager; - DCHECK(task_queue_manager_); -} - -LazyNow VirtualTimeDomain::CreateLazyNow() const { - base::AutoLock lock(lock_); - return LazyNow(now_); -} - -base::TimeTicks VirtualTimeDomain::Now() const { - base::AutoLock lock(lock_); - return now_; -} - -void VirtualTimeDomain::RequestWakeup(base::TimeTicks now, - base::TimeDelta delay) { - // We don't need to do anything here because the caller of AdvanceTo is - // responsible for calling TaskQueueManager::MaybeScheduleImmediateWork if - // needed. -} - -bool VirtualTimeDomain::MaybeAdvanceTime() { - return false; -} - -void VirtualTimeDomain::AsValueIntoInternal( - base::trace_event::TracedValue* state) const {} - -void VirtualTimeDomain::AdvanceTo(base::TimeTicks now) { - base::AutoLock lock(lock_); - DCHECK_GE(now, now_); - now_ = now; -} - -void VirtualTimeDomain::RequestDoWork() { - task_queue_manager_->MaybeScheduleImmediateWork(FROM_HERE); -} - -const char* VirtualTimeDomain::GetName() const { - return "VirtualTimeDomain"; -} - -} // namespace scheduler
diff --git a/components/scheduler/base/virtual_time_domain.h b/components/scheduler/base/virtual_time_domain.h deleted file mode 100644 index e522533..0000000 --- a/components/scheduler/base/virtual_time_domain.h +++ /dev/null
@@ -1,55 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_BASE_VIRTUAL_TIME_DOMAIN_H_ -#define COMPONENTS_SCHEDULER_BASE_VIRTUAL_TIME_DOMAIN_H_ - -#include "base/callback.h" -#include "base/macros.h" -#include "components/scheduler/base/time_domain.h" -#include "components/scheduler/scheduler_export.h" - -namespace scheduler { - -class SCHEDULER_EXPORT VirtualTimeDomain : public TimeDomain { - public: - VirtualTimeDomain(TimeDomain::Observer* observer, - base::TimeTicks initial_time); - ~VirtualTimeDomain() override; - - // TimeDomain implementation: - LazyNow CreateLazyNow() const override; - base::TimeTicks Now() const override; - bool MaybeAdvanceTime() override; - const char* GetName() const override; - - // Advances this time domain to |now|. NOTE |now| is supposed to be - // monotonically increasing. NOTE it's the responsibility of the caller to - // call TaskQueueManager::MaybeScheduleImmediateWork if needed. - void AdvanceTo(base::TimeTicks now); - - using TimeDomain::ClearExpiredWakeups; - - protected: - void OnRegisterWithTaskQueueManager( - TaskQueueManager* task_queue_manager) override; - void RequestWakeup(base::TimeTicks now, base::TimeDelta delay) override; - void AsValueIntoInternal( - base::trace_event::TracedValue* state) const override; - - void RequestDoWork(); - - private: - mutable base::Lock lock_; // Protects |now_|. - base::TimeTicks now_; - - TaskQueueManager* task_queue_manager_; // NOT OWNED - base::Closure do_work_closure_; - - DISALLOW_COPY_AND_ASSIGN(VirtualTimeDomain); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_BASE_VIRTUAL_TIME_DOMAIN_H_
diff --git a/components/scheduler/base/work_queue.cc b/components/scheduler/base/work_queue.cc deleted file mode 100644 index ec770cb..0000000 --- a/components/scheduler/base/work_queue.cc +++ /dev/null
@@ -1,111 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/base/work_queue.h" - -#include "components/scheduler/base/work_queue_sets.h" - -namespace scheduler { -namespace internal { - -WorkQueue::WorkQueue(TaskQueueImpl* task_queue, const char* name) - : work_queue_sets_(nullptr), - task_queue_(task_queue), - work_queue_set_index_(0), - name_(name) {} - -void WorkQueue::AsValueInto(base::trace_event::TracedValue* state) const { - // Remove const to search |work_queue_| in the destructive manner. Restore the - // content from |visited| later. - std::queue<TaskQueueImpl::Task>* mutable_queue = - const_cast<std::queue<TaskQueueImpl::Task>*>(&work_queue_); - std::queue<TaskQueueImpl::Task> visited; - while (!mutable_queue->empty()) { - TaskQueueImpl::TaskAsValueInto(mutable_queue->front(), state); - visited.push(std::move(mutable_queue->front())); - mutable_queue->pop(); - } - *mutable_queue = std::move(visited); -} - -WorkQueue::~WorkQueue() { - DCHECK(!work_queue_sets_) << task_queue_ ->GetName() << " : " - << work_queue_sets_->name() << " : " << name_; -} - -const TaskQueueImpl::Task* WorkQueue::GetFrontTask() const { - if (work_queue_.empty()) - return nullptr; - return &work_queue_.front(); -} - -bool WorkQueue::GetFrontTaskEnqueueOrder(EnqueueOrder* enqueue_order) const { - if (work_queue_.empty()) - return false; - *enqueue_order = work_queue_.front().enqueue_order(); - return true; -} - -void WorkQueue::Push(TaskQueueImpl::Task task) { - bool was_empty = work_queue_.empty(); - work_queue_.push(std::move(task)); - if (was_empty && work_queue_sets_) - work_queue_sets_->OnPushQueue(this); -} - -void WorkQueue::PushAndSetEnqueueOrder(TaskQueueImpl::Task task, - EnqueueOrder enqueue_order) { - bool was_empty = work_queue_.empty(); - work_queue_.push(std::move(task)); - work_queue_.back().set_enqueue_order(enqueue_order); - - if (was_empty && work_queue_sets_) - work_queue_sets_->OnPushQueue(this); -} - -void WorkQueue::PopTaskForTest() { - work_queue_.pop(); -} - -void WorkQueue::SwapLocked(std::queue<TaskQueueImpl::Task>& incoming_queue) { - std::swap(work_queue_, incoming_queue); - - if (!work_queue_.empty() && work_queue_sets_) - work_queue_sets_->OnPushQueue(this); - task_queue_->TraceQueueSize(true); -} - -TaskQueueImpl::Task WorkQueue::TakeTaskFromWorkQueue() { - DCHECK(work_queue_sets_); - DCHECK(!work_queue_.empty()); - TaskQueueImpl::Task pending_task = std::move(work_queue_.front()); - work_queue_.pop(); - work_queue_sets_->OnPopQueue(this); - task_queue_->TraceQueueSize(false); - return pending_task; -} - -void WorkQueue::AssignToWorkQueueSets(WorkQueueSets* work_queue_sets) { - work_queue_sets_ = work_queue_sets; -} - -void WorkQueue::AssignSetIndex(size_t work_queue_set_index) { - work_queue_set_index_ = work_queue_set_index; -} - -bool WorkQueue::ShouldRunBefore(const WorkQueue* other_queue) const { - DCHECK(!work_queue_.empty()); - DCHECK(!other_queue->work_queue_.empty()); - EnqueueOrder enqueue_order = 0; - EnqueueOrder other_enqueue_order = 0; - bool have_task = GetFrontTaskEnqueueOrder(&enqueue_order); - bool have_other_task = - other_queue->GetFrontTaskEnqueueOrder(&other_enqueue_order); - DCHECK(have_task); - DCHECK(have_other_task); - return enqueue_order < other_enqueue_order; -} - -} // namespace internal -} // namespace scheduler
diff --git a/components/scheduler/base/work_queue.h b/components/scheduler/base/work_queue.h deleted file mode 100644 index c97c34c6..0000000 --- a/components/scheduler/base/work_queue.h +++ /dev/null
@@ -1,98 +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 CONTENT_RENDERER_SCHEDULER_BASE_WORK_QUEUE_H_ -#define CONTENT_RENDERER_SCHEDULER_BASE_WORK_QUEUE_H_ - -#include <stddef.h> - -#include <set> - -#include "base/trace_event/trace_event.h" -#include "base/trace_event/trace_event_argument.h" -#include "components/scheduler/base/enqueue_order.h" -#include "components/scheduler/base/task_queue_impl.h" -#include "components/scheduler/scheduler_export.h" - -namespace scheduler { -namespace internal { -class WorkQueueSets; - -class SCHEDULER_EXPORT WorkQueue { - public: - WorkQueue(TaskQueueImpl* task_queue, const char* name); - ~WorkQueue(); - - // Associates this work queue with the given work queue sets. This must be - // called before any tasks can be inserted into this work queue. - void AssignToWorkQueueSets(WorkQueueSets* work_queue_sets); - - // Assigns the current set index. - void AssignSetIndex(size_t work_queue_set_index); - - void AsValueInto(base::trace_event::TracedValue* state) const; - - // Clears the |work_queue_|. - void Clear(); - - // returns true if the |work_queue_| is empty. - bool Empty() const { return work_queue_.empty(); } - - // If the |work_queue_| isn't empty, |enqueue_order| gets set to the enqueue - // order of the front task and the function returns true. Otherwise the - // function returns false. - bool GetFrontTaskEnqueueOrder(EnqueueOrder* enqueue_order) const; - - // Returns the first task in this queue or null if the queue is empty. - const TaskQueueImpl::Task* GetFrontTask() const; - - // Pushes the task onto the |work_queue_| and informs the WorkQueueSets if - // the head changed. - void Push(TaskQueueImpl::Task task); - - // Pushes the task onto the |work_queue_|, sets the |enqueue_order| and - // informs the WorkQueueSets if the head changed. - void PushAndSetEnqueueOrder(TaskQueueImpl::Task task, - EnqueueOrder enqueue_order); - - // Swap the |work_queue_| with |incoming_queue| and informs the - // WorkQueueSets if the head changed. Assumes |task_queue_->any_thread_lock_| - // is locked. - void SwapLocked(std::queue<TaskQueueImpl::Task>& incoming_queue); - - size_t Size() const { return work_queue_.size(); } - - // Pulls a task off the |work_queue_| and informs the WorkQueueSets. - TaskQueueImpl::Task TakeTaskFromWorkQueue(); - - const char* name() const { return name_; } - - TaskQueueImpl* task_queue() const { return task_queue_; } - - WorkQueueSets* work_queue_sets() const { return work_queue_sets_; } - - size_t work_queue_set_index() const { return work_queue_set_index_; } - - // Test support function. This should not be used in production code. - void PopTaskForTest(); - - // Returns true if the front task in this queue has an older enqueue order - // than the front task of |other_queue|. Both queue are assumed to be - // non-empty. - bool ShouldRunBefore(const WorkQueue* other_queue) const; - - private: - std::queue<TaskQueueImpl::Task> work_queue_; - WorkQueueSets* work_queue_sets_; // NOT OWNED. - TaskQueueImpl* task_queue_; // NOT OWNED. - size_t work_queue_set_index_; - const char* name_; - - DISALLOW_COPY_AND_ASSIGN(WorkQueue); -}; - -} // namespace internal -} // namespace scheduler - -#endif // CONTENT_RENDERER_SCHEDULER_BASE_WORK_QUEUE_H_
diff --git a/components/scheduler/base/work_queue_sets.cc b/components/scheduler/base/work_queue_sets.cc deleted file mode 100644 index 96c5da4..0000000 --- a/components/scheduler/base/work_queue_sets.cc +++ /dev/null
@@ -1,146 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/base/work_queue_sets.h" - -#include "base/logging.h" -#include "components/scheduler/base/work_queue.h" - -namespace scheduler { -namespace internal { - -WorkQueueSets::WorkQueueSets(size_t num_sets, const char* name) - : enqueue_order_to_work_queue_maps_(num_sets), name_(name) {} - -WorkQueueSets::~WorkQueueSets() {} - -void WorkQueueSets::AddQueue(WorkQueue* work_queue, size_t set_index) { - DCHECK(!work_queue->work_queue_sets()); - DCHECK_LT(set_index, enqueue_order_to_work_queue_maps_.size()); - EnqueueOrder enqueue_order; - bool has_enqueue_order = work_queue->GetFrontTaskEnqueueOrder(&enqueue_order); - work_queue->AssignToWorkQueueSets(this); - work_queue->AssignSetIndex(set_index); - if (!has_enqueue_order) - return; - enqueue_order_to_work_queue_maps_[set_index].insert( - std::make_pair(enqueue_order, work_queue)); -} - -void WorkQueueSets::RemoveQueue(WorkQueue* work_queue) { - DCHECK_EQ(this, work_queue->work_queue_sets()); - EnqueueOrder enqueue_order; - bool has_enqueue_order = work_queue->GetFrontTaskEnqueueOrder(&enqueue_order); - work_queue->AssignToWorkQueueSets(nullptr); - if (!has_enqueue_order) - return; - size_t set_index = work_queue->work_queue_set_index(); - DCHECK_LT(set_index, enqueue_order_to_work_queue_maps_.size()); - DCHECK_EQ( - work_queue, - enqueue_order_to_work_queue_maps_[set_index].find(enqueue_order)->second); - enqueue_order_to_work_queue_maps_[set_index].erase(enqueue_order); -} - -void WorkQueueSets::ChangeSetIndex(WorkQueue* work_queue, size_t set_index) { - DCHECK_EQ(this, work_queue->work_queue_sets()); - DCHECK_LT(set_index, enqueue_order_to_work_queue_maps_.size()); - EnqueueOrder enqueue_order; - bool has_enqueue_order = work_queue->GetFrontTaskEnqueueOrder(&enqueue_order); - size_t old_set = work_queue->work_queue_set_index(); - DCHECK_LT(old_set, enqueue_order_to_work_queue_maps_.size()); - DCHECK_NE(old_set, set_index); - work_queue->AssignSetIndex(set_index); - if (!has_enqueue_order) - return; - enqueue_order_to_work_queue_maps_[old_set].erase(enqueue_order); - enqueue_order_to_work_queue_maps_[set_index].insert( - std::make_pair(enqueue_order, work_queue)); -} - -void WorkQueueSets::OnPushQueue(WorkQueue* work_queue) { - // NOTE if this funciton changes, we need to keep |WorkQueueSets::AddQueue| in - // sync. - DCHECK_EQ(this, work_queue->work_queue_sets()); - EnqueueOrder enqueue_order; - bool has_enqueue_order = work_queue->GetFrontTaskEnqueueOrder(&enqueue_order); - DCHECK(has_enqueue_order); - size_t set_index = work_queue->work_queue_set_index(); - DCHECK_LT(set_index, enqueue_order_to_work_queue_maps_.size()) - << " set_index = " << set_index; - enqueue_order_to_work_queue_maps_[set_index].insert( - std::make_pair(enqueue_order, work_queue)); -} - -void WorkQueueSets::OnPopQueue(WorkQueue* work_queue) { - size_t set_index = work_queue->work_queue_set_index(); - DCHECK_EQ(this, work_queue->work_queue_sets()); - DCHECK_LT(set_index, enqueue_order_to_work_queue_maps_.size()); - DCHECK(!enqueue_order_to_work_queue_maps_[set_index].empty()) - << " set_index = " << set_index; - DCHECK_EQ(enqueue_order_to_work_queue_maps_[set_index].begin()->second, - work_queue) - << " set_index = " << set_index; - // O(1) amortised. - enqueue_order_to_work_queue_maps_[set_index].erase( - enqueue_order_to_work_queue_maps_[set_index].begin()); - EnqueueOrder enqueue_order; - bool has_enqueue_order = work_queue->GetFrontTaskEnqueueOrder(&enqueue_order); - if (!has_enqueue_order) - return; - enqueue_order_to_work_queue_maps_[set_index].insert( - std::make_pair(enqueue_order, work_queue)); -} - -bool WorkQueueSets::GetOldestQueueInSet(size_t set_index, - WorkQueue** out_work_queue) const { - DCHECK_LT(set_index, enqueue_order_to_work_queue_maps_.size()); - if (enqueue_order_to_work_queue_maps_[set_index].empty()) - return false; - *out_work_queue = - enqueue_order_to_work_queue_maps_[set_index].begin()->second; -#ifndef NDEBUG - EnqueueOrder enqueue_order; - DCHECK((*out_work_queue)->GetFrontTaskEnqueueOrder(&enqueue_order)); - DCHECK_EQ(enqueue_order, - enqueue_order_to_work_queue_maps_[set_index].begin()->first); -#endif - return true; -} - -bool WorkQueueSets::IsSetEmpty(size_t set_index) const { - DCHECK_LT(set_index, enqueue_order_to_work_queue_maps_.size()) - << " set_index = " << set_index; - return enqueue_order_to_work_queue_maps_[set_index].empty(); -} - -#if DCHECK_IS_ON() || !defined(NDEBUG) -bool WorkQueueSets::ContainsWorkQueueForTest( - const WorkQueue* work_queue) const { - EnqueueOrder enqueue_order; - bool has_enqueue_order = work_queue->GetFrontTaskEnqueueOrder(&enqueue_order); - - for (const EnqueueOrderToWorkQueueMap& map : - enqueue_order_to_work_queue_maps_) { - for (const EnqueueOrderToWorkQueueMap::value_type& key_value_pair : map) { - if (key_value_pair.second == work_queue) { - DCHECK(has_enqueue_order); - DCHECK_EQ(key_value_pair.first, enqueue_order); - DCHECK_EQ(this, work_queue->work_queue_sets()); - return true; - } - } - } - - if (work_queue->work_queue_sets() == this) { - DCHECK(!has_enqueue_order); - return true; - } - - return false; -} -#endif - -} // namespace internal -} // namespace scheduler
diff --git a/components/scheduler/base/work_queue_sets.h b/components/scheduler/base/work_queue_sets.h deleted file mode 100644 index 0c2c2dcf..0000000 --- a/components/scheduler/base/work_queue_sets.h +++ /dev/null
@@ -1,68 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_BASE_WORK_QUEUE_SETS_H_ -#define COMPONENTS_SCHEDULER_BASE_WORK_QUEUE_SETS_H_ - -#include <stddef.h> - -#include <map> -#include <vector> - -#include "base/logging.h" -#include "base/macros.h" -#include "base/trace_event/trace_event_argument.h" -#include "components/scheduler/base/task_queue_impl.h" -#include "components/scheduler/scheduler_export.h" - -namespace scheduler { -namespace internal { -class TaskQueueImpl; - -class SCHEDULER_EXPORT WorkQueueSets { - public: - WorkQueueSets(size_t num_sets, const char* name); - ~WorkQueueSets(); - - // O(log num queues) - void AddQueue(WorkQueue* queue, size_t set_index); - - // O(log num queues) - void RemoveQueue(WorkQueue* work_queue); - - // O(log num queues) - void ChangeSetIndex(WorkQueue* queue, size_t set_index); - - // O(log num queues) - void OnPushQueue(WorkQueue* work_queue); - - // If empty it's O(1) amortized, otherwise it's O(log num queues) - void OnPopQueue(WorkQueue* work_queue); - - // O(1) - bool GetOldestQueueInSet(size_t set_index, WorkQueue** out_work_queue) const; - - // O(1) - bool IsSetEmpty(size_t set_index) const; - -#if DCHECK_IS_ON() || !defined(NDEBUG) - // Note this iterates over everything in |enqueue_order_to_work_queue_maps_|. - // It's intended for use with DCHECKS and for testing - bool ContainsWorkQueueForTest(const WorkQueue* queue) const; -#endif - - const char* name() const { return name_; } - - private: - typedef std::map<EnqueueOrder, WorkQueue*> EnqueueOrderToWorkQueueMap; - std::vector<EnqueueOrderToWorkQueueMap> enqueue_order_to_work_queue_maps_; - const char* name_; - - DISALLOW_COPY_AND_ASSIGN(WorkQueueSets); -}; - -} // namespace internal -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_BASE_WORK_QUEUE_SETS_H_
diff --git a/components/scheduler/base/work_queue_sets_unittest.cc b/components/scheduler/base/work_queue_sets_unittest.cc deleted file mode 100644 index 4466db1f..0000000 --- a/components/scheduler/base/work_queue_sets_unittest.cc +++ /dev/null
@@ -1,259 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/base/work_queue_sets.h" - -#include <stddef.h> - -#include "base/memory/ptr_util.h" -#include "components/scheduler/base/work_queue.h" -#include "testing/gmock/include/gmock/gmock.h" - -namespace scheduler { -class TimeDomain; - -namespace internal { - -class WorkQueueSetsTest : public testing::Test { - public: - void SetUp() override { - work_queue_sets_.reset(new WorkQueueSets(kNumSets, "test")); - } - - void TearDown() override { - for (std::unique_ptr<WorkQueue>& work_queue : work_queues_) { - if (work_queue->work_queue_sets()) - work_queue_sets_->RemoveQueue(work_queue.get()); - } - } - - protected: - enum { - kNumSets = 5 // An arbitary choice. - }; - - WorkQueue* NewTaskQueue(const char* queue_name) { - WorkQueue* queue = new WorkQueue(nullptr, "test"); - work_queues_.push_back(base::WrapUnique(queue)); - work_queue_sets_->AddQueue(queue, TaskQueue::CONTROL_PRIORITY); - return queue; - } - - TaskQueueImpl::Task FakeTaskWithEnqueueOrder(int enqueue_order) { - TaskQueueImpl::Task fake_task(FROM_HERE, base::Closure(), base::TimeTicks(), - 0, true); - fake_task.set_enqueue_order(enqueue_order); - return fake_task; - } - - std::vector<std::unique_ptr<WorkQueue>> work_queues_; - std::unique_ptr<WorkQueueSets> work_queue_sets_; -}; - -TEST_F(WorkQueueSetsTest, ChangeSetIndex) { - WorkQueue* work_queue = NewTaskQueue("queue"); - size_t set = TaskQueue::NORMAL_PRIORITY; - work_queue_sets_->ChangeSetIndex(work_queue, set); - - EXPECT_EQ(set, work_queue->work_queue_set_index()); -} - -TEST_F(WorkQueueSetsTest, GetOldestQueueInSet_QueueEmpty) { - WorkQueue* work_queue = NewTaskQueue("queue"); - size_t set = TaskQueue::NORMAL_PRIORITY; - work_queue_sets_->ChangeSetIndex(work_queue, set); - - WorkQueue* selected_work_queue; - EXPECT_FALSE( - work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue)); -} - -TEST_F(WorkQueueSetsTest, OnPushQueue) { - WorkQueue* work_queue = NewTaskQueue("queue"); - size_t set = TaskQueue::NORMAL_PRIORITY; - work_queue_sets_->ChangeSetIndex(work_queue, set); - - WorkQueue* selected_work_queue; - EXPECT_FALSE( - work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue)); - - work_queue->Push(FakeTaskWithEnqueueOrder(10)); - work_queue_sets_->OnPushQueue(work_queue); - - EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue)); - EXPECT_EQ(work_queue, selected_work_queue); -} - -TEST_F(WorkQueueSetsTest, GetOldestQueueInSet_SingleTaskInSet) { - WorkQueue* work_queue = NewTaskQueue("queue"); - work_queue->Push(FakeTaskWithEnqueueOrder(10)); - size_t set = 1; - work_queue_sets_->ChangeSetIndex(work_queue, set); - - WorkQueue* selected_work_queue; - EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue)); - EXPECT_EQ(work_queue, selected_work_queue); -} - -TEST_F(WorkQueueSetsTest, GetOldestQueueInSet_MultipleAgesInSet) { - WorkQueue* queue1 = NewTaskQueue("queue1"); - WorkQueue* queue2 = NewTaskQueue("queue2"); - WorkQueue* queue3 = NewTaskQueue("queue2"); - queue1->Push(FakeTaskWithEnqueueOrder(6)); - queue2->Push(FakeTaskWithEnqueueOrder(5)); - queue3->Push(FakeTaskWithEnqueueOrder(4)); - size_t set = 2; - work_queue_sets_->ChangeSetIndex(queue1, set); - work_queue_sets_->ChangeSetIndex(queue2, set); - work_queue_sets_->ChangeSetIndex(queue3, set); - - WorkQueue* selected_work_queue; - EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue)); - EXPECT_EQ(queue3, selected_work_queue); -} - -TEST_F(WorkQueueSetsTest, OnPopQueue) { - WorkQueue* queue1 = NewTaskQueue("queue1"); - WorkQueue* queue2 = NewTaskQueue("queue2"); - WorkQueue* queue3 = NewTaskQueue("queue3"); - queue1->Push(FakeTaskWithEnqueueOrder(6)); - queue2->Push(FakeTaskWithEnqueueOrder(3)); - queue2->Push(FakeTaskWithEnqueueOrder(1)); - queue3->Push(FakeTaskWithEnqueueOrder(4)); - size_t set = 3; - work_queue_sets_->ChangeSetIndex(queue1, set); - work_queue_sets_->ChangeSetIndex(queue2, set); - work_queue_sets_->ChangeSetIndex(queue3, set); - - WorkQueue* selected_work_queue; - EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue)); - EXPECT_EQ(queue2, selected_work_queue); - - queue2->PopTaskForTest(); - work_queue_sets_->OnPopQueue(queue2); - - EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue)); - EXPECT_EQ(queue2, selected_work_queue); -} - -TEST_F(WorkQueueSetsTest, OnPopQueue_QueueBecomesEmpty) { - WorkQueue* queue1 = NewTaskQueue("queue"); - WorkQueue* queue2 = NewTaskQueue("queue"); - WorkQueue* queue3 = NewTaskQueue("queue"); - queue1->Push(FakeTaskWithEnqueueOrder(6)); - queue2->Push(FakeTaskWithEnqueueOrder(5)); - queue3->Push(FakeTaskWithEnqueueOrder(4)); - size_t set = 4; - work_queue_sets_->ChangeSetIndex(queue1, set); - work_queue_sets_->ChangeSetIndex(queue2, set); - work_queue_sets_->ChangeSetIndex(queue3, set); - - WorkQueue* selected_work_queue; - EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue)); - EXPECT_EQ(queue3, selected_work_queue); - - queue3->PopTaskForTest(); - work_queue_sets_->OnPopQueue(queue3); - - EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue)); - EXPECT_EQ(queue2, selected_work_queue); -} - -TEST_F(WorkQueueSetsTest, - GetOldestQueueInSet_MultipleAgesInSetIntegerRollover) { - WorkQueue* queue1 = NewTaskQueue("queue1"); - WorkQueue* queue2 = NewTaskQueue("queue2"); - WorkQueue* queue3 = NewTaskQueue("queue3"); - queue1->Push(FakeTaskWithEnqueueOrder(0x7ffffff1)); - queue2->Push(FakeTaskWithEnqueueOrder(0x7ffffff0)); - queue3->Push(FakeTaskWithEnqueueOrder(-0x7ffffff1)); - size_t set = 1; - work_queue_sets_->ChangeSetIndex(queue1, set); - work_queue_sets_->ChangeSetIndex(queue2, set); - work_queue_sets_->ChangeSetIndex(queue3, set); - - WorkQueue* selected_work_queue; - EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue)); - EXPECT_EQ(queue2, selected_work_queue); -} - -TEST_F(WorkQueueSetsTest, GetOldestQueueInSet_MultipleAgesInSet_RemoveQueue) { - WorkQueue* queue1 = NewTaskQueue("queue1"); - WorkQueue* queue2 = NewTaskQueue("queue2"); - WorkQueue* queue3 = NewTaskQueue("queue3"); - queue1->Push(FakeTaskWithEnqueueOrder(6)); - queue2->Push(FakeTaskWithEnqueueOrder(5)); - queue3->Push(FakeTaskWithEnqueueOrder(4)); - size_t set = 1; - work_queue_sets_->ChangeSetIndex(queue1, set); - work_queue_sets_->ChangeSetIndex(queue2, set); - work_queue_sets_->ChangeSetIndex(queue3, set); - work_queue_sets_->RemoveQueue(queue3); - - WorkQueue* selected_work_queue; - EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue)); - EXPECT_EQ(queue2, selected_work_queue); -} - -TEST_F(WorkQueueSetsTest, ChangeSetIndex_Complex) { - WorkQueue* queue1 = NewTaskQueue("queue1"); - WorkQueue* queue2 = NewTaskQueue("queue2"); - WorkQueue* queue3 = NewTaskQueue("queue3"); - WorkQueue* queue4 = NewTaskQueue("queue4"); - queue1->Push(FakeTaskWithEnqueueOrder(6)); - queue2->Push(FakeTaskWithEnqueueOrder(5)); - queue3->Push(FakeTaskWithEnqueueOrder(4)); - queue4->Push(FakeTaskWithEnqueueOrder(3)); - size_t set1 = 1; - size_t set2 = 2; - work_queue_sets_->ChangeSetIndex(queue1, set1); - work_queue_sets_->ChangeSetIndex(queue2, set1); - work_queue_sets_->ChangeSetIndex(queue3, set2); - work_queue_sets_->ChangeSetIndex(queue4, set2); - - WorkQueue* selected_work_queue; - EXPECT_TRUE( - work_queue_sets_->GetOldestQueueInSet(set1, &selected_work_queue)); - EXPECT_EQ(queue2, selected_work_queue); - - EXPECT_TRUE( - work_queue_sets_->GetOldestQueueInSet(set2, &selected_work_queue)); - EXPECT_EQ(queue4, selected_work_queue); - - work_queue_sets_->ChangeSetIndex(queue4, set1); - - EXPECT_TRUE( - work_queue_sets_->GetOldestQueueInSet(set1, &selected_work_queue)); - EXPECT_EQ(queue4, selected_work_queue); - - EXPECT_TRUE( - work_queue_sets_->GetOldestQueueInSet(set2, &selected_work_queue)); - EXPECT_EQ(queue3, selected_work_queue); -} - -TEST_F(WorkQueueSetsTest, IsSetEmpty_NoWork) { - size_t set = 2; - EXPECT_TRUE(work_queue_sets_->IsSetEmpty(set)); - - WorkQueue* work_queue = NewTaskQueue("queue"); - work_queue_sets_->ChangeSetIndex(work_queue, set); - EXPECT_TRUE(work_queue_sets_->IsSetEmpty(set)); -} - -TEST_F(WorkQueueSetsTest, IsSetEmpty_Work) { - size_t set = 2; - EXPECT_TRUE(work_queue_sets_->IsSetEmpty(set)); - - WorkQueue* work_queue = NewTaskQueue("queue"); - work_queue->Push(FakeTaskWithEnqueueOrder(1)); - work_queue_sets_->ChangeSetIndex(work_queue, set); - EXPECT_FALSE(work_queue_sets_->IsSetEmpty(set)); - - work_queue->PopTaskForTest(); - work_queue_sets_->OnPopQueue(work_queue); - EXPECT_TRUE(work_queue_sets_->IsSetEmpty(set)); -} - -} // namespace internal -} // namespace scheduler
diff --git a/components/scheduler/child/DEPS b/components/scheduler/child/DEPS deleted file mode 100644 index 87faf73..0000000 --- a/components/scheduler/child/DEPS +++ /dev/null
@@ -1,13 +0,0 @@ -include_rules = [ - "+components/scheduler/base", - "+components/scheduler/scheduler_export.h", - "+third_party/WebKit/public/platform", -] - -specific_include_rules = { - "(test_time_source|.*test)\.cc": [ - "+cc/test", - "+content/test", - "+components/scheduler/test", - ], -}
diff --git a/components/scheduler/child/child_scheduler.h b/components/scheduler/child/child_scheduler.h deleted file mode 100644 index 113be64..0000000 --- a/components/scheduler/child/child_scheduler.h +++ /dev/null
@@ -1,70 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_CHILD_CHILD_SCHEDULER_H_ -#define COMPONENTS_SCHEDULER_CHILD_CHILD_SCHEDULER_H_ - -#include "base/macros.h" -#include "base/message_loop/message_loop.h" -#include "components/scheduler/base/task_queue.h" -#include "components/scheduler/child/single_thread_idle_task_runner.h" -#include "components/scheduler/scheduler_export.h" - -namespace base { -class MessageLoop; -} - -namespace scheduler { -class TaskQueue; - -class SCHEDULER_EXPORT ChildScheduler { - public: - virtual ~ChildScheduler() {} - - // Returns the default task runner. - virtual scoped_refptr<TaskQueue> DefaultTaskRunner() = 0; - - // Returns the idle task runner. Tasks posted to this runner may be reordered - // relative to other task types and may be starved for an arbitrarily long - // time if no idle time is available. - virtual scoped_refptr<SingleThreadIdleTaskRunner> IdleTaskRunner() = 0; - - // Returns true if there is high priority work pending on the main thread - // and the caller should yield to let the scheduler service that work. Note - // that this is a stricter condition than |IsHighPriorityWorkAnticipated|, - // restricted to the case where real work is pending. - // Must be called from the thread this scheduler was created on. - virtual bool ShouldYieldForHighPriorityWork() = 0; - - // Returns true if a currently running idle task could exceed its deadline - // without impacting user experience too much. This should only be used if - // there is a task which cannot be pre-empted and is likely to take longer - // than the largest expected idle task deadline. It should NOT be polled to - // check whether more work can be performed on the current idle task after - // its deadline has expired - post a new idle task for the continuation of the - // work in this case. - // Must be called from the thread this scheduler was created on. - virtual bool CanExceedIdleDeadlineIfRequired() const = 0; - - // Adds or removes a task observer from the scheduler. The observer will be - // notified before and after every executed task. These functions can only be - // called on the thread this scheduler was created on. - virtual void AddTaskObserver( - base::MessageLoop::TaskObserver* task_observer) = 0; - virtual void RemoveTaskObserver( - base::MessageLoop::TaskObserver* task_observer) = 0; - - // Shuts down the scheduler by dropping any remaining pending work in the work - // queues. After this call any work posted to the task runners will be - // silently dropped. - virtual void Shutdown() = 0; - - protected: - ChildScheduler() {} - DISALLOW_COPY_AND_ASSIGN(ChildScheduler); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_CHILD_CHILD_SCHEDULER_H_
diff --git a/components/scheduler/child/compositor_worker_scheduler.cc b/components/scheduler/child/compositor_worker_scheduler.cc deleted file mode 100644 index fb2f569d..0000000 --- a/components/scheduler/child/compositor_worker_scheduler.cc +++ /dev/null
@@ -1,166 +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 "components/scheduler/child/compositor_worker_scheduler.h" - -#include "base/message_loop/message_loop.h" -#include "base/threading/thread.h" - -namespace scheduler { - -// TODO(scheduler-dev): Get rid of this asap! -namespace { -class CompositorWorkerTaskRunnerWrapper : public TaskQueue { - public: - explicit CompositorWorkerTaskRunnerWrapper( - scoped_refptr<base::SingleThreadTaskRunner> task_runner) - : task_runner_(task_runner) {} - - // TaskQueue implementation: - void UnregisterTaskQueue() override { NOTREACHED(); } - - bool RunsTasksOnCurrentThread() const override { - return task_runner_->RunsTasksOnCurrentThread(); - } - - bool PostDelayedTask(const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) override { - return task_runner_->PostDelayedTask(from_here, task, delay); - } - - bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) override { - return task_runner_->PostNonNestableDelayedTask(from_here, task, delay); - } - - void SetQueueEnabled(bool enabled) override { NOTREACHED(); } - - bool IsQueueEnabled() const override { - NOTREACHED(); - return true; - } - - bool IsEmpty() const override { - NOTREACHED(); - return false; - }; - - bool HasPendingImmediateWork() const override { - NOTREACHED(); - return false; - }; - - bool NeedsPumping() const override { - NOTREACHED(); - return false; - }; - - const char* GetName() const override { - NOTREACHED(); - return nullptr; - }; - - void SetQueuePriority(QueuePriority priority) override { NOTREACHED(); } - - QueuePriority GetQueuePriority() const override { - NOTREACHED(); - return QueuePriority::NORMAL_PRIORITY; - }; - - void SetPumpPolicy(PumpPolicy pump_policy) override { NOTREACHED(); } - - PumpPolicy GetPumpPolicy() const override { - NOTREACHED(); - return PumpPolicy::AUTO; - }; - - void PumpQueue(LazyNow*, bool may_post_dowork) override { NOTREACHED(); } - - void AddTaskObserver( - base::MessageLoop::TaskObserver* task_observer) override { - NOTREACHED(); - } - - void RemoveTaskObserver( - base::MessageLoop::TaskObserver* task_observer) override { - NOTREACHED(); - } - - void SetTimeDomain(TimeDomain* domain) override { NOTREACHED(); } - - TimeDomain* GetTimeDomain() const override { - NOTREACHED(); - return nullptr; - } - - void SetBlameContext(base::trace_event::BlameContext*) override { - NOTREACHED(); - } - - private: - ~CompositorWorkerTaskRunnerWrapper() override {} - - scoped_refptr<base::SingleThreadTaskRunner> task_runner_; -}; -} // namespace - -CompositorWorkerScheduler::CompositorWorkerScheduler(base::Thread* thread) - : thread_(thread) {} - -CompositorWorkerScheduler::~CompositorWorkerScheduler() {} - -void CompositorWorkerScheduler::Init() {} - -scoped_refptr<TaskQueue> CompositorWorkerScheduler::DefaultTaskRunner() { - // TODO(sad): Implement a more robust scheduler that can do idle tasks for GC - // without regressing performance of the rest of the system. - return make_scoped_refptr( - new CompositorWorkerTaskRunnerWrapper(thread_->task_runner())); -} - -scoped_refptr<scheduler::SingleThreadIdleTaskRunner> -CompositorWorkerScheduler::IdleTaskRunner() { - // TODO(flackr): This posts idle tasks as regular tasks. We need to create - // an idle task runner with the semantics we want for the compositor thread - // which runs them after the current frame has been drawn before the next - // vsync. https://crbug.com/609532 - return make_scoped_refptr(new SingleThreadIdleTaskRunner( - thread_->task_runner(), thread_->task_runner(), this, - "compositor.scheduler")); -} - -bool CompositorWorkerScheduler::CanExceedIdleDeadlineIfRequired() const { - return false; -} - -bool CompositorWorkerScheduler::ShouldYieldForHighPriorityWork() { - return false; -} - -void CompositorWorkerScheduler::AddTaskObserver( - base::MessageLoop::TaskObserver* task_observer) { - thread_->message_loop()->AddTaskObserver(task_observer); -} - -void CompositorWorkerScheduler::RemoveTaskObserver( - base::MessageLoop::TaskObserver* task_observer) { - thread_->message_loop()->RemoveTaskObserver(task_observer); -} - -void CompositorWorkerScheduler::Shutdown() {} - -void CompositorWorkerScheduler::OnIdleTaskPosted() {} - -base::TimeTicks CompositorWorkerScheduler::WillProcessIdleTask() { - // TODO(flackr): Return the next frame time as the deadline instead. - // TODO(flackr): Ensure that oilpan GC does happen on the compositor thread - // even though we will have no long idle periods. https://crbug.com/609531 - return base::TimeTicks::Now() + base::TimeDelta::FromMillisecondsD(16.7); -} - -void CompositorWorkerScheduler::DidProcessIdleTask() {} - -} // namespace scheduler
diff --git a/components/scheduler/child/compositor_worker_scheduler.h b/components/scheduler/child/compositor_worker_scheduler.h deleted file mode 100644 index 46e7046..0000000 --- a/components/scheduler/child/compositor_worker_scheduler.h +++ /dev/null
@@ -1,53 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_CHILD_COMPOSITOR_WORKER_SCHEDULER_H_ -#define COMPONENTS_SCHEDULER_CHILD_COMPOSITOR_WORKER_SCHEDULER_H_ - -#include "base/macros.h" -#include "components/scheduler/child/single_thread_idle_task_runner.h" -#include "components/scheduler/child/worker_scheduler.h" -#include "components/scheduler/scheduler_export.h" - -namespace base { -class Thread; -} - -namespace scheduler { - -class SCHEDULER_EXPORT CompositorWorkerScheduler - : public WorkerScheduler, - public SingleThreadIdleTaskRunner::Delegate { - public: - explicit CompositorWorkerScheduler(base::Thread* thread); - ~CompositorWorkerScheduler() override; - - // WorkerScheduler: - void Init() override; - - // ChildScheduler: - scoped_refptr<TaskQueue> DefaultTaskRunner() override; - scoped_refptr<scheduler::SingleThreadIdleTaskRunner> IdleTaskRunner() - override; - bool ShouldYieldForHighPriorityWork() override; - bool CanExceedIdleDeadlineIfRequired() const override; - void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer) override; - void RemoveTaskObserver( - base::MessageLoop::TaskObserver* task_observer) override; - void Shutdown() override; - - // SingleThreadIdleTaskRunner::Delegate: - void OnIdleTaskPosted() override; - base::TimeTicks WillProcessIdleTask() override; - void DidProcessIdleTask() override; - - private: - base::Thread* thread_; - - DISALLOW_COPY_AND_ASSIGN(CompositorWorkerScheduler); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_CHILD_COMPOSITOR_WORKER_SCHEDULER_H_
diff --git a/components/scheduler/child/idle_helper.cc b/components/scheduler/child/idle_helper.cc deleted file mode 100644 index 0f6c82f6..0000000 --- a/components/scheduler/child/idle_helper.cc +++ /dev/null
@@ -1,486 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/child/idle_helper.h" - -#include "base/time/time.h" -#include "base/trace_event/trace_event.h" -#include "base/trace_event/trace_event_argument.h" -#include "components/scheduler/base/real_time_domain.h" -#include "components/scheduler/base/task_queue.h" -#include "components/scheduler/base/task_queue_manager.h" -#include "components/scheduler/child/scheduler_helper.h" -#include "components/scheduler/child/scheduler_tqm_delegate.h" - -namespace scheduler { - -IdleHelper::IdleHelper( - SchedulerHelper* helper, - Delegate* delegate, - const char* tracing_category, - const char* disabled_by_default_tracing_category, - const char* idle_period_tracing_name, - base::TimeDelta required_quiescence_duration_before_long_idle_period) - : helper_(helper), - delegate_(delegate), - idle_queue_( - helper_->NewTaskQueue(TaskQueue::Spec("idle_tq").SetPumpPolicy( - TaskQueue::PumpPolicy::MANUAL))), - state_(helper, - delegate, - tracing_category, - disabled_by_default_tracing_category, - idle_period_tracing_name), - required_quiescence_duration_before_long_idle_period_( - required_quiescence_duration_before_long_idle_period), - disabled_by_default_tracing_category_( - disabled_by_default_tracing_category), - weak_factory_(this) { - weak_idle_helper_ptr_ = weak_factory_.GetWeakPtr(); - enable_next_long_idle_period_closure_.Reset( - base::Bind(&IdleHelper::EnableLongIdlePeriod, weak_idle_helper_ptr_)); - on_idle_task_posted_closure_.Reset(base::Bind( - &IdleHelper::OnIdleTaskPostedOnMainThread, weak_idle_helper_ptr_)); - - idle_task_runner_ = make_scoped_refptr(new SingleThreadIdleTaskRunner( - idle_queue_, helper_->ControlAfterWakeUpTaskRunner(), this, - tracing_category)); - - idle_queue_->SetQueueEnabled(false); - idle_queue_->SetQueuePriority(TaskQueue::BEST_EFFORT_PRIORITY); - - helper_->AddTaskObserver(this); -} - -IdleHelper::~IdleHelper() { - helper_->RemoveTaskObserver(this); -} - -IdleHelper::Delegate::Delegate() { -} - -IdleHelper::Delegate::~Delegate() { -} - -scoped_refptr<SingleThreadIdleTaskRunner> IdleHelper::IdleTaskRunner() { - helper_->CheckOnValidThread(); - return idle_task_runner_; -} - -IdleHelper::IdlePeriodState IdleHelper::ComputeNewLongIdlePeriodState( - const base::TimeTicks now, - base::TimeDelta* next_long_idle_period_delay_out) { - helper_->CheckOnValidThread(); - - if (!delegate_->CanEnterLongIdlePeriod(now, - next_long_idle_period_delay_out)) { - return IdlePeriodState::NOT_IN_IDLE_PERIOD; - } - - base::TimeTicks next_pending_delayed_task; - base::TimeDelta max_long_idle_period_duration = - base::TimeDelta::FromMilliseconds(kMaximumIdlePeriodMillis); - base::TimeDelta long_idle_period_duration; - if (helper_->real_time_domain()->NextScheduledRunTime( - &next_pending_delayed_task)) { - // Limit the idle period duration to be before the next pending task. - long_idle_period_duration = std::min(next_pending_delayed_task - now, - max_long_idle_period_duration); - } else { - long_idle_period_duration = max_long_idle_period_duration; - } - - if (long_idle_period_duration >= - base::TimeDelta::FromMilliseconds(kMinimumIdlePeriodDurationMillis)) { - *next_long_idle_period_delay_out = long_idle_period_duration; - if (!idle_queue_->HasPendingImmediateWork()) { - return IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED; - } else if (long_idle_period_duration == max_long_idle_period_duration) { - return IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE; - } else { - return IdlePeriodState::IN_LONG_IDLE_PERIOD; - } - } else { - // If we can't start the idle period yet then try again after wakeup. - *next_long_idle_period_delay_out = base::TimeDelta::FromMilliseconds( - kRetryEnableLongIdlePeriodDelayMillis); - return IdlePeriodState::NOT_IN_IDLE_PERIOD; - } -} - -bool IdleHelper::ShouldWaitForQuiescence() { - helper_->CheckOnValidThread(); - - if (helper_->IsShutdown()) - return false; - - if (required_quiescence_duration_before_long_idle_period_ == - base::TimeDelta()) - return false; - - bool system_is_quiescent = helper_->GetAndClearSystemIsQuiescentBit(); - TRACE_EVENT1(disabled_by_default_tracing_category_, "ShouldWaitForQuiescence", - "system_is_quiescent", system_is_quiescent); - return !system_is_quiescent; -} - -void IdleHelper::EnableLongIdlePeriod() { - TRACE_EVENT0(disabled_by_default_tracing_category_, "EnableLongIdlePeriod"); - helper_->CheckOnValidThread(); - if (helper_->IsShutdown()) - return; - - // End any previous idle period. - EndIdlePeriod(); - - if (ShouldWaitForQuiescence()) { - helper_->ControlTaskRunner()->PostDelayedTask( - FROM_HERE, enable_next_long_idle_period_closure_.callback(), - required_quiescence_duration_before_long_idle_period_); - delegate_->IsNotQuiescent(); - return; - } - - base::TimeTicks now(helper_->scheduler_tqm_delegate()->NowTicks()); - base::TimeDelta next_long_idle_period_delay; - IdlePeriodState new_idle_period_state = - ComputeNewLongIdlePeriodState(now, &next_long_idle_period_delay); - if (IsInIdlePeriod(new_idle_period_state)) { - StartIdlePeriod(new_idle_period_state, now, - now + next_long_idle_period_delay); - } else { - // Otherwise wait for the next long idle period delay before trying again. - helper_->ControlTaskRunner()->PostDelayedTask( - FROM_HERE, enable_next_long_idle_period_closure_.callback(), - next_long_idle_period_delay); - } -} - -void IdleHelper::StartIdlePeriod(IdlePeriodState new_state, - base::TimeTicks now, - base::TimeTicks idle_period_deadline) { - DCHECK_GT(idle_period_deadline, now); - helper_->CheckOnValidThread(); - DCHECK(IsInIdlePeriod(new_state)); - - base::TimeDelta idle_period_duration(idle_period_deadline - now); - if (idle_period_duration < - base::TimeDelta::FromMilliseconds(kMinimumIdlePeriodDurationMillis)) { - TRACE_EVENT1(disabled_by_default_tracing_category_, - "NotStartingIdlePeriodBecauseDeadlineIsTooClose", - "idle_period_duration_ms", - idle_period_duration.InMillisecondsF()); - return; - } - - TRACE_EVENT0(disabled_by_default_tracing_category_, "StartIdlePeriod"); - idle_queue_->SetQueueEnabled(true); - LazyNow lazy_now(now); - idle_queue_->PumpQueue(&lazy_now, true); - - state_.UpdateState(new_state, idle_period_deadline, now); -} - -void IdleHelper::EndIdlePeriod() { - helper_->CheckOnValidThread(); - TRACE_EVENT0(disabled_by_default_tracing_category_, "EndIdlePeriod"); - - enable_next_long_idle_period_closure_.Cancel(); - on_idle_task_posted_closure_.Cancel(); - - // If we weren't already within an idle period then early-out. - if (!IsInIdlePeriod(state_.idle_period_state())) - return; - - idle_queue_->SetQueueEnabled(false); - state_.UpdateState(IdlePeriodState::NOT_IN_IDLE_PERIOD, base::TimeTicks(), - base::TimeTicks()); -} - -void IdleHelper::WillProcessTask(const base::PendingTask& pending_task) { -} - -void IdleHelper::DidProcessTask(const base::PendingTask& pending_task) { - helper_->CheckOnValidThread(); - TRACE_EVENT0(disabled_by_default_tracing_category_, "DidProcessTask"); - if (IsInIdlePeriod(state_.idle_period_state()) && - state_.idle_period_state() != - IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED && - helper_->scheduler_tqm_delegate()->NowTicks() >= - state_.idle_period_deadline()) { - // If the idle period deadline has now been reached, either end the idle - // period or trigger a new long-idle period. - if (IsInLongIdlePeriod(state_.idle_period_state())) { - EnableLongIdlePeriod(); - } else { - DCHECK(IdlePeriodState::IN_SHORT_IDLE_PERIOD == - state_.idle_period_state()); - EndIdlePeriod(); - } - } -} - -void IdleHelper::UpdateLongIdlePeriodStateAfterIdleTask() { - helper_->CheckOnValidThread(); - DCHECK(IsInLongIdlePeriod(state_.idle_period_state())); - TRACE_EVENT0(disabled_by_default_tracing_category_, - "UpdateLongIdlePeriodStateAfterIdleTask"); - - if (!idle_queue_->HasPendingImmediateWork()) { - // If there are no more idle tasks then pause long idle period ticks until a - // new idle task is posted. - state_.UpdateState(IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED, - state_.idle_period_deadline(), base::TimeTicks()); - } else if (idle_queue_->NeedsPumping()) { - // If there is still idle work to do then just start the next idle period. - base::TimeDelta next_long_idle_period_delay; - if (state_.idle_period_state() == - IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE) { - // If we are in a max deadline long idle period then start the next - // idle period immediately. - next_long_idle_period_delay = base::TimeDelta(); - } else { - // Otherwise ensure that we kick the scheduler at the right time to - // initiate the next idle period. - next_long_idle_period_delay = std::max( - base::TimeDelta(), state_.idle_period_deadline() - - helper_->scheduler_tqm_delegate()->NowTicks()); - } - if (next_long_idle_period_delay.is_zero()) { - EnableLongIdlePeriod(); - } else { - helper_->ControlTaskRunner()->PostDelayedTask( - FROM_HERE, enable_next_long_idle_period_closure_.callback(), - next_long_idle_period_delay); - } - } -} - -base::TimeTicks IdleHelper::CurrentIdleTaskDeadline() const { - helper_->CheckOnValidThread(); - return state_.idle_period_deadline(); -} - -void IdleHelper::OnIdleTaskPosted() { - TRACE_EVENT0(disabled_by_default_tracing_category_, "OnIdleTaskPosted"); - if (idle_task_runner_->RunsTasksOnCurrentThread()) { - OnIdleTaskPostedOnMainThread(); - } else { - helper_->ControlTaskRunner()->PostTask( - FROM_HERE, on_idle_task_posted_closure_.callback()); - } -} - -void IdleHelper::OnIdleTaskPostedOnMainThread() { - TRACE_EVENT0(disabled_by_default_tracing_category_, - "OnIdleTaskPostedOnMainThread"); - if (state_.idle_period_state() == - IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED) { - // Restart long idle period ticks. - helper_->ControlTaskRunner()->PostTask( - FROM_HERE, enable_next_long_idle_period_closure_.callback()); - } -} - -base::TimeTicks IdleHelper::WillProcessIdleTask() { - helper_->CheckOnValidThread(); - state_.TraceIdleIdleTaskStart(); - return CurrentIdleTaskDeadline(); -} - -void IdleHelper::DidProcessIdleTask() { - helper_->CheckOnValidThread(); - state_.TraceIdleIdleTaskEnd(); - if (IsInLongIdlePeriod(state_.idle_period_state())) { - UpdateLongIdlePeriodStateAfterIdleTask(); - } -} - -// static -bool IdleHelper::IsInIdlePeriod(IdlePeriodState state) { - return state != IdlePeriodState::NOT_IN_IDLE_PERIOD; -} - -// static -bool IdleHelper::IsInLongIdlePeriod(IdlePeriodState state) { - return state == IdlePeriodState::IN_LONG_IDLE_PERIOD || - state == IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE || - state == IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED; -} - -bool IdleHelper::CanExceedIdleDeadlineIfRequired() const { - TRACE_EVENT0(disabled_by_default_tracing_category_, - "CanExceedIdleDeadlineIfRequired"); - helper_->CheckOnValidThread(); - return state_.idle_period_state() == - IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE; -} - -IdleHelper::IdlePeriodState IdleHelper::SchedulerIdlePeriodState() const { - return state_.idle_period_state(); -} - -IdleHelper::State::State(SchedulerHelper* helper, - Delegate* delegate, - const char* tracing_category, - const char* disabled_by_default_tracing_category, - const char* idle_period_tracing_name) - : helper_(helper), - delegate_(delegate), - idle_period_state_(IdlePeriodState::NOT_IN_IDLE_PERIOD), - idle_period_trace_event_started_(false), - running_idle_task_for_tracing_(false), - tracing_category_(tracing_category), - disabled_by_default_tracing_category_( - disabled_by_default_tracing_category), - idle_period_tracing_name_(idle_period_tracing_name) { -} - -IdleHelper::State::~State() { -} - -IdleHelper::IdlePeriodState IdleHelper::State::idle_period_state() const { - helper_->CheckOnValidThread(); - return idle_period_state_; -} - -base::TimeTicks IdleHelper::State::idle_period_deadline() const { - helper_->CheckOnValidThread(); - return idle_period_deadline_; -} - -void IdleHelper::State::UpdateState(IdlePeriodState new_state, - base::TimeTicks new_deadline, - base::TimeTicks optional_now) { - IdlePeriodState old_idle_period_state = idle_period_state_; - - helper_->CheckOnValidThread(); - if (new_state == idle_period_state_) { - DCHECK_EQ(new_deadline, idle_period_deadline_); - return; - } - - bool is_tracing; - TRACE_EVENT_CATEGORY_GROUP_ENABLED(tracing_category_, &is_tracing); - if (is_tracing) { - base::TimeTicks now(optional_now.is_null() - ? helper_->scheduler_tqm_delegate()->NowTicks() - : optional_now); - TraceEventIdlePeriodStateChange( - new_state, running_idle_task_for_tracing_, idle_period_deadline_, now); - } - - idle_period_state_ = new_state; - idle_period_deadline_ = new_deadline; - - // Inform the delegate if we are starting or ending an idle period. - if (IsInIdlePeriod(new_state) && !IsInIdlePeriod(old_idle_period_state)) { - delegate_->OnIdlePeriodStarted(); - } else if (!IsInIdlePeriod(new_state) && - IsInIdlePeriod(old_idle_period_state)) { - delegate_->OnIdlePeriodEnded(); - } -} - -void IdleHelper::State::TraceIdleIdleTaskStart() { - helper_->CheckOnValidThread(); - - bool is_tracing; - TRACE_EVENT_CATEGORY_GROUP_ENABLED(tracing_category_, &is_tracing); - if (is_tracing) { - TraceEventIdlePeriodStateChange( - idle_period_state_, true, idle_period_deadline_, - base::TimeTicks::Now()); - } -} - -void IdleHelper::State::TraceIdleIdleTaskEnd() { - helper_->CheckOnValidThread(); - - bool is_tracing; - TRACE_EVENT_CATEGORY_GROUP_ENABLED(tracing_category_, &is_tracing); - if (is_tracing) { - TraceEventIdlePeriodStateChange( - idle_period_state_, false, idle_period_deadline_, - base::TimeTicks::Now()); - } -} - -void IdleHelper::State::TraceEventIdlePeriodStateChange( - IdlePeriodState new_state, - bool new_running_idle_task, - base::TimeTicks new_deadline, - base::TimeTicks now) { - TRACE_EVENT2(disabled_by_default_tracing_category_, "SetIdlePeriodState", - "old_state", - IdleHelper::IdlePeriodStateToString(idle_period_state_), - "new_state", IdleHelper::IdlePeriodStateToString(new_state)); - - if (idle_period_trace_event_started_ && running_idle_task_for_tracing_ && - !new_running_idle_task) { - running_idle_task_for_tracing_ = false; - if (!idle_period_deadline_.is_null() && now > idle_period_deadline_) { - TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0( - tracing_category_, idle_period_tracing_name_, this, - "DeadlineOverrun", - std::max(idle_period_deadline_, - last_idle_task_trace_time_).ToInternalValue()); - } - } - - if (IsInIdlePeriod(new_state)) { - if (!idle_period_trace_event_started_) { - idle_period_trace_event_started_ = true; - TRACE_EVENT_ASYNC_BEGIN1( - tracing_category_, idle_period_tracing_name_, this, - "idle_period_length_ms", (new_deadline - now).ToInternalValue()); - } - - if (new_running_idle_task) { - last_idle_task_trace_time_ = now; - running_idle_task_for_tracing_ = true; - TRACE_EVENT_ASYNC_STEP_INTO0( - tracing_category_, idle_period_tracing_name_, this, - "RunningIdleTask"); - } else if (new_state == IdlePeriodState::IN_SHORT_IDLE_PERIOD) { - TRACE_EVENT_ASYNC_STEP_INTO0( - tracing_category_, idle_period_tracing_name_, this, - "ShortIdlePeriod"); - } else if (IsInLongIdlePeriod(new_state) && - new_state != IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED) { - TRACE_EVENT_ASYNC_STEP_INTO0( - tracing_category_, idle_period_tracing_name_, this, - "LongIdlePeriod"); - } else if (new_state == IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED) { - TRACE_EVENT_ASYNC_STEP_INTO0( - tracing_category_, idle_period_tracing_name_, this, - "LongIdlePeriodPaused"); - } - } else if (idle_period_trace_event_started_) { - idle_period_trace_event_started_ = false; - TRACE_EVENT_ASYNC_END0(tracing_category_, idle_period_tracing_name_, this); - } -} - -// static -const char* IdleHelper::IdlePeriodStateToString( - IdlePeriodState idle_period_state) { - switch (idle_period_state) { - case IdlePeriodState::NOT_IN_IDLE_PERIOD: - return "not_in_idle_period"; - case IdlePeriodState::IN_SHORT_IDLE_PERIOD: - return "in_short_idle_period"; - case IdlePeriodState::IN_LONG_IDLE_PERIOD: - return "in_long_idle_period"; - case IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE: - return "in_long_idle_period_with_max_deadline"; - case IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED: - return "in_long_idle_period_paused"; - default: - NOTREACHED(); - return nullptr; - } -} - -} // namespace scheduler
diff --git a/components/scheduler/child/idle_helper.h b/components/scheduler/child/idle_helper.h deleted file mode 100644 index 333c867..0000000 --- a/components/scheduler/child/idle_helper.h +++ /dev/null
@@ -1,221 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_CHILD_IDLE_HELPER_H_ -#define COMPONENTS_SCHEDULER_CHILD_IDLE_HELPER_H_ - -#include "base/macros.h" -#include "base/message_loop/message_loop.h" -#include "components/scheduler/base/cancelable_closure_holder.h" -#include "components/scheduler/base/task_queue_selector.h" -#include "components/scheduler/child/scheduler_helper.h" -#include "components/scheduler/child/single_thread_idle_task_runner.h" -#include "components/scheduler/scheduler_export.h" - -namespace scheduler { - -class SchedulerHelper; - -// Common scheduler functionality for Idle tasks. -class SCHEDULER_EXPORT IdleHelper - : public base::MessageLoop::TaskObserver, - public SingleThreadIdleTaskRunner::Delegate { - public: - // Used to by scheduler implementations to customize idle behaviour. - class SCHEDULER_EXPORT Delegate { - public: - Delegate(); - virtual ~Delegate(); - - // If it's ok to enter a long idle period, return true. Otherwise return - // false and set next_long_idle_period_delay_out so we know when to try - // again. - virtual bool CanEnterLongIdlePeriod( - base::TimeTicks now, - base::TimeDelta* next_long_idle_period_delay_out) = 0; - - // Signals that the Long Idle Period hasn't started yet because the system - // isn't quiescent. - virtual void IsNotQuiescent() = 0; - - // Signals that we have started an Idle Period. - virtual void OnIdlePeriodStarted() = 0; - - // Signals that we have finished an Idle Period. - virtual void OnIdlePeriodEnded() = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(Delegate); - }; - - // Keep IdleHelper::IdlePeriodStateToString in sync with this enum. - enum class IdlePeriodState { - NOT_IN_IDLE_PERIOD, - IN_SHORT_IDLE_PERIOD, - IN_LONG_IDLE_PERIOD, - IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE, - IN_LONG_IDLE_PERIOD_PAUSED, - // Must be the last entry. - IDLE_PERIOD_STATE_COUNT, - FIRST_IDLE_PERIOD_STATE = NOT_IN_IDLE_PERIOD, - }; - - // The maximum length of an idle period. - static const int kMaximumIdlePeriodMillis = 50; - - // |helper| and |delegate| are not owned by IdleHelper object and must - // outlive it. - IdleHelper( - SchedulerHelper* helper, - Delegate* delegate, - const char* tracing_category, - const char* disabled_by_default_tracing_category, - const char* idle_period_tracing_name, - base::TimeDelta required_quiescence_duration_before_long_idle_period); - ~IdleHelper() override; - - // Returns the idle task runner. Tasks posted to this runner may be reordered - // relative to other task types and may be starved for an arbitrarily long - // time if no idle time is available. - scoped_refptr<SingleThreadIdleTaskRunner> IdleTaskRunner(); - - // If |required_quiescence_duration_before_long_idle_period_| is zero then - // immediately initiate a long idle period, otherwise check if any tasks have - // run recently and if so, check again after a delay of - // |required_quiescence_duration_before_long_idle_period_|. - // Calling this function will end any previous idle period immediately, and - // potentially again later if - // |required_quiescence_duration_before_long_idle_period_| is non-zero. - // NOTE EndIdlePeriod will disable the long idle periods. - void EnableLongIdlePeriod(); - - // Start an idle period with a given idle period deadline. - void StartIdlePeriod(IdlePeriodState new_idle_period_state, - base::TimeTicks now, - base::TimeTicks idle_period_deadline); - - // This will end an idle period either started with StartIdlePeriod or - // EnableLongIdlePeriod. - void EndIdlePeriod(); - - // Returns true if a currently running idle task could exceed its deadline - // without impacting user experience too much. This should only be used if - // there is a task which cannot be pre-empted and is likely to take longer - // than the largest expected idle task deadline. It should NOT be polled to - // check whether more work can be performed on the current idle task after - // its deadline has expired - post a new idle task for the continuation of the - // work in this case. - // Must be called from the thread this class was created on. - bool CanExceedIdleDeadlineIfRequired() const; - - // Returns the deadline for the current idle task. - base::TimeTicks CurrentIdleTaskDeadline() const; - - // SingleThreadIdleTaskRunner::Delegate implementation: - void OnIdleTaskPosted() override; - base::TimeTicks WillProcessIdleTask() override; - void DidProcessIdleTask() override; - - // base::MessageLoop::TaskObserver implementation: - void WillProcessTask(const base::PendingTask& pending_task) override; - void DidProcessTask(const base::PendingTask& pending_task) override; - - IdlePeriodState SchedulerIdlePeriodState() const; - static const char* IdlePeriodStateToString(IdlePeriodState state); - - private: - friend class BaseIdleHelperTest; - friend class IdleHelperTest; - - class State { - public: - State(SchedulerHelper* helper, - Delegate* delegate, - const char* tracing_category, - const char* disabled_by_default_tracing_category, - const char* idle_period_tracing_name); - virtual ~State(); - - void UpdateState(IdlePeriodState new_state, - base::TimeTicks new_deadline, - base::TimeTicks optional_now); - bool IsIdlePeriodPaused() const; - - IdlePeriodState idle_period_state() const; - base::TimeTicks idle_period_deadline() const; - - void TraceIdleIdleTaskStart(); - void TraceIdleIdleTaskEnd(); - - private: - void TraceEventIdlePeriodStateChange(IdlePeriodState new_state, - bool new_running_idle_task, - base::TimeTicks new_deadline, - base::TimeTicks optional_now); - - SchedulerHelper* helper_; // NOT OWNED - Delegate* delegate_; // NOT OWNED - - IdlePeriodState idle_period_state_; - base::TimeTicks idle_period_deadline_; - - base::TimeTicks last_idle_task_trace_time_; - bool idle_period_trace_event_started_; - bool running_idle_task_for_tracing_; - const char* tracing_category_; - const char* disabled_by_default_tracing_category_; - const char* idle_period_tracing_name_; - - DISALLOW_COPY_AND_ASSIGN(State); - }; - - // The minimum duration of an idle period. - static const int kMinimumIdlePeriodDurationMillis = 1; - - // The minimum delay to wait between retrying to initiate a long idle time. - static const int kRetryEnableLongIdlePeriodDelayMillis = 1; - - // Returns the new idle period state for the next long idle period. Fills in - // |next_long_idle_period_delay_out| with the next time we should try to - // initiate the next idle period. - IdlePeriodState ComputeNewLongIdlePeriodState( - const base::TimeTicks now, - base::TimeDelta* next_long_idle_period_delay_out); - - bool ShouldWaitForQuiescence(); - void OnIdleTaskPostedOnMainThread(); - void UpdateLongIdlePeriodStateAfterIdleTask(); - - void SetIdlePeriodState(IdlePeriodState new_state, - base::TimeTicks new_deadline, - base::TimeTicks optional_now); - - // Returns true if |state| represents being within an idle period state. - static bool IsInIdlePeriod(IdlePeriodState state); - // Returns true if |state| represents being within a long idle period state. - static bool IsInLongIdlePeriod(IdlePeriodState state); - - SchedulerHelper* helper_; // NOT OWNED - Delegate* delegate_; // NOT OWNED - scoped_refptr<TaskQueue> idle_queue_; - scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_; - - CancelableClosureHolder enable_next_long_idle_period_closure_; - CancelableClosureHolder on_idle_task_posted_closure_; - - State state_; - - base::TimeDelta required_quiescence_duration_before_long_idle_period_; - - const char* disabled_by_default_tracing_category_; - - base::WeakPtr<IdleHelper> weak_idle_helper_ptr_; - base::WeakPtrFactory<IdleHelper> weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(IdleHelper); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_CHILD_IDLE_HELPER_H_
diff --git a/components/scheduler/child/idle_helper_unittest.cc b/components/scheduler/child/idle_helper_unittest.cc deleted file mode 100644 index 2290004..0000000 --- a/components/scheduler/child/idle_helper_unittest.cc +++ /dev/null
@@ -1,1160 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/child/idle_helper.h" - -#include <utility> - -#include "base/callback.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/run_loop.h" -#include "base/test/simple_test_tick_clock.h" -#include "cc/test/ordered_simple_task_runner.h" -#include "components/scheduler/base/real_time_domain.h" -#include "components/scheduler/base/task_queue.h" -#include "components/scheduler/base/task_queue_manager.h" -#include "components/scheduler/base/test_time_source.h" -#include "components/scheduler/child/scheduler_helper.h" -#include "components/scheduler/child/scheduler_tqm_delegate_for_test.h" -#include "components/scheduler/child/scheduler_tqm_delegate_impl.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using testing::_; -using testing::AnyNumber; -using testing::AtLeast; -using testing::Exactly; -using testing::Invoke; -using testing::Return; - -namespace scheduler { - -namespace { -void AppendToVectorTestTask(std::vector<std::string>* vector, - std::string value) { - vector->push_back(value); -} - -void AppendToVectorIdleTestTask(std::vector<std::string>* vector, - std::string value, - base::TimeTicks deadline) { - AppendToVectorTestTask(vector, value); -} - -void NullTask() { -} - -void NullIdleTask(base::TimeTicks deadline) { -} - -void AppendToVectorReentrantTask(base::SingleThreadTaskRunner* task_runner, - std::vector<int>* vector, - int* reentrant_count, - int max_reentrant_count) { - vector->push_back((*reentrant_count)++); - if (*reentrant_count < max_reentrant_count) { - task_runner->PostTask( - FROM_HERE, - base::Bind(AppendToVectorReentrantTask, base::Unretained(task_runner), - vector, reentrant_count, max_reentrant_count)); - } -} - -void IdleTestTask(int* run_count, - base::TimeTicks* deadline_out, - base::TimeTicks deadline) { - (*run_count)++; - *deadline_out = deadline; -} - -int max_idle_task_reposts = 2; - -void RepostingIdleTestTask(SingleThreadIdleTaskRunner* idle_task_runner, - int* run_count, - base::TimeTicks* deadline_out, - base::TimeTicks deadline) { - if ((*run_count + 1) < max_idle_task_reposts) { - idle_task_runner->PostIdleTask( - FROM_HERE, - base::Bind(&RepostingIdleTestTask, base::Unretained(idle_task_runner), - run_count, deadline_out)); - } - *deadline_out = deadline; - (*run_count)++; -} - -void RepostingUpdateClockIdleTestTask( - SingleThreadIdleTaskRunner* idle_task_runner, - int* run_count, - base::SimpleTestTickClock* clock, - base::TimeDelta advance_time, - std::vector<base::TimeTicks>* deadlines, - base::TimeTicks deadline) { - if ((*run_count + 1) < max_idle_task_reposts) { - idle_task_runner->PostIdleTask( - FROM_HERE, base::Bind(&RepostingUpdateClockIdleTestTask, - base::Unretained(idle_task_runner), run_count, - clock, advance_time, deadlines)); - } - deadlines->push_back(deadline); - (*run_count)++; - clock->Advance(advance_time); -} - -void RepeatingTask(base::SingleThreadTaskRunner* task_runner, - int num_repeats, - base::TimeDelta delay) { - if (num_repeats > 1) { - task_runner->PostDelayedTask( - FROM_HERE, base::Bind(&RepeatingTask, base::Unretained(task_runner), - num_repeats - 1, delay), - delay); - } -} - -void UpdateClockIdleTestTask(base::SimpleTestTickClock* clock, - int* run_count, - base::TimeTicks set_time, - base::TimeTicks deadline) { - clock->Advance(set_time - clock->NowTicks()); - (*run_count)++; -} - -void UpdateClockToDeadlineIdleTestTask(base::SimpleTestTickClock* clock, - int* run_count, - base::TimeTicks deadline) { - UpdateClockIdleTestTask(clock, run_count, deadline, deadline); -} - -void EndIdlePeriodIdleTask(IdleHelper* idle_helper, base::TimeTicks deadline) { - idle_helper->EndIdlePeriod(); -} - -scoped_refptr<SchedulerTqmDelegate> CreateTaskRunnerDelegate( - base::MessageLoop* message_loop, - scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner, - std::unique_ptr<TestTimeSource> test_time_source) { - if (message_loop) - return SchedulerTqmDelegateImpl::Create(message_loop, - std::move(test_time_source)); - - return SchedulerTqmDelegateForTest::Create(mock_task_runner, - std::move(test_time_source)); -} - -}; // namespace - -class IdleHelperForTest : public IdleHelper, public IdleHelper::Delegate { - public: - explicit IdleHelperForTest( - SchedulerHelper* scheduler_helper, - base::TimeDelta required_quiescence_duration_before_long_idle_period) - : IdleHelper(scheduler_helper, - this, - "test.idle", - TRACE_DISABLED_BY_DEFAULT("test.idle"), - "TestSchedulerIdlePeriod", - required_quiescence_duration_before_long_idle_period) {} - - ~IdleHelperForTest() override {} - - // SchedulerHelperDelegate implementation: - MOCK_METHOD2(CanEnterLongIdlePeriod, - bool(base::TimeTicks now, - base::TimeDelta* next_long_idle_period_delay_out)); - - MOCK_METHOD0(IsNotQuiescent, void()); - MOCK_METHOD0(OnIdlePeriodStarted, void()); - MOCK_METHOD0(OnIdlePeriodEnded, void()); -}; - -class BaseIdleHelperTest : public testing::Test { - public: - BaseIdleHelperTest( - base::MessageLoop* message_loop, - base::TimeDelta required_quiescence_duration_before_long_idle_period) - : clock_(new base::SimpleTestTickClock()), - mock_task_runner_( - message_loop - ? nullptr - : new cc::OrderedSimpleTaskRunner(clock_.get(), false)), - message_loop_(message_loop), - main_task_runner_(CreateTaskRunnerDelegate( - message_loop, - mock_task_runner_, - base::WrapUnique(new TestTimeSource(clock_.get())))), - scheduler_helper_( - new SchedulerHelper(main_task_runner_, - "test.idle", - TRACE_DISABLED_BY_DEFAULT("test.idle"), - TRACE_DISABLED_BY_DEFAULT("test.idle.debug"))), - idle_helper_(new IdleHelperForTest( - scheduler_helper_.get(), - required_quiescence_duration_before_long_idle_period)), - default_task_runner_(scheduler_helper_->DefaultTaskRunner()), - idle_task_runner_(idle_helper_->IdleTaskRunner()) { - clock_->Advance(base::TimeDelta::FromMicroseconds(5000)); - } - - ~BaseIdleHelperTest() override {} - - void SetUp() override { - EXPECT_CALL(*idle_helper_, OnIdlePeriodStarted()).Times(AnyNumber()); - EXPECT_CALL(*idle_helper_, OnIdlePeriodEnded()).Times(AnyNumber()); - EXPECT_CALL(*idle_helper_, CanEnterLongIdlePeriod(_, _)) - .Times(AnyNumber()) - .WillRepeatedly(Return(true)); - } - - void TearDown() override { - DCHECK(!mock_task_runner_.get() || !message_loop_.get()); - if (mock_task_runner_.get()) { - // Check that all tests stop posting tasks. - mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true); - while (mock_task_runner_->RunUntilIdle()) { - } - } else { - base::RunLoop().RunUntilIdle(); - } - } - - void RunUntilIdle() { - // Only one of mock_task_runner_ or message_loop_ should be set. - DCHECK(!mock_task_runner_.get() || !message_loop_.get()); - if (mock_task_runner_.get()) - mock_task_runner_->RunUntilIdle(); - else - base::RunLoop().RunUntilIdle(); - } - - template <typename E> - static void CallForEachEnumValue(E first, - E last, - const char* (*function)(E)) { - for (E val = first; val < last; - val = static_cast<E>(static_cast<int>(val) + 1)) { - (*function)(val); - } - } - - static void CheckAllTaskQueueIdToString() { - CallForEachEnumValue<IdleHelper::IdlePeriodState>( - IdleHelper::IdlePeriodState::FIRST_IDLE_PERIOD_STATE, - IdleHelper::IdlePeriodState::IDLE_PERIOD_STATE_COUNT, - &IdleHelper::IdlePeriodStateToString); - } - - bool IsInIdlePeriod() const { - return idle_helper_->IsInIdlePeriod( - idle_helper_->SchedulerIdlePeriodState()); - } - - protected: - static base::TimeDelta maximum_idle_period_duration() { - return base::TimeDelta::FromMilliseconds( - IdleHelper::kMaximumIdlePeriodMillis); - } - - static base::TimeDelta retry_enable_long_idle_period_delay() { - return base::TimeDelta::FromMilliseconds( - IdleHelper::kRetryEnableLongIdlePeriodDelayMillis); - } - - static base::TimeDelta minimum_idle_period_duration() { - return base::TimeDelta::FromMilliseconds( - IdleHelper::kMinimumIdlePeriodDurationMillis); - } - - base::TimeTicks CurrentIdleTaskDeadline() { - return idle_helper_->CurrentIdleTaskDeadline(); - } - - void CheckIdlePeriodStateIs(const char* expected) { - EXPECT_STREQ(expected, IdleHelper::IdlePeriodStateToString( - idle_helper_->SchedulerIdlePeriodState())); - } - - std::unique_ptr<base::SimpleTestTickClock> clock_; - // Only one of mock_task_runner_ or message_loop_ will be set. - scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_; - std::unique_ptr<base::MessageLoop> message_loop_; - - scoped_refptr<SchedulerTqmDelegate> main_task_runner_; - std::unique_ptr<SchedulerHelper> scheduler_helper_; - std::unique_ptr<IdleHelperForTest> idle_helper_; - scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_; - scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_; - - DISALLOW_COPY_AND_ASSIGN(BaseIdleHelperTest); -}; - -class IdleHelperTest : public BaseIdleHelperTest { - public: - IdleHelperTest() : BaseIdleHelperTest(nullptr, base::TimeDelta()) {} - - ~IdleHelperTest() override {} - - TaskQueueManager* task_queue_manager() const { - return scheduler_helper_->GetTaskQueueManagerForTesting(); - } - - private: - DISALLOW_COPY_AND_ASSIGN(IdleHelperTest); -}; - -TEST_F(IdleHelperTest, TestPostIdleTask) { - int run_count = 0; - base::TimeTicks expected_deadline = - clock_->NowTicks() + base::TimeDelta::FromMilliseconds(2300); - base::TimeTicks deadline_in_task; - - clock_->Advance(base::TimeDelta::FromMilliseconds(100)); - idle_task_runner_->PostIdleTask( - FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); - - RunUntilIdle(); - EXPECT_EQ(0, run_count); - - idle_helper_->StartIdlePeriod( - IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), - expected_deadline); - RunUntilIdle(); - EXPECT_EQ(1, run_count); - EXPECT_EQ(expected_deadline, deadline_in_task); -} - -TEST_F(IdleHelperTest, TestPostIdleTask_EndIdlePeriod) { - int run_count = 0; - base::TimeTicks deadline_in_task; - - clock_->Advance(base::TimeDelta::FromMilliseconds(100)); - idle_task_runner_->PostIdleTask( - FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); - - RunUntilIdle(); - EXPECT_EQ(0, run_count); - - idle_helper_->StartIdlePeriod( - IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), - clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); - idle_helper_->EndIdlePeriod(); - RunUntilIdle(); - EXPECT_EQ(0, run_count); -} - -TEST_F(IdleHelperTest, TestRepostingIdleTask) { - base::TimeTicks actual_deadline; - int run_count = 0; - - max_idle_task_reposts = 2; - idle_task_runner_->PostIdleTask( - FROM_HERE, - base::Bind(&RepostingIdleTestTask, base::RetainedRef(idle_task_runner_), - &run_count, &actual_deadline)); - idle_helper_->StartIdlePeriod( - IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), - clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); - RunUntilIdle(); - EXPECT_EQ(1, run_count); - - // Reposted tasks shouldn't run until next idle period. - RunUntilIdle(); - EXPECT_EQ(1, run_count); - - idle_helper_->StartIdlePeriod( - IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), - clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); - RunUntilIdle(); - EXPECT_EQ(2, run_count); -} - -TEST_F(IdleHelperTest, TestIdleTaskExceedsDeadline) { - int run_count = 0; - - // Post two UpdateClockToDeadlineIdleTestTask tasks. - idle_task_runner_->PostIdleTask( - FROM_HERE, - base::Bind(&UpdateClockToDeadlineIdleTestTask, clock_.get(), &run_count)); - idle_task_runner_->PostIdleTask( - FROM_HERE, - base::Bind(&UpdateClockToDeadlineIdleTestTask, clock_.get(), &run_count)); - - idle_helper_->StartIdlePeriod( - IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), - clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); - RunUntilIdle(); - // Only the first idle task should execute since it's used up the deadline. - EXPECT_EQ(1, run_count); - - idle_helper_->EndIdlePeriod(); - idle_helper_->StartIdlePeriod( - IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), - clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); - RunUntilIdle(); - // Second task should be run on the next idle period. - EXPECT_EQ(2, run_count); -} - -TEST_F(IdleHelperTest, TestPostIdleTaskAfterWakeup) { - base::TimeTicks deadline_in_task; - int run_count = 0; - - idle_task_runner_->PostIdleTaskAfterWakeup( - FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); - - idle_helper_->StartIdlePeriod( - IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), - clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); - RunUntilIdle(); - // Shouldn't run yet as no other task woke up the scheduler. - EXPECT_EQ(0, run_count); - - // Must start a new idle period before idle task runs. - idle_task_runner_->PostIdleTaskAfterWakeup( - FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); - - idle_helper_->StartIdlePeriod( - IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), - clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); - RunUntilIdle(); - // Another after wakeup idle task shouldn't wake the scheduler. - EXPECT_EQ(0, run_count); - - default_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask)); - - RunUntilIdle(); - idle_helper_->StartIdlePeriod( - IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), - clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); - RunUntilIdle(); - // Execution of default task queue task should trigger execution of idle task. - EXPECT_EQ(2, run_count); -} - -TEST_F(IdleHelperTest, TestPostIdleTaskAfterWakeupWhileAwake) { - base::TimeTicks deadline_in_task; - int run_count = 0; - - idle_task_runner_->PostIdleTaskAfterWakeup( - FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); - default_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask)); - - RunUntilIdle(); - // Must start a new idle period before idle task runs. - idle_helper_->StartIdlePeriod( - IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), - clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); - RunUntilIdle(); - // Should run as the scheduler was already awakened by the normal task. - EXPECT_EQ(1, run_count); -} - -TEST_F(IdleHelperTest, TestPostIdleTaskWakesAfterWakeupIdleTask) { - base::TimeTicks deadline_in_task; - int run_count = 0; - - idle_task_runner_->PostIdleTaskAfterWakeup( - FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); - idle_task_runner_->PostIdleTask( - FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); - - idle_helper_->StartIdlePeriod( - IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), - clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); - RunUntilIdle(); - // Must start a new idle period before after-wakeup idle task runs. - idle_helper_->StartIdlePeriod( - IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), - clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); - RunUntilIdle(); - // Normal idle task should wake up after-wakeup idle task. - EXPECT_EQ(2, run_count); -} - -class IdleHelperTestWithIdlePeriodObserver : public BaseIdleHelperTest { - public: - IdleHelperTestWithIdlePeriodObserver() - : BaseIdleHelperTest(nullptr, base::TimeDelta()) {} - - ~IdleHelperTestWithIdlePeriodObserver() override {} - - void SetUp() override { - // Don't set expectations on IdleHelper::Delegate. - } - - TaskQueueManager* task_queue_manager() const { - return scheduler_helper_->GetTaskQueueManagerForTesting(); - } - - void ExpectIdlePeriodStartsButNeverEnds() { - EXPECT_CALL(*idle_helper_, OnIdlePeriodStarted()).Times(1); - EXPECT_CALL(*idle_helper_, OnIdlePeriodEnded()).Times(0); - } - - void ExpectIdlePeriodStartsAndEnds(const testing::Cardinality& cardinality) { - EXPECT_CALL(*idle_helper_, OnIdlePeriodStarted()).Times(cardinality); - EXPECT_CALL(*idle_helper_, OnIdlePeriodEnded()).Times(cardinality); - } - - private: - DISALLOW_COPY_AND_ASSIGN(IdleHelperTestWithIdlePeriodObserver); -}; - -TEST_F(IdleHelperTestWithIdlePeriodObserver, TestEnterButNotExitIdlePeriod) { - ExpectIdlePeriodStartsButNeverEnds(); - - idle_helper_->StartIdlePeriod( - IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), - clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); -} - -TEST_F(IdleHelperTestWithIdlePeriodObserver, TestEnterAndExitIdlePeriod) { - BaseIdleHelperTest* fixture = this; - ON_CALL(*idle_helper_, OnIdlePeriodStarted()) - .WillByDefault( - Invoke([fixture]() { EXPECT_TRUE(fixture->IsInIdlePeriod()); })); - ON_CALL(*idle_helper_, OnIdlePeriodEnded()) - .WillByDefault( - Invoke([fixture]() { EXPECT_FALSE(fixture->IsInIdlePeriod()); })); - - ExpectIdlePeriodStartsAndEnds(Exactly(1)); - - idle_helper_->StartIdlePeriod( - IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), - clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); - idle_helper_->EndIdlePeriod(); -} - -class IdleHelperWithMessageLoopTest : public BaseIdleHelperTest { - public: - IdleHelperWithMessageLoopTest() - : BaseIdleHelperTest(new base::MessageLoop(), base::TimeDelta()) {} - ~IdleHelperWithMessageLoopTest() override {} - - void PostFromNestedRunloop(std::vector< - std::pair<SingleThreadIdleTaskRunner::IdleTask, bool>>* tasks) { - base::MessageLoop::ScopedNestableTaskAllower allow(message_loop_.get()); - for (std::pair<SingleThreadIdleTaskRunner::IdleTask, bool>& pair : *tasks) { - if (pair.second) { - idle_task_runner_->PostIdleTask(FROM_HERE, pair.first); - } else { - idle_task_runner_->PostNonNestableIdleTask(FROM_HERE, pair.first); - } - } - idle_helper_->StartIdlePeriod( - IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), - clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); - base::RunLoop().RunUntilIdle(); - } - - void SetUp() override { - EXPECT_CALL(*idle_helper_, OnIdlePeriodStarted()).Times(AnyNumber()); - EXPECT_CALL(*idle_helper_, OnIdlePeriodEnded()).Times(AnyNumber()); - } - - private: - DISALLOW_COPY_AND_ASSIGN(IdleHelperWithMessageLoopTest); -}; - -TEST_F(IdleHelperWithMessageLoopTest, - NonNestableIdleTaskDoesntExecuteInNestedLoop) { - std::vector<std::string> order; - idle_task_runner_->PostIdleTask( - FROM_HERE, - base::Bind(&AppendToVectorIdleTestTask, &order, std::string("1"))); - idle_task_runner_->PostIdleTask( - FROM_HERE, - base::Bind(&AppendToVectorIdleTestTask, &order, std::string("2"))); - - std::vector<std::pair<SingleThreadIdleTaskRunner::IdleTask, bool>> - tasks_to_post_from_nested_loop; - tasks_to_post_from_nested_loop.push_back(std::make_pair( - base::Bind(&AppendToVectorIdleTestTask, &order, std::string("3")), - false)); - tasks_to_post_from_nested_loop.push_back(std::make_pair( - base::Bind(&AppendToVectorIdleTestTask, &order, std::string("4")), true)); - tasks_to_post_from_nested_loop.push_back(std::make_pair( - base::Bind(&AppendToVectorIdleTestTask, &order, std::string("5")), true)); - - default_task_runner_->PostTask( - FROM_HERE, - base::Bind(&IdleHelperWithMessageLoopTest::PostFromNestedRunloop, - base::Unretained(this), - base::Unretained(&tasks_to_post_from_nested_loop))); - - idle_helper_->StartIdlePeriod( - IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), - clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); - RunUntilIdle(); - // Note we expect task 3 to run last because it's non-nestable. - EXPECT_THAT(order, testing::ElementsAre(std::string("1"), std::string("2"), - std::string("4"), std::string("5"), - std::string("3"))); -} - -TEST_F(IdleHelperTestWithIdlePeriodObserver, TestLongIdlePeriod) { - base::TimeTicks expected_deadline = - clock_->NowTicks() + maximum_idle_period_duration(); - base::TimeTicks deadline_in_task; - int run_count = 0; - - idle_task_runner_->PostIdleTask( - FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); - - EXPECT_CALL(*idle_helper_, CanEnterLongIdlePeriod(_, _)) - .Times(1) - .WillRepeatedly(Return(true)); - ExpectIdlePeriodStartsButNeverEnds(); - - RunUntilIdle(); - EXPECT_EQ(0, run_count); // Shouldn't run yet as no idle period. - - idle_helper_->EnableLongIdlePeriod(); - RunUntilIdle(); - EXPECT_EQ(1, run_count); // Should have run in a long idle time. - EXPECT_EQ(expected_deadline, deadline_in_task); -} - -TEST_F(IdleHelperTest, TestLongIdlePeriodWithPendingDelayedTask) { - base::TimeDelta pending_task_delay = base::TimeDelta::FromMilliseconds(30); - base::TimeTicks expected_deadline = clock_->NowTicks() + pending_task_delay; - base::TimeTicks deadline_in_task; - int run_count = 0; - - idle_task_runner_->PostIdleTask( - FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); - default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask), - pending_task_delay); - - idle_helper_->EnableLongIdlePeriod(); - RunUntilIdle(); - EXPECT_EQ(1, run_count); // Should have run in a long idle time. - EXPECT_EQ(expected_deadline, deadline_in_task); -} - -TEST_F(IdleHelperTest, TestLongIdlePeriodWithLatePendingDelayedTask) { - base::TimeDelta pending_task_delay = base::TimeDelta::FromMilliseconds(10); - base::TimeTicks deadline_in_task; - int run_count = 0; - - default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask), - pending_task_delay); - - // Advance clock until after delayed task was meant to be run. - clock_->Advance(base::TimeDelta::FromMilliseconds(20)); - - // Post an idle task and then EnableLongIdlePeriod. Since there is a late - // pending delayed task this shouldn't actually start an idle period. - idle_task_runner_->PostIdleTask( - FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); - idle_helper_->EnableLongIdlePeriod(); - RunUntilIdle(); - EXPECT_EQ(0, run_count); - - // After the delayed task has been run we should trigger an idle period. - clock_->Advance(maximum_idle_period_duration()); - RunUntilIdle(); - EXPECT_EQ(1, run_count); -} - -TEST_F(IdleHelperTestWithIdlePeriodObserver, TestLongIdlePeriodRepeating) { - mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true); - std::vector<base::TimeTicks> actual_deadlines; - int run_count = 0; - - EXPECT_CALL(*idle_helper_, CanEnterLongIdlePeriod(_, _)) - .Times(4) - .WillRepeatedly(Return(true)); - ExpectIdlePeriodStartsAndEnds(AtLeast(2)); - - max_idle_task_reposts = 3; - base::TimeTicks clock_before(clock_->NowTicks()); - base::TimeDelta idle_task_runtime(base::TimeDelta::FromMilliseconds(10)); - idle_task_runner_->PostIdleTask( - FROM_HERE, - base::Bind(&RepostingUpdateClockIdleTestTask, - base::RetainedRef(idle_task_runner_), &run_count, clock_.get(), - idle_task_runtime, &actual_deadlines)); - - // Check each idle task runs in their own idle period. - idle_helper_->EnableLongIdlePeriod(); - RunUntilIdle(); - EXPECT_EQ(3, run_count); - EXPECT_THAT( - actual_deadlines, - testing::ElementsAre( - clock_before + maximum_idle_period_duration(), - clock_before + idle_task_runtime + maximum_idle_period_duration(), - clock_before + (2 * idle_task_runtime) + - maximum_idle_period_duration())); - - max_idle_task_reposts = 5; - idle_task_runner_->PostIdleTask( - FROM_HERE, - base::Bind(&RepostingUpdateClockIdleTestTask, - base::RetainedRef(idle_task_runner_), &run_count, clock_.get(), - idle_task_runtime, &actual_deadlines)); - idle_task_runner_->PostIdleTask( - FROM_HERE, - base::Bind(&EndIdlePeriodIdleTask, base::Unretained(idle_helper_.get()))); - - // Ensure that reposting tasks stop after EndIdlePeriod is called. - RunUntilIdle(); - EXPECT_EQ(4, run_count); -} - -TEST_F(IdleHelperTest, TestLongIdlePeriodDoesNotWakeScheduler) { - base::TimeTicks deadline_in_task; - int run_count = 0; - - // Start a long idle period and get the time it should end. - idle_helper_->EnableLongIdlePeriod(); - // The scheduler should not run the enable_next_long_idle_period task if - // there are no idle tasks and no other task woke up the scheduler, thus - // the idle period deadline shouldn't update at the end of the current long - // idle period. - base::TimeTicks idle_period_deadline = CurrentIdleTaskDeadline(); - clock_->Advance(maximum_idle_period_duration()); - RunUntilIdle(); - - base::TimeTicks new_idle_period_deadline = CurrentIdleTaskDeadline(); - EXPECT_EQ(idle_period_deadline, new_idle_period_deadline); - - // Posting a after-wakeup idle task also shouldn't wake the scheduler or - // initiate the next long idle period. - idle_task_runner_->PostIdleTaskAfterWakeup( - FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); - RunUntilIdle(); - new_idle_period_deadline = CurrentIdleTaskDeadline(); - EXPECT_EQ(idle_period_deadline, new_idle_period_deadline); - EXPECT_EQ(0, run_count); - - // Running a normal task should initiate a new long idle period though. - default_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask)); - RunUntilIdle(); - new_idle_period_deadline = CurrentIdleTaskDeadline(); - EXPECT_EQ(idle_period_deadline + maximum_idle_period_duration(), - new_idle_period_deadline); - - EXPECT_EQ(1, run_count); -} - -TEST_F(IdleHelperTestWithIdlePeriodObserver, - TestLongIdlePeriodWhenNotCanEnterLongIdlePeriod) { - base::TimeDelta delay = base::TimeDelta::FromMilliseconds(1000); - base::TimeDelta halfDelay = base::TimeDelta::FromMilliseconds(500); - base::TimeTicks delayOver = clock_->NowTicks() + delay; - base::TimeTicks deadline_in_task; - int run_count = 0; - - ON_CALL(*idle_helper_, CanEnterLongIdlePeriod(_, _)) - .WillByDefault(Invoke( - [delay, delayOver](base::TimeTicks now, - base::TimeDelta* next_long_idle_period_delay_out) { - if (now >= delayOver) - return true; - *next_long_idle_period_delay_out = delay; - return false; - })); - - EXPECT_CALL(*idle_helper_, CanEnterLongIdlePeriod(_, _)).Times(2); - EXPECT_CALL(*idle_helper_, OnIdlePeriodStarted()).Times(AnyNumber()); - - idle_task_runner_->PostIdleTask( - FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); - - // Make sure Idle tasks don't run until the delay has occurred. - idle_helper_->EnableLongIdlePeriod(); - RunUntilIdle(); - EXPECT_EQ(0, run_count); - - clock_->Advance(halfDelay); - RunUntilIdle(); - EXPECT_EQ(0, run_count); - - // Delay is finished, idle task should run. - clock_->Advance(halfDelay); - RunUntilIdle(); - EXPECT_EQ(1, run_count); -} - -TEST_F(IdleHelperTest, TestLongIdlePeriodImmediatelyRestartsIfMaxDeadline) { - std::vector<base::TimeTicks> actual_deadlines; - int run_count = 0; - - base::TimeTicks clock_before(clock_->NowTicks()); - base::TimeDelta idle_task_runtime(base::TimeDelta::FromMilliseconds(10)); - - // The second idle period should happen immediately after the first the - // they have max deadlines. - max_idle_task_reposts = 2; - idle_task_runner_->PostIdleTask( - FROM_HERE, - base::Bind(&RepostingUpdateClockIdleTestTask, - base::RetainedRef(idle_task_runner_), &run_count, clock_.get(), - idle_task_runtime, &actual_deadlines)); - - idle_helper_->EnableLongIdlePeriod(); - RunUntilIdle(); - EXPECT_EQ(2, run_count); - EXPECT_THAT( - actual_deadlines, - testing::ElementsAre( - clock_before + maximum_idle_period_duration(), - clock_before + idle_task_runtime + maximum_idle_period_duration())); -} - -TEST_F(IdleHelperTest, TestLongIdlePeriodRestartWaitsIfNotMaxDeadline) { - base::TimeTicks actual_deadline; - int run_count = 0; - - base::TimeDelta pending_task_delay(base::TimeDelta::FromMilliseconds(20)); - base::TimeDelta idle_task_duration(base::TimeDelta::FromMilliseconds(10)); - base::TimeTicks expected_deadline(clock_->NowTicks() + pending_task_delay + - maximum_idle_period_duration() + - retry_enable_long_idle_period_delay()); - - // Post delayed task to ensure idle period doesn't have a max deadline. - default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask), - pending_task_delay); - - max_idle_task_reposts = 2; - idle_task_runner_->PostIdleTask( - FROM_HERE, - base::Bind(&RepostingIdleTestTask, base::RetainedRef(idle_task_runner_), - &run_count, &actual_deadline)); - idle_helper_->EnableLongIdlePeriod(); - RunUntilIdle(); - EXPECT_EQ(1, run_count); - clock_->Advance(idle_task_duration); - - // Next idle period shouldn't happen until the pending task has been run. - RunUntilIdle(); - EXPECT_EQ(1, run_count); - - // Once the pending task is run the new idle period should start. - clock_->Advance(pending_task_delay - idle_task_duration); - - // Since the idle period tried to start before the pending task ran we have to - // wait for the idle helper to retry starting the long idle period. - clock_->Advance(retry_enable_long_idle_period_delay()); - RunUntilIdle(); - - EXPECT_EQ(2, run_count); - EXPECT_EQ(expected_deadline, actual_deadline); -} - -TEST_F(IdleHelperTest, TestLongIdlePeriodPaused) { - mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true); - std::vector<base::TimeTicks> actual_deadlines; - int run_count = 0; - - // If there are no idle tasks posted we should start in the paused state. - idle_helper_->EnableLongIdlePeriod(); - CheckIdlePeriodStateIs("in_long_idle_period_paused"); - // There shouldn't be any delayed tasks posted by the idle helper when paused. - base::TimeTicks next_pending_delayed_task; - EXPECT_FALSE(scheduler_helper_->real_time_domain()->NextScheduledRunTime( - &next_pending_delayed_task)); - - // Posting a task should transition us to the an active state. - max_idle_task_reposts = 2; - base::TimeTicks clock_before(clock_->NowTicks()); - base::TimeDelta idle_task_runtime(base::TimeDelta::FromMilliseconds(10)); - idle_task_runner_->PostIdleTask( - FROM_HERE, - base::Bind(&RepostingUpdateClockIdleTestTask, - base::RetainedRef(idle_task_runner_), &run_count, clock_.get(), - idle_task_runtime, &actual_deadlines)); - RunUntilIdle(); - EXPECT_EQ(2, run_count); - EXPECT_THAT( - actual_deadlines, - testing::ElementsAre( - clock_before + maximum_idle_period_duration(), - clock_before + idle_task_runtime + maximum_idle_period_duration())); - - // Once all task have been run we should go back to the paused state. - CheckIdlePeriodStateIs("in_long_idle_period_paused"); - EXPECT_FALSE(scheduler_helper_->real_time_domain()->NextScheduledRunTime( - &next_pending_delayed_task)); - - idle_helper_->EndIdlePeriod(); - CheckIdlePeriodStateIs("not_in_idle_period"); -} - -TEST_F(IdleHelperTest, TestLongIdlePeriodWhenShutdown) { - base::TimeTicks deadline_in_task; - int run_count = 0; - - idle_task_runner_->PostIdleTask( - FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); - scheduler_helper_->Shutdown(); - - // We shouldn't be able to enter a long idle period when shutdown - idle_helper_->EnableLongIdlePeriod(); - RunUntilIdle(); - CheckIdlePeriodStateIs("not_in_idle_period"); - EXPECT_EQ(0, run_count); -} - -void TestCanExceedIdleDeadlineIfRequiredTask(IdleHelperForTest* idle_helper, - bool* can_exceed_idle_deadline_out, - int* run_count, - base::TimeTicks deadline) { - *can_exceed_idle_deadline_out = - idle_helper->CanExceedIdleDeadlineIfRequired(); - (*run_count)++; -} - -TEST_F(IdleHelperTest, CanExceedIdleDeadlineIfRequired) { - int run_count = 0; - bool can_exceed_idle_deadline = false; - - // Should return false if not in an idle period. - EXPECT_FALSE(idle_helper_->CanExceedIdleDeadlineIfRequired()); - - // Should return false for short idle periods. - idle_task_runner_->PostIdleTask( - FROM_HERE, - base::Bind(&TestCanExceedIdleDeadlineIfRequiredTask, idle_helper_.get(), - &can_exceed_idle_deadline, &run_count)); - idle_helper_->StartIdlePeriod( - IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), - clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); - RunUntilIdle(); - EXPECT_EQ(1, run_count); - EXPECT_FALSE(can_exceed_idle_deadline); - - // Should return false for a long idle period which is shortened due to a - // pending delayed task. - default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask), - base::TimeDelta::FromMilliseconds(10)); - idle_task_runner_->PostIdleTask( - FROM_HERE, - base::Bind(&TestCanExceedIdleDeadlineIfRequiredTask, idle_helper_.get(), - &can_exceed_idle_deadline, &run_count)); - idle_helper_->EnableLongIdlePeriod(); - RunUntilIdle(); - EXPECT_EQ(2, run_count); - EXPECT_FALSE(can_exceed_idle_deadline); - - // Next long idle period will be for the maximum time, so - // CanExceedIdleDeadlineIfRequired should return true. - clock_->Advance(maximum_idle_period_duration()); - idle_task_runner_->PostIdleTask( - FROM_HERE, - base::Bind(&TestCanExceedIdleDeadlineIfRequiredTask, idle_helper_.get(), - &can_exceed_idle_deadline, &run_count)); - RunUntilIdle(); - EXPECT_EQ(3, run_count); - EXPECT_TRUE(can_exceed_idle_deadline); -} - -class IdleHelperWithQuiescencePeriodTest : public BaseIdleHelperTest { - public: - enum { - kQuiescenceDelayMs = 100, - kLongIdlePeriodMs = 50, - }; - - IdleHelperWithQuiescencePeriodTest() - : BaseIdleHelperTest( - nullptr, - base::TimeDelta::FromMilliseconds(kQuiescenceDelayMs)) {} - - ~IdleHelperWithQuiescencePeriodTest() override {} - - void SetUp() override { - EXPECT_CALL(*idle_helper_, OnIdlePeriodStarted()).Times(AnyNumber()); - EXPECT_CALL(*idle_helper_, OnIdlePeriodEnded()).Times(AnyNumber()); - EXPECT_CALL(*idle_helper_, CanEnterLongIdlePeriod(_, _)) - .Times(AnyNumber()) - .WillRepeatedly(Return(true)); - EXPECT_CALL(*idle_helper_, IsNotQuiescent()).Times(AnyNumber()); - } - - void MakeNonQuiescent() { - // Run an arbitrary task so we're deemed to be not quiescent. - default_task_runner_->PostTask(FROM_HERE, base::Bind(NullTask)); - RunUntilIdle(); - } - - private: - DISALLOW_COPY_AND_ASSIGN(IdleHelperWithQuiescencePeriodTest); -}; - -class IdleHelperWithQuiescencePeriodTestWithIdlePeriodObserver : - public IdleHelperWithQuiescencePeriodTest { - public: - - IdleHelperWithQuiescencePeriodTestWithIdlePeriodObserver() - : IdleHelperWithQuiescencePeriodTest() {} - - ~IdleHelperWithQuiescencePeriodTestWithIdlePeriodObserver() override {} - - void SetUp() override { - // Don't set expectations on IdleHelper::Delegate. - } - - private: - DISALLOW_COPY_AND_ASSIGN( - IdleHelperWithQuiescencePeriodTestWithIdlePeriodObserver); -}; - - -TEST_F(IdleHelperWithQuiescencePeriodTest, - LongIdlePeriodStartsImmediatelyIfQuiescent) { - base::TimeTicks actual_deadline; - int run_count = 0; - max_idle_task_reposts = 1; - idle_task_runner_->PostIdleTask( - FROM_HERE, - base::Bind(&RepostingIdleTestTask, base::RetainedRef(idle_task_runner_), - &run_count, &actual_deadline)); - - idle_helper_->EnableLongIdlePeriod(); - RunUntilIdle(); - - EXPECT_EQ(1, run_count); -} - -TEST_F(IdleHelperWithQuiescencePeriodTestWithIdlePeriodObserver, - LongIdlePeriodDoesNotStartsImmediatelyIfBusy) { - MakeNonQuiescent(); - EXPECT_CALL(*idle_helper_, OnIdlePeriodStarted()).Times(0); - EXPECT_CALL(*idle_helper_, OnIdlePeriodEnded()).Times(0); - EXPECT_CALL(*idle_helper_, CanEnterLongIdlePeriod(_, _)).Times(0); - EXPECT_CALL(*idle_helper_, IsNotQuiescent()).Times(AtLeast(1)); - - base::TimeTicks actual_deadline; - int run_count = 0; - max_idle_task_reposts = 1; - idle_task_runner_->PostIdleTask( - FROM_HERE, - base::Bind(&RepostingIdleTestTask, base::RetainedRef(idle_task_runner_), - &run_count, &actual_deadline)); - - idle_helper_->EnableLongIdlePeriod(); - RunUntilIdle(); - - EXPECT_EQ(0, run_count); - - scheduler_helper_->Shutdown(); -} - -TEST_F(IdleHelperWithQuiescencePeriodTest, - LongIdlePeriodStartsAfterQuiescence) { - MakeNonQuiescent(); - mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true); - - // Run a repeating task so we're deemed to be busy for the next 400ms. - default_task_runner_->PostTask( - FROM_HERE, - base::Bind(&RepeatingTask, base::Unretained(default_task_runner_.get()), - 10, base::TimeDelta::FromMilliseconds(40))); - - int run_count = 0; - // In this scenario EnableLongIdlePeriod deems us not to be quiescent 5x in - // a row. - base::TimeTicks expected_deadline = - clock_->NowTicks() + base::TimeDelta::FromMilliseconds( - 5 * kQuiescenceDelayMs + kLongIdlePeriodMs); - base::TimeTicks deadline_in_task; - idle_task_runner_->PostIdleTask( - FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); - - idle_helper_->EnableLongIdlePeriod(); - RunUntilIdle(); - EXPECT_EQ(1, run_count); - EXPECT_EQ(expected_deadline, deadline_in_task); -} - -TEST_F(IdleHelperWithQuiescencePeriodTest, - QuescienceCheckedForAfterLongIdlePeriodEnds) { - mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true); - - idle_task_runner_->PostIdleTask(FROM_HERE, base::Bind(&NullIdleTask)); - idle_helper_->EnableLongIdlePeriod(); - RunUntilIdle(); - - // Post a normal task to make the scheduler non-quiescent. - default_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask)); - RunUntilIdle(); - - // Post an idle task. The idle task won't run initially because the system is - // not judged to be quiescent, but should be run after the quiescence delay. - int run_count = 0; - base::TimeTicks deadline_in_task; - base::TimeTicks expected_deadline = - clock_->NowTicks() + - base::TimeDelta::FromMilliseconds(kQuiescenceDelayMs + kLongIdlePeriodMs); - idle_task_runner_->PostIdleTask( - FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); - idle_helper_->EnableLongIdlePeriod(); - RunUntilIdle(); - - EXPECT_EQ(1, run_count); - EXPECT_EQ(expected_deadline, deadline_in_task); -} - -TEST_F(IdleHelperTest, NoShortIdlePeriodWhenDeadlineTooClose) { - int run_count = 0; - base::TimeTicks deadline_in_task; - - idle_task_runner_->PostIdleTask( - FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); - - base::TimeDelta half_a_ms(base::TimeDelta::FromMicroseconds(50)); - base::TimeTicks less_than_min_deadline( - clock_->NowTicks() + minimum_idle_period_duration() - half_a_ms); - base::TimeTicks more_than_min_deadline( - clock_->NowTicks() + minimum_idle_period_duration() + half_a_ms); - - idle_helper_->StartIdlePeriod( - IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), - less_than_min_deadline); - RunUntilIdle(); - EXPECT_EQ(0, run_count); - - idle_helper_->StartIdlePeriod( - IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), - more_than_min_deadline); - RunUntilIdle(); - EXPECT_EQ(1, run_count); -} - -TEST_F(IdleHelperTest, NoLongIdlePeriodWhenDeadlineTooClose) { - int run_count = 0; - base::TimeTicks deadline_in_task; - - base::TimeDelta half_a_ms(base::TimeDelta::FromMicroseconds(50)); - base::TimeDelta less_than_min_deadline_duration( - minimum_idle_period_duration() - half_a_ms); - base::TimeDelta more_than_min_deadline_duration( - minimum_idle_period_duration() + half_a_ms); - - idle_task_runner_->PostIdleTask( - FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); - default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask), - less_than_min_deadline_duration); - - idle_helper_->EnableLongIdlePeriod(); - RunUntilIdle(); - EXPECT_EQ(0, run_count); - - idle_helper_->EndIdlePeriod(); - clock_->Advance(maximum_idle_period_duration()); - RunUntilIdle(); - EXPECT_EQ(0, run_count); - - default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask), - more_than_min_deadline_duration); - idle_helper_->EnableLongIdlePeriod(); - RunUntilIdle(); - EXPECT_EQ(1, run_count); -} - -} // namespace scheduler
diff --git a/components/scheduler/child/scheduler_helper.cc b/components/scheduler/child/scheduler_helper.cc deleted file mode 100644 index 57cbbc38..0000000 --- a/components/scheduler/child/scheduler_helper.cc +++ /dev/null
@@ -1,164 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/child/scheduler_helper.h" - -#include "base/time/default_tick_clock.h" -#include "base/trace_event/trace_event.h" -#include "base/trace_event/trace_event_argument.h" -#include "components/scheduler/base/task_queue_impl.h" -#include "components/scheduler/child/scheduler_tqm_delegate.h" - -namespace scheduler { - -SchedulerHelper::SchedulerHelper( - scoped_refptr<SchedulerTqmDelegate> task_queue_manager_delegate, - const char* tracing_category, - const char* disabled_by_default_tracing_category, - const char* disabled_by_default_verbose_tracing_category) - : task_queue_manager_delegate_(task_queue_manager_delegate), - task_queue_manager_( - new TaskQueueManager(task_queue_manager_delegate, - tracing_category, - disabled_by_default_tracing_category, - disabled_by_default_verbose_tracing_category)), - control_task_runner_(NewTaskQueue( - TaskQueue::Spec("control_tq") - .SetWakeupPolicy(TaskQueue::WakeupPolicy::DONT_WAKE_OTHER_QUEUES) - .SetShouldNotifyObservers(false))), - control_after_wakeup_task_runner_(NewTaskQueue( - TaskQueue::Spec("control_after_wakeup_tq") - .SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP) - .SetWakeupPolicy(TaskQueue::WakeupPolicy::DONT_WAKE_OTHER_QUEUES) - .SetShouldNotifyObservers(false))), - default_task_runner_(NewTaskQueue( - TaskQueue::Spec("default_tq").SetShouldMonitorQuiescence(true))), - observer_(nullptr), - tracing_category_(tracing_category), - disabled_by_default_tracing_category_( - disabled_by_default_tracing_category) { - control_task_runner_->SetQueuePriority(TaskQueue::CONTROL_PRIORITY); - control_after_wakeup_task_runner_->SetQueuePriority( - TaskQueue::CONTROL_PRIORITY); - - task_queue_manager_->SetWorkBatchSize(4); - - DCHECK(task_queue_manager_delegate_); - task_queue_manager_delegate_->SetDefaultTaskRunner( - default_task_runner_.get()); -} - -SchedulerHelper::~SchedulerHelper() { - Shutdown(); -} - -void SchedulerHelper::Shutdown() { - CheckOnValidThread(); - if (task_queue_manager_) - task_queue_manager_->SetObserver(nullptr); - task_queue_manager_.reset(); - task_queue_manager_delegate_->RestoreDefaultTaskRunner(); -} - -scoped_refptr<TaskQueue> SchedulerHelper::NewTaskQueue( - const TaskQueue::Spec& spec) { - DCHECK(task_queue_manager_.get()); - return task_queue_manager_->NewTaskQueue(spec); -} - -scoped_refptr<TaskQueue> SchedulerHelper::DefaultTaskRunner() { - CheckOnValidThread(); - return default_task_runner_; -} - -scoped_refptr<TaskQueue> SchedulerHelper::ControlTaskRunner() { - return control_task_runner_; -} - -scoped_refptr<TaskQueue> SchedulerHelper::ControlAfterWakeUpTaskRunner() { - return control_after_wakeup_task_runner_; -} - -void SchedulerHelper::SetWorkBatchSizeForTesting(size_t work_batch_size) { - CheckOnValidThread(); - DCHECK(task_queue_manager_.get()); - task_queue_manager_->SetWorkBatchSize(work_batch_size); -} - -TaskQueueManager* SchedulerHelper::GetTaskQueueManagerForTesting() { - CheckOnValidThread(); - return task_queue_manager_.get(); -} - -const scoped_refptr<SchedulerTqmDelegate>& -SchedulerHelper::scheduler_tqm_delegate() const { - return task_queue_manager_delegate_; -} - - -bool SchedulerHelper::GetAndClearSystemIsQuiescentBit() { - CheckOnValidThread(); - DCHECK(task_queue_manager_.get()); - return task_queue_manager_->GetAndClearSystemIsQuiescentBit(); -} - -void SchedulerHelper::AddTaskObserver( - base::MessageLoop::TaskObserver* task_observer) { - CheckOnValidThread(); - if (task_queue_manager_) - task_queue_manager_->AddTaskObserver(task_observer); -} - -void SchedulerHelper::RemoveTaskObserver( - base::MessageLoop::TaskObserver* task_observer) { - CheckOnValidThread(); - if (task_queue_manager_) - task_queue_manager_->RemoveTaskObserver(task_observer); -} - -void SchedulerHelper::SetObserver(Observer* observer) { - CheckOnValidThread(); - observer_ = observer; - DCHECK(task_queue_manager_); - task_queue_manager_->SetObserver(this); -} - -RealTimeDomain* SchedulerHelper::real_time_domain() const { - CheckOnValidThread(); - DCHECK(task_queue_manager_); - return task_queue_manager_->real_time_domain(); -} - -void SchedulerHelper::RegisterTimeDomain(TimeDomain* time_domain) { - CheckOnValidThread(); - DCHECK(task_queue_manager_); - task_queue_manager_->RegisterTimeDomain(time_domain); -} - -void SchedulerHelper::UnregisterTimeDomain(TimeDomain* time_domain) { - CheckOnValidThread(); - if (task_queue_manager_) - task_queue_manager_->UnregisterTimeDomain(time_domain); -} - -void SchedulerHelper::OnUnregisterTaskQueue( - const scoped_refptr<TaskQueue>& queue) { - if (observer_) - observer_->OnUnregisterTaskQueue(queue); -} - -void SchedulerHelper::OnTriedToExecuteBlockedTask( - const TaskQueue& queue, - const base::PendingTask& task) { - if (observer_) - observer_->OnTriedToExecuteBlockedTask(queue, task); -} - -TaskQueue* SchedulerHelper::CurrentlyExecutingTaskQueue() const { - if (!task_queue_manager_) - return nullptr; - return task_queue_manager_->currently_executing_task_queue(); -} - -} // namespace scheduler
diff --git a/components/scheduler/child/scheduler_helper.h b/components/scheduler/child/scheduler_helper.h deleted file mode 100644 index c19f023..0000000 --- a/components/scheduler/child/scheduler_helper.h +++ /dev/null
@@ -1,131 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_CHILD_SCHEDULER_HELPER_H_ -#define COMPONENTS_SCHEDULER_CHILD_SCHEDULER_HELPER_H_ - -#include <stddef.h> - -#include "base/macros.h" -#include "base/time/tick_clock.h" -#include "components/scheduler/base/task_queue_manager.h" -#include "components/scheduler/base/task_queue_selector.h" -#include "components/scheduler/scheduler_export.h" - -namespace base { -class TickClock; -} - -namespace scheduler { - -class SchedulerTqmDelegate; - -// Common scheduler functionality for default tasks. -class SCHEDULER_EXPORT SchedulerHelper - : public TaskQueueManager::Observer { - public: - // Category strings must have application lifetime (statics or - // literals). They may not include " chars. - SchedulerHelper( - scoped_refptr<SchedulerTqmDelegate> task_queue_manager_delegate, - const char* tracing_category, - const char* disabled_by_default_tracing_category, - const char* disabled_by_default_verbose_tracing_category); - ~SchedulerHelper() override; - - // TaskQueueManager::Observer implementation: - void OnUnregisterTaskQueue(const scoped_refptr<TaskQueue>& queue) override; - void OnTriedToExecuteBlockedTask(const TaskQueue& queue, - const base::PendingTask& task) override; - - // Returns the default task runner. - scoped_refptr<TaskQueue> DefaultTaskRunner(); - - // Returns the control task runner. Tasks posted to this runner are executed - // with the highest priority. Care must be taken to avoid starvation of other - // task queues. - scoped_refptr<TaskQueue> ControlTaskRunner(); - - // Returns the control task after wakeup runner. Tasks posted to this runner - // are executed with the highest priority but do not cause the scheduler to - // wake up. Care must be taken to avoid starvation of other task queues. - scoped_refptr<TaskQueue> ControlAfterWakeUpTaskRunner(); - - // Adds or removes a task observer from the scheduler. The observer will be - // notified before and after every executed task. These functions can only be - // called on the thread this class was created on. - void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer); - void RemoveTaskObserver(base::MessageLoop::TaskObserver* task_observer); - - void SetTaskTimeTracker(TaskTimeTracker* task_time_tracker) { - if (task_queue_manager_) - task_queue_manager_->SetTaskTimeTracker(task_time_tracker); - } - - // Shuts down the scheduler by dropping any remaining pending work in the work - // queues. After this call any work posted to the task runners will be - // silently dropped. - void Shutdown(); - - // Returns true if Shutdown() has been called. Otherwise returns false. - bool IsShutdown() const { return !task_queue_manager_.get(); } - - void CheckOnValidThread() const { - DCHECK(thread_checker_.CalledOnValidThread()); - } - - // Creates a new TaskQueue with the given |spec|. - scoped_refptr<TaskQueue> NewTaskQueue(const TaskQueue::Spec& spec); - - class SCHEDULER_EXPORT Observer { - public: - virtual ~Observer() {} - - // Called when |queue| is unregistered. - virtual void OnUnregisterTaskQueue( - const scoped_refptr<TaskQueue>& queue) = 0; - - // Called when the scheduler tried to execute a task from a disabled - // queue. See TaskQueue::Spec::SetShouldReportWhenExecutionBlocked. - virtual void OnTriedToExecuteBlockedTask(const TaskQueue& queue, - const base::PendingTask& task) = 0; - }; - - // Called once to set the Observer. This function is called on the main - // thread. If |observer| is null, then no callbacks will occur. - // Note |observer| is expected to outlive the SchedulerHelper. - void SetObserver(Observer* observer); - - // Accessor methods. - RealTimeDomain* real_time_domain() const; - void RegisterTimeDomain(TimeDomain* time_domain); - void UnregisterTimeDomain(TimeDomain* time_domain); - const scoped_refptr<SchedulerTqmDelegate>& scheduler_tqm_delegate() const; - bool GetAndClearSystemIsQuiescentBit(); - TaskQueue* CurrentlyExecutingTaskQueue() const; - - // Test helpers. - void SetWorkBatchSizeForTesting(size_t work_batch_size); - TaskQueueManager* GetTaskQueueManagerForTesting(); - - private: - friend class SchedulerHelperTest; - - base::ThreadChecker thread_checker_; - scoped_refptr<SchedulerTqmDelegate> task_queue_manager_delegate_; - std::unique_ptr<TaskQueueManager> task_queue_manager_; - scoped_refptr<TaskQueue> control_task_runner_; - scoped_refptr<TaskQueue> control_after_wakeup_task_runner_; - scoped_refptr<TaskQueue> default_task_runner_; - - Observer* observer_; // NOT OWNED - const char* tracing_category_; - const char* disabled_by_default_tracing_category_; - - DISALLOW_COPY_AND_ASSIGN(SchedulerHelper); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_CHILD_SCHEDULER_HELPER_H_
diff --git a/components/scheduler/child/scheduler_helper_unittest.cc b/components/scheduler/child/scheduler_helper_unittest.cc deleted file mode 100644 index 73cbbdc..0000000 --- a/components/scheduler/child/scheduler_helper_unittest.cc +++ /dev/null
@@ -1,228 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/child/scheduler_helper.h" - -#include "base/callback.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/test/simple_test_tick_clock.h" -#include "cc/test/ordered_simple_task_runner.h" -#include "components/scheduler/base/lazy_now.h" -#include "components/scheduler/base/task_queue.h" -#include "components/scheduler/base/test_time_source.h" -#include "components/scheduler/child/scheduler_tqm_delegate_for_test.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using testing::_; -using testing::AnyNumber; -using testing::Invoke; -using testing::Return; - -namespace scheduler { - -namespace { -void AppendToVectorTestTask(std::vector<std::string>* vector, - std::string value) { - vector->push_back(value); -} - -void AppendToVectorReentrantTask(base::SingleThreadTaskRunner* task_runner, - std::vector<int>* vector, - int* reentrant_count, - int max_reentrant_count) { - vector->push_back((*reentrant_count)++); - if (*reentrant_count < max_reentrant_count) { - task_runner->PostTask( - FROM_HERE, - base::Bind(AppendToVectorReentrantTask, base::Unretained(task_runner), - vector, reentrant_count, max_reentrant_count)); - } -} - -}; // namespace - -class SchedulerHelperTest : public testing::Test { - public: - SchedulerHelperTest() - : clock_(new base::SimpleTestTickClock()), - mock_task_runner_(new cc::OrderedSimpleTaskRunner(clock_.get(), false)), - main_task_runner_(SchedulerTqmDelegateForTest::Create( - mock_task_runner_, - base::WrapUnique(new TestTimeSource(clock_.get())))), - scheduler_helper_(new SchedulerHelper( - main_task_runner_, - "test.scheduler", - TRACE_DISABLED_BY_DEFAULT("test.scheduler"), - TRACE_DISABLED_BY_DEFAULT("test.scheduler.dbg"))), - default_task_runner_(scheduler_helper_->DefaultTaskRunner()) { - clock_->Advance(base::TimeDelta::FromMicroseconds(5000)); - } - - ~SchedulerHelperTest() override {} - - void TearDown() override { - // Check that all tests stop posting tasks. - mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true); - while (mock_task_runner_->RunUntilIdle()) { - } - } - - void RunUntilIdle() { mock_task_runner_->RunUntilIdle(); } - - template <typename E> - static void CallForEachEnumValue(E first, - E last, - const char* (*function)(E)) { - for (E val = first; val < last; - val = static_cast<E>(static_cast<int>(val) + 1)) { - (*function)(val); - } - } - - protected: - std::unique_ptr<base::SimpleTestTickClock> clock_; - scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_; - - scoped_refptr<SchedulerTqmDelegateForTest> main_task_runner_; - std::unique_ptr<SchedulerHelper> scheduler_helper_; - scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_; - - DISALLOW_COPY_AND_ASSIGN(SchedulerHelperTest); -}; - -TEST_F(SchedulerHelperTest, TestPostDefaultTask) { - std::vector<std::string> run_order; - default_task_runner_->PostTask( - FROM_HERE, base::Bind(&AppendToVectorTestTask, &run_order, "D1")); - default_task_runner_->PostTask( - FROM_HERE, base::Bind(&AppendToVectorTestTask, &run_order, "D2")); - default_task_runner_->PostTask( - FROM_HERE, base::Bind(&AppendToVectorTestTask, &run_order, "D3")); - default_task_runner_->PostTask( - FROM_HERE, base::Bind(&AppendToVectorTestTask, &run_order, "D4")); - - RunUntilIdle(); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("D1"), std::string("D2"), - std::string("D3"), std::string("D4"))); -} - -TEST_F(SchedulerHelperTest, TestRentrantTask) { - int count = 0; - std::vector<int> run_order; - default_task_runner_->PostTask( - FROM_HERE, base::Bind(AppendToVectorReentrantTask, - base::RetainedRef(default_task_runner_), &run_order, - &count, 5)); - RunUntilIdle(); - - EXPECT_THAT(run_order, testing::ElementsAre(0, 1, 2, 3, 4)); -} - -TEST_F(SchedulerHelperTest, IsShutdown) { - EXPECT_FALSE(scheduler_helper_->IsShutdown()); - - scheduler_helper_->Shutdown(); - EXPECT_TRUE(scheduler_helper_->IsShutdown()); -} - -TEST_F(SchedulerHelperTest, DefaultTaskRunnerRegistration) { - EXPECT_EQ(main_task_runner_->default_task_runner(), - scheduler_helper_->DefaultTaskRunner()); - scheduler_helper_->Shutdown(); - EXPECT_EQ(nullptr, main_task_runner_->default_task_runner()); -} - -namespace { -class MockTaskObserver : public base::MessageLoop::TaskObserver { - public: - MOCK_METHOD1(DidProcessTask, void(const base::PendingTask& task)); - MOCK_METHOD1(WillProcessTask, void(const base::PendingTask& task)); -}; - -void NopTask() {} -} // namespace - -TEST_F(SchedulerHelperTest, ObserversNotifiedFor_DefaultTaskRunner) { - MockTaskObserver observer; - scheduler_helper_->AddTaskObserver(&observer); - - scheduler_helper_->DefaultTaskRunner()->PostTask(FROM_HERE, - base::Bind(&NopTask)); - - EXPECT_CALL(observer, WillProcessTask(_)).Times(1); - EXPECT_CALL(observer, DidProcessTask(_)).Times(1); - RunUntilIdle(); -} - -TEST_F(SchedulerHelperTest, ObserversNotNotifiedFor_ControlTaskRunner) { - MockTaskObserver observer; - scheduler_helper_->AddTaskObserver(&observer); - - scheduler_helper_->ControlTaskRunner()->PostTask(FROM_HERE, - base::Bind(&NopTask)); - - EXPECT_CALL(observer, WillProcessTask(_)).Times(0); - EXPECT_CALL(observer, DidProcessTask(_)).Times(0); - RunUntilIdle(); -} - -TEST_F(SchedulerHelperTest, - ObserversNotNotifiedFor_ControlAfterWakeUpTaskRunner) { - MockTaskObserver observer; - scheduler_helper_->AddTaskObserver(&observer); - - scheduler_helper_->ControlAfterWakeUpTaskRunner()->PostTask( - FROM_HERE, base::Bind(&NopTask)); - - EXPECT_CALL(observer, WillProcessTask(_)).Times(0); - EXPECT_CALL(observer, DidProcessTask(_)).Times(0); - LazyNow lazy_now(clock_.get()); - scheduler_helper_->ControlAfterWakeUpTaskRunner()->PumpQueue(&lazy_now, true); - RunUntilIdle(); -} - -namespace { - -class MockObserver : public SchedulerHelper::Observer { - public: - MOCK_METHOD1(OnUnregisterTaskQueue, - void(const scoped_refptr<TaskQueue>& queue)); - MOCK_METHOD2(OnTriedToExecuteBlockedTask, - void(const TaskQueue& queue, const base::PendingTask& task)); -}; - -} // namespace - -TEST_F(SchedulerHelperTest, OnUnregisterTaskQueue) { - MockObserver observer; - scheduler_helper_->SetObserver(&observer); - - scoped_refptr<TaskQueue> task_queue = - scheduler_helper_->NewTaskQueue(TaskQueue::Spec("test_queue")); - - EXPECT_CALL(observer, OnUnregisterTaskQueue(_)).Times(1); - task_queue->UnregisterTaskQueue(); - - scheduler_helper_->SetObserver(nullptr); -} - -TEST_F(SchedulerHelperTest, OnTriedToExecuteBlockedTask) { - MockObserver observer; - scheduler_helper_->SetObserver(&observer); - - scoped_refptr<TaskQueue> task_queue = scheduler_helper_->NewTaskQueue( - TaskQueue::Spec("test_queue").SetShouldReportWhenExecutionBlocked(true)); - task_queue->SetQueueEnabled(false); - task_queue->PostTask(FROM_HERE, base::Bind(&NopTask)); - - EXPECT_CALL(observer, OnTriedToExecuteBlockedTask(_, _)).Times(1); - RunUntilIdle(); - - scheduler_helper_->SetObserver(nullptr); -} - -} // namespace scheduler
diff --git a/components/scheduler/child/scheduler_tqm_delegate.h b/components/scheduler/child/scheduler_tqm_delegate.h deleted file mode 100644 index bb294450..0000000 --- a/components/scheduler/child/scheduler_tqm_delegate.h +++ /dev/null
@@ -1,37 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_CHILD_SCHEDULER_TQM_DELEGATE_H_ -#define COMPONENTS_SCHEDULER_CHILD_SCHEDULER_TQM_DELEGATE_H_ - -#include "base/macros.h" -#include "base/message_loop/message_loop.h" -#include "components/scheduler/base/task_queue_manager_delegate.h" -#include "components/scheduler/scheduler_export.h" - -namespace scheduler { - -class SCHEDULER_EXPORT SchedulerTqmDelegate : public TaskQueueManagerDelegate { - public: - SchedulerTqmDelegate() {} - - // If the underlying task runner supports the concept of a default task - // runner, the delegate should implement this function to redirect that task - // runner to the scheduler. - virtual void SetDefaultTaskRunner( - scoped_refptr<base::SingleThreadTaskRunner> task_runner) = 0; - - // Similarly this method can be used to restore the original task runner when - // the scheduler no longer wants to intercept tasks. - virtual void RestoreDefaultTaskRunner() = 0; - - protected: - ~SchedulerTqmDelegate() override {} - - DISALLOW_COPY_AND_ASSIGN(SchedulerTqmDelegate); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_CHILD_SCHEDULER_TQM_DELEGATE_H_
diff --git a/components/scheduler/child/scheduler_tqm_delegate_for_test.cc b/components/scheduler/child/scheduler_tqm_delegate_for_test.cc deleted file mode 100644 index 87b96f6..0000000 --- a/components/scheduler/child/scheduler_tqm_delegate_for_test.cc +++ /dev/null
@@ -1,67 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/child/scheduler_tqm_delegate_for_test.h" - -#include <utility> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "components/scheduler/base/task_queue_manager_delegate_for_test.h" - -namespace scheduler { - -// static -scoped_refptr<SchedulerTqmDelegateForTest> SchedulerTqmDelegateForTest::Create( - scoped_refptr<base::SingleThreadTaskRunner> task_runner, - std::unique_ptr<base::TickClock> time_source) { - return make_scoped_refptr( - new SchedulerTqmDelegateForTest(task_runner, std::move(time_source))); -} - -SchedulerTqmDelegateForTest::SchedulerTqmDelegateForTest( - scoped_refptr<base::SingleThreadTaskRunner> task_runner, - std::unique_ptr<base::TickClock> time_source) - : task_runner_( - TaskQueueManagerDelegateForTest::Create(task_runner, - std::move(time_source))) {} - -SchedulerTqmDelegateForTest::~SchedulerTqmDelegateForTest() {} - -void SchedulerTqmDelegateForTest::SetDefaultTaskRunner( - scoped_refptr<base::SingleThreadTaskRunner> task_runner) { - default_task_runner_ = std::move(task_runner); -} - -void SchedulerTqmDelegateForTest::RestoreDefaultTaskRunner() { - default_task_runner_ = nullptr; -} - -bool SchedulerTqmDelegateForTest::PostDelayedTask( - const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) { - return task_runner_->PostDelayedTask(from_here, task, delay); -} - -bool SchedulerTqmDelegateForTest::PostNonNestableDelayedTask( - const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) { - return task_runner_->PostNonNestableDelayedTask(from_here, task, delay); -} - -bool SchedulerTqmDelegateForTest::RunsTasksOnCurrentThread() const { - return task_runner_->RunsTasksOnCurrentThread(); -} - -bool SchedulerTqmDelegateForTest::IsNested() const { - return task_runner_->IsNested(); -} - -base::TimeTicks SchedulerTqmDelegateForTest::NowTicks() { - return task_runner_->NowTicks(); -} - -} // namespace scheduler
diff --git a/components/scheduler/child/scheduler_tqm_delegate_for_test.h b/components/scheduler/child/scheduler_tqm_delegate_for_test.h deleted file mode 100644 index aeb2da12..0000000 --- a/components/scheduler/child/scheduler_tqm_delegate_for_test.h +++ /dev/null
@@ -1,59 +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 CONTENT_RENDERER_SCHEDULER_TQM_DELEGATE_FOR_TEST_H_ -#define CONTENT_RENDERER_SCHEDULER_TQM_DELEGATE_FOR_TEST_H_ - -#include <memory> - -#include "base/macros.h" -#include "base/test/simple_test_tick_clock.h" -#include "components/scheduler/child/scheduler_tqm_delegate.h" - -namespace scheduler { - -class TaskQueueManagerDelegateForTest; - -class SchedulerTqmDelegateForTest : public SchedulerTqmDelegate { - public: - static scoped_refptr<SchedulerTqmDelegateForTest> Create( - scoped_refptr<base::SingleThreadTaskRunner> task_runner, - std::unique_ptr<base::TickClock> time_source); - - // SchedulerTqmDelegate implementation - void SetDefaultTaskRunner( - scoped_refptr<base::SingleThreadTaskRunner> task_runner) override; - void RestoreDefaultTaskRunner() override; - bool PostDelayedTask(const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) override; - bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) override; - bool RunsTasksOnCurrentThread() const override; - bool IsNested() const override; - base::TimeTicks NowTicks() override; - - base::SingleThreadTaskRunner* default_task_runner() const { - return default_task_runner_.get(); - } - - protected: - ~SchedulerTqmDelegateForTest() override; - - private: - SchedulerTqmDelegateForTest( - scoped_refptr<base::SingleThreadTaskRunner> task_runner, - std::unique_ptr<base::TickClock> time_source); - - scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_; - - scoped_refptr<TaskQueueManagerDelegateForTest> task_runner_; - - DISALLOW_COPY_AND_ASSIGN(SchedulerTqmDelegateForTest); -}; - -} // namespace scheduler - -#endif // CONTENT_RENDERER_SCHEDULER_TQM_DELEGATE_FOR_TEST_H_
diff --git a/components/scheduler/child/scheduler_tqm_delegate_impl.cc b/components/scheduler/child/scheduler_tqm_delegate_impl.cc deleted file mode 100644 index ee4abcb3..0000000 --- a/components/scheduler/child/scheduler_tqm_delegate_impl.cc +++ /dev/null
@@ -1,67 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/child/scheduler_tqm_delegate_impl.h" - -#include <utility> - -namespace scheduler { - -// static -scoped_refptr<SchedulerTqmDelegateImpl> SchedulerTqmDelegateImpl::Create( - base::MessageLoop* message_loop, - std::unique_ptr<base::TickClock> time_source) { - return make_scoped_refptr( - new SchedulerTqmDelegateImpl(message_loop, std::move(time_source))); -} - -SchedulerTqmDelegateImpl::SchedulerTqmDelegateImpl( - base::MessageLoop* message_loop, - std::unique_ptr<base::TickClock> time_source) - : message_loop_(message_loop), - message_loop_task_runner_(message_loop->task_runner()), - time_source_(std::move(time_source)) {} - -SchedulerTqmDelegateImpl::~SchedulerTqmDelegateImpl() { - RestoreDefaultTaskRunner(); -} - -void SchedulerTqmDelegateImpl::SetDefaultTaskRunner( - scoped_refptr<base::SingleThreadTaskRunner> task_runner) { - message_loop_->SetTaskRunner(task_runner); -} - -void SchedulerTqmDelegateImpl::RestoreDefaultTaskRunner() { - if (base::MessageLoop::current() == message_loop_) - message_loop_->SetTaskRunner(message_loop_task_runner_); -} - -bool SchedulerTqmDelegateImpl::PostDelayedTask( - const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) { - return message_loop_task_runner_->PostDelayedTask(from_here, task, delay); -} - -bool SchedulerTqmDelegateImpl::PostNonNestableDelayedTask( - const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) { - return message_loop_task_runner_->PostNonNestableDelayedTask(from_here, task, - delay); -} - -bool SchedulerTqmDelegateImpl::RunsTasksOnCurrentThread() const { - return message_loop_task_runner_->RunsTasksOnCurrentThread(); -} - -bool SchedulerTqmDelegateImpl::IsNested() const { - return message_loop_->IsNested(); -} - -base::TimeTicks SchedulerTqmDelegateImpl::NowTicks() { - return time_source_->NowTicks(); -} - -} // namespace scheduler
diff --git a/components/scheduler/child/scheduler_tqm_delegate_impl.h b/components/scheduler/child/scheduler_tqm_delegate_impl.h deleted file mode 100644 index aca86e2..0000000 --- a/components/scheduler/child/scheduler_tqm_delegate_impl.h +++ /dev/null
@@ -1,56 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_CHILD_SCHEDULER_TQM_DELEGATE_IMPL_H_ -#define COMPONENTS_SCHEDULER_CHILD_SCHEDULER_TQM_DELEGATE_IMPL_H_ - -#include <memory> - -#include "base/macros.h" -#include "base/message_loop/message_loop.h" -#include "base/time/tick_clock.h" -#include "components/scheduler/child/scheduler_tqm_delegate.h" -#include "components/scheduler/scheduler_export.h" - -namespace scheduler { - -class SCHEDULER_EXPORT SchedulerTqmDelegateImpl : public SchedulerTqmDelegate { - public: - // |message_loop| is not owned and must outlive the lifetime of this object. - static scoped_refptr<SchedulerTqmDelegateImpl> Create( - base::MessageLoop* message_loop, - std::unique_ptr<base::TickClock> time_source); - - // SchedulerTqmDelegate implementation - void SetDefaultTaskRunner( - scoped_refptr<base::SingleThreadTaskRunner> task_runner) override; - void RestoreDefaultTaskRunner() override; - bool PostDelayedTask(const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) override; - bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) override; - bool RunsTasksOnCurrentThread() const override; - bool IsNested() const override; - base::TimeTicks NowTicks() override; - - protected: - ~SchedulerTqmDelegateImpl() override; - - private: - SchedulerTqmDelegateImpl(base::MessageLoop* message_loop, - std::unique_ptr<base::TickClock> time_source); - - // Not owned. - base::MessageLoop* message_loop_; - scoped_refptr<SingleThreadTaskRunner> message_loop_task_runner_; - std::unique_ptr<base::TickClock> time_source_; - - DISALLOW_COPY_AND_ASSIGN(SchedulerTqmDelegateImpl); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_CHILD_SCHEDULER_TQM_DELEGATE_IMPL_H_
diff --git a/components/scheduler/child/scheduler_tqm_delegate_impl_unittest.cc b/components/scheduler/child/scheduler_tqm_delegate_impl_unittest.cc deleted file mode 100644 index b6e42be..0000000 --- a/components/scheduler/child/scheduler_tqm_delegate_impl_unittest.cc +++ /dev/null
@@ -1,31 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/child/scheduler_tqm_delegate_impl.h" - -#include "base/memory/ptr_util.h" -#include "base/message_loop/message_loop.h" -#include "base/test/test_simple_task_runner.h" -#include "base/time/default_tick_clock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace scheduler { - -TEST(SchedulerTqmDelegateImplTest, TestTaskRunnerOverriding) { - base::MessageLoop loop; - scoped_refptr<base::SingleThreadTaskRunner> original_runner( - loop.task_runner()); - scoped_refptr<base::SingleThreadTaskRunner> custom_runner( - new base::TestSimpleTaskRunner()); - { - scoped_refptr<SchedulerTqmDelegateImpl> delegate( - SchedulerTqmDelegateImpl::Create( - &loop, base::WrapUnique(new base::DefaultTickClock()))); - delegate->SetDefaultTaskRunner(custom_runner); - DCHECK_EQ(custom_runner, loop.task_runner()); - } - DCHECK_EQ(original_runner, loop.task_runner()); -} - -} // namespace scheduler
diff --git a/components/scheduler/child/single_thread_idle_task_runner.cc b/components/scheduler/child/single_thread_idle_task_runner.cc deleted file mode 100644 index e73adf5..0000000 --- a/components/scheduler/child/single_thread_idle_task_runner.cc +++ /dev/null
@@ -1,90 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/child/single_thread_idle_task_runner.h" - -#include "base/location.h" -#include "base/trace_event/blame_context.h" -#include "base/trace_event/trace_event.h" - -namespace scheduler { - -SingleThreadIdleTaskRunner::SingleThreadIdleTaskRunner( - scoped_refptr<base::SingleThreadTaskRunner> idle_priority_task_runner, - scoped_refptr<base::SingleThreadTaskRunner> after_wakeup_task_runner, - Delegate* delegate, - const char* tracing_category) - : idle_priority_task_runner_(idle_priority_task_runner), - after_wakeup_task_runner_(after_wakeup_task_runner), - delegate_(delegate), - tracing_category_(tracing_category), - blame_context_(nullptr), - weak_factory_(this) { - DCHECK(!idle_priority_task_runner_ || - idle_priority_task_runner_->RunsTasksOnCurrentThread()); - DCHECK(!after_wakeup_task_runner_ || - after_wakeup_task_runner_->RunsTasksOnCurrentThread()); - weak_scheduler_ptr_ = weak_factory_.GetWeakPtr(); -} - -SingleThreadIdleTaskRunner::~SingleThreadIdleTaskRunner() { -} - -SingleThreadIdleTaskRunner::Delegate::Delegate() { -} - -SingleThreadIdleTaskRunner::Delegate::~Delegate() { -} - -bool SingleThreadIdleTaskRunner::RunsTasksOnCurrentThread() const { - return idle_priority_task_runner_->RunsTasksOnCurrentThread(); -} - -void SingleThreadIdleTaskRunner::PostIdleTask( - const tracked_objects::Location& from_here, - const IdleTask& idle_task) { - delegate_->OnIdleTaskPosted(); - idle_priority_task_runner_->PostTask( - from_here, base::Bind(&SingleThreadIdleTaskRunner::RunTask, - weak_scheduler_ptr_, idle_task)); -} - -void SingleThreadIdleTaskRunner::PostNonNestableIdleTask( - const tracked_objects::Location& from_here, - const IdleTask& idle_task) { - delegate_->OnIdleTaskPosted(); - idle_priority_task_runner_->PostNonNestableTask( - from_here, base::Bind(&SingleThreadIdleTaskRunner::RunTask, - weak_scheduler_ptr_, idle_task)); -} - -void SingleThreadIdleTaskRunner::PostIdleTaskAfterWakeup( - const tracked_objects::Location& from_here, - const IdleTask& idle_task) { - // Don't signal posting of idle task to the delegate here, wait until the - // after-wakeup task posts the real idle task. - after_wakeup_task_runner_->PostTask( - FROM_HERE, base::Bind(&SingleThreadIdleTaskRunner::PostIdleTask, - weak_scheduler_ptr_, from_here, idle_task)); -} - -void SingleThreadIdleTaskRunner::RunTask(IdleTask idle_task) { - base::TimeTicks deadline = delegate_->WillProcessIdleTask(); - TRACE_EVENT1(tracing_category_, "SingleThreadIdleTaskRunner::RunTask", - "allotted_time_ms", - (deadline - base::TimeTicks::Now()).InMillisecondsF()); - if (blame_context_) - blame_context_->Enter(); - idle_task.Run(deadline); - if (blame_context_) - blame_context_->Leave(); - delegate_->DidProcessIdleTask(); -} - -void SingleThreadIdleTaskRunner::SetBlameContext( - base::trace_event::BlameContext* blame_context) { - blame_context_ = blame_context; -} - -} // namespace scheduler
diff --git a/components/scheduler/child/single_thread_idle_task_runner.h b/components/scheduler/child/single_thread_idle_task_runner.h deleted file mode 100644 index 0448586..0000000 --- a/components/scheduler/child/single_thread_idle_task_runner.h +++ /dev/null
@@ -1,99 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_CHILD_SINGLE_THREAD_IDLE_TASK_RUNNER_H_ -#define COMPONENTS_SCHEDULER_CHILD_SINGLE_THREAD_IDLE_TASK_RUNNER_H_ - -#include "base/bind.h" -#include "base/callback.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/single_thread_task_runner.h" -#include "base/time/time.h" -#include "base/trace_event/trace_event.h" -#include "components/scheduler/scheduler_export.h" - -namespace base { -namespace trace_event { -class BlameContext; -} -} - -namespace scheduler { - -// A SingleThreadIdleTaskRunner is a task runner for running idle tasks. Idle -// tasks have an unbound argument which is bound to a deadline -// (in base::TimeTicks) when they are run. The idle task is expected to -// complete by this deadline. -class SingleThreadIdleTaskRunner - : public base::RefCountedThreadSafe<SingleThreadIdleTaskRunner> { - public: - typedef base::Callback<void(base::TimeTicks)> IdleTask; - - // Used to request idle task deadlines and signal posting of idle tasks. - class SCHEDULER_EXPORT Delegate { - public: - Delegate(); - virtual ~Delegate(); - - // Signals that an idle task has been posted. This will be called on the - // posting thread, which may not be the same thread as the - // SingleThreadIdleTaskRunner runs on. - virtual void OnIdleTaskPosted() = 0; - - // Signals that a new idle task is about to be run and returns the deadline - // for this idle task. - virtual base::TimeTicks WillProcessIdleTask() = 0; - - // Signals that an idle task has finished being run. - virtual void DidProcessIdleTask() = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(Delegate); - }; - - // NOTE Category strings must have application lifetime (statics or - // literals). They may not include " chars. - SingleThreadIdleTaskRunner( - scoped_refptr<base::SingleThreadTaskRunner> idle_priority_task_runner, - scoped_refptr<base::SingleThreadTaskRunner> after_wakeup_task_runner, - Delegate* Delegate, - const char* tracing_category); - - virtual void PostIdleTask(const tracked_objects::Location& from_here, - const IdleTask& idle_task); - - virtual void PostNonNestableIdleTask( - const tracked_objects::Location& from_here, - const IdleTask& idle_task); - - virtual void PostIdleTaskAfterWakeup( - const tracked_objects::Location& from_here, - const IdleTask& idle_task); - - bool RunsTasksOnCurrentThread() const; - - void SetBlameContext(base::trace_event::BlameContext* blame_context); - - protected: - virtual ~SingleThreadIdleTaskRunner(); - - private: - friend class base::RefCountedThreadSafe<SingleThreadIdleTaskRunner>; - - void RunTask(IdleTask idle_task); - - scoped_refptr<base::SingleThreadTaskRunner> idle_priority_task_runner_; - scoped_refptr<base::SingleThreadTaskRunner> after_wakeup_task_runner_; - Delegate* delegate_; // NOT OWNED - const char* tracing_category_; - base::trace_event::BlameContext* blame_context_; // Not owned. - base::WeakPtr<SingleThreadIdleTaskRunner> weak_scheduler_ptr_; - base::WeakPtrFactory<SingleThreadIdleTaskRunner> weak_factory_; - DISALLOW_COPY_AND_ASSIGN(SingleThreadIdleTaskRunner); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_CHILD_SINGLE_THREAD_IDLE_TASK_RUNNER_H_
diff --git a/components/scheduler/child/web_scheduler_impl.cc b/components/scheduler/child/web_scheduler_impl.cc deleted file mode 100644 index 2025f17..0000000 --- a/components/scheduler/child/web_scheduler_impl.cc +++ /dev/null
@@ -1,92 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/child/web_scheduler_impl.h" - -#include "base/bind.h" -#include "base/memory/ptr_util.h" -#include "base/single_thread_task_runner.h" -#include "components/scheduler/child/web_task_runner_impl.h" -#include "components/scheduler/child/worker_scheduler.h" -#include "third_party/WebKit/public/platform/WebTraceLocation.h" -#include "third_party/WebKit/public/platform/WebViewScheduler.h" - -namespace scheduler { - -WebSchedulerImpl::WebSchedulerImpl( - ChildScheduler* child_scheduler, - scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner, - scoped_refptr<TaskQueue> loading_task_runner, - scoped_refptr<TaskQueue> timer_task_runner) - : child_scheduler_(child_scheduler), - idle_task_runner_(idle_task_runner), - timer_task_runner_(timer_task_runner), - loading_web_task_runner_(new WebTaskRunnerImpl(loading_task_runner)), - timer_web_task_runner_(new WebTaskRunnerImpl(timer_task_runner)) {} - -WebSchedulerImpl::~WebSchedulerImpl() { -} - -void WebSchedulerImpl::shutdown() { - child_scheduler_->Shutdown(); -} - -bool WebSchedulerImpl::shouldYieldForHighPriorityWork() { - return child_scheduler_->ShouldYieldForHighPriorityWork(); -} - -bool WebSchedulerImpl::canExceedIdleDeadlineIfRequired() { - return child_scheduler_->CanExceedIdleDeadlineIfRequired(); -} - -void WebSchedulerImpl::runIdleTask( - std::unique_ptr<blink::WebThread::IdleTask> task, - base::TimeTicks deadline) { - task->run((deadline - base::TimeTicks()).InSecondsF()); -} - -void WebSchedulerImpl::postIdleTask(const blink::WebTraceLocation& location, - blink::WebThread::IdleTask* task) { - DCHECK(idle_task_runner_); - idle_task_runner_->PostIdleTask( - location, - base::Bind(&WebSchedulerImpl::runIdleTask, - base::Passed(base::WrapUnique(task)))); -} - -void WebSchedulerImpl::postNonNestableIdleTask( - const blink::WebTraceLocation& location, - blink::WebThread::IdleTask* task) { - DCHECK(idle_task_runner_); - idle_task_runner_->PostNonNestableIdleTask( - location, - base::Bind(&WebSchedulerImpl::runIdleTask, - base::Passed(base::WrapUnique(task)))); -} - -void WebSchedulerImpl::postIdleTaskAfterWakeup( - const blink::WebTraceLocation& location, - blink::WebThread::IdleTask* task) { - DCHECK(idle_task_runner_); - idle_task_runner_->PostIdleTaskAfterWakeup( - location, - base::Bind(&WebSchedulerImpl::runIdleTask, - base::Passed(base::WrapUnique(task)))); -} - -blink::WebTaskRunner* WebSchedulerImpl::loadingTaskRunner() { - return loading_web_task_runner_.get(); -} - -blink::WebTaskRunner* WebSchedulerImpl::timerTaskRunner() { - return timer_web_task_runner_.get(); -} - -std::unique_ptr<blink::WebViewScheduler> -WebSchedulerImpl::createWebViewScheduler(blink::WebView*) { - NOTREACHED(); - return nullptr; -} - -} // namespace scheduler
diff --git a/components/scheduler/child/web_scheduler_impl.h b/components/scheduler/child/web_scheduler_impl.h deleted file mode 100644 index 0219a94..0000000 --- a/components/scheduler/child/web_scheduler_impl.h +++ /dev/null
@@ -1,66 +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 CONTENT_CHILD_SCHEDULER_BASE_WEB_SCHEDULER_IMPL_H_ -#define CONTENT_CHILD_SCHEDULER_BASE_WEB_SCHEDULER_IMPL_H_ - -#include <memory> - -#include "base/memory/ref_counted.h" -#include "base/time/time.h" -#include "components/scheduler/scheduler_export.h" -#include "third_party/WebKit/public/platform/WebScheduler.h" -#include "third_party/WebKit/public/platform/WebThread.h" - -namespace scheduler { - -class ChildScheduler; -class SingleThreadIdleTaskRunner; -class TaskQueue; -class WebTaskRunnerImpl; - -class SCHEDULER_EXPORT WebSchedulerImpl : public blink::WebScheduler { - public: - WebSchedulerImpl(ChildScheduler* child_scheduler, - scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner, - scoped_refptr<TaskQueue> loading_task_runner, - scoped_refptr<TaskQueue> timer_task_runner); - ~WebSchedulerImpl() override; - - // blink::WebScheduler implementation: - void shutdown() override; - bool shouldYieldForHighPriorityWork() override; - bool canExceedIdleDeadlineIfRequired() override; - void postIdleTask(const blink::WebTraceLocation& location, - blink::WebThread::IdleTask* task) override; - void postNonNestableIdleTask(const blink::WebTraceLocation& location, - blink::WebThread::IdleTask* task) override; - void postIdleTaskAfterWakeup(const blink::WebTraceLocation& location, - blink::WebThread::IdleTask* task) override; - blink::WebTaskRunner* loadingTaskRunner() override; - blink::WebTaskRunner* timerTaskRunner() override; - std::unique_ptr<blink::WebViewScheduler> createWebViewScheduler( - blink::WebView*) override; - void suspendTimerQueue() override {} - void resumeTimerQueue() override {} - void addPendingNavigation( - blink::WebScheduler::NavigatingFrameType type) override {} - void removePendingNavigation( - blink::WebScheduler::NavigatingFrameType type) override {} - void onNavigationStarted() override {} - - private: - static void runIdleTask(std::unique_ptr<blink::WebThread::IdleTask> task, - base::TimeTicks deadline); - - ChildScheduler* child_scheduler_; // NOT OWNED - scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_; - scoped_refptr<TaskQueue> timer_task_runner_; - std::unique_ptr<WebTaskRunnerImpl> loading_web_task_runner_; - std::unique_ptr<WebTaskRunnerImpl> timer_web_task_runner_; -}; - -} // namespace scheduler - -#endif // CONTENT_CHILD_SCHEDULER_BASE_WEB_SCHEDULER_IMPL_H_
diff --git a/components/scheduler/child/web_task_runner_impl.cc b/components/scheduler/child/web_task_runner_impl.cc deleted file mode 100644 index 0b22780..0000000 --- a/components/scheduler/child/web_task_runner_impl.cc +++ /dev/null
@@ -1,72 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/child/web_task_runner_impl.h" - -#include "base/bind.h" -#include "base/location.h" -#include "base/memory/ptr_util.h" -#include "components/scheduler/base/task_queue.h" -#include "components/scheduler/base/time_domain.h" -#include "third_party/WebKit/public/platform/WebTraceLocation.h" - -namespace scheduler { - -WebTaskRunnerImpl::WebTaskRunnerImpl(scoped_refptr<TaskQueue> task_queue) - : task_queue_(task_queue) {} - -WebTaskRunnerImpl::~WebTaskRunnerImpl() {} - -void WebTaskRunnerImpl::postTask(const blink::WebTraceLocation& location, - blink::WebTaskRunner::Task* task) { - task_queue_->PostTask( - location, - base::Bind(&WebTaskRunnerImpl::runTask, - base::Passed(base::WrapUnique(task)))); -} - -void WebTaskRunnerImpl::postDelayedTask( - const blink::WebTraceLocation& location, - blink::WebTaskRunner::Task* task, - double delayMs) { - DCHECK_GE(delayMs, 0.0); - task_queue_->PostDelayedTask( - location, - base::Bind(&WebTaskRunnerImpl::runTask, - base::Passed(base::WrapUnique(task))), - base::TimeDelta::FromMillisecondsD(delayMs)); -} - -bool WebTaskRunnerImpl::runsTasksOnCurrentThread() { - return task_queue_->RunsTasksOnCurrentThread(); -} - -double WebTaskRunnerImpl::virtualTimeSeconds() const { - return (Now() - base::TimeTicks::UnixEpoch()).InSecondsF(); -} - -double WebTaskRunnerImpl::monotonicallyIncreasingVirtualTimeSeconds() const { - return Now().ToInternalValue() / - static_cast<double>(base::Time::kMicrosecondsPerSecond); -} - -base::TimeTicks WebTaskRunnerImpl::Now() const { - TimeDomain* time_domain = task_queue_->GetTimeDomain(); - // It's possible task_queue_ has been Unregistered which can lead to a null - // TimeDomain. If that happens just return the current real time. - if (!time_domain) - return base::TimeTicks::Now(); - return time_domain->Now(); -} - -std::unique_ptr<blink::WebTaskRunner> WebTaskRunnerImpl::clone() { - return base::WrapUnique(new WebTaskRunnerImpl(task_queue_)); -} - -void WebTaskRunnerImpl::runTask( - std::unique_ptr<blink::WebTaskRunner::Task> task) { - task->run(); -} - -} // namespace scheduler
diff --git a/components/scheduler/child/web_task_runner_impl.h b/components/scheduler/child/web_task_runner_impl.h deleted file mode 100644 index 0773a95..0000000 --- a/components/scheduler/child/web_task_runner_impl.h +++ /dev/null
@@ -1,54 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_CHILD_WEB_TASK_RUNNER_H_ -#define COMPONENTS_SCHEDULER_CHILD_WEB_TASK_RUNNER_H_ - -#include <memory> - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/time/time.h" -#include "components/scheduler/scheduler_export.h" -#include "third_party/WebKit/public/platform/WebTaskRunner.h" - -namespace scheduler { -class TaskQueue; - -class SCHEDULER_EXPORT WebTaskRunnerImpl : public blink::WebTaskRunner { - public: - explicit WebTaskRunnerImpl(scoped_refptr<TaskQueue> task_queue); - - ~WebTaskRunnerImpl() override; - - // blink::WebTaskRunner implementation: - void postTask(const blink::WebTraceLocation& web_location, - blink::WebTaskRunner::Task* task) override; - void postDelayedTask(const blink::WebTraceLocation& web_location, - blink::WebTaskRunner::Task* task, - double delayMs) override; - bool runsTasksOnCurrentThread() override; - double virtualTimeSeconds() const override; - double monotonicallyIncreasingVirtualTimeSeconds() const override; - std::unique_ptr<blink::WebTaskRunner> clone() override; - - // blink::WebTaskRunner::Task should be wrapped by base::Passed() when - // used with base::Bind(). See https://crbug.com/551356. - // runTask() is a helper to call blink::WebTaskRunner::Task::run from - // std::unique_ptr<blink::WebTaskRunner::Task>. - // runTask() is placed here because std::unique_ptr<> cannot be used from - // Blink. - static void runTask(std::unique_ptr<blink::WebTaskRunner::Task>); - - private: - base::TimeTicks Now() const; - - scoped_refptr<TaskQueue> task_queue_; - - DISALLOW_COPY_AND_ASSIGN(WebTaskRunnerImpl); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_CHILD_WEB_TASK_RUNNER_H_
diff --git a/components/scheduler/child/webthread_base.cc b/components/scheduler/child/webthread_base.cc deleted file mode 100644 index cf2ea07..0000000 --- a/components/scheduler/child/webthread_base.cc +++ /dev/null
@@ -1,104 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// An implementation of WebThread in terms of base::MessageLoop and -// base::Thread - -#include "components/scheduler/child/webthread_base.h" - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/memory/ptr_util.h" -#include "base/pending_task.h" -#include "base/threading/platform_thread.h" -#include "components/scheduler/child/single_thread_idle_task_runner.h" -#include "third_party/WebKit/public/platform/WebTraceLocation.h" - -namespace scheduler { - -class WebThreadBase::TaskObserverAdapter - : public base::MessageLoop::TaskObserver { - public: - explicit TaskObserverAdapter(WebThread::TaskObserver* observer) - : observer_(observer) {} - - void WillProcessTask(const base::PendingTask& pending_task) override { - observer_->willProcessTask(); - } - - void DidProcessTask(const base::PendingTask& pending_task) override { - observer_->didProcessTask(); - } - - private: - WebThread::TaskObserver* observer_; -}; - -WebThreadBase::WebThreadBase() { -} - -WebThreadBase::~WebThreadBase() { - for (auto& observer_entry : task_observer_map_) { - delete observer_entry.second; - } -} - -void WebThreadBase::addTaskObserver(TaskObserver* observer) { - CHECK(isCurrentThread()); - std::pair<TaskObserverMap::iterator, bool> result = task_observer_map_.insert( - std::make_pair(observer, nullptr)); - if (result.second) - result.first->second = new TaskObserverAdapter(observer); - AddTaskObserverInternal(result.first->second); -} - -void WebThreadBase::removeTaskObserver(TaskObserver* observer) { - CHECK(isCurrentThread()); - TaskObserverMap::iterator iter = task_observer_map_.find(observer); - if (iter == task_observer_map_.end()) - return; - RemoveTaskObserverInternal(iter->second); - delete iter->second; - task_observer_map_.erase(iter); -} - -void WebThreadBase::AddTaskObserverInternal( - base::MessageLoop::TaskObserver* observer) { - base::MessageLoop::current()->AddTaskObserver(observer); -} - -void WebThreadBase::RemoveTaskObserverInternal( - base::MessageLoop::TaskObserver* observer) { - base::MessageLoop::current()->RemoveTaskObserver(observer); -} - -// static -void WebThreadBase::RunWebThreadIdleTask( - std::unique_ptr<blink::WebThread::IdleTask> idle_task, - base::TimeTicks deadline) { - idle_task->run((deadline - base::TimeTicks()).InSecondsF()); -} - -void WebThreadBase::postIdleTask(const blink::WebTraceLocation& location, - IdleTask* idle_task) { - GetIdleTaskRunner()->PostIdleTask( - location, - base::Bind(&WebThreadBase::RunWebThreadIdleTask, - base::Passed(base::WrapUnique(idle_task)))); -} - -void WebThreadBase::postIdleTaskAfterWakeup( - const blink::WebTraceLocation& location, - IdleTask* idle_task) { - GetIdleTaskRunner()->PostIdleTaskAfterWakeup( - location, - base::Bind(&WebThreadBase::RunWebThreadIdleTask, - base::Passed(base::WrapUnique(idle_task)))); -} - -bool WebThreadBase::isCurrentThread() const { - return GetTaskRunner()->BelongsToCurrentThread(); -} - -} // namespace scheduler
diff --git a/components/scheduler/child/webthread_base.h b/components/scheduler/child/webthread_base.h deleted file mode 100644 index 0546cd9..0000000 --- a/components/scheduler/child/webthread_base.h +++ /dev/null
@@ -1,64 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_CHILD_WEBTHREAD_BASE_H_ -#define COMPONENTS_SCHEDULER_CHILD_WEBTHREAD_BASE_H_ - -#include <map> -#include <memory> - -#include "base/threading/thread.h" -#include "components/scheduler/scheduler_export.h" -#include "third_party/WebKit/public/platform/WebThread.h" -#include "third_party/WebKit/public/platform/WebTraceLocation.h" - -namespace scheduler { -class SingleThreadIdleTaskRunner; - -class SCHEDULER_EXPORT WebThreadBase : public blink::WebThread { - public: - ~WebThreadBase() override; - - // blink::WebThread implementation. - bool isCurrentThread() const override; - blink::PlatformThreadId threadId() const override = 0; - - virtual void postIdleTask(const blink::WebTraceLocation& location, - IdleTask* idle_task); - virtual void postIdleTaskAfterWakeup(const blink::WebTraceLocation& location, - IdleTask* idle_task); - - void addTaskObserver(TaskObserver* observer) override; - void removeTaskObserver(TaskObserver* observer) override; - - // Returns the base::Bind-compatible task runner for posting tasks to this - // thread. Can be called from any thread. - virtual base::SingleThreadTaskRunner* GetTaskRunner() const = 0; - - // Returns the base::Bind-compatible task runner for posting idle tasks to - // this thread. Can be called from any thread. - virtual scheduler::SingleThreadIdleTaskRunner* GetIdleTaskRunner() const = 0; - - protected: - class TaskObserverAdapter; - - WebThreadBase(); - - virtual void AddTaskObserverInternal( - base::MessageLoop::TaskObserver* observer); - virtual void RemoveTaskObserverInternal( - base::MessageLoop::TaskObserver* observer); - - static void RunWebThreadIdleTask( - std::unique_ptr<blink::WebThread::IdleTask> idle_task, - base::TimeTicks deadline); - - private: - typedef std::map<TaskObserver*, TaskObserverAdapter*> TaskObserverMap; - TaskObserverMap task_observer_map_; -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_CHILD_WEBTHREAD_BASE_H_
diff --git a/components/scheduler/child/webthread_impl_for_worker_scheduler.cc b/components/scheduler/child/webthread_impl_for_worker_scheduler.cc deleted file mode 100644 index ff7ec33..0000000 --- a/components/scheduler/child/webthread_impl_for_worker_scheduler.cc +++ /dev/null
@@ -1,129 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/child/webthread_impl_for_worker_scheduler.h" - -#include "base/bind.h" -#include "base/location.h" -#include "base/memory/ptr_util.h" -#include "base/single_thread_task_runner.h" -#include "base/synchronization/waitable_event.h" -#include "base/time/default_tick_clock.h" -#include "components/scheduler/base/task_queue.h" -#include "components/scheduler/child/scheduler_tqm_delegate_impl.h" -#include "components/scheduler/child/web_scheduler_impl.h" -#include "components/scheduler/child/web_task_runner_impl.h" -#include "components/scheduler/child/worker_scheduler_impl.h" -#include "third_party/WebKit/public/platform/WebTraceLocation.h" - -namespace scheduler { - -WebThreadImplForWorkerScheduler::WebThreadImplForWorkerScheduler( - const char* name) - : WebThreadImplForWorkerScheduler(name, base::Thread::Options()) {} - -WebThreadImplForWorkerScheduler::WebThreadImplForWorkerScheduler( - const char* name, - base::Thread::Options options) - : thread_(new base::Thread(name ? name : std::string())) { - bool started = thread_->StartWithOptions(options); - CHECK(started); - thread_task_runner_ = thread_->task_runner(); -} - -void WebThreadImplForWorkerScheduler::Init() { - base::WaitableEvent completion( - base::WaitableEvent::ResetPolicy::AUTOMATIC, - base::WaitableEvent::InitialState::NOT_SIGNALED); - thread_task_runner_->PostTask( - FROM_HERE, base::Bind(&WebThreadImplForWorkerScheduler::InitOnThread, - base::Unretained(this), &completion)); - completion.Wait(); -} - -WebThreadImplForWorkerScheduler::~WebThreadImplForWorkerScheduler() { - if (task_runner_delegate_) { - base::WaitableEvent completion( - base::WaitableEvent::ResetPolicy::AUTOMATIC, - base::WaitableEvent::InitialState::NOT_SIGNALED); - // Restore the original task runner so that the thread can tear itself down. - thread_task_runner_->PostTask( - FROM_HERE, - base::Bind(&WebThreadImplForWorkerScheduler::RestoreTaskRunnerOnThread, - base::Unretained(this), &completion)); - completion.Wait(); - } - thread_->Stop(); -} - -void WebThreadImplForWorkerScheduler::InitOnThread( - base::WaitableEvent* completion) { - // TODO(alexclarke): Do we need to unify virtual time for workers and the - // main thread? - worker_scheduler_ = CreateWorkerScheduler(); - worker_scheduler_->Init(); - task_runner_ = worker_scheduler_->DefaultTaskRunner(); - idle_task_runner_ = worker_scheduler_->IdleTaskRunner(); - web_scheduler_.reset(new WebSchedulerImpl( - worker_scheduler_.get(), worker_scheduler_->IdleTaskRunner(), - worker_scheduler_->DefaultTaskRunner(), - worker_scheduler_->DefaultTaskRunner())); - base::MessageLoop::current()->AddDestructionObserver(this); - web_task_runner_ = base::WrapUnique(new WebTaskRunnerImpl(task_runner_)); - completion->Signal(); -} - -void WebThreadImplForWorkerScheduler::RestoreTaskRunnerOnThread( - base::WaitableEvent* completion) { - task_runner_delegate_->RestoreDefaultTaskRunner(); - completion->Signal(); -} - -void WebThreadImplForWorkerScheduler::WillDestroyCurrentMessageLoop() { - task_runner_ = nullptr; - idle_task_runner_ = nullptr; - web_scheduler_.reset(); - worker_scheduler_.reset(); -} - -std::unique_ptr<scheduler::WorkerScheduler> -WebThreadImplForWorkerScheduler::CreateWorkerScheduler() { - task_runner_delegate_ = SchedulerTqmDelegateImpl::Create( - thread_->message_loop(), base::WrapUnique(new base::DefaultTickClock())); - return WorkerScheduler::Create(task_runner_delegate_); -} - -blink::PlatformThreadId WebThreadImplForWorkerScheduler::threadId() const { - return thread_->GetThreadId(); -} - -blink::WebScheduler* WebThreadImplForWorkerScheduler::scheduler() const { - return web_scheduler_.get(); -} - -base::SingleThreadTaskRunner* WebThreadImplForWorkerScheduler::GetTaskRunner() - const { - return task_runner_.get(); -} - -SingleThreadIdleTaskRunner* WebThreadImplForWorkerScheduler::GetIdleTaskRunner() - const { - return idle_task_runner_.get(); -} - -blink::WebTaskRunner* WebThreadImplForWorkerScheduler::getWebTaskRunner() { - return web_task_runner_.get(); -} - -void WebThreadImplForWorkerScheduler::AddTaskObserverInternal( - base::MessageLoop::TaskObserver* observer) { - worker_scheduler_->AddTaskObserver(observer); -} - -void WebThreadImplForWorkerScheduler::RemoveTaskObserverInternal( - base::MessageLoop::TaskObserver* observer) { - worker_scheduler_->RemoveTaskObserver(observer); -} - -} // namespace scheduler
diff --git a/components/scheduler/child/webthread_impl_for_worker_scheduler.h b/components/scheduler/child/webthread_impl_for_worker_scheduler.h deleted file mode 100644 index e2e3b3c..0000000 --- a/components/scheduler/child/webthread_impl_for_worker_scheduler.h +++ /dev/null
@@ -1,77 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_CHILD_WEBTHREAD_IMPL_FOR_WORKER_SCHEDULER_H_ -#define COMPONENTS_SCHEDULER_CHILD_WEBTHREAD_IMPL_FOR_WORKER_SCHEDULER_H_ - -#include "base/threading/thread.h" -#include "components/scheduler/base/task_queue_manager.h" -#include "components/scheduler/child/webthread_base.h" - -namespace base { -class WaitableEvent; -}; - -namespace blink { -class WebScheduler; -}; - -namespace scheduler { -class SchedulerTqmDelegate; -class SingleThreadIdleTaskRunner; -class TaskQueue; -class WebSchedulerImpl; -class WebTaskRunnerImpl; -class WorkerScheduler; - -class SCHEDULER_EXPORT WebThreadImplForWorkerScheduler - : public WebThreadBase, - public base::MessageLoop::DestructionObserver { - public: - explicit WebThreadImplForWorkerScheduler(const char* name); - WebThreadImplForWorkerScheduler(const char* name, - base::Thread::Options options); - ~WebThreadImplForWorkerScheduler() override; - - void Init(); - - // blink::WebThread implementation. - blink::WebScheduler* scheduler() const override; - blink::PlatformThreadId threadId() const override; - blink::WebTaskRunner* getWebTaskRunner() override; - - // WebThreadBase implementation. - base::SingleThreadTaskRunner* GetTaskRunner() const override; - scheduler::SingleThreadIdleTaskRunner* GetIdleTaskRunner() const override; - - // base::MessageLoop::DestructionObserver implementation. - void WillDestroyCurrentMessageLoop() override; - - protected: - base::Thread* thread() const { return thread_.get(); } - - private: - virtual std::unique_ptr<scheduler::WorkerScheduler> CreateWorkerScheduler(); - - void AddTaskObserverInternal( - base::MessageLoop::TaskObserver* observer) override; - void RemoveTaskObserverInternal( - base::MessageLoop::TaskObserver* observer) override; - - void InitOnThread(base::WaitableEvent* completion); - void RestoreTaskRunnerOnThread(base::WaitableEvent* completion); - - std::unique_ptr<base::Thread> thread_; - std::unique_ptr<scheduler::WorkerScheduler> worker_scheduler_; - std::unique_ptr<scheduler::WebSchedulerImpl> web_scheduler_; - scoped_refptr<base::SingleThreadTaskRunner> thread_task_runner_; - scoped_refptr<TaskQueue> task_runner_; - scoped_refptr<scheduler::SingleThreadIdleTaskRunner> idle_task_runner_; - scoped_refptr<SchedulerTqmDelegate> task_runner_delegate_; - std::unique_ptr<WebTaskRunnerImpl> web_task_runner_; -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_CHILD_WEBTHREAD_IMPL_FOR_WORKER_SCHEDULER_H_
diff --git a/components/scheduler/child/webthread_impl_for_worker_scheduler_unittest.cc b/components/scheduler/child/webthread_impl_for_worker_scheduler_unittest.cc deleted file mode 100644 index 13a777b..0000000 --- a/components/scheduler/child/webthread_impl_for_worker_scheduler_unittest.cc +++ /dev/null
@@ -1,206 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/child/webthread_impl_for_worker_scheduler.h" - -#include "base/macros.h" -#include "base/synchronization/waitable_event.h" -#include "components/scheduler/child/web_scheduler_impl.h" -#include "components/scheduler/child/worker_scheduler_impl.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/WebKit/public/platform/WebTraceLocation.h" - -using testing::_; -using testing::AnyOf; -using testing::ElementsAre; -using testing::Invoke; - -namespace scheduler { -namespace { - -class NopTask : public blink::WebTaskRunner::Task { - public: - ~NopTask() override {} - - void run() override {} -}; - -class MockTask : public blink::WebTaskRunner::Task { - public: - ~MockTask() override {} - - MOCK_METHOD0(run, void()); -}; - -class MockIdleTask : public blink::WebThread::IdleTask { - public: - ~MockIdleTask() override {} - - MOCK_METHOD1(run, void(double deadline)); -}; - -class TestObserver : public blink::WebThread::TaskObserver { - public: - explicit TestObserver(std::string* calls) : calls_(calls) {} - - ~TestObserver() override {} - - void willProcessTask() override { calls_->append(" willProcessTask"); } - - void didProcessTask() override { calls_->append(" didProcessTask"); } - - private: - std::string* calls_; // NOT OWNED -}; - -class TestTask : public blink::WebTaskRunner::Task { - public: - explicit TestTask(std::string* calls) : calls_(calls) {} - - ~TestTask() override {} - - void run() override { calls_->append(" run"); } - - private: - std::string* calls_; // NOT OWNED -}; - -void addTaskObserver(WebThreadImplForWorkerScheduler* thread, - TestObserver* observer) { - thread->addTaskObserver(observer); -} - -void removeTaskObserver(WebThreadImplForWorkerScheduler* thread, - TestObserver* observer) { - thread->removeTaskObserver(observer); -} - -void shutdownOnThread(WebThreadImplForWorkerScheduler* thread) { - WebSchedulerImpl* web_scheduler_impl = - static_cast<WebSchedulerImpl*>(thread->scheduler()); - web_scheduler_impl->shutdown(); -} - -} // namespace - -class WebThreadImplForWorkerSchedulerTest : public testing::Test { - public: - WebThreadImplForWorkerSchedulerTest() {} - - ~WebThreadImplForWorkerSchedulerTest() override {} - - void SetUp() override { - thread_.reset(new WebThreadImplForWorkerScheduler("test thread")); - thread_->Init(); - } - - void RunOnWorkerThread(const tracked_objects::Location& from_here, - const base::Closure& task) { - base::WaitableEvent completion( - base::WaitableEvent::ResetPolicy::AUTOMATIC, - base::WaitableEvent::InitialState::NOT_SIGNALED); - thread_->GetTaskRunner()->PostTask( - from_here, - base::Bind(&WebThreadImplForWorkerSchedulerTest::RunOnWorkerThreadTask, - base::Unretained(this), task, &completion)); - completion.Wait(); - } - - protected: - void RunOnWorkerThreadTask(const base::Closure& task, - base::WaitableEvent* completion) { - task.Run(); - completion->Signal(); - } - - std::unique_ptr<WebThreadImplForWorkerScheduler> thread_; - - DISALLOW_COPY_AND_ASSIGN(WebThreadImplForWorkerSchedulerTest); -}; - -TEST_F(WebThreadImplForWorkerSchedulerTest, TestDefaultTask) { - std::unique_ptr<MockTask> task(new MockTask()); - base::WaitableEvent completion( - base::WaitableEvent::ResetPolicy::AUTOMATIC, - base::WaitableEvent::InitialState::NOT_SIGNALED); - - EXPECT_CALL(*task, run()); - ON_CALL(*task, run()) - .WillByDefault(Invoke([&completion]() { completion.Signal(); })); - - thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(), - task.release()); - completion.Wait(); -} - -TEST_F(WebThreadImplForWorkerSchedulerTest, - TestTaskExecutedBeforeThreadDeletion) { - std::unique_ptr<MockTask> task(new MockTask()); - base::WaitableEvent completion( - base::WaitableEvent::ResetPolicy::AUTOMATIC, - base::WaitableEvent::InitialState::NOT_SIGNALED); - - EXPECT_CALL(*task, run()); - ON_CALL(*task, run()) - .WillByDefault(Invoke([&completion]() { completion.Signal(); })); - - thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(), - task.release()); - thread_.reset(); -} - -TEST_F(WebThreadImplForWorkerSchedulerTest, TestIdleTask) { - std::unique_ptr<MockIdleTask> task(new MockIdleTask()); - base::WaitableEvent completion( - base::WaitableEvent::ResetPolicy::AUTOMATIC, - base::WaitableEvent::InitialState::NOT_SIGNALED); - - EXPECT_CALL(*task, run(_)); - ON_CALL(*task, run(_)) - .WillByDefault(Invoke([&completion](double) { completion.Signal(); })); - - thread_->postIdleTask(blink::WebTraceLocation(), task.release()); - // We need to post a wakeup task or idle work will never happen. - thread_->getWebTaskRunner()->postDelayedTask(blink::WebTraceLocation(), - new NopTask(), 50ll); - - completion.Wait(); -} - -TEST_F(WebThreadImplForWorkerSchedulerTest, TestTaskObserver) { - std::string calls; - TestObserver observer(&calls); - - RunOnWorkerThread(FROM_HERE, - base::Bind(&addTaskObserver, thread_.get(), &observer)); - thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(), - new TestTask(&calls)); - RunOnWorkerThread(FROM_HERE, - base::Bind(&removeTaskObserver, thread_.get(), &observer)); - - // We need to be careful what we test here. We want to make sure the - // observers are un in the expected order before and after the task. - // Sometimes we get an internal scheduler task running before or after - // TestTask as well. This is not a bug, and we need to make sure the test - // doesn't fail when that happens. - EXPECT_THAT(calls, testing::HasSubstr("willProcessTask run didProcessTask")); -} - -TEST_F(WebThreadImplForWorkerSchedulerTest, TestShutdown) { - std::unique_ptr<MockTask> task(new MockTask()); - std::unique_ptr<MockTask> delayed_task(new MockTask()); - - EXPECT_CALL(*task, run()).Times(0); - EXPECT_CALL(*delayed_task, run()).Times(0); - - RunOnWorkerThread(FROM_HERE, base::Bind(&shutdownOnThread, thread_.get())); - thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(), - task.release()); - thread_->getWebTaskRunner()->postDelayedTask(blink::WebTraceLocation(), - task.release(), 50ll); - thread_.reset(); -} - -} // namespace scheduler
diff --git a/components/scheduler/child/worker_scheduler.cc b/components/scheduler/child/worker_scheduler.cc deleted file mode 100644 index 1bf3cb0..0000000 --- a/components/scheduler/child/worker_scheduler.cc +++ /dev/null
@@ -1,28 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/child/worker_scheduler.h" - -#include <utility> - -#include "base/memory/ptr_util.h" -#include "base/message_loop/message_loop.h" -#include "components/scheduler/child/scheduler_tqm_delegate.h" -#include "components/scheduler/child/worker_scheduler_impl.h" - -namespace scheduler { - -WorkerScheduler::WorkerScheduler() { -} - -WorkerScheduler::~WorkerScheduler() { -} - -// static -std::unique_ptr<WorkerScheduler> WorkerScheduler::Create( - scoped_refptr<SchedulerTqmDelegate> main_task_runner) { - return base::WrapUnique(new WorkerSchedulerImpl(std::move(main_task_runner))); -} - -} // namespace scheduler
diff --git a/components/scheduler/child/worker_scheduler.h b/components/scheduler/child/worker_scheduler.h deleted file mode 100644 index 076b5385..0000000 --- a/components/scheduler/child/worker_scheduler.h +++ /dev/null
@@ -1,40 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_CHILD_WORKER_SCHEDULER_H_ -#define COMPONENTS_SCHEDULER_CHILD_WORKER_SCHEDULER_H_ - -#include <memory> - -#include "base/macros.h" -#include "base/message_loop/message_loop.h" -#include "components/scheduler/child/child_scheduler.h" -#include "components/scheduler/child/single_thread_idle_task_runner.h" -#include "components/scheduler/scheduler_export.h" - -namespace base { -class MessageLoop; -} - -namespace scheduler { -class SchedulerTqmDelegate; - -class SCHEDULER_EXPORT WorkerScheduler : public ChildScheduler { - public: - ~WorkerScheduler() override; - static std::unique_ptr<WorkerScheduler> Create( - scoped_refptr<SchedulerTqmDelegate> main_task_runner); - - // Must be called before the scheduler can be used. Does any post construction - // initialization needed such as initializing idle period detection. - virtual void Init() = 0; - - protected: - WorkerScheduler(); - DISALLOW_COPY_AND_ASSIGN(WorkerScheduler); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_CHILD_WORKER_SCHEDULER_H_
diff --git a/components/scheduler/child/worker_scheduler_impl.cc b/components/scheduler/child/worker_scheduler_impl.cc deleted file mode 100644 index e74328d..0000000 --- a/components/scheduler/child/worker_scheduler_impl.cc +++ /dev/null
@@ -1,93 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/child/worker_scheduler_impl.h" - -#include "base/bind.h" -#include "base/trace_event/trace_event.h" -#include "base/trace_event/trace_event_argument.h" -#include "components/scheduler/base/task_queue.h" -#include "components/scheduler/child/scheduler_tqm_delegate.h" - -namespace scheduler { - -WorkerSchedulerImpl::WorkerSchedulerImpl( - scoped_refptr<SchedulerTqmDelegate> main_task_runner) - : helper_(main_task_runner, - "worker.scheduler", - TRACE_DISABLED_BY_DEFAULT("worker.scheduler"), - TRACE_DISABLED_BY_DEFAULT("worker.scheduler.debug")), - idle_helper_(&helper_, - this, - "worker.scheduler", - TRACE_DISABLED_BY_DEFAULT("worker.scheduler"), - "WorkerSchedulerIdlePeriod", - base::TimeDelta::FromMilliseconds(300)) { - initialized_ = false; - TRACE_EVENT_OBJECT_CREATED_WITH_ID( - TRACE_DISABLED_BY_DEFAULT("worker.scheduler"), "WorkerScheduler", this); -} - -WorkerSchedulerImpl::~WorkerSchedulerImpl() { - TRACE_EVENT_OBJECT_DELETED_WITH_ID( - TRACE_DISABLED_BY_DEFAULT("worker.scheduler"), "WorkerScheduler", this); -} - -void WorkerSchedulerImpl::Init() { - initialized_ = true; - idle_helper_.EnableLongIdlePeriod(); -} - -scoped_refptr<TaskQueue> WorkerSchedulerImpl::DefaultTaskRunner() { - DCHECK(initialized_); - return helper_.DefaultTaskRunner(); -} - -scoped_refptr<SingleThreadIdleTaskRunner> -WorkerSchedulerImpl::IdleTaskRunner() { - DCHECK(initialized_); - return idle_helper_.IdleTaskRunner(); -} - -bool WorkerSchedulerImpl::CanExceedIdleDeadlineIfRequired() const { - DCHECK(initialized_); - return idle_helper_.CanExceedIdleDeadlineIfRequired(); -} - -bool WorkerSchedulerImpl::ShouldYieldForHighPriorityWork() { - // We don't consider any work as being high priority on workers. - return false; -} - -void WorkerSchedulerImpl::AddTaskObserver( - base::MessageLoop::TaskObserver* task_observer) { - DCHECK(initialized_); - helper_.AddTaskObserver(task_observer); -} - -void WorkerSchedulerImpl::RemoveTaskObserver( - base::MessageLoop::TaskObserver* task_observer) { - DCHECK(initialized_); - helper_.RemoveTaskObserver(task_observer); -} - -void WorkerSchedulerImpl::Shutdown() { - DCHECK(initialized_); - helper_.Shutdown(); -} - -SchedulerHelper* WorkerSchedulerImpl::GetSchedulerHelperForTesting() { - return &helper_; -} - -bool WorkerSchedulerImpl::CanEnterLongIdlePeriod(base::TimeTicks, - base::TimeDelta*) { - return true; -} - -base::TimeTicks WorkerSchedulerImpl::CurrentIdleTaskDeadlineForTesting() const { - return idle_helper_.CurrentIdleTaskDeadline(); -} - -} // namespace scheduler
diff --git a/components/scheduler/child/worker_scheduler_impl.h b/components/scheduler/child/worker_scheduler_impl.h deleted file mode 100644 index 83446cf..0000000 --- a/components/scheduler/child/worker_scheduler_impl.h +++ /dev/null
@@ -1,66 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_CHILD_WORKER_SCHEDULER_IMPL_H_ -#define COMPONENTS_SCHEDULER_CHILD_WORKER_SCHEDULER_IMPL_H_ - -#include "base/macros.h" -#include "components/scheduler/child/idle_helper.h" -#include "components/scheduler/child/scheduler_helper.h" -#include "components/scheduler/child/worker_scheduler.h" -#include "components/scheduler/scheduler_export.h" - -namespace base { -namespace trace_event { -class ConvertableToTraceFormat; -} -} - -namespace scheduler { - -class SchedulerTqmDelegate; - -class SCHEDULER_EXPORT WorkerSchedulerImpl : public WorkerScheduler, - public IdleHelper::Delegate { - public: - explicit WorkerSchedulerImpl( - scoped_refptr<SchedulerTqmDelegate> main_task_runner); - ~WorkerSchedulerImpl() override; - - // WorkerScheduler implementation: - scoped_refptr<TaskQueue> DefaultTaskRunner() override; - scoped_refptr<SingleThreadIdleTaskRunner> IdleTaskRunner() override; - bool CanExceedIdleDeadlineIfRequired() const override; - bool ShouldYieldForHighPriorityWork() override; - void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer) override; - void RemoveTaskObserver( - base::MessageLoop::TaskObserver* task_observer) override; - void Init() override; - void Shutdown() override; - - SchedulerHelper* GetSchedulerHelperForTesting(); - base::TimeTicks CurrentIdleTaskDeadlineForTesting() const; - - protected: - // IdleHelper::Delegate implementation: - bool CanEnterLongIdlePeriod( - base::TimeTicks now, - base::TimeDelta* next_long_idle_period_delay_out) override; - void IsNotQuiescent() override {} - void OnIdlePeriodStarted() override {} - void OnIdlePeriodEnded() override {} - - private: - void MaybeStartLongIdlePeriod(); - - SchedulerHelper helper_; - IdleHelper idle_helper_; - bool initialized_; - - DISALLOW_COPY_AND_ASSIGN(WorkerSchedulerImpl); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_CHILD_WORKER_SCHEDULER_IMPL_H_
diff --git a/components/scheduler/child/worker_scheduler_impl_unittest.cc b/components/scheduler/child/worker_scheduler_impl_unittest.cc deleted file mode 100644 index c5ff4a62..0000000 --- a/components/scheduler/child/worker_scheduler_impl_unittest.cc +++ /dev/null
@@ -1,385 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/child/worker_scheduler_impl.h" - -#include "base/callback.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/strings/stringprintf.h" -#include "base/test/simple_test_tick_clock.h" -#include "cc/test/ordered_simple_task_runner.h" -#include "components/scheduler/base/test_time_source.h" -#include "components/scheduler/child/scheduler_tqm_delegate_for_test.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using testing::ElementsAreArray; - -namespace scheduler { - -namespace { -void NopTask() { -} - -int TimeTicksToIntMs(const base::TimeTicks& time) { - return static_cast<int>((time - base::TimeTicks()).InMilliseconds()); -} - -void RecordTimelineTask(std::vector<std::string>* timeline, - base::SimpleTestTickClock* clock) { - timeline->push_back(base::StringPrintf("run RecordTimelineTask @ %d", - TimeTicksToIntMs(clock->NowTicks()))); -} - -void AppendToVectorTestTask(std::vector<std::string>* vector, - std::string value) { - vector->push_back(value); -} - -void AppendToVectorIdleTestTask(std::vector<std::string>* vector, - std::string value, - base::TimeTicks deadline) { - AppendToVectorTestTask(vector, value); -} - -void TimelineIdleTestTask(std::vector<std::string>* timeline, - base::TimeTicks deadline) { - timeline->push_back(base::StringPrintf("run TimelineIdleTestTask deadline %d", - TimeTicksToIntMs(deadline))); -} - -}; // namespace - -class WorkerSchedulerImplForTest : public WorkerSchedulerImpl { - public: - WorkerSchedulerImplForTest( - scoped_refptr<SchedulerTqmDelegate> main_task_runner, - base::SimpleTestTickClock* clock_) - : WorkerSchedulerImpl(main_task_runner), - clock_(clock_), - timeline_(nullptr) {} - - void RecordTimelineEvents(std::vector<std::string>* timeline) { - timeline_ = timeline; - } - - private: - bool CanEnterLongIdlePeriod( - base::TimeTicks now, - base::TimeDelta* next_long_idle_period_delay_out) override { - if (timeline_) { - timeline_->push_back(base::StringPrintf("CanEnterLongIdlePeriod @ %d", - TimeTicksToIntMs(now))); - } - return WorkerSchedulerImpl::CanEnterLongIdlePeriod( - now, next_long_idle_period_delay_out); - } - - void IsNotQuiescent() override { - if (timeline_) { - timeline_->push_back(base::StringPrintf( - "IsNotQuiescent @ %d", TimeTicksToIntMs(clock_->NowTicks()))); - } - WorkerSchedulerImpl::IsNotQuiescent(); - } - - base::SimpleTestTickClock* clock_; // NOT OWNED - std::vector<std::string>* timeline_; // NOT OWNED -}; - -class WorkerSchedulerImplTest : public testing::Test { - public: - WorkerSchedulerImplTest() - : clock_(new base::SimpleTestTickClock()), - mock_task_runner_(new cc::OrderedSimpleTaskRunner(clock_.get(), true)), - main_task_runner_(SchedulerTqmDelegateForTest::Create( - mock_task_runner_, - base::WrapUnique(new TestTimeSource(clock_.get())))), - scheduler_( - new WorkerSchedulerImplForTest(main_task_runner_, clock_.get())), - timeline_(nullptr) { - clock_->Advance(base::TimeDelta::FromMicroseconds(5000)); - } - - ~WorkerSchedulerImplTest() override {} - - void TearDown() override { - // Check that all tests stop posting tasks. - while (mock_task_runner_->RunUntilIdle()) { - } - } - - void Init() { - scheduler_->Init(); - default_task_runner_ = scheduler_->DefaultTaskRunner(); - idle_task_runner_ = scheduler_->IdleTaskRunner(); - timeline_ = nullptr; - } - - void RecordTimelineEvents(std::vector<std::string>* timeline) { - timeline_ = timeline; - scheduler_->RecordTimelineEvents(timeline); - } - - void RunUntilIdle() { - if (timeline_) { - timeline_->push_back(base::StringPrintf( - "RunUntilIdle begin @ %d", TimeTicksToIntMs(clock_->NowTicks()))); - } - mock_task_runner_->RunUntilIdle(); - if (timeline_) { - timeline_->push_back(base::StringPrintf( - "RunUntilIdle end @ %d", TimeTicksToIntMs(clock_->NowTicks()))); - } - } - - // Helper for posting several tasks of specific types. |task_descriptor| is a - // string with space delimited task identifiers. The first letter of each - // task identifier specifies the task type: - // - 'D': Default task - // - 'I': Idle task - void PostTestTasks(std::vector<std::string>* run_order, - const std::string& task_descriptor) { - std::istringstream stream(task_descriptor); - while (!stream.eof()) { - std::string task; - stream >> task; - switch (task[0]) { - case 'D': - default_task_runner_->PostTask( - FROM_HERE, base::Bind(&AppendToVectorTestTask, run_order, task)); - break; - case 'I': - idle_task_runner_->PostIdleTask( - FROM_HERE, - base::Bind(&AppendToVectorIdleTestTask, run_order, task)); - break; - default: - NOTREACHED(); - } - } - } - - static base::TimeDelta maximum_idle_period_duration() { - return base::TimeDelta::FromMilliseconds( - IdleHelper::kMaximumIdlePeriodMillis); - } - - protected: - std::unique_ptr<base::SimpleTestTickClock> clock_; - // Only one of mock_task_runner_ or message_loop_ will be set. - scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_; - - scoped_refptr<SchedulerTqmDelegate> main_task_runner_; - std::unique_ptr<WorkerSchedulerImplForTest> scheduler_; - scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_; - scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_; - std::vector<std::string>* timeline_; // NOT OWNED - - DISALLOW_COPY_AND_ASSIGN(WorkerSchedulerImplTest); -}; - -TEST_F(WorkerSchedulerImplTest, TestPostDefaultTask) { - Init(); - - std::vector<std::string> run_order; - PostTestTasks(&run_order, "D1 D2 D3 D4"); - - RunUntilIdle(); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("D1"), std::string("D2"), - std::string("D3"), std::string("D4"))); -} - -TEST_F(WorkerSchedulerImplTest, TestPostIdleTask) { - Init(); - - std::vector<std::string> run_order; - PostTestTasks(&run_order, "I1"); - - RunUntilIdle(); - EXPECT_THAT(run_order, testing::ElementsAre(std::string("I1"))); -} - -TEST_F(WorkerSchedulerImplTest, TestPostDefaultAndIdleTasks) { - Init(); - - std::vector<std::string> run_order; - PostTestTasks(&run_order, "I1 D2 D3 D4"); - - RunUntilIdle(); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("D2"), std::string("D3"), - std::string("D4"), std::string("I1"))); -} - -TEST_F(WorkerSchedulerImplTest, TestPostDefaultDelayedAndIdleTasks) { - Init(); - - std::vector<std::string> run_order; - PostTestTasks(&run_order, "I1 D2 D3 D4"); - - default_task_runner_->PostDelayedTask( - FROM_HERE, base::Bind(&AppendToVectorTestTask, &run_order, "DELAYED"), - base::TimeDelta::FromMilliseconds(1000)); - - RunUntilIdle(); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("D2"), std::string("D3"), - std::string("D4"), std::string("I1"), - std::string("DELAYED"))); -} - -TEST_F(WorkerSchedulerImplTest, TestIdleTaskWhenIsNotQuiescent) { - std::vector<std::string> timeline; - RecordTimelineEvents(&timeline); - Init(); - - timeline.push_back("Post default task"); - // Post a delayed task timed to occur mid way during the long idle period. - default_task_runner_->PostTask( - FROM_HERE, base::Bind(&RecordTimelineTask, base::Unretained(&timeline), - base::Unretained(clock_.get()))); - RunUntilIdle(); - - timeline.push_back("Post idle task"); - idle_task_runner_->PostIdleTask(FROM_HERE, - base::Bind(&TimelineIdleTestTask, &timeline)); - - RunUntilIdle(); - - std::string expected_timeline[] = {"CanEnterLongIdlePeriod @ 5", - "Post default task", - "run RecordTimelineTask @ 5", - "Post idle task", - "IsNotQuiescent @ 5", - "CanEnterLongIdlePeriod @ 305", - "run TimelineIdleTestTask deadline 355"}; - - EXPECT_THAT(timeline, ElementsAreArray(expected_timeline)); -} - -TEST_F(WorkerSchedulerImplTest, TestIdleDeadlineWithPendingDelayedTask) { - std::vector<std::string> timeline; - RecordTimelineEvents(&timeline); - Init(); - - timeline.push_back("Post delayed and idle tasks"); - // Post a delayed task timed to occur mid way during the long idle period. - default_task_runner_->PostDelayedTask( - FROM_HERE, base::Bind(&RecordTimelineTask, base::Unretained(&timeline), - base::Unretained(clock_.get())), - base::TimeDelta::FromMilliseconds(20)); - idle_task_runner_->PostIdleTask(FROM_HERE, - base::Bind(&TimelineIdleTestTask, &timeline)); - - RunUntilIdle(); - - std::string expected_timeline[] = { - "CanEnterLongIdlePeriod @ 5", - "Post delayed and idle tasks", - "CanEnterLongIdlePeriod @ 5", - "run TimelineIdleTestTask deadline 25", // Note the short 20ms deadline. - "run RecordTimelineTask @ 25"}; - - EXPECT_THAT(timeline, ElementsAreArray(expected_timeline)); -} - -TEST_F(WorkerSchedulerImplTest, - TestIdleDeadlineWithPendingDelayedTaskFarInTheFuture) { - std::vector<std::string> timeline; - RecordTimelineEvents(&timeline); - Init(); - - timeline.push_back("Post delayed and idle tasks"); - // Post a delayed task timed to occur well after the long idle period. - default_task_runner_->PostDelayedTask( - FROM_HERE, base::Bind(&RecordTimelineTask, base::Unretained(&timeline), - base::Unretained(clock_.get())), - base::TimeDelta::FromMilliseconds(500)); - idle_task_runner_->PostIdleTask(FROM_HERE, - base::Bind(&TimelineIdleTestTask, &timeline)); - - RunUntilIdle(); - - std::string expected_timeline[] = { - "CanEnterLongIdlePeriod @ 5", - "Post delayed and idle tasks", - "CanEnterLongIdlePeriod @ 5", - "run TimelineIdleTestTask deadline 55", // Note the full 50ms deadline. - "run RecordTimelineTask @ 505"}; - - EXPECT_THAT(timeline, ElementsAreArray(expected_timeline)); -} - -TEST_F(WorkerSchedulerImplTest, TestPostIdleTaskAfterRunningUntilIdle) { - Init(); - - default_task_runner_->PostDelayedTask( - FROM_HERE, base::Bind(&NopTask), base::TimeDelta::FromMilliseconds(1000)); - RunUntilIdle(); - - std::vector<std::string> run_order; - PostTestTasks(&run_order, "I1 I2 D3"); - - RunUntilIdle(); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("D3"), std::string("I1"), - std::string("I2"))); -} - -TEST_F(WorkerSchedulerImplTest, TestLongIdlePeriodTimeline) { - Init(); - - std::vector<std::string> timeline; - RecordTimelineEvents(&timeline); - - // The scheduler should not run the initiate_next_long_idle_period task if - // there are no idle tasks and no other task woke up the scheduler, thus - // the idle period deadline shouldn't update at the end of the current long - // idle period. - base::TimeTicks idle_period_deadline = - scheduler_->CurrentIdleTaskDeadlineForTesting(); - clock_->Advance(maximum_idle_period_duration()); - RunUntilIdle(); - - base::TimeTicks new_idle_period_deadline = - scheduler_->CurrentIdleTaskDeadlineForTesting(); - EXPECT_EQ(idle_period_deadline, new_idle_period_deadline); - - // Posting a after-wakeup idle task also shouldn't wake the scheduler or - // initiate the next long idle period. - timeline.push_back("PostIdleTaskAfterWakeup"); - idle_task_runner_->PostIdleTaskAfterWakeup( - FROM_HERE, base::Bind(&TimelineIdleTestTask, &timeline)); - RunUntilIdle(); - new_idle_period_deadline = scheduler_->CurrentIdleTaskDeadlineForTesting(); - - // Running a normal task should initiate a new long idle period after waiting - // 300ms for quiescence. - timeline.push_back("Post RecordTimelineTask"); - default_task_runner_->PostTask( - FROM_HERE, base::Bind(&RecordTimelineTask, base::Unretained(&timeline), - base::Unretained(clock_.get()))); - RunUntilIdle(); - - std::string expected_timeline[] = { - "RunUntilIdle begin @ 55", - "RunUntilIdle end @ 55", - "PostIdleTaskAfterWakeup", - "RunUntilIdle begin @ 55", // NOTE idle task doesn't run till later. - "RunUntilIdle end @ 55", - "Post RecordTimelineTask", - "RunUntilIdle begin @ 55", - "run RecordTimelineTask @ 55", - "IsNotQuiescent @ 55", // NOTE we have to wait for quiescence. - "CanEnterLongIdlePeriod @ 355", - "run TimelineIdleTestTask deadline 405", - "RunUntilIdle end @ 355"}; - - EXPECT_THAT(timeline, ElementsAreArray(expected_timeline)); -} - -} // namespace scheduler
diff --git a/components/scheduler/common/scheduler_switches.cc b/components/scheduler/common/scheduler_switches.cc deleted file mode 100644 index 8498ee70..0000000 --- a/components/scheduler/common/scheduler_switches.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 "components/scheduler/common/scheduler_switches.h" - -namespace scheduler { -namespace switches { - -// Disable task throttling of timer tasks from background pages. -const char kDisableBackgroundTimerThrottling[] = - "disable-background-timer-throttling"; - -} // namespace switches -} // namespace scheduler
diff --git a/components/scheduler/common/scheduler_switches.h b/components/scheduler/common/scheduler_switches.h deleted file mode 100644 index fd738e1..0000000 --- a/components/scheduler/common/scheduler_switches.h +++ /dev/null
@@ -1,16 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_COMMON_SCHEDULER_SWITCHES_H_ -#define COMPONENTS_SCHEDULER_COMMON_SCHEDULER_SWITCHES_H_ - -namespace scheduler { -namespace switches { - -extern const char kDisableBackgroundTimerThrottling[]; - -} // namespace switches -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_COMMON_SCHEDULER_SWITCHES_H_
diff --git a/components/scheduler/renderer/DEPS b/components/scheduler/renderer/DEPS deleted file mode 100644 index f278ea0a..0000000 --- a/components/scheduler/renderer/DEPS +++ /dev/null
@@ -1,18 +0,0 @@ -include_rules = [ - "+components/scheduler/base", - "+components/scheduler/child", - "+components/scheduler/common", - "+components/scheduler/scheduler_export.h", - "+cc/base", - "+cc/output", - "+ui/gfx", - "+third_party/WebKit/public/platform", - "+third_party/WebKit/public/web", - "+v8", -] - -specific_include_rules = { - ".*test\.cc": [ - "+cc/test", - ], -}
diff --git a/components/scheduler/renderer/auto_advancing_virtual_time_domain.cc b/components/scheduler/renderer/auto_advancing_virtual_time_domain.cc deleted file mode 100644 index 8d589a7..0000000 --- a/components/scheduler/renderer/auto_advancing_virtual_time_domain.cc +++ /dev/null
@@ -1,43 +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 "components/scheduler/renderer/auto_advancing_virtual_time_domain.h" - -namespace scheduler { - -AutoAdvancingVirtualTimeDomain::AutoAdvancingVirtualTimeDomain( - base::TimeTicks initial_time) - : VirtualTimeDomain(nullptr, initial_time), - can_advance_virtual_time_(true) {} - -AutoAdvancingVirtualTimeDomain::~AutoAdvancingVirtualTimeDomain() {} - -bool AutoAdvancingVirtualTimeDomain::MaybeAdvanceTime() { - base::TimeTicks run_time; - if (!can_advance_virtual_time_ || !NextScheduledRunTime(&run_time)) { - return false; - } - AdvanceTo(run_time); - return true; -} - -void AutoAdvancingVirtualTimeDomain::RequestWakeup(base::TimeTicks now, - base::TimeDelta delay) { - base::TimeTicks dummy; - if (can_advance_virtual_time_ && !NextScheduledRunTime(&dummy)) - RequestDoWork(); -} - -void AutoAdvancingVirtualTimeDomain::SetCanAdvanceVirtualTime( - bool can_advance_virtual_time) { - can_advance_virtual_time_ = can_advance_virtual_time; - if (can_advance_virtual_time_) - RequestDoWork(); -} - -const char* AutoAdvancingVirtualTimeDomain::GetName() const { - return "AutoAdvancingVirtualTimeDomain"; -} - -} // namespace scheduler
diff --git a/components/scheduler/renderer/auto_advancing_virtual_time_domain.h b/components/scheduler/renderer/auto_advancing_virtual_time_domain.h deleted file mode 100644 index 82b58d6..0000000 --- a/components/scheduler/renderer/auto_advancing_virtual_time_domain.h +++ /dev/null
@@ -1,45 +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 COMPONENTS_SCHEDULER_RENDERER_AUTO_ADVANCING_VIRTUAL_TIME_DOMAIN_H_ -#define COMPONENTS_SCHEDULER_RENDERER_AUTO_ADVANCING_VIRTUAL_TIME_DOMAIN_H_ - -#include "base/macros.h" -#include "components/scheduler/base/virtual_time_domain.h" - -namespace scheduler { - -// A time domain that runs tasks sequentially in time order but doesn't sleep -// between delayed tasks. -// -// KEY: A-E are delayed tasks -// | A B C D E (Execution with RealTimeDomain) -// |-----------------------------> time -// -// |ABCDE (Execution with AutoAdvancingVirtualTimeDomain) -// |-----------------------------> time -class SCHEDULER_EXPORT AutoAdvancingVirtualTimeDomain - : public VirtualTimeDomain { - public: - explicit AutoAdvancingVirtualTimeDomain(base::TimeTicks initial_time); - ~AutoAdvancingVirtualTimeDomain() override; - - // TimeDomain implementation: - bool MaybeAdvanceTime() override; - void RequestWakeup(base::TimeTicks now, base::TimeDelta delay) override; - const char* GetName() const override; - - // Controls whether or not virtual time is allowed to advance, when the - // TaskQueueManager runs out of immediate work to do. - void SetCanAdvanceVirtualTime(bool can_advance_virtual_time); - - private: - bool can_advance_virtual_time_; - - DISALLOW_COPY_AND_ASSIGN(AutoAdvancingVirtualTimeDomain); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_RENDERER_AUTO_ADVANCING_VIRTUAL_TIME_DOMAIN_H_
diff --git a/components/scheduler/renderer/auto_advancing_virtual_time_domain_unittest.cc b/components/scheduler/renderer/auto_advancing_virtual_time_domain_unittest.cc deleted file mode 100644 index 3ce01a71..0000000 --- a/components/scheduler/renderer/auto_advancing_virtual_time_domain_unittest.cc +++ /dev/null
@@ -1,98 +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 "components/scheduler/renderer/auto_advancing_virtual_time_domain.h" - -#include "base/memory/ptr_util.h" -#include "base/test/simple_test_tick_clock.h" -#include "cc/test/ordered_simple_task_runner.h" -#include "components/scheduler/base/task_queue_manager.h" -#include "components/scheduler/base/test_task_time_tracker.h" -#include "components/scheduler/base/test_time_source.h" -#include "components/scheduler/child/scheduler_tqm_delegate_for_test.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace scheduler { - -class AutoAdvancingVirtualTimeDomainTest : public testing::Test { - public: - AutoAdvancingVirtualTimeDomainTest() {} - ~AutoAdvancingVirtualTimeDomainTest() override {} - - void SetUp() override { - clock_.reset(new base::SimpleTestTickClock()); - clock_->Advance(base::TimeDelta::FromMicroseconds(5000)); - - test_time_source_.reset(new TestTimeSource(clock_.get())); - mock_task_runner_ = make_scoped_refptr( - new cc::OrderedSimpleTaskRunner(clock_.get(), false)); - main_task_runner_ = SchedulerTqmDelegateForTest::Create( - mock_task_runner_, base::WrapUnique(new TestTimeSource(clock_.get()))); - - manager_ = base::WrapUnique(new TaskQueueManager( - main_task_runner_, "test.scheduler", "test.scheduler", - "test.scheduler.debug")); - manager_->SetTaskTimeTracker(&test_task_time_tracker_); - task_runner_ = - manager_->NewTaskQueue(TaskQueue::Spec("test_task_queue")); - initial_time_= clock_->NowTicks(); - auto_advancing_time_domain_.reset( - new AutoAdvancingVirtualTimeDomain(initial_time_)); - manager_->RegisterTimeDomain(auto_advancing_time_domain_.get()); - task_runner_->SetTimeDomain(auto_advancing_time_domain_.get()); - } - - void TearDown() override { - task_runner_->UnregisterTaskQueue(); - manager_->UnregisterTimeDomain(auto_advancing_time_domain_.get()); - } - - base::TimeTicks initial_time_; - std::unique_ptr<base::SimpleTestTickClock> clock_; - std::unique_ptr<TestTimeSource> test_time_source_; - scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_; - scoped_refptr<SchedulerTqmDelegate> main_task_runner_; - std::unique_ptr<TaskQueueManager> manager_; - scoped_refptr<TaskQueue> task_runner_; - std::unique_ptr<AutoAdvancingVirtualTimeDomain> auto_advancing_time_domain_; - TestTaskTimeTracker test_task_time_tracker_; -}; - -namespace { -void NopTask(bool* task_run) { - *task_run = true; -} -} // namesapce - -TEST_F(AutoAdvancingVirtualTimeDomainTest, VirtualTimeAdvances) { - base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10); - bool task_run = false; - task_runner_->PostDelayedTask( - FROM_HERE, base::Bind(NopTask, &task_run), delay); - - mock_task_runner_->RunUntilIdle(); - - EXPECT_EQ(initial_time_, clock_->NowTicks()); - EXPECT_EQ(initial_time_ + delay, - auto_advancing_time_domain_->CreateLazyNow().Now()); - EXPECT_TRUE(task_run); -} - -TEST_F(AutoAdvancingVirtualTimeDomainTest, VirtualTimeDoesNotAdvance) { - base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10); - bool task_run = false; - task_runner_->PostDelayedTask( - FROM_HERE, base::Bind(NopTask, &task_run), delay); - - auto_advancing_time_domain_->SetCanAdvanceVirtualTime(false); - - mock_task_runner_->RunUntilIdle(); - - EXPECT_EQ(initial_time_, clock_->NowTicks()); - EXPECT_EQ(initial_time_, auto_advancing_time_domain_->CreateLazyNow().Now()); - EXPECT_FALSE(task_run); -} - -} // namespace scheduler
diff --git a/components/scheduler/renderer/deadline_task_runner.cc b/components/scheduler/renderer/deadline_task_runner.cc deleted file mode 100644 index fd6859f..0000000 --- a/components/scheduler/renderer/deadline_task_runner.cc +++ /dev/null
@@ -1,40 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/renderer/deadline_task_runner.h" - -#include "base/bind.h" - -namespace scheduler { - -DeadlineTaskRunner::DeadlineTaskRunner( - const base::Closure& callback, - scoped_refptr<base::SingleThreadTaskRunner> task_runner) - : callback_(callback), task_runner_(task_runner) { - cancelable_run_internal_.Reset( - base::Bind(&DeadlineTaskRunner::RunInternal, base::Unretained(this))); -} - -DeadlineTaskRunner::~DeadlineTaskRunner() { -} - -void DeadlineTaskRunner::SetDeadline(const tracked_objects::Location& from_here, - base::TimeDelta delay, - base::TimeTicks now) { - DCHECK(delay > base::TimeDelta()); - base::TimeTicks deadline = now + delay; - if (deadline_.is_null() || deadline < deadline_) { - deadline_ = deadline; - cancelable_run_internal_.Cancel(); - task_runner_->PostDelayedTask(from_here, - cancelable_run_internal_.callback(), delay); - } -} - -void DeadlineTaskRunner::RunInternal() { - deadline_ = base::TimeTicks(); - callback_.Run(); -} - -} // namespace scheduler
diff --git a/components/scheduler/renderer/deadline_task_runner.h b/components/scheduler/renderer/deadline_task_runner.h deleted file mode 100644 index 9ac4823..0000000 --- a/components/scheduler/renderer/deadline_task_runner.h +++ /dev/null
@@ -1,50 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_RENDERER_DEADLINE_TASK_RUNNER_H_ -#define COMPONENTS_SCHEDULER_RENDERER_DEADLINE_TASK_RUNNER_H_ - -#include "base/callback.h" -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "base/single_thread_task_runner.h" -#include "base/time/time.h" -#include "components/scheduler/base/cancelable_closure_holder.h" -#include "components/scheduler/scheduler_export.h" - -namespace scheduler { - -// Runs a posted task at latest by a given deadline, but possibly sooner. -class SCHEDULER_EXPORT DeadlineTaskRunner { - public: - DeadlineTaskRunner(const base::Closure& callback, - scoped_refptr<base::SingleThreadTaskRunner> task_runner); - - ~DeadlineTaskRunner(); - - // If there is no outstanding task then a task is posted to run after |delay|. - // If there is an outstanding task which is scheduled to run: - // a) sooner - then this is a NOP. - // b) later - then the outstanding task is cancelled and a new task is - // posted to run after |delay|. - // - // Once the deadline task has run, we reset. - void SetDeadline(const tracked_objects::Location& from_here, - base::TimeDelta delay, - base::TimeTicks now); - - private: - void RunInternal(); - - CancelableClosureHolder cancelable_run_internal_; - base::Closure callback_; - base::TimeTicks deadline_; - scoped_refptr<base::SingleThreadTaskRunner> task_runner_; - - DISALLOW_COPY_AND_ASSIGN(DeadlineTaskRunner); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_RENDERER_DEADLINE_TASK_RUNNER_H_
diff --git a/components/scheduler/renderer/deadline_task_runner_unittest.cc b/components/scheduler/renderer/deadline_task_runner_unittest.cc deleted file mode 100644 index 058a341..0000000 --- a/components/scheduler/renderer/deadline_task_runner_unittest.cc +++ /dev/null
@@ -1,101 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/renderer/deadline_task_runner.h" - -#include <memory> - -#include "base/test/simple_test_tick_clock.h" -#include "cc/test/ordered_simple_task_runner.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace scheduler { - -class DeadlineTaskRunnerTest : public testing::Test { - public: - DeadlineTaskRunnerTest() {} - ~DeadlineTaskRunnerTest() override {} - - void SetUp() override { - clock_.reset(new base::SimpleTestTickClock()); - clock_->Advance(base::TimeDelta::FromMicroseconds(5000)); - mock_task_runner_ = new cc::OrderedSimpleTaskRunner(clock_.get(), true); - deadline_task_runner_.reset(new DeadlineTaskRunner( - base::Bind(&DeadlineTaskRunnerTest::TestTask, base::Unretained(this)), - mock_task_runner_)); - run_times_.clear(); - } - - bool RunUntilIdle() { return mock_task_runner_->RunUntilIdle(); } - - void TestTask() { run_times_.push_back(clock_->NowTicks()); } - - std::unique_ptr<base::SimpleTestTickClock> clock_; - scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_; - std::unique_ptr<DeadlineTaskRunner> deadline_task_runner_; - std::vector<base::TimeTicks> run_times_; -}; - -TEST_F(DeadlineTaskRunnerTest, RunOnce) { - base::TimeTicks start_time = clock_->NowTicks(); - base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10); - deadline_task_runner_->SetDeadline(FROM_HERE, delay, clock_->NowTicks()); - RunUntilIdle(); - - EXPECT_THAT(run_times_, testing::ElementsAre(start_time + delay)); -}; - -TEST_F(DeadlineTaskRunnerTest, RunTwice) { - base::TimeDelta delay1 = base::TimeDelta::FromMilliseconds(10); - base::TimeTicks deadline1 = clock_->NowTicks() + delay1; - deadline_task_runner_->SetDeadline(FROM_HERE, delay1, clock_->NowTicks()); - RunUntilIdle(); - - base::TimeDelta delay2 = base::TimeDelta::FromMilliseconds(100); - base::TimeTicks deadline2 = clock_->NowTicks() + delay2; - deadline_task_runner_->SetDeadline(FROM_HERE, delay2, clock_->NowTicks()); - RunUntilIdle(); - - EXPECT_THAT(run_times_, testing::ElementsAre(deadline1, deadline2)); -}; - -TEST_F(DeadlineTaskRunnerTest, EarlierDeadlinesTakePrecidence) { - base::TimeTicks start_time = clock_->NowTicks(); - base::TimeDelta delay1 = base::TimeDelta::FromMilliseconds(1); - base::TimeDelta delay10 = base::TimeDelta::FromMilliseconds(10); - base::TimeDelta delay100 = base::TimeDelta::FromMilliseconds(100); - deadline_task_runner_->SetDeadline(FROM_HERE, delay100, clock_->NowTicks()); - deadline_task_runner_->SetDeadline(FROM_HERE, delay10, clock_->NowTicks()); - deadline_task_runner_->SetDeadline(FROM_HERE, delay1, clock_->NowTicks()); - - RunUntilIdle(); - - EXPECT_THAT(run_times_, testing::ElementsAre(start_time + delay1)); -}; - -TEST_F(DeadlineTaskRunnerTest, LaterDeadlinesIgnored) { - base::TimeTicks start_time = clock_->NowTicks(); - base::TimeDelta delay100 = base::TimeDelta::FromMilliseconds(100); - base::TimeDelta delay10000 = base::TimeDelta::FromMilliseconds(10000); - deadline_task_runner_->SetDeadline(FROM_HERE, delay100, clock_->NowTicks()); - deadline_task_runner_->SetDeadline(FROM_HERE, delay10000, clock_->NowTicks()); - - RunUntilIdle(); - - EXPECT_THAT(run_times_, testing::ElementsAre(start_time + delay100)); -}; - -TEST_F(DeadlineTaskRunnerTest, DeleteDeadlineTaskRunnerAfterPosting) { - deadline_task_runner_->SetDeadline( - FROM_HERE, base::TimeDelta::FromMilliseconds(10), clock_->NowTicks()); - - // Deleting the pending task should cancel it. - deadline_task_runner_.reset(nullptr); - RunUntilIdle(); - - EXPECT_TRUE(run_times_.empty()); -}; - -} // namespace scheduler
diff --git a/components/scheduler/renderer/idle_time_estimator.cc b/components/scheduler/renderer/idle_time_estimator.cc deleted file mode 100644 index 30c91561..0000000 --- a/components/scheduler/renderer/idle_time_estimator.cc +++ /dev/null
@@ -1,74 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/renderer/idle_time_estimator.h" - -#include "base/time/default_tick_clock.h" - -namespace scheduler { - -IdleTimeEstimator::IdleTimeEstimator( - const scoped_refptr<TaskQueue>& compositor_task_runner, - base::TickClock* time_source, - int sample_count, - double estimation_percentile) - : compositor_task_runner_(compositor_task_runner), - per_frame_compositor_task_runtime_(sample_count), - time_source_(time_source), - estimation_percentile_(estimation_percentile), - nesting_level_(0), - did_commit_(false) { - compositor_task_runner_->AddTaskObserver(this); -} - -IdleTimeEstimator::~IdleTimeEstimator() { - compositor_task_runner_->RemoveTaskObserver(this); -} - -base::TimeDelta IdleTimeEstimator::GetExpectedIdleDuration( - base::TimeDelta compositor_frame_interval) const { - base::TimeDelta expected_compositor_task_runtime_ = - per_frame_compositor_task_runtime_.Percentile(estimation_percentile_); - return std::max(base::TimeDelta(), compositor_frame_interval - - expected_compositor_task_runtime_); -} - -void IdleTimeEstimator::DidCommitFrameToCompositor() { - // This will run inside of a WillProcessTask / DidProcessTask pair, let - // DidProcessTask know a frame was comitted. - if (nesting_level_ == 1) - did_commit_ = true; -} - -void IdleTimeEstimator::Clear() { - task_start_time_ = base::TimeTicks(); - prev_commit_time_ = base::TimeTicks(); - cumulative_compositor_runtime_ = base::TimeDelta(); - per_frame_compositor_task_runtime_.Clear(); - did_commit_ = false; -} - -void IdleTimeEstimator::WillProcessTask(const base::PendingTask& pending_task) { - nesting_level_++; - if (nesting_level_ == 1) - task_start_time_ = time_source_->NowTicks(); -} - -void IdleTimeEstimator::DidProcessTask(const base::PendingTask& pending_task) { - nesting_level_--; - DCHECK_GE(nesting_level_, 0); - if (nesting_level_ != 0) - return; - - cumulative_compositor_runtime_ += time_source_->NowTicks() - task_start_time_; - - if (did_commit_) { - per_frame_compositor_task_runtime_.InsertSample( - cumulative_compositor_runtime_); - cumulative_compositor_runtime_ = base::TimeDelta(); - did_commit_ = false; - } -} - -} // namespace scheduler
diff --git a/components/scheduler/renderer/idle_time_estimator.h b/components/scheduler/renderer/idle_time_estimator.h deleted file mode 100644 index 3664a38..0000000 --- a/components/scheduler/renderer/idle_time_estimator.h +++ /dev/null
@@ -1,58 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_RENDERER_IDLE_TIME_ESTIMATOR_H_ -#define COMPONENTS_SCHEDULER_RENDERER_IDLE_TIME_ESTIMATOR_H_ - -#include "base/macros.h" -#include "base/message_loop/message_loop.h" -#include "base/time/tick_clock.h" -#include "cc/base/rolling_time_delta_history.h" -#include "components/scheduler/base/task_queue.h" -#include "components/scheduler/scheduler_export.h" - -namespace scheduler { - -// Estimates how much idle time there is available. Ignores nested tasks. -class SCHEDULER_EXPORT IdleTimeEstimator - : public base::MessageLoop::TaskObserver { - public: - IdleTimeEstimator(const scoped_refptr<TaskQueue>& compositor_task_runner, - base::TickClock* time_source, - int sample_count, - double estimation_percentile); - - ~IdleTimeEstimator() override; - - // Expected Idle time is defined as: |compositor_frame_interval| minus - // expected compositor task duration. - base::TimeDelta GetExpectedIdleDuration( - base::TimeDelta compositor_frame_interval) const; - - void DidCommitFrameToCompositor(); - - void Clear(); - - // TaskObserver implementation: - void WillProcessTask(const base::PendingTask& pending_task) override; - void DidProcessTask(const base::PendingTask& pending_task) override; - - private: - scoped_refptr<TaskQueue> compositor_task_runner_; - cc::RollingTimeDeltaHistory per_frame_compositor_task_runtime_; - base::TickClock* time_source_; // NOT OWNED - double estimation_percentile_; - - base::TimeTicks task_start_time_; - base::TimeTicks prev_commit_time_; - base::TimeDelta cumulative_compositor_runtime_; - int nesting_level_; - bool did_commit_; - - DISALLOW_COPY_AND_ASSIGN(IdleTimeEstimator); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_RENDERER_IDLE_TIME_ESTIMATOR_H_
diff --git a/components/scheduler/renderer/idle_time_estimator_unittest.cc b/components/scheduler/renderer/idle_time_estimator_unittest.cc deleted file mode 100644 index d7d67a8..0000000 --- a/components/scheduler/renderer/idle_time_estimator_unittest.cc +++ /dev/null
@@ -1,169 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/renderer/idle_time_estimator.h" - -#include "base/memory/ptr_util.h" -#include "base/test/simple_test_tick_clock.h" -#include "cc/test/ordered_simple_task_runner.h" -#include "components/scheduler/base/task_queue_manager.h" -#include "components/scheduler/base/test_task_time_tracker.h" -#include "components/scheduler/base/test_time_source.h" -#include "components/scheduler/child/scheduler_tqm_delegate_for_test.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace scheduler { - -class IdleTimeEstimatorForTest : public IdleTimeEstimator { - public: - IdleTimeEstimatorForTest( - const scoped_refptr<TaskQueue>& compositor_task_runner, - TestTimeSource* test_time_source, - int sample_count, - double estimation_percentile) - : IdleTimeEstimator(compositor_task_runner, - test_time_source, - sample_count, - estimation_percentile) {} -}; - -class IdleTimeEstimatorTest : public testing::Test { - public: - IdleTimeEstimatorTest() - : frame_length_(base::TimeDelta::FromMilliseconds(16)) {} - - ~IdleTimeEstimatorTest() override {} - - void SetUp() override { - clock_.reset(new base::SimpleTestTickClock()); - clock_->Advance(base::TimeDelta::FromMicroseconds(5000)); - test_time_source_.reset(new TestTimeSource(clock_.get())); - mock_task_runner_ = make_scoped_refptr( - new cc::OrderedSimpleTaskRunner(clock_.get(), false)); - main_task_runner_ = SchedulerTqmDelegateForTest::Create( - mock_task_runner_, base::MakeUnique<TestTimeSource>(clock_.get())); - manager_ = base::MakeUnique<TaskQueueManager>( - main_task_runner_, "test.scheduler", "test.scheduler", - "test.scheduler.debug"); - compositor_task_runner_ = - manager_->NewTaskQueue(TaskQueue::Spec("compositor_tq")); - estimator_.reset(new IdleTimeEstimatorForTest( - compositor_task_runner_, test_time_source_.get(), 10, 50)); - } - - void SimulateFrameWithOneCompositorTask(int compositor_time) { - base::TimeDelta non_idle_time = - base::TimeDelta::FromMilliseconds(compositor_time); - base::PendingTask task(FROM_HERE, base::Closure()); - estimator_->WillProcessTask(task); - clock_->Advance(non_idle_time); - estimator_->DidCommitFrameToCompositor(); - estimator_->DidProcessTask(task); - if (non_idle_time < frame_length_) - clock_->Advance(frame_length_ - non_idle_time); - } - - void SimulateFrameWithTwoCompositorTasks(int compositor_time1, - int compositor_time2) { - base::TimeDelta non_idle_time1 = - base::TimeDelta::FromMilliseconds(compositor_time1); - base::TimeDelta non_idle_time2 = - base::TimeDelta::FromMilliseconds(compositor_time2); - base::PendingTask task(FROM_HERE, base::Closure()); - estimator_->WillProcessTask(task); - clock_->Advance(non_idle_time1); - estimator_->DidProcessTask(task); - - estimator_->WillProcessTask(task); - clock_->Advance(non_idle_time2); - estimator_->DidCommitFrameToCompositor(); - estimator_->DidProcessTask(task); - - base::TimeDelta idle_time = frame_length_ - non_idle_time1 - non_idle_time2; - clock_->Advance(idle_time); - } - - std::unique_ptr<base::SimpleTestTickClock> clock_; - std::unique_ptr<TestTimeSource> test_time_source_; - scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_; - scoped_refptr<SchedulerTqmDelegate> main_task_runner_; - std::unique_ptr<TaskQueueManager> manager_; - scoped_refptr<TaskQueue> compositor_task_runner_; - std::unique_ptr<IdleTimeEstimatorForTest> estimator_; - const base::TimeDelta frame_length_; - TestTaskTimeTracker test_task_time_tracker_; -}; - -TEST_F(IdleTimeEstimatorTest, InitialTimeEstimateWithNoData) { - EXPECT_EQ(frame_length_, estimator_->GetExpectedIdleDuration(frame_length_)); -} - -TEST_F(IdleTimeEstimatorTest, BasicEstimation_SteadyState) { - SimulateFrameWithOneCompositorTask(5); - SimulateFrameWithOneCompositorTask(5); - - EXPECT_EQ(base::TimeDelta::FromMilliseconds(11), - estimator_->GetExpectedIdleDuration(frame_length_)); -} - -TEST_F(IdleTimeEstimatorTest, BasicEstimation_Variable) { - SimulateFrameWithOneCompositorTask(5); - SimulateFrameWithOneCompositorTask(6); - SimulateFrameWithOneCompositorTask(7); - SimulateFrameWithOneCompositorTask(7); - SimulateFrameWithOneCompositorTask(7); - SimulateFrameWithOneCompositorTask(8); - - // We expect it to return the median. - EXPECT_EQ(base::TimeDelta::FromMilliseconds(9), - estimator_->GetExpectedIdleDuration(frame_length_)); -} - -TEST_F(IdleTimeEstimatorTest, NoIdleTime) { - SimulateFrameWithOneCompositorTask(100); - SimulateFrameWithOneCompositorTask(100); - - EXPECT_EQ(base::TimeDelta::FromMilliseconds(0), - estimator_->GetExpectedIdleDuration(frame_length_)); -} - -TEST_F(IdleTimeEstimatorTest, Clear) { - SimulateFrameWithOneCompositorTask(5); - SimulateFrameWithOneCompositorTask(5); - - EXPECT_EQ(base::TimeDelta::FromMilliseconds(11), - estimator_->GetExpectedIdleDuration(frame_length_)); - estimator_->Clear(); - - EXPECT_EQ(frame_length_, estimator_->GetExpectedIdleDuration(frame_length_)); -} - -TEST_F(IdleTimeEstimatorTest, Estimation_MultipleTasks) { - SimulateFrameWithTwoCompositorTasks(1, 4); - SimulateFrameWithTwoCompositorTasks(1, 4); - - EXPECT_EQ(base::TimeDelta::FromMilliseconds(11), - estimator_->GetExpectedIdleDuration(frame_length_)); -} - -TEST_F(IdleTimeEstimatorTest, IgnoresNestedTasks) { - SimulateFrameWithOneCompositorTask(5); - SimulateFrameWithOneCompositorTask(5); - - base::PendingTask task(FROM_HERE, base::Closure()); - estimator_->WillProcessTask(task); - SimulateFrameWithTwoCompositorTasks(4, 4); - SimulateFrameWithTwoCompositorTasks(4, 4); - SimulateFrameWithTwoCompositorTasks(4, 4); - SimulateFrameWithTwoCompositorTasks(4, 4); - estimator_->DidCommitFrameToCompositor(); - estimator_->DidProcessTask(task); - - EXPECT_EQ(base::TimeDelta::FromMilliseconds(11), - estimator_->GetExpectedIdleDuration(frame_length_)); -} - - -} // namespace scheduler
diff --git a/components/scheduler/renderer/render_widget_scheduling_state.cc b/components/scheduler/renderer/render_widget_scheduling_state.cc deleted file mode 100644 index 77e9939..0000000 --- a/components/scheduler/renderer/render_widget_scheduling_state.cc +++ /dev/null
@@ -1,65 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/renderer/render_widget_scheduling_state.h" - -#include "components/scheduler/renderer/render_widget_signals.h" - -namespace scheduler { - -RenderWidgetSchedulingState::RenderWidgetSchedulingState( - RenderWidgetSignals* render_widget_scheduling_signals) - : render_widget_signals_(render_widget_scheduling_signals), - hidden_(false), - has_touch_handler_(false) { - render_widget_signals_->IncNumVisibleRenderWidgets(); -} - -RenderWidgetSchedulingState::~RenderWidgetSchedulingState() { - if (hidden_) - return; - - render_widget_signals_->DecNumVisibleRenderWidgets(); - - if (has_touch_handler_) { - render_widget_signals_->DecNumVisibleRenderWidgetsWithTouchHandlers(); - } -} - -void RenderWidgetSchedulingState::SetHidden(bool hidden) { - if (hidden_ == hidden) - return; - - hidden_ = hidden; - - if (hidden_) { - render_widget_signals_->DecNumVisibleRenderWidgets(); - if (has_touch_handler_) { - render_widget_signals_->DecNumVisibleRenderWidgetsWithTouchHandlers(); - } - } else { - render_widget_signals_->IncNumVisibleRenderWidgets(); - if (has_touch_handler_) { - render_widget_signals_->IncNumVisibleRenderWidgetsWithTouchHandlers(); - } - } -} - -void RenderWidgetSchedulingState::SetHasTouchHandler(bool has_touch_handler) { - if (has_touch_handler_ == has_touch_handler) - return; - - has_touch_handler_ = has_touch_handler; - - if (hidden_) - return; - - if (has_touch_handler_) { - render_widget_signals_->IncNumVisibleRenderWidgetsWithTouchHandlers(); - } else { - render_widget_signals_->DecNumVisibleRenderWidgetsWithTouchHandlers(); - } -} - -} // namespace scheduler
diff --git a/components/scheduler/renderer/render_widget_scheduling_state.h b/components/scheduler/renderer/render_widget_scheduling_state.h deleted file mode 100644 index 7ad0427..0000000 --- a/components/scheduler/renderer/render_widget_scheduling_state.h +++ /dev/null
@@ -1,34 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_RENDERER_RENDER_WIDGET_SCHEDULING_STATE_H_ -#define COMPONENTS_SCHEDULER_RENDERER_RENDER_WIDGET_SCHEDULING_STATE_H_ - -#include "components/scheduler/scheduler_export.h" - -namespace scheduler { - -class RenderWidgetSignals; - -class SCHEDULER_EXPORT RenderWidgetSchedulingState { - public: - void SetHidden(bool hidden); - void SetHasTouchHandler(bool has_touch_handler); - - ~RenderWidgetSchedulingState(); - - private: - friend class RenderWidgetSignals; - - explicit RenderWidgetSchedulingState( - RenderWidgetSignals* render_widget_scheduling_signals); - - RenderWidgetSignals* render_widget_signals_; // NOT OWNED - bool hidden_; - bool has_touch_handler_; -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_RENDERER_RENDER_WIDGET_SCHEDULING_STATE_H_
diff --git a/components/scheduler/renderer/render_widget_signals.cc b/components/scheduler/renderer/render_widget_signals.cc deleted file mode 100644 index 800103c..0000000 --- a/components/scheduler/renderer/render_widget_signals.cc +++ /dev/null
@@ -1,63 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/renderer/render_widget_signals.h" - -#include "base/logging.h" -#include "base/memory/ptr_util.h" -#include "components/scheduler/renderer/render_widget_scheduling_state.h" -#include "components/scheduler/scheduler_export.h" - -namespace scheduler { - -RenderWidgetSignals::RenderWidgetSignals(Observer* observer) - : observer_(observer), - num_visible_render_widgets_(0), - num_visible_render_widgets_with_touch_handlers_(0) {} - -std::unique_ptr<RenderWidgetSchedulingState> -RenderWidgetSignals::NewRenderWidgetSchedulingState() { - return base::WrapUnique(new RenderWidgetSchedulingState(this)); -} - -void RenderWidgetSignals::IncNumVisibleRenderWidgets() { - num_visible_render_widgets_++; - - if (num_visible_render_widgets_ == 1) - observer_->SetAllRenderWidgetsHidden(false); -} - -void RenderWidgetSignals::DecNumVisibleRenderWidgets() { - num_visible_render_widgets_--; - DCHECK_GE(num_visible_render_widgets_, 0); - - if (num_visible_render_widgets_ == 0) - observer_->SetAllRenderWidgetsHidden(true); -} - -void RenderWidgetSignals::IncNumVisibleRenderWidgetsWithTouchHandlers() { - num_visible_render_widgets_with_touch_handlers_++; - - if (num_visible_render_widgets_with_touch_handlers_ == 1) - observer_->SetHasVisibleRenderWidgetWithTouchHandler(true); -} - -void RenderWidgetSignals::DecNumVisibleRenderWidgetsWithTouchHandlers() { - num_visible_render_widgets_with_touch_handlers_--; - DCHECK_GE(num_visible_render_widgets_with_touch_handlers_, 0); - - if (num_visible_render_widgets_with_touch_handlers_ == 0) - observer_->SetHasVisibleRenderWidgetWithTouchHandler(false); -} - -void RenderWidgetSignals::AsValueInto( - base::trace_event::TracedValue* state) const { - state->BeginDictionary("renderer_widget_signals"); - state->SetInteger("num_visible_render_widgets", num_visible_render_widgets_); - state->SetInteger("num_visible_render_widgets_with_touch_handlers", - num_visible_render_widgets_with_touch_handlers_); - state->EndDictionary(); -} - -} // namespace scheduler
diff --git a/components/scheduler/renderer/render_widget_signals.h b/components/scheduler/renderer/render_widget_signals.h deleted file mode 100644 index 9e645b2..0000000 --- a/components/scheduler/renderer/render_widget_signals.h +++ /dev/null
@@ -1,58 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_RENDERER_RENDER_WIDGET_SIGNALS_H_ -#define COMPONENTS_SCHEDULER_RENDERER_RENDER_WIDGET_SIGNALS_H_ - -#include <memory> - -#include "base/trace_event/trace_event.h" -#include "base/trace_event/trace_event_argument.h" -#include "components/scheduler/scheduler_export.h" - -namespace scheduler { - -class RenderWidgetSchedulingState; - -class SCHEDULER_EXPORT RenderWidgetSignals { - public: - class SCHEDULER_EXPORT Observer { - public: - virtual ~Observer() {} - - // If |hidden| is true then all render widgets managed by this renderer - // process have been hidden. - // If |hidden| is false at least one render widget managed by this renderer - // process has become visible and the renderer is no longer hidden. - // Will be called on the main thread. - virtual void SetAllRenderWidgetsHidden(bool hidden) = 0; - - // Tells the observer whether or not we have at least one touch handler on - // a visible render widget. Will be called on the main thread. - virtual void SetHasVisibleRenderWidgetWithTouchHandler( - bool has_visible_render_widget_with_touch_handler) = 0; - }; - - explicit RenderWidgetSignals(Observer* observer); - - std::unique_ptr<RenderWidgetSchedulingState> NewRenderWidgetSchedulingState(); - - void AsValueInto(base::trace_event::TracedValue* state) const; - - private: - friend class RenderWidgetSchedulingState; - - void IncNumVisibleRenderWidgets(); - void DecNumVisibleRenderWidgets(); - void IncNumVisibleRenderWidgetsWithTouchHandlers(); - void DecNumVisibleRenderWidgetsWithTouchHandlers(); - - Observer* observer_; // NOT OWNED - int num_visible_render_widgets_; - int num_visible_render_widgets_with_touch_handlers_; -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_RENDERER_RENDER_WIDGET_SIGNALS_H_
diff --git a/components/scheduler/renderer/render_widget_signals_unittest.cpp b/components/scheduler/renderer/render_widget_signals_unittest.cpp deleted file mode 100644 index 60d1de5b2..0000000 --- a/components/scheduler/renderer/render_widget_signals_unittest.cpp +++ /dev/null
@@ -1,266 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/renderer/render_widget_signals.h" - -#include "base/macros.h" -#include "components/scheduler/renderer/render_widget_scheduling_state.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using testing::AnyNumber; -using testing::Mock; -using testing::_; - -namespace scheduler { - -namespace { -class MockObserver : public RenderWidgetSignals::Observer { - public: - MockObserver() {} - virtual ~MockObserver() {} - - MOCK_METHOD1(SetAllRenderWidgetsHidden, void(bool hidden)); - MOCK_METHOD1(SetHasVisibleRenderWidgetWithTouchHandler, - void(bool has_visible_render_widget_with_touch_handler)); - - private: - DISALLOW_COPY_AND_ASSIGN(MockObserver); -}; -} - -class RenderWidgetSignalsTest : public testing::Test { - public: - RenderWidgetSignalsTest() {} - ~RenderWidgetSignalsTest() override {} - - void SetUp() override { - mock_observer_.reset(new MockObserver()); - render_widget_signals_.reset(new RenderWidgetSignals(mock_observer_.get())); - } - - void IgnoreWidgetCreationCallbacks() { - EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(false)) - .Times(AnyNumber()); - } - - void IgnoreWidgetDestructionCallbacks() { - EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(true)) - .Times(AnyNumber()); - } - - std::unique_ptr<MockObserver> mock_observer_; - std::unique_ptr<RenderWidgetSignals> render_widget_signals_; -}; - -TEST_F(RenderWidgetSignalsTest, RenderWidgetSchedulingStateLifeCycle) { - EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(false)).Times(1); - std::unique_ptr<RenderWidgetSchedulingState> widget1_state = - render_widget_signals_->NewRenderWidgetSchedulingState(); - Mock::VerifyAndClearExpectations(mock_observer_.get()); - - EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(true)).Times(1); -} - -TEST_F(RenderWidgetSignalsTest, RenderWidget_Hidden) { - IgnoreWidgetCreationCallbacks(); - std::unique_ptr<RenderWidgetSchedulingState> widget1_state = - render_widget_signals_->NewRenderWidgetSchedulingState(); - Mock::VerifyAndClearExpectations(mock_observer_.get()); - - EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(true)).Times(1); - widget1_state->SetHidden(true); - Mock::VerifyAndClearExpectations(mock_observer_.get()); - - IgnoreWidgetDestructionCallbacks(); -} - -TEST_F(RenderWidgetSignalsTest, RenderWidget_HiddenThreeTimesShownOnce) { - IgnoreWidgetCreationCallbacks(); - std::unique_ptr<RenderWidgetSchedulingState> widget1_state = - render_widget_signals_->NewRenderWidgetSchedulingState(); - Mock::VerifyAndClearExpectations(mock_observer_.get()); - - EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(true)).Times(1); - widget1_state->SetHidden(true); - widget1_state->SetHidden(true); - widget1_state->SetHidden(true); - Mock::VerifyAndClearExpectations(mock_observer_.get()); - - EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(false)).Times(1); - widget1_state->SetHidden(false); - Mock::VerifyAndClearExpectations(mock_observer_.get()); - - IgnoreWidgetDestructionCallbacks(); -} - -TEST_F(RenderWidgetSignalsTest, MultipleRenderWidgetsBecomeHiddenThenVisible) { - IgnoreWidgetCreationCallbacks(); - std::unique_ptr<RenderWidgetSchedulingState> widget1_state = - render_widget_signals_->NewRenderWidgetSchedulingState(); - std::unique_ptr<RenderWidgetSchedulingState> widget2_state = - render_widget_signals_->NewRenderWidgetSchedulingState(); - std::unique_ptr<RenderWidgetSchedulingState> widget3_state = - render_widget_signals_->NewRenderWidgetSchedulingState(); - Mock::VerifyAndClearExpectations(mock_observer_.get()); - - // Widgets are initially assumed to be visible so start hiding them, we should - // not get any calls to SetAllRenderWidgetsHidden till the last one is hidden. - EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(_)).Times(0); - widget1_state->SetHidden(true); - widget2_state->SetHidden(true); - Mock::VerifyAndClearExpectations(mock_observer_.get()); - - EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(true)).Times(1); - widget3_state->SetHidden(true); - Mock::VerifyAndClearExpectations(mock_observer_.get()); - - // We should get a call back once the first widget is unhidden and no more - // after that. - EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(false)).Times(1); - widget1_state->SetHidden(false); - Mock::VerifyAndClearExpectations(mock_observer_.get()); - - EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(_)).Times(0); - widget2_state->SetHidden(false); - widget3_state->SetHidden(false); - Mock::VerifyAndClearExpectations(mock_observer_.get()); - - IgnoreWidgetDestructionCallbacks(); -} - -TEST_F(RenderWidgetSignalsTest, TouchHandlerAddedAndRemoved_VisibleWidget) { - IgnoreWidgetCreationCallbacks(); - - std::unique_ptr<RenderWidgetSchedulingState> widget_state = - render_widget_signals_->NewRenderWidgetSchedulingState(); - Mock::VerifyAndClearExpectations(mock_observer_.get()); - - EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(true)) - .Times(1); - widget_state->SetHasTouchHandler(true); - Mock::VerifyAndClearExpectations(mock_observer_.get()); - - EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(false)) - .Times(1); - widget_state->SetHasTouchHandler(false); - Mock::VerifyAndClearExpectations(mock_observer_.get()); - - IgnoreWidgetDestructionCallbacks(); -} - -TEST_F(RenderWidgetSignalsTest, - TouchHandlerAddedThriceAndRemovedOnce_VisibleWidget) { - IgnoreWidgetCreationCallbacks(); - - std::unique_ptr<RenderWidgetSchedulingState> widget_state = - render_widget_signals_->NewRenderWidgetSchedulingState(); - Mock::VerifyAndClearExpectations(mock_observer_.get()); - - EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(true)) - .Times(1); - widget_state->SetHasTouchHandler(true); - widget_state->SetHasTouchHandler(true); - widget_state->SetHasTouchHandler(true); - Mock::VerifyAndClearExpectations(mock_observer_.get()); - - EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(false)) - .Times(1); - widget_state->SetHasTouchHandler(false); - Mock::VerifyAndClearExpectations(mock_observer_.get()); - - IgnoreWidgetDestructionCallbacks(); -} - -TEST_F(RenderWidgetSignalsTest, TouchHandlerAddedAndRemoved_HiddenWidget) { - IgnoreWidgetCreationCallbacks(); - - std::unique_ptr<RenderWidgetSchedulingState> widget_state = - render_widget_signals_->NewRenderWidgetSchedulingState(); - EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(true)).Times(1); - widget_state->SetHidden(true); - Mock::VerifyAndClearExpectations(mock_observer_.get()); - - EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(_)) - .Times(0); - widget_state->SetHasTouchHandler(true); - widget_state->SetHasTouchHandler(false); - Mock::VerifyAndClearExpectations(mock_observer_.get()); - - IgnoreWidgetDestructionCallbacks(); -} - -TEST_F(RenderWidgetSignalsTest, - MultipleTouchHandlerAddedAndRemoved_VisibleWidgets) { - IgnoreWidgetCreationCallbacks(); - - std::unique_ptr<RenderWidgetSchedulingState> widget1_state = - render_widget_signals_->NewRenderWidgetSchedulingState(); - std::unique_ptr<RenderWidgetSchedulingState> widget2_state = - render_widget_signals_->NewRenderWidgetSchedulingState(); - std::unique_ptr<RenderWidgetSchedulingState> widget3_state = - render_widget_signals_->NewRenderWidgetSchedulingState(); - Mock::VerifyAndClearExpectations(mock_observer_.get()); - - // We should only get a callback for the first widget with a touch handler. - EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(true)) - .Times(1); - widget1_state->SetHasTouchHandler(true); - Mock::VerifyAndClearExpectations(mock_observer_.get()); - - EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(_)) - .Times(0); - widget2_state->SetHasTouchHandler(true); - widget3_state->SetHasTouchHandler(true); - Mock::VerifyAndClearExpectations(mock_observer_.get()); - - // We should only get a callback when the last touch handler is removed. - EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(_)) - .Times(0); - widget1_state->SetHasTouchHandler(false); - widget2_state->SetHasTouchHandler(false); - Mock::VerifyAndClearExpectations(mock_observer_.get()); - - EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(false)) - .Times(1); - widget3_state->SetHasTouchHandler(false); - Mock::VerifyAndClearExpectations(mock_observer_.get()); - - IgnoreWidgetDestructionCallbacks(); -} - -TEST_F(RenderWidgetSignalsTest, - TouchHandlerAddedThenWigetDeleted_VisibleWidget) { - IgnoreWidgetCreationCallbacks(); - - std::unique_ptr<RenderWidgetSchedulingState> widget_state = - render_widget_signals_->NewRenderWidgetSchedulingState(); - Mock::VerifyAndClearExpectations(mock_observer_.get()); - - EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(true)) - .Times(1); - widget_state->SetHasTouchHandler(true); - Mock::VerifyAndClearExpectations(mock_observer_.get()); - - EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(false)) - .Times(1); - IgnoreWidgetDestructionCallbacks(); -} - -TEST_F(RenderWidgetSignalsTest, - TouchHandlerAddedThenWigetDeleted_HiddenWidget) { - IgnoreWidgetCreationCallbacks(); - - std::unique_ptr<RenderWidgetSchedulingState> widget_state = - render_widget_signals_->NewRenderWidgetSchedulingState(); - EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(true)).Times(1); - widget_state->SetHidden(true); - Mock::VerifyAndClearExpectations(mock_observer_.get()); - - EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(_)) - .Times(0); - IgnoreWidgetDestructionCallbacks(); -} - -} // namespace scheduler
diff --git a/components/scheduler/renderer/renderer_scheduler.cc b/components/scheduler/renderer/renderer_scheduler.cc deleted file mode 100644 index dd7bade..0000000 --- a/components/scheduler/renderer/renderer_scheduler.cc +++ /dev/null
@@ -1,77 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/renderer/renderer_scheduler.h" - -#include "base/command_line.h" -#include "base/feature_list.h" -#include "base/memory/ptr_util.h" -#include "base/message_loop/message_loop.h" -#include "base/metrics/field_trial.h" -#include "base/time/default_tick_clock.h" -#include "base/trace_event/trace_event.h" -#include "base/trace_event/trace_event_impl.h" -#include "components/scheduler/child/scheduler_tqm_delegate_impl.h" -#include "components/scheduler/common/scheduler_switches.h" -#include "components/scheduler/renderer/renderer_scheduler_impl.h" - -namespace scheduler { -namespace { -const base::Feature kExpensiveTaskBlockingPolicyFeature{ - "SchedulerExpensiveTaskBlocking", base::FEATURE_ENABLED_BY_DEFAULT}; -} - -RendererScheduler::RendererScheduler() { -} - -RendererScheduler::~RendererScheduler() { -} - -RendererScheduler::RAILModeObserver::~RAILModeObserver() = default; - -// static -std::unique_ptr<RendererScheduler> RendererScheduler::Create() { - // Ensure worker.scheduler, worker.scheduler.debug and - // renderer.scheduler.debug appear as an option in about://tracing - base::trace_event::TraceLog::GetCategoryGroupEnabled( - TRACE_DISABLED_BY_DEFAULT("worker.scheduler")); - base::trace_event::TraceLog::GetCategoryGroupEnabled( - TRACE_DISABLED_BY_DEFAULT("worker.scheduler.debug")); - base::trace_event::TraceLog::GetCategoryGroupEnabled( - TRACE_DISABLED_BY_DEFAULT("renderer.scheduler.debug")); - - base::MessageLoop* message_loop = base::MessageLoop::current(); - std::unique_ptr<RendererSchedulerImpl> scheduler( - new RendererSchedulerImpl(SchedulerTqmDelegateImpl::Create( - message_loop, base::WrapUnique(new base::DefaultTickClock())))); - - // Runtime features are not currently available in html_viewer. - if (base::FeatureList::GetInstance()) { - bool blocking_allowed = - base::FeatureList::IsEnabled(kExpensiveTaskBlockingPolicyFeature); - // Also check the old style FieldTrial API for perf waterfall compatibility. - const std::string group_name = base::FieldTrialList::FindFullName( - kExpensiveTaskBlockingPolicyFeature.name); - blocking_allowed |= base::StartsWith(group_name, "Enabled", - base::CompareCase::INSENSITIVE_ASCII); - scheduler->SetExpensiveTaskBlockingAllowed(blocking_allowed); - } - return base::WrapUnique<RendererScheduler>(scheduler.release()); -} - -// static -const char* RendererScheduler::InputEventStateToString( - InputEventState input_event_state) { - switch (input_event_state) { - case InputEventState::EVENT_CONSUMED_BY_COMPOSITOR: - return "event_consumed_by_compositor"; - case InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD: - return "event_forwarded_to_main_thread"; - default: - NOTREACHED(); - return nullptr; - } -} - -} // namespace scheduler
diff --git a/components/scheduler/renderer/renderer_scheduler.h b/components/scheduler/renderer/renderer_scheduler.h deleted file mode 100644 index 33d75ab..0000000 --- a/components/scheduler/renderer/renderer_scheduler.h +++ /dev/null
@@ -1,188 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_RENDERER_RENDERER_SCHEDULER_H_ -#define COMPONENTS_SCHEDULER_RENDERER_RENDERER_SCHEDULER_H_ - -#include <memory> - -#include "base/macros.h" -#include "base/message_loop/message_loop.h" -#include "components/scheduler/child/child_scheduler.h" -#include "components/scheduler/child/single_thread_idle_task_runner.h" -#include "components/scheduler/renderer/render_widget_scheduling_state.h" -#include "components/scheduler/scheduler_export.h" -#include "third_party/WebKit/public/platform/WebScheduler.h" -#include "third_party/WebKit/public/web/WebInputEvent.h" -#include "v8/include/v8.h" - -namespace base { -namespace trace_event { -class BlameContext; -} -} - -namespace cc { -struct BeginFrameArgs; -} - -namespace blink { -class WebLocalFrame; -class WebThread; -} - -namespace scheduler { - -class RenderWidgetSchedulingState; - -class SCHEDULER_EXPORT RendererScheduler : public ChildScheduler { - public: - class SCHEDULER_EXPORT RAILModeObserver { - public: - virtual ~RAILModeObserver(); - virtual void OnRAILModeChanged(v8::RAILMode rail_mode) = 0; - }; - - ~RendererScheduler() override; - static std::unique_ptr<RendererScheduler> Create(); - - // Returns the compositor task runner. - virtual scoped_refptr<TaskQueue> CompositorTaskRunner() = 0; - - // Creates a WebThread implementation for the renderer main thread. - virtual std::unique_ptr<blink::WebThread> CreateMainThread() = 0; - - // Returns the loading task runner. This queue is intended for tasks related - // to resource dispatch, foreground HTML parsing, etc... - virtual scoped_refptr<TaskQueue> LoadingTaskRunner() = 0; - - // Returns the timer task runner. This queue is intended for DOM Timers. - // TODO(alexclarke): Get rid of this default timer queue. - virtual scoped_refptr<TaskQueue> TimerTaskRunner() = 0; - - // Returns a new loading task runner. This queue is intended for tasks related - // to resource dispatch, foreground HTML parsing, etc... - virtual scoped_refptr<TaskQueue> NewLoadingTaskRunner(const char* name) = 0; - - // Returns a new timer task runner. This queue is intended for DOM Timers. - virtual scoped_refptr<TaskQueue> NewTimerTaskRunner(const char* name) = 0; - - // Returns a task runner for tasks which should never get throttled. - virtual scoped_refptr<TaskQueue> NewUnthrottledTaskRunner( - const char* name) = 0; - - // Returns a new RenderWidgetSchedulingState. The signals from this will be - // used to make scheduling decisions. - virtual std::unique_ptr<RenderWidgetSchedulingState> - NewRenderWidgetSchedulingState() = 0; - - // Called to notify about the start of an extended period where no frames - // need to be drawn. Must be called from the main thread. - virtual void BeginFrameNotExpectedSoon() = 0; - - // Called to notify about the start of a new frame. Must be called from the - // main thread. - virtual void WillBeginFrame(const cc::BeginFrameArgs& args) = 0; - - // Called to notify that a previously begun frame was committed. Must be - // called from the main thread. - virtual void DidCommitFrameToCompositor() = 0; - - // Keep RendererScheduler::InputEventStateToString in sync with this enum. - enum class InputEventState { - EVENT_CONSUMED_BY_COMPOSITOR, - EVENT_FORWARDED_TO_MAIN_THREAD, - }; - static const char* InputEventStateToString(InputEventState input_event_state); - - // Tells the scheduler that the system processed an input event. Called by the - // compositor (impl) thread. Note it's expected that every call to - // DidHandleInputEventOnCompositorThread where |event_state| is - // EVENT_FORWARDED_TO_MAIN_THREAD will be followed by a corresponding call - // to DidHandleInputEventOnMainThread. - virtual void DidHandleInputEventOnCompositorThread( - const blink::WebInputEvent& web_input_event, - InputEventState event_state) = 0; - - // Tells the scheduler that the system processed an input event. Must be - // called from the main thread. - virtual void DidHandleInputEventOnMainThread( - const blink::WebInputEvent& web_input_event) = 0; - - // Tells the scheduler that the system is displaying an input animation (e.g. - // a fling). Called by the compositor (impl) thread. - virtual void DidAnimateForInputOnCompositorThread() = 0; - - // Tells the scheduler that the renderer process has been backgrounded, i.e., - // there are no critical, user facing activities (visual, audio, etc...) - // driven by this process. A stricter condition than |OnRendererHidden()|, the - // process is assumed to be foregrounded when the scheduler is constructed. - // Must be called on the main thread. - virtual void OnRendererBackgrounded() = 0; - - // Tells the scheduler that the renderer process has been foregrounded. - // This is the assumed state when the scheduler is constructed. - // Must be called on the main thread. - virtual void OnRendererForegrounded() = 0; - - // Tells the scheduler that the render process should be suspended. This can - // only be done when the renderer is backgrounded. The renderer will be - // automatically resumed when foregrounded. - virtual void SuspendRenderer() = 0; - - // Tells the scheduler that a navigation task is pending. While any main-frame - // navigation tasks are pending, the scheduler will ensure that loading tasks - // are not blocked even if they are expensive. Must be called on the main - // thread. - virtual void AddPendingNavigation( - blink::WebScheduler::NavigatingFrameType type) = 0; - - // Tells the scheduler that a navigation task is no longer pending. - // Must be called on the main thread. - virtual void RemovePendingNavigation( - blink::WebScheduler::NavigatingFrameType type) = 0; - - // Tells the scheduler that a navigation has started. The scheduler will - // prioritize loading tasks for a short duration afterwards. - // Must be called from the main thread. - virtual void OnNavigationStarted() = 0; - - // Returns true if the scheduler has reason to believe that high priority work - // may soon arrive on the main thread, e.g., if gesture events were observed - // recently. - // Must be called from the main thread. - virtual bool IsHighPriorityWorkAnticipated() = 0; - - // Suspends the timer queue and increments the timer queue suspension count. - // May only be called from the main thread. - virtual void SuspendTimerQueue() = 0; - - // Decrements the timer queue suspension count and re-enables the timer queue - // if the suspension count is zero and the current schduler policy allows it. - virtual void ResumeTimerQueue() = 0; - - // Sets whether to allow suspension of timers after the backgrounded signal is - // received via OnRendererBackgrounded. Defaults to disabled. - virtual void SetTimerQueueSuspensionWhenBackgroundedEnabled(bool enabled) = 0; - - // Sets the default blame context to which top level work should be - // attributed in this renderer. |blame_context| must outlive this scheduler. - virtual void SetTopLevelBlameContext( - base::trace_event::BlameContext* blame_context) = 0; - - // The renderer scheduler maintains an estimated RAIL mode[1]. This observer - // can be used to get notified when the mode changes. The observer will be - // called on the main thread and must outlive this class. - // [1] - // https://developers.google.com/web/tools/chrome-devtools/profile/evaluate-performance/rail - virtual void SetRAILModeObserver(RAILModeObserver* observer) = 0; - - protected: - RendererScheduler(); - DISALLOW_COPY_AND_ASSIGN(RendererScheduler); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_RENDERER_RENDERER_SCHEDULER_H_
diff --git a/components/scheduler/renderer/renderer_scheduler_impl.cc b/components/scheduler/renderer/renderer_scheduler_impl.cc deleted file mode 100644 index 56e84f4..0000000 --- a/components/scheduler/renderer/renderer_scheduler_impl.cc +++ /dev/null
@@ -1,1506 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/renderer/renderer_scheduler_impl.h" - -#include "base/bind.h" -#include "base/debug/stack_trace.h" -#include "base/logging.h" -#include "base/memory/ptr_util.h" -#include "base/metrics/histogram_macros.h" -#include "base/trace_event/trace_event.h" -#include "base/trace_event/trace_event_argument.h" -#include "cc/output/begin_frame_args.h" -#include "components/scheduler/base/task_queue_impl.h" -#include "components/scheduler/base/task_queue_selector.h" -#include "components/scheduler/base/virtual_time_domain.h" -#include "components/scheduler/child/scheduler_tqm_delegate.h" -#include "components/scheduler/renderer/auto_advancing_virtual_time_domain.h" -#include "components/scheduler/renderer/web_view_scheduler_impl.h" -#include "components/scheduler/renderer/webthread_impl_for_renderer_scheduler.h" - -namespace scheduler { -namespace { -// The run time of loading tasks is strongly bimodal. The vast majority are -// very cheap, but there are usually a handful of very expensive tasks (e.g ~1 -// second on a mobile device) so we take a very pessimistic view when estimating -// the cost of loading tasks. -const int kLoadingTaskEstimationSampleCount = 1000; -const double kLoadingTaskEstimationPercentile = 99; -const int kTimerTaskEstimationSampleCount = 1000; -const double kTimerTaskEstimationPercentile = 99; -const int kShortIdlePeriodDurationSampleCount = 10; -const double kShortIdlePeriodDurationPercentile = 50; -// Amount of idle time left in a frame (as a ratio of the vsync interval) above -// which main thread compositing can be considered fast. -const double kFastCompositingIdleTimeThreshold = .2; -} // namespace - -RendererSchedulerImpl::RendererSchedulerImpl( - scoped_refptr<SchedulerTqmDelegate> main_task_runner) - : helper_(main_task_runner, - "renderer.scheduler", - TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), - TRACE_DISABLED_BY_DEFAULT("renderer.scheduler.debug")), - idle_helper_(&helper_, - this, - "renderer.scheduler", - TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), - "RendererSchedulerIdlePeriod", - base::TimeDelta()), - render_widget_scheduler_signals_(this), - control_task_runner_(helper_.ControlTaskRunner()), - compositor_task_runner_(helper_.NewTaskQueue( - TaskQueue::Spec("compositor_tq").SetShouldMonitorQuiescence(true))), - delayed_update_policy_runner_( - base::Bind(&RendererSchedulerImpl::UpdatePolicy, - base::Unretained(this)), - helper_.ControlTaskRunner()), - main_thread_only_(this, - compositor_task_runner_, - helper_.scheduler_tqm_delegate().get()), - policy_may_need_update_(&any_thread_lock_), - weak_factory_(this) { - throttling_helper_.reset(new ThrottlingHelper(this, "renderer.scheduler")); - update_policy_closure_ = base::Bind(&RendererSchedulerImpl::UpdatePolicy, - weak_factory_.GetWeakPtr()); - end_renderer_hidden_idle_period_closure_.Reset(base::Bind( - &RendererSchedulerImpl::EndIdlePeriod, weak_factory_.GetWeakPtr())); - - suspend_timers_when_backgrounded_closure_.Reset( - base::Bind(&RendererSchedulerImpl::SuspendTimerQueueWhenBackgrounded, - weak_factory_.GetWeakPtr())); - - default_loading_task_runner_ = NewLoadingTaskRunner("default_loading_tq"); - default_timer_task_runner_ = NewTimerTaskRunner("default_timer_tq"); - - TRACE_EVENT_OBJECT_CREATED_WITH_ID( - TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", - this); - - helper_.SetObserver(this); - helper_.SetTaskTimeTracker(this); -} - -RendererSchedulerImpl::~RendererSchedulerImpl() { - TRACE_EVENT_OBJECT_DELETED_WITH_ID( - TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", - this); - - for (const scoped_refptr<TaskQueue>& loading_queue : loading_task_runners_) { - loading_queue->RemoveTaskObserver( - &MainThreadOnly().loading_task_cost_estimator); - } - for (const scoped_refptr<TaskQueue>& timer_queue : timer_task_runners_) { - timer_queue->RemoveTaskObserver( - &MainThreadOnly().timer_task_cost_estimator); - } - - if (virtual_time_domain_) - UnregisterTimeDomain(virtual_time_domain_.get()); - - // Ensure the renderer scheduler was shut down explicitly, because otherwise - // we could end up having stale pointers to the Blink heap which has been - // terminated by this point. - DCHECK(MainThreadOnly().was_shutdown); -} - -RendererSchedulerImpl::MainThreadOnly::MainThreadOnly( - RendererSchedulerImpl* renderer_scheduler_impl, - const scoped_refptr<TaskQueue>& compositor_task_runner, - base::TickClock* time_source) - : loading_task_cost_estimator(time_source, - kLoadingTaskEstimationSampleCount, - kLoadingTaskEstimationPercentile), - timer_task_cost_estimator(time_source, - kTimerTaskEstimationSampleCount, - kTimerTaskEstimationPercentile), - queueing_time_estimator(renderer_scheduler_impl, - base::TimeDelta::FromSeconds(1)), - idle_time_estimator(compositor_task_runner, - time_source, - kShortIdlePeriodDurationSampleCount, - kShortIdlePeriodDurationPercentile), - current_use_case(UseCase::NONE), - timer_queue_suspend_count(0), - navigation_task_expected_count(0), - expensive_task_policy(ExpensiveTaskPolicy::RUN), - renderer_hidden(false), - renderer_backgrounded(false), - renderer_suspended(false), - timer_queue_suspension_when_backgrounded_enabled(false), - timer_queue_suspended_when_backgrounded(false), - was_shutdown(false), - loading_tasks_seem_expensive(false), - timer_tasks_seem_expensive(false), - touchstart_expected_soon(false), - have_seen_a_begin_main_frame(false), - have_reported_blocking_intervention_in_current_policy(false), - have_reported_blocking_intervention_since_navigation(false), - has_visible_render_widget_with_touch_handler(false), - begin_frame_not_expected_soon(false), - expensive_task_blocking_allowed(true), - in_idle_period_for_testing(false), - use_virtual_time(false), - rail_mode_observer(nullptr) {} - -RendererSchedulerImpl::MainThreadOnly::~MainThreadOnly() {} - -RendererSchedulerImpl::AnyThread::AnyThread() - : awaiting_touch_start_response(false), - in_idle_period(false), - begin_main_frame_on_critical_path(false), - last_gesture_was_compositor_driven(false), - default_gesture_prevented(true), - have_seen_touchstart(false) {} - -RendererSchedulerImpl::AnyThread::~AnyThread() {} - -RendererSchedulerImpl::CompositorThreadOnly::CompositorThreadOnly() - : last_input_type(blink::WebInputEvent::Undefined) {} - -RendererSchedulerImpl::CompositorThreadOnly::~CompositorThreadOnly() {} - -void RendererSchedulerImpl::Shutdown() { - throttling_helper_.reset(); - helper_.Shutdown(); - MainThreadOnly().was_shutdown = true; - MainThreadOnly().rail_mode_observer = nullptr; -} - -std::unique_ptr<blink::WebThread> RendererSchedulerImpl::CreateMainThread() { - return base::WrapUnique(new WebThreadImplForRendererScheduler(this)); -} - -scoped_refptr<TaskQueue> RendererSchedulerImpl::DefaultTaskRunner() { - return helper_.DefaultTaskRunner(); -} - -scoped_refptr<TaskQueue> RendererSchedulerImpl::CompositorTaskRunner() { - helper_.CheckOnValidThread(); - return compositor_task_runner_; -} - -scoped_refptr<SingleThreadIdleTaskRunner> -RendererSchedulerImpl::IdleTaskRunner() { - return idle_helper_.IdleTaskRunner(); -} - -scoped_refptr<TaskQueue> RendererSchedulerImpl::LoadingTaskRunner() { - helper_.CheckOnValidThread(); - return default_loading_task_runner_; -} - -scoped_refptr<TaskQueue> RendererSchedulerImpl::TimerTaskRunner() { - helper_.CheckOnValidThread(); - return default_timer_task_runner_; -} - -scoped_refptr<TaskQueue> RendererSchedulerImpl::ControlTaskRunner() { - helper_.CheckOnValidThread(); - return helper_.ControlTaskRunner(); -} - -scoped_refptr<TaskQueue> RendererSchedulerImpl::NewLoadingTaskRunner( - const char* name) { - helper_.CheckOnValidThread(); - scoped_refptr<TaskQueue> loading_task_queue(helper_.NewTaskQueue( - TaskQueue::Spec(name).SetShouldMonitorQuiescence(true).SetTimeDomain( - MainThreadOnly().use_virtual_time ? GetVirtualTimeDomain() - : nullptr))); - loading_task_runners_.insert(loading_task_queue); - loading_task_queue->SetQueueEnabled( - MainThreadOnly().current_policy.loading_queue_policy.is_enabled); - loading_task_queue->SetQueuePriority( - MainThreadOnly().current_policy.loading_queue_policy.priority); - if (MainThreadOnly().current_policy.loading_queue_policy.time_domain_type == - TimeDomainType::THROTTLED) { - throttling_helper_->IncreaseThrottleRefCount(loading_task_queue.get()); - } - loading_task_queue->AddTaskObserver( - &MainThreadOnly().loading_task_cost_estimator); - return loading_task_queue; -} - -scoped_refptr<TaskQueue> RendererSchedulerImpl::NewTimerTaskRunner( - const char* name) { - helper_.CheckOnValidThread(); - // TODO(alexclarke): Consider using ApplyTaskQueuePolicy() for brevity. - scoped_refptr<TaskQueue> timer_task_queue( - helper_.NewTaskQueue(TaskQueue::Spec(name) - .SetShouldMonitorQuiescence(true) - .SetShouldReportWhenExecutionBlocked(true) - .SetTimeDomain(MainThreadOnly().use_virtual_time - ? GetVirtualTimeDomain() - : nullptr))); - timer_task_runners_.insert(timer_task_queue); - timer_task_queue->SetQueueEnabled( - MainThreadOnly().current_policy.timer_queue_policy.is_enabled); - timer_task_queue->SetQueuePriority( - MainThreadOnly().current_policy.timer_queue_policy.priority); - if (MainThreadOnly().current_policy.timer_queue_policy.time_domain_type == - TimeDomainType::THROTTLED) { - throttling_helper_->IncreaseThrottleRefCount(timer_task_queue.get()); - } - timer_task_queue->AddTaskObserver( - &MainThreadOnly().timer_task_cost_estimator); - return timer_task_queue; -} - -scoped_refptr<TaskQueue> RendererSchedulerImpl::NewUnthrottledTaskRunner( - const char* name) { - helper_.CheckOnValidThread(); - scoped_refptr<TaskQueue> unthrottled_task_queue(helper_.NewTaskQueue( - TaskQueue::Spec(name).SetShouldMonitorQuiescence(true).SetTimeDomain( - MainThreadOnly().use_virtual_time ? GetVirtualTimeDomain() - : nullptr))); - unthrottled_task_runners_.insert(unthrottled_task_queue); - return unthrottled_task_queue; -} - -std::unique_ptr<RenderWidgetSchedulingState> -RendererSchedulerImpl::NewRenderWidgetSchedulingState() { - return render_widget_scheduler_signals_.NewRenderWidgetSchedulingState(); -} - -void RendererSchedulerImpl::OnUnregisterTaskQueue( - const scoped_refptr<TaskQueue>& task_queue) { - if (throttling_helper_.get()) - throttling_helper_->UnregisterTaskQueue(task_queue.get()); - - if (loading_task_runners_.find(task_queue) != loading_task_runners_.end()) { - task_queue->RemoveTaskObserver( - &MainThreadOnly().loading_task_cost_estimator); - loading_task_runners_.erase(task_queue); - } else if (timer_task_runners_.find(task_queue) != - timer_task_runners_.end()) { - task_queue->RemoveTaskObserver(&MainThreadOnly().timer_task_cost_estimator); - timer_task_runners_.erase(task_queue); - } else if (unthrottled_task_runners_.find(task_queue) != - unthrottled_task_runners_.end()) { - unthrottled_task_runners_.erase(task_queue); - } -} - -bool RendererSchedulerImpl::CanExceedIdleDeadlineIfRequired() const { - return idle_helper_.CanExceedIdleDeadlineIfRequired(); -} - -void RendererSchedulerImpl::AddTaskObserver( - base::MessageLoop::TaskObserver* task_observer) { - helper_.AddTaskObserver(task_observer); -} - -void RendererSchedulerImpl::RemoveTaskObserver( - base::MessageLoop::TaskObserver* task_observer) { - helper_.RemoveTaskObserver(task_observer); -} - -void RendererSchedulerImpl::WillBeginFrame(const cc::BeginFrameArgs& args) { - TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), - "RendererSchedulerImpl::WillBeginFrame", "args", args.AsValue()); - helper_.CheckOnValidThread(); - if (helper_.IsShutdown()) - return; - - EndIdlePeriod(); - MainThreadOnly().estimated_next_frame_begin = args.frame_time + args.interval; - MainThreadOnly().have_seen_a_begin_main_frame = true; - MainThreadOnly().begin_frame_not_expected_soon = false; - MainThreadOnly().compositor_frame_interval = args.interval; - { - base::AutoLock lock(any_thread_lock_); - AnyThread().begin_main_frame_on_critical_path = args.on_critical_path; - } -} - -void RendererSchedulerImpl::DidCommitFrameToCompositor() { - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), - "RendererSchedulerImpl::DidCommitFrameToCompositor"); - helper_.CheckOnValidThread(); - if (helper_.IsShutdown()) - return; - - base::TimeTicks now(helper_.scheduler_tqm_delegate()->NowTicks()); - if (now < MainThreadOnly().estimated_next_frame_begin) { - // TODO(rmcilroy): Consider reducing the idle period based on the runtime of - // the next pending delayed tasks (as currently done in for long idle times) - idle_helper_.StartIdlePeriod( - IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, now, - MainThreadOnly().estimated_next_frame_begin); - } - - MainThreadOnly().idle_time_estimator.DidCommitFrameToCompositor(); -} - -void RendererSchedulerImpl::BeginFrameNotExpectedSoon() { - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), - "RendererSchedulerImpl::BeginFrameNotExpectedSoon"); - helper_.CheckOnValidThread(); - if (helper_.IsShutdown()) - return; - - MainThreadOnly().begin_frame_not_expected_soon = true; - idle_helper_.EnableLongIdlePeriod(); - { - base::AutoLock lock(any_thread_lock_); - AnyThread().begin_main_frame_on_critical_path = false; - } -} - -void RendererSchedulerImpl::SetAllRenderWidgetsHidden(bool hidden) { - TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), - "RendererSchedulerImpl::SetAllRenderWidgetsHidden", "hidden", - hidden); - - helper_.CheckOnValidThread(); - - if (helper_.IsShutdown() || MainThreadOnly().renderer_hidden == hidden) - return; - - end_renderer_hidden_idle_period_closure_.Cancel(); - - if (hidden) { - idle_helper_.EnableLongIdlePeriod(); - - // Ensure that we stop running idle tasks after a few seconds of being - // hidden. - base::TimeDelta end_idle_when_hidden_delay = - base::TimeDelta::FromMilliseconds(kEndIdleWhenHiddenDelayMillis); - control_task_runner_->PostDelayedTask( - FROM_HERE, end_renderer_hidden_idle_period_closure_.callback(), - end_idle_when_hidden_delay); - MainThreadOnly().renderer_hidden = true; - } else { - MainThreadOnly().renderer_hidden = false; - EndIdlePeriod(); - } - - // TODO(alexclarke): Should we update policy here? - TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( - TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", - this, AsValue(helper_.scheduler_tqm_delegate()->NowTicks())); -} - -void RendererSchedulerImpl::SetHasVisibleRenderWidgetWithTouchHandler( - bool has_visible_render_widget_with_touch_handler) { - helper_.CheckOnValidThread(); - if (has_visible_render_widget_with_touch_handler == - MainThreadOnly().has_visible_render_widget_with_touch_handler) - return; - - MainThreadOnly().has_visible_render_widget_with_touch_handler = - has_visible_render_widget_with_touch_handler; - - base::AutoLock lock(any_thread_lock_); - UpdatePolicyLocked(UpdateType::FORCE_UPDATE); -} - -void RendererSchedulerImpl::OnRendererBackgrounded() { - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), - "RendererSchedulerImpl::OnRendererBackgrounded"); - helper_.CheckOnValidThread(); - if (helper_.IsShutdown() || MainThreadOnly().renderer_backgrounded) - return; - - MainThreadOnly().renderer_backgrounded = true; - if (!MainThreadOnly().timer_queue_suspension_when_backgrounded_enabled) - return; - - suspend_timers_when_backgrounded_closure_.Cancel(); - base::TimeDelta suspend_timers_when_backgrounded_delay = - base::TimeDelta::FromMilliseconds( - kSuspendTimersWhenBackgroundedDelayMillis); - control_task_runner_->PostDelayedTask( - FROM_HERE, suspend_timers_when_backgrounded_closure_.callback(), - suspend_timers_when_backgrounded_delay); -} - -void RendererSchedulerImpl::OnRendererForegrounded() { - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), - "RendererSchedulerImpl::OnRendererForegrounded"); - helper_.CheckOnValidThread(); - if (helper_.IsShutdown() || !MainThreadOnly().renderer_backgrounded) - return; - - MainThreadOnly().renderer_backgrounded = false; - MainThreadOnly().renderer_suspended = false; - suspend_timers_when_backgrounded_closure_.Cancel(); - ResumeTimerQueueWhenForegrounded(); -} - -void RendererSchedulerImpl::SuspendRenderer() { - helper_.CheckOnValidThread(); - DCHECK(MainThreadOnly().renderer_backgrounded); - if (helper_.IsShutdown()) - return; - suspend_timers_when_backgrounded_closure_.Cancel(); - // TODO(hajimehoshi): We might need to suspend not only timer queue but also - // e.g. loading tasks or postMessage. - MainThreadOnly().renderer_suspended = true; - SuspendTimerQueueWhenBackgrounded(); -} - -void RendererSchedulerImpl::EndIdlePeriod() { - if (MainThreadOnly().in_idle_period_for_testing) - return; - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), - "RendererSchedulerImpl::EndIdlePeriod"); - helper_.CheckOnValidThread(); - idle_helper_.EndIdlePeriod(); -} - -void RendererSchedulerImpl::EndIdlePeriodForTesting( - const base::Closure& callback, - base::TimeTicks time_remaining) { - MainThreadOnly().in_idle_period_for_testing = false; - EndIdlePeriod(); - callback.Run(); -} - -bool RendererSchedulerImpl::PolicyNeedsUpdateForTesting() { - return policy_may_need_update_.IsSet(); -} - -// static -bool RendererSchedulerImpl::ShouldPrioritizeInputEvent( - const blink::WebInputEvent& web_input_event) { - // We regard MouseMove events with the left mouse button down as a signal - // that the user is doing something requiring a smooth frame rate. - if (web_input_event.type == blink::WebInputEvent::MouseMove && - (web_input_event.modifiers & blink::WebInputEvent::LeftButtonDown)) { - return true; - } - // Ignore all other mouse events because they probably don't signal user - // interaction needing a smooth framerate. NOTE isMouseEventType returns false - // for mouse wheel events, hence we regard them as user input. - // Ignore keyboard events because it doesn't really make sense to enter - // compositor priority for them. - if (blink::WebInputEvent::isMouseEventType(web_input_event.type) || - blink::WebInputEvent::isKeyboardEventType(web_input_event.type)) { - return false; - } - return true; -} - -void RendererSchedulerImpl::DidHandleInputEventOnCompositorThread( - const blink::WebInputEvent& web_input_event, - InputEventState event_state) { - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), - "RendererSchedulerImpl::DidHandleInputEventOnCompositorThread"); - if (!ShouldPrioritizeInputEvent(web_input_event)) - return; - - UpdateForInputEventOnCompositorThread(web_input_event.type, event_state); -} - -void RendererSchedulerImpl::DidAnimateForInputOnCompositorThread() { - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), - "RendererSchedulerImpl::DidAnimateForInputOnCompositorThread"); - base::AutoLock lock(any_thread_lock_); - AnyThread().fling_compositor_escalation_deadline = - helper_.scheduler_tqm_delegate()->NowTicks() + - base::TimeDelta::FromMilliseconds(kFlingEscalationLimitMillis); -} - -void RendererSchedulerImpl::UpdateForInputEventOnCompositorThread( - blink::WebInputEvent::Type type, - InputEventState input_event_state) { - base::AutoLock lock(any_thread_lock_); - base::TimeTicks now = helper_.scheduler_tqm_delegate()->NowTicks(); - - // TODO(alexclarke): Move WebInputEventTraits where we can access it from here - // and record the name rather than the integer representation. - TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), - "RendererSchedulerImpl::UpdateForInputEventOnCompositorThread", - "type", static_cast<int>(type), "input_event_state", - InputEventStateToString(input_event_state)); - - base::TimeDelta unused_policy_duration; - UseCase previous_use_case = - ComputeCurrentUseCase(now, &unused_policy_duration); - bool was_awaiting_touch_start_response = - AnyThread().awaiting_touch_start_response; - - AnyThread().user_model.DidStartProcessingInputEvent(type, now); - - if (input_event_state == InputEventState::EVENT_CONSUMED_BY_COMPOSITOR) - AnyThread().user_model.DidFinishProcessingInputEvent(now); - - if (type) { - switch (type) { - case blink::WebInputEvent::TouchStart: - AnyThread().awaiting_touch_start_response = true; - // This is just a fail-safe to reset the state of - // |last_gesture_was_compositor_driven| to the default. We don't know - // yet where the gesture will run. - AnyThread().last_gesture_was_compositor_driven = false; - AnyThread().have_seen_touchstart = true; - // Assume the default gesture is prevented until we see evidence - // otherwise. - AnyThread().default_gesture_prevented = true; - break; - - case blink::WebInputEvent::TouchMove: - // Observation of consecutive touchmoves is a strong signal that the - // page is consuming the touch sequence, in which case touchstart - // response prioritization is no longer necessary. Otherwise, the - // initial touchmove should preserve the touchstart response pending - // state. - if (AnyThread().awaiting_touch_start_response && - CompositorThreadOnly().last_input_type == - blink::WebInputEvent::TouchMove) { - AnyThread().awaiting_touch_start_response = false; - } - break; - - case blink::WebInputEvent::GesturePinchUpdate: - case blink::WebInputEvent::GestureScrollUpdate: - // If we see events for an established gesture, we can lock it to the - // appropriate thread as the gesture can no longer be cancelled. - AnyThread().last_gesture_was_compositor_driven = - input_event_state == InputEventState::EVENT_CONSUMED_BY_COMPOSITOR; - AnyThread().awaiting_touch_start_response = false; - AnyThread().default_gesture_prevented = false; - break; - - case blink::WebInputEvent::GestureFlingCancel: - AnyThread().fling_compositor_escalation_deadline = base::TimeTicks(); - break; - - case blink::WebInputEvent::GestureTapDown: - case blink::WebInputEvent::GestureShowPress: - case blink::WebInputEvent::GestureScrollEnd: - // With no observable effect, these meta events do not indicate a - // meaningful touchstart response and should not impact task priority. - break; - - default: - AnyThread().awaiting_touch_start_response = false; - break; - } - } - - // Avoid unnecessary policy updates if the use case did not change. - UseCase use_case = ComputeCurrentUseCase(now, &unused_policy_duration); - - if (use_case != previous_use_case || - was_awaiting_touch_start_response != - AnyThread().awaiting_touch_start_response) { - EnsureUrgentPolicyUpdatePostedOnMainThread(FROM_HERE); - } - CompositorThreadOnly().last_input_type = type; -} - -void RendererSchedulerImpl::DidHandleInputEventOnMainThread( - const blink::WebInputEvent& web_input_event) { - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), - "RendererSchedulerImpl::DidHandleInputEventOnMainThread"); - helper_.CheckOnValidThread(); - if (ShouldPrioritizeInputEvent(web_input_event)) { - base::AutoLock lock(any_thread_lock_); - AnyThread().user_model.DidFinishProcessingInputEvent( - helper_.scheduler_tqm_delegate()->NowTicks()); - } -} - -bool RendererSchedulerImpl::IsHighPriorityWorkAnticipated() { - helper_.CheckOnValidThread(); - if (helper_.IsShutdown()) - return false; - - MaybeUpdatePolicy(); - // The touchstart, synchronized gesture and main-thread gesture use cases - // indicate a strong likelihood of high-priority work in the near future. - UseCase use_case = MainThreadOnly().current_use_case; - return MainThreadOnly().touchstart_expected_soon || - use_case == UseCase::TOUCHSTART || - use_case == UseCase::MAIN_THREAD_GESTURE || - use_case == UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING || - use_case == UseCase::SYNCHRONIZED_GESTURE; -} - -bool RendererSchedulerImpl::ShouldYieldForHighPriorityWork() { - helper_.CheckOnValidThread(); - if (helper_.IsShutdown()) - return false; - - MaybeUpdatePolicy(); - // We only yield if there's a urgent task to be run now, or we are expecting - // one soon (touch start). - // Note: even though the control queue has the highest priority we don't yield - // for it since these tasks are not user-provided work and they are only - // intended to run before the next task, not interrupt the tasks. - switch (MainThreadOnly().current_use_case) { - case UseCase::COMPOSITOR_GESTURE: - case UseCase::NONE: - return MainThreadOnly().touchstart_expected_soon; - - case UseCase::MAIN_THREAD_GESTURE: - case UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING: - case UseCase::SYNCHRONIZED_GESTURE: - return compositor_task_runner_->HasPendingImmediateWork() || - MainThreadOnly().touchstart_expected_soon; - - case UseCase::TOUCHSTART: - return true; - - case UseCase::LOADING: - return false; - - default: - NOTREACHED(); - return false; - } -} - -base::TimeTicks RendererSchedulerImpl::CurrentIdleTaskDeadlineForTesting() - const { - return idle_helper_.CurrentIdleTaskDeadline(); -} - -void RendererSchedulerImpl::RunIdleTasksForTesting( - const base::Closure& callback) { - MainThreadOnly().in_idle_period_for_testing = true; - IdleTaskRunner()->PostIdleTask( - FROM_HERE, - base::Bind(&RendererSchedulerImpl::EndIdlePeriodForTesting, - weak_factory_.GetWeakPtr(), callback)); - idle_helper_.EnableLongIdlePeriod(); -} - -void RendererSchedulerImpl::MaybeUpdatePolicy() { - helper_.CheckOnValidThread(); - if (policy_may_need_update_.IsSet()) { - UpdatePolicy(); - } -} - -void RendererSchedulerImpl::EnsureUrgentPolicyUpdatePostedOnMainThread( - const tracked_objects::Location& from_here) { - // TODO(scheduler-dev): Check that this method isn't called from the main - // thread. - any_thread_lock_.AssertAcquired(); - if (!policy_may_need_update_.IsSet()) { - policy_may_need_update_.SetWhileLocked(true); - control_task_runner_->PostTask(from_here, update_policy_closure_); - } -} - -void RendererSchedulerImpl::UpdatePolicy() { - base::AutoLock lock(any_thread_lock_); - UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED); -} - -void RendererSchedulerImpl::ForceUpdatePolicy() { - base::AutoLock lock(any_thread_lock_); - UpdatePolicyLocked(UpdateType::FORCE_UPDATE); -} - -void RendererSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) { - helper_.CheckOnValidThread(); - any_thread_lock_.AssertAcquired(); - if (helper_.IsShutdown()) - return; - - base::TimeTicks now = helper_.scheduler_tqm_delegate()->NowTicks(); - policy_may_need_update_.SetWhileLocked(false); - - base::TimeDelta expected_use_case_duration; - UseCase use_case = ComputeCurrentUseCase(now, &expected_use_case_duration); - MainThreadOnly().current_use_case = use_case; - - base::TimeDelta touchstart_expected_flag_valid_for_duration; - bool touchstart_expected_soon = false; - if (MainThreadOnly().has_visible_render_widget_with_touch_handler) { - touchstart_expected_soon = AnyThread().user_model.IsGestureExpectedSoon( - now, &touchstart_expected_flag_valid_for_duration); - } - MainThreadOnly().touchstart_expected_soon = touchstart_expected_soon; - - base::TimeDelta longest_jank_free_task_duration = - EstimateLongestJankFreeTaskDuration(); - MainThreadOnly().longest_jank_free_task_duration = - longest_jank_free_task_duration; - - bool loading_tasks_seem_expensive = false; - bool timer_tasks_seem_expensive = false; - loading_tasks_seem_expensive = - MainThreadOnly().loading_task_cost_estimator.expected_task_duration() > - longest_jank_free_task_duration; - timer_tasks_seem_expensive = - MainThreadOnly().timer_task_cost_estimator.expected_task_duration() > - longest_jank_free_task_duration; - MainThreadOnly().timer_tasks_seem_expensive = timer_tasks_seem_expensive; - MainThreadOnly().loading_tasks_seem_expensive = loading_tasks_seem_expensive; - - // The |new_policy_duration| is the minimum of |expected_use_case_duration| - // and |touchstart_expected_flag_valid_for_duration| unless one is zero in - // which case we choose the other. - base::TimeDelta new_policy_duration = expected_use_case_duration; - if (new_policy_duration.is_zero() || - (touchstart_expected_flag_valid_for_duration > base::TimeDelta() && - new_policy_duration > touchstart_expected_flag_valid_for_duration)) { - new_policy_duration = touchstart_expected_flag_valid_for_duration; - } - - if (new_policy_duration > base::TimeDelta()) { - MainThreadOnly().current_policy_expiration_time = now + new_policy_duration; - delayed_update_policy_runner_.SetDeadline(FROM_HERE, new_policy_duration, - now); - } else { - MainThreadOnly().current_policy_expiration_time = base::TimeTicks(); - } - - // Avoid prioritizing main thread compositing (e.g., rAF) if it is extremely - // slow, because that can cause starvation in other task sources. - bool main_thread_compositing_is_fast = - MainThreadOnly().idle_time_estimator.GetExpectedIdleDuration( - MainThreadOnly().compositor_frame_interval) > - MainThreadOnly().compositor_frame_interval * - kFastCompositingIdleTimeThreshold; - - Policy new_policy; - ExpensiveTaskPolicy expensive_task_policy = ExpensiveTaskPolicy::RUN; - new_policy.rail_mode = v8::PERFORMANCE_ANIMATION; - - switch (use_case) { - case UseCase::COMPOSITOR_GESTURE: - if (touchstart_expected_soon) { - new_policy.rail_mode = v8::PERFORMANCE_RESPONSE; - expensive_task_policy = ExpensiveTaskPolicy::BLOCK; - new_policy.compositor_queue_policy.priority = TaskQueue::HIGH_PRIORITY; - } else { - // What we really want to do is priorize loading tasks, but that doesn't - // seem to be safe. Instead we do that by proxy by deprioritizing - // compositor tasks. This should be safe since we've already gone to the - // pain of fixing ordering issues with them. - new_policy.compositor_queue_policy.priority = - TaskQueue::BEST_EFFORT_PRIORITY; - } - break; - - case UseCase::SYNCHRONIZED_GESTURE: - new_policy.compositor_queue_policy.priority = - main_thread_compositing_is_fast ? TaskQueue::HIGH_PRIORITY - : TaskQueue::NORMAL_PRIORITY; - if (touchstart_expected_soon) { - new_policy.rail_mode = v8::PERFORMANCE_RESPONSE; - expensive_task_policy = ExpensiveTaskPolicy::BLOCK; - } else { - expensive_task_policy = ExpensiveTaskPolicy::THROTTLE; - } - break; - - case UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING: - // In main thread input handling scenarios we don't have perfect knowledge - // about which things we should be prioritizing, so we don't attempt to - // block expensive tasks because we don't know whether they were integral - // to the page's functionality or not. - new_policy.compositor_queue_policy.priority = - main_thread_compositing_is_fast ? TaskQueue::HIGH_PRIORITY - : TaskQueue::NORMAL_PRIORITY; - break; - - case UseCase::MAIN_THREAD_GESTURE: - // A main thread gesture is for example a scroll gesture which is handled - // by the main thread. Since we know the established gesture type, we can - // be a little more aggressive about prioritizing compositing and input - // handling over other tasks. - new_policy.compositor_queue_policy.priority = TaskQueue::HIGH_PRIORITY; - if (touchstart_expected_soon) { - new_policy.rail_mode = v8::PERFORMANCE_RESPONSE; - expensive_task_policy = ExpensiveTaskPolicy::BLOCK; - } else { - expensive_task_policy = ExpensiveTaskPolicy::THROTTLE; - } - break; - - case UseCase::TOUCHSTART: - new_policy.rail_mode = v8::PERFORMANCE_RESPONSE; - new_policy.compositor_queue_policy.priority = TaskQueue::HIGH_PRIORITY; - new_policy.loading_queue_policy.is_enabled = false; - new_policy.timer_queue_policy.is_enabled = false; - // NOTE this is a nop due to the above. - expensive_task_policy = ExpensiveTaskPolicy::BLOCK; - break; - - case UseCase::NONE: - // It's only safe to block tasks that if we are expecting a compositor - // driven gesture. - if (touchstart_expected_soon && - AnyThread().last_gesture_was_compositor_driven) { - new_policy.rail_mode = v8::PERFORMANCE_RESPONSE; - expensive_task_policy = ExpensiveTaskPolicy::BLOCK; - } - break; - - case UseCase::LOADING: - new_policy.rail_mode = v8::PERFORMANCE_LOAD; - new_policy.loading_queue_policy.priority = TaskQueue::HIGH_PRIORITY; - new_policy.default_queue_policy.priority = TaskQueue::HIGH_PRIORITY; - break; - - default: - NOTREACHED(); - } - - // TODO(skyostil): Add an idle state for foreground tabs too. - if (MainThreadOnly().renderer_hidden) - new_policy.rail_mode = v8::PERFORMANCE_IDLE; - - if (expensive_task_policy == ExpensiveTaskPolicy::BLOCK && - (!MainThreadOnly().expensive_task_blocking_allowed || - !MainThreadOnly().have_seen_a_begin_main_frame || - MainThreadOnly().navigation_task_expected_count > 0)) { - expensive_task_policy = ExpensiveTaskPolicy::RUN; - } - - switch (expensive_task_policy) { - case ExpensiveTaskPolicy::RUN: - break; - - case ExpensiveTaskPolicy::BLOCK: - if (loading_tasks_seem_expensive) - new_policy.loading_queue_policy.is_enabled = false; - if (timer_tasks_seem_expensive) - new_policy.timer_queue_policy.is_enabled = false; - break; - - case ExpensiveTaskPolicy::THROTTLE: - if (loading_tasks_seem_expensive) { - new_policy.loading_queue_policy.time_domain_type = - TimeDomainType::THROTTLED; - } - if (timer_tasks_seem_expensive) { - new_policy.timer_queue_policy.time_domain_type = - TimeDomainType::THROTTLED; - } - break; - } - MainThreadOnly().expensive_task_policy = expensive_task_policy; - - if (MainThreadOnly().timer_queue_suspend_count != 0 || - MainThreadOnly().timer_queue_suspended_when_backgrounded) { - new_policy.timer_queue_policy.is_enabled = false; - // TODO(alexclarke): Figure out if we really need to do this. - new_policy.timer_queue_policy.time_domain_type = TimeDomainType::REAL; - } - - if (MainThreadOnly().renderer_suspended) { - new_policy.loading_queue_policy.is_enabled = false; - DCHECK(!new_policy.timer_queue_policy.is_enabled); - } - - if (MainThreadOnly().use_virtual_time) { - new_policy.compositor_queue_policy.time_domain_type = - TimeDomainType::VIRTUAL; - new_policy.default_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; - new_policy.loading_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; - new_policy.timer_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; - } - - // Tracing is done before the early out check, because it's quite possible we - // will otherwise miss this information in traces. - TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( - TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", - this, AsValueLocked(now)); - TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "use_case", - use_case); - TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "rail_mode", - new_policy.rail_mode); - TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), - "touchstart_expected_soon", - MainThreadOnly().touchstart_expected_soon); - TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), - "expensive_task_policy", expensive_task_policy); - TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), - "RendererScheduler.loading_tasks_seem_expensive", - MainThreadOnly().loading_tasks_seem_expensive); - TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), - "RendererScheduler.timer_tasks_seem_expensive", - MainThreadOnly().timer_tasks_seem_expensive); - - // TODO(alexclarke): Can we get rid of force update now? - if (update_type == UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED && - new_policy == MainThreadOnly().current_policy) { - return; - } - - ApplyTaskQueuePolicy(compositor_task_runner_.get(), - MainThreadOnly().current_policy.compositor_queue_policy, - new_policy.compositor_queue_policy); - - for (const scoped_refptr<TaskQueue>& loading_queue : loading_task_runners_) { - ApplyTaskQueuePolicy(loading_queue.get(), - MainThreadOnly().current_policy.loading_queue_policy, - new_policy.loading_queue_policy); - } - - for (const scoped_refptr<TaskQueue>& timer_queue : timer_task_runners_) { - ApplyTaskQueuePolicy(timer_queue.get(), - MainThreadOnly().current_policy.timer_queue_policy, - new_policy.timer_queue_policy); - } - MainThreadOnly().have_reported_blocking_intervention_in_current_policy = - false; - - // TODO(alexclarke): We shouldn't have to prioritize the default queue, but it - // appears to be necessary since the order of loading tasks and IPCs (which - // are mostly dispatched on the default queue) need to be preserved. - ApplyTaskQueuePolicy(helper_.DefaultTaskRunner().get(), - MainThreadOnly().current_policy.default_queue_policy, - new_policy.default_queue_policy); - if (MainThreadOnly().rail_mode_observer && - new_policy.rail_mode != MainThreadOnly().current_policy.rail_mode) { - MainThreadOnly().rail_mode_observer->OnRAILModeChanged( - new_policy.rail_mode); - } - - DCHECK(compositor_task_runner_->IsQueueEnabled()); - MainThreadOnly().current_policy = new_policy; -} - -void RendererSchedulerImpl::ApplyTaskQueuePolicy( - TaskQueue* task_queue, - const TaskQueuePolicy& old_task_queue_policy, - const TaskQueuePolicy& new_task_queue_policy) const { - if (old_task_queue_policy.is_enabled != new_task_queue_policy.is_enabled) { - throttling_helper_->SetQueueEnabled(task_queue, - new_task_queue_policy.is_enabled); - } - - if (old_task_queue_policy.priority != new_task_queue_policy.priority) - task_queue->SetQueuePriority(new_task_queue_policy.priority); - - if (old_task_queue_policy.time_domain_type != - new_task_queue_policy.time_domain_type) { - if (old_task_queue_policy.time_domain_type == TimeDomainType::THROTTLED) { - throttling_helper_->DecreaseThrottleRefCount(task_queue); - } else if (new_task_queue_policy.time_domain_type == - TimeDomainType::THROTTLED) { - throttling_helper_->IncreaseThrottleRefCount(task_queue); - } else if (new_task_queue_policy.time_domain_type == - TimeDomainType::VIRTUAL) { - DCHECK(virtual_time_domain_); - task_queue->SetTimeDomain(virtual_time_domain_.get()); - } - } -} - -RendererSchedulerImpl::UseCase RendererSchedulerImpl::ComputeCurrentUseCase( - base::TimeTicks now, - base::TimeDelta* expected_use_case_duration) const { - any_thread_lock_.AssertAcquired(); - // Special case for flings. This is needed because we don't get notification - // of a fling ending (although we do for cancellation). - if (AnyThread().fling_compositor_escalation_deadline > now && - !AnyThread().awaiting_touch_start_response) { - *expected_use_case_duration = - AnyThread().fling_compositor_escalation_deadline - now; - return UseCase::COMPOSITOR_GESTURE; - } - // Above all else we want to be responsive to user input. - *expected_use_case_duration = - AnyThread().user_model.TimeLeftInUserGesture(now); - if (*expected_use_case_duration > base::TimeDelta()) { - // Has a gesture been fully established? - if (AnyThread().awaiting_touch_start_response) { - // No, so arrange for compositor tasks to be run at the highest priority. - return UseCase::TOUCHSTART; - } - - // Yes a gesture has been established. Based on how the gesture is handled - // we need to choose between one of four use cases: - // 1. COMPOSITOR_GESTURE where the gesture is processed only on the - // compositor thread. - // 2. MAIN_THREAD_GESTURE where the gesture is processed only on the main - // thread. - // 3. MAIN_THREAD_CUSTOM_INPUT_HANDLING where the main thread processes a - // stream of input events and has prevented a default gesture from being - // started. - // 4. SYNCHRONIZED_GESTURE where the gesture is processed on both threads. - // TODO(skyostil): Consider removing in_idle_period_ and - // HadAnIdlePeriodRecently() unless we need them here. - if (AnyThread().last_gesture_was_compositor_driven) { - if (AnyThread().begin_main_frame_on_critical_path) { - return UseCase::SYNCHRONIZED_GESTURE; - } else { - return UseCase::COMPOSITOR_GESTURE; - } - } - if (AnyThread().default_gesture_prevented) { - return UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING; - } else { - return UseCase::MAIN_THREAD_GESTURE; - } - } - - // TODO(alexclarke): return UseCase::LOADING if signals suggest the system is - // in the initial 1s of RAIL loading. - return UseCase::NONE; -} - -base::TimeDelta RendererSchedulerImpl::EstimateLongestJankFreeTaskDuration() - const { - switch (MainThreadOnly().current_use_case) { - case UseCase::TOUCHSTART: - case UseCase::COMPOSITOR_GESTURE: - case UseCase::LOADING: - case UseCase::NONE: - return base::TimeDelta::FromMilliseconds(kRailsResponseTimeMillis); - - case UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING: - case UseCase::MAIN_THREAD_GESTURE: - case UseCase::SYNCHRONIZED_GESTURE: - return MainThreadOnly().idle_time_estimator.GetExpectedIdleDuration( - MainThreadOnly().compositor_frame_interval); - - default: - NOTREACHED(); - return base::TimeDelta::FromMilliseconds(kRailsResponseTimeMillis); - } -} - -bool RendererSchedulerImpl::CanEnterLongIdlePeriod( - base::TimeTicks now, - base::TimeDelta* next_long_idle_period_delay_out) { - helper_.CheckOnValidThread(); - - MaybeUpdatePolicy(); - if (MainThreadOnly().current_use_case == UseCase::TOUCHSTART) { - // Don't start a long idle task in touch start priority, try again when - // the policy is scheduled to end. - *next_long_idle_period_delay_out = - std::max(base::TimeDelta(), - MainThreadOnly().current_policy_expiration_time - now); - return false; - } - return true; -} - -SchedulerHelper* RendererSchedulerImpl::GetSchedulerHelperForTesting() { - return &helper_; -} - -TaskCostEstimator* -RendererSchedulerImpl::GetLoadingTaskCostEstimatorForTesting() { - return &MainThreadOnly().loading_task_cost_estimator; -} - -TaskCostEstimator* -RendererSchedulerImpl::GetTimerTaskCostEstimatorForTesting() { - return &MainThreadOnly().timer_task_cost_estimator; -} - -IdleTimeEstimator* RendererSchedulerImpl::GetIdleTimeEstimatorForTesting() { - return &MainThreadOnly().idle_time_estimator; -} - -void RendererSchedulerImpl::SuspendTimerQueue() { - MainThreadOnly().timer_queue_suspend_count++; - ForceUpdatePolicy(); -#ifndef NDEBUG - DCHECK(!default_timer_task_runner_->IsQueueEnabled()); - for (const auto& runner : timer_task_runners_) { - DCHECK(!runner->IsQueueEnabled()); - } -#endif -} - -void RendererSchedulerImpl::ResumeTimerQueue() { - MainThreadOnly().timer_queue_suspend_count--; - DCHECK_GE(MainThreadOnly().timer_queue_suspend_count, 0); - ForceUpdatePolicy(); -} - -void RendererSchedulerImpl::SetTimerQueueSuspensionWhenBackgroundedEnabled( - bool enabled) { - // Note that this will only take effect for the next backgrounded signal. - MainThreadOnly().timer_queue_suspension_when_backgrounded_enabled = enabled; -} - -std::unique_ptr<base::trace_event::ConvertableToTraceFormat> -RendererSchedulerImpl::AsValue(base::TimeTicks optional_now) const { - base::AutoLock lock(any_thread_lock_); - return AsValueLocked(optional_now); -} - -// static -const char* RendererSchedulerImpl::ExpensiveTaskPolicyToString( - ExpensiveTaskPolicy expensive_task_policy) { - switch (expensive_task_policy) { - case ExpensiveTaskPolicy::RUN: - return "RUN"; - case ExpensiveTaskPolicy::BLOCK: - return "BLOCK"; - case ExpensiveTaskPolicy::THROTTLE: - return "THROTTLE"; - default: - NOTREACHED(); - return nullptr; - } -} - -std::unique_ptr<base::trace_event::ConvertableToTraceFormat> -RendererSchedulerImpl::AsValueLocked(base::TimeTicks optional_now) const { - helper_.CheckOnValidThread(); - any_thread_lock_.AssertAcquired(); - - if (optional_now.is_null()) - optional_now = helper_.scheduler_tqm_delegate()->NowTicks(); - std::unique_ptr<base::trace_event::TracedValue> state( - new base::trace_event::TracedValue()); - state->SetBoolean( - "has_visible_render_widget_with_touch_handler", - MainThreadOnly().has_visible_render_widget_with_touch_handler); - state->SetString("current_use_case", - UseCaseToString(MainThreadOnly().current_use_case)); - state->SetString("rail_mode", - RAILModeToString(MainThreadOnly().current_policy.rail_mode)); - state->SetBoolean("expensive_task_blocking_allowed", - MainThreadOnly().expensive_task_blocking_allowed); - state->SetBoolean("loading_tasks_seem_expensive", - MainThreadOnly().loading_tasks_seem_expensive); - state->SetBoolean("timer_tasks_seem_expensive", - MainThreadOnly().timer_tasks_seem_expensive); - state->SetBoolean("begin_frame_not_expected_soon", - MainThreadOnly().begin_frame_not_expected_soon); - state->SetBoolean("touchstart_expected_soon", - MainThreadOnly().touchstart_expected_soon); - state->SetString("idle_period_state", - IdleHelper::IdlePeriodStateToString( - idle_helper_.SchedulerIdlePeriodState())); - state->SetBoolean("renderer_hidden", MainThreadOnly().renderer_hidden); - state->SetBoolean("have_seen_a_begin_main_frame", - MainThreadOnly().have_seen_a_begin_main_frame); - state->SetBoolean( - "have_reported_blocking_intervention_in_current_policy", - MainThreadOnly().have_reported_blocking_intervention_in_current_policy); - state->SetBoolean( - "have_reported_blocking_intervention_since_navigation", - MainThreadOnly().have_reported_blocking_intervention_since_navigation); - state->SetBoolean("renderer_backgrounded", - MainThreadOnly().renderer_backgrounded); - state->SetBoolean("timer_queue_suspended_when_backgrounded", - MainThreadOnly().timer_queue_suspended_when_backgrounded); - state->SetInteger("timer_queue_suspend_count", - MainThreadOnly().timer_queue_suspend_count); - state->SetDouble("now", (optional_now - base::TimeTicks()).InMillisecondsF()); - state->SetDouble( - "rails_loading_priority_deadline", - (AnyThread().rails_loading_priority_deadline - base::TimeTicks()) - .InMillisecondsF()); - state->SetDouble( - "fling_compositor_escalation_deadline", - (AnyThread().fling_compositor_escalation_deadline - base::TimeTicks()) - .InMillisecondsF()); - state->SetInteger("navigation_task_expected_count", - MainThreadOnly().navigation_task_expected_count); - state->SetDouble("last_idle_period_end_time", - (AnyThread().last_idle_period_end_time - base::TimeTicks()) - .InMillisecondsF()); - state->SetBoolean("awaiting_touch_start_response", - AnyThread().awaiting_touch_start_response); - state->SetBoolean("begin_main_frame_on_critical_path", - AnyThread().begin_main_frame_on_critical_path); - state->SetBoolean("last_gesture_was_compositor_driven", - AnyThread().last_gesture_was_compositor_driven); - state->SetBoolean("default_gesture_prevented", - AnyThread().default_gesture_prevented); - state->SetDouble("expected_loading_task_duration", - MainThreadOnly() - .loading_task_cost_estimator.expected_task_duration() - .InMillisecondsF()); - state->SetDouble("expected_timer_task_duration", - MainThreadOnly() - .timer_task_cost_estimator.expected_task_duration() - .InMillisecondsF()); - // TODO(skyostil): Can we somehow trace how accurate these estimates were? - state->SetDouble( - "longest_jank_free_task_duration", - MainThreadOnly().longest_jank_free_task_duration.InMillisecondsF()); - state->SetDouble( - "compositor_frame_interval", - MainThreadOnly().compositor_frame_interval.InMillisecondsF()); - state->SetDouble( - "estimated_next_frame_begin", - (MainThreadOnly().estimated_next_frame_begin - base::TimeTicks()) - .InMillisecondsF()); - state->SetBoolean("in_idle_period", AnyThread().in_idle_period); - - state->SetString( - "expensive_task_policy", - ExpensiveTaskPolicyToString(MainThreadOnly().expensive_task_policy)); - - AnyThread().user_model.AsValueInto(state.get()); - render_widget_scheduler_signals_.AsValueInto(state.get()); - - return std::move(state); -} - -void RendererSchedulerImpl::OnIdlePeriodStarted() { - base::AutoLock lock(any_thread_lock_); - AnyThread().in_idle_period = true; - UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED); -} - -void RendererSchedulerImpl::OnIdlePeriodEnded() { - base::AutoLock lock(any_thread_lock_); - AnyThread().last_idle_period_end_time = - helper_.scheduler_tqm_delegate()->NowTicks(); - AnyThread().in_idle_period = false; - UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED); -} - -void RendererSchedulerImpl::AddPendingNavigation( - blink::WebScheduler::NavigatingFrameType type) { - helper_.CheckOnValidThread(); - if (type == blink::WebScheduler::NavigatingFrameType::kMainFrame) { - MainThreadOnly().navigation_task_expected_count++; - UpdatePolicy(); - } -} - -void RendererSchedulerImpl::RemovePendingNavigation( - blink::WebScheduler::NavigatingFrameType type) { - helper_.CheckOnValidThread(); - DCHECK_GT(MainThreadOnly().navigation_task_expected_count, 0); - if (type == blink::WebScheduler::NavigatingFrameType::kMainFrame && - MainThreadOnly().navigation_task_expected_count > 0) { - MainThreadOnly().navigation_task_expected_count--; - UpdatePolicy(); - } -} - -void RendererSchedulerImpl::OnNavigationStarted() { - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), - "RendererSchedulerImpl::OnNavigationStarted"); - base::AutoLock lock(any_thread_lock_); - AnyThread().rails_loading_priority_deadline = - helper_.scheduler_tqm_delegate()->NowTicks() + - base::TimeDelta::FromMilliseconds( - kRailsInitialLoadingPrioritizationMillis); - ResetForNavigationLocked(); -} - -bool RendererSchedulerImpl::HadAnIdlePeriodRecently(base::TimeTicks now) const { - return (now - AnyThread().last_idle_period_end_time) <= - base::TimeDelta::FromMilliseconds( - kIdlePeriodStarvationThresholdMillis); -} - -void RendererSchedulerImpl::SuspendTimerQueueWhenBackgrounded() { - DCHECK(MainThreadOnly().renderer_backgrounded); - if (MainThreadOnly().timer_queue_suspended_when_backgrounded) - return; - - MainThreadOnly().timer_queue_suspended_when_backgrounded = true; - ForceUpdatePolicy(); -} - -void RendererSchedulerImpl::ResumeTimerQueueWhenForegrounded() { - DCHECK(!MainThreadOnly().renderer_backgrounded); - if (!MainThreadOnly().timer_queue_suspended_when_backgrounded) - return; - - MainThreadOnly().timer_queue_suspended_when_backgrounded = false; - ForceUpdatePolicy(); -} - -void RendererSchedulerImpl::ResetForNavigationLocked() { - helper_.CheckOnValidThread(); - any_thread_lock_.AssertAcquired(); - AnyThread().user_model.Reset(helper_.scheduler_tqm_delegate()->NowTicks()); - AnyThread().have_seen_touchstart = false; - MainThreadOnly().loading_task_cost_estimator.Clear(); - MainThreadOnly().timer_task_cost_estimator.Clear(); - MainThreadOnly().idle_time_estimator.Clear(); - MainThreadOnly().have_seen_a_begin_main_frame = false; - MainThreadOnly().have_reported_blocking_intervention_since_navigation = false; - UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED); -} - -void RendererSchedulerImpl::SetTopLevelBlameContext( - base::trace_event::BlameContext* blame_context) { - // Any task that runs in the default task runners belongs to the context of - // all frames (as opposed to a particular frame). Note that the task itself - // may still enter a more specific blame context if necessary. - // - // Per-frame task runners (loading, timers, etc.) are configured with a more - // specific blame context by WebFrameSchedulerImpl. - control_task_runner_->SetBlameContext(blame_context); - DefaultTaskRunner()->SetBlameContext(blame_context); - default_loading_task_runner_->SetBlameContext(blame_context); - default_timer_task_runner_->SetBlameContext(blame_context); - compositor_task_runner_->SetBlameContext(blame_context); - idle_helper_.IdleTaskRunner()->SetBlameContext(blame_context); -} - -void RendererSchedulerImpl::SetRAILModeObserver(RAILModeObserver* observer) { - MainThreadOnly().rail_mode_observer = observer; -} - -void RendererSchedulerImpl::RegisterTimeDomain(TimeDomain* time_domain) { - helper_.RegisterTimeDomain(time_domain); -} - -void RendererSchedulerImpl::UnregisterTimeDomain(TimeDomain* time_domain) { - helper_.UnregisterTimeDomain(time_domain); -} - -void RendererSchedulerImpl::SetExpensiveTaskBlockingAllowed(bool allowed) { - MainThreadOnly().expensive_task_blocking_allowed = allowed; -} - -base::TickClock* RendererSchedulerImpl::tick_clock() const { - return helper_.scheduler_tqm_delegate().get(); -} - -void RendererSchedulerImpl::AddWebViewScheduler( - WebViewSchedulerImpl* web_view_scheduler) { - MainThreadOnly().web_view_schedulers.insert(web_view_scheduler); -} - -void RendererSchedulerImpl::RemoveWebViewScheduler( - WebViewSchedulerImpl* web_view_scheduler) { - DCHECK(MainThreadOnly().web_view_schedulers.find(web_view_scheduler) != - MainThreadOnly().web_view_schedulers.end()); - MainThreadOnly().web_view_schedulers.erase(web_view_scheduler); -} - -void RendererSchedulerImpl::BroadcastConsoleWarning( - const std::string& message) { - helper_.CheckOnValidThread(); - for (auto* web_view_scheduler : MainThreadOnly().web_view_schedulers) - web_view_scheduler->AddConsoleWarning(message); -} - -void RendererSchedulerImpl::OnTriedToExecuteBlockedTask( - const TaskQueue& queue, - const base::PendingTask& task) { - if (!MainThreadOnly().expensive_task_blocking_allowed || - MainThreadOnly().current_use_case == UseCase::TOUCHSTART || - MainThreadOnly().longest_jank_free_task_duration < - base::TimeDelta::FromMilliseconds(kRailsResponseTimeMillis) || - MainThreadOnly().timer_queue_suspend_count || - MainThreadOnly().timer_queue_suspended_when_backgrounded) { - return; - } - if (!MainThreadOnly().timer_tasks_seem_expensive && - !MainThreadOnly().loading_tasks_seem_expensive) { - return; - } - if (!MainThreadOnly().have_reported_blocking_intervention_in_current_policy) { - MainThreadOnly().have_reported_blocking_intervention_in_current_policy = - true; - TRACE_EVENT_INSTANT0("renderer.scheduler", - "RendererSchedulerImpl::TaskBlocked", - TRACE_EVENT_SCOPE_THREAD); - } - - if (!MainThreadOnly().have_reported_blocking_intervention_since_navigation) { - { - base::AutoLock lock(any_thread_lock_); - if (!AnyThread().have_seen_touchstart) - return; - } - MainThreadOnly().have_reported_blocking_intervention_since_navigation = - true; - BroadcastConsoleWarning( - "Blink deferred a task in order to make scrolling smoother. " - "Your timer and network tasks should take less than 50ms to run " - "to avoid this. Please see " - "https://developers.google.com/web/tools/chrome-devtools/profile/evaluate-performance/rail" - " and https://crbug.com/574343#c40 for more information."); - } -} - -void RendererSchedulerImpl::ReportTaskTime(base::TimeTicks start_time, - base::TimeTicks end_time) { - MainThreadOnly().queueing_time_estimator.OnToplevelTaskCompleted(start_time, - end_time); - MainThreadOnly().long_task_tracker.RecordLongTask( - start_time, end_time - start_time); - UMA_HISTOGRAM_CUSTOM_COUNTS("RendererScheduler.TaskTime", - (end_time - start_time).InMicroseconds(), 1, - 1000000, 50); -} - -LongTaskTracker::LongTaskTiming RendererSchedulerImpl::GetLongTaskTiming() { - return MainThreadOnly().long_task_tracker.GetLongTaskTiming(); -} - -void RendererSchedulerImpl::OnQueueingTimeForWindowEstimated( - base::TimeDelta queueing_time) { - UMA_HISTOGRAM_TIMES("RendererScheduler.ExpectedTaskQueueingDuration", - queueing_time); - TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), - "estimated_queueing_time_for_window", - queueing_time.InMillisecondsF()); -} - -AutoAdvancingVirtualTimeDomain* RendererSchedulerImpl::GetVirtualTimeDomain() { - if (!virtual_time_domain_) { - virtual_time_domain_.reset( - new AutoAdvancingVirtualTimeDomain(tick_clock()->NowTicks())); - RegisterTimeDomain(virtual_time_domain_.get()); - } - return virtual_time_domain_.get(); -} - -void RendererSchedulerImpl::EnableVirtualTime() { - MainThreadOnly().use_virtual_time = true; - - // The |unthrottled_task_runners_| are not actively managed by UpdatePolicy(). - AutoAdvancingVirtualTimeDomain* time_domain = GetVirtualTimeDomain(); - for (const scoped_refptr<TaskQueue>& task_queue : unthrottled_task_runners_) - task_queue->SetTimeDomain(time_domain); - - throttling_helper_->EnableVirtualTime(); - - ForceUpdatePolicy(); -} - -// static -const char* RendererSchedulerImpl::UseCaseToString(UseCase use_case) { - switch (use_case) { - case UseCase::NONE: - return "none"; - case UseCase::COMPOSITOR_GESTURE: - return "compositor_gesture"; - case UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING: - return "main_thread_custom_input_handling"; - case UseCase::SYNCHRONIZED_GESTURE: - return "synchronized_gesture"; - case UseCase::TOUCHSTART: - return "touchstart"; - case UseCase::LOADING: - return "loading"; - case UseCase::MAIN_THREAD_GESTURE: - return "main_thread_gesture"; - default: - NOTREACHED(); - return nullptr; - } -} - -// static -const char* RendererSchedulerImpl::RAILModeToString(v8::RAILMode rail_mode) { - switch (rail_mode) { - case v8::PERFORMANCE_RESPONSE: - return "response"; - case v8::PERFORMANCE_ANIMATION: - return "animation"; - case v8::PERFORMANCE_IDLE: - return "idle"; - case v8::PERFORMANCE_LOAD: - return "load"; - default: - NOTREACHED(); - return nullptr; - } -} - -} // namespace scheduler
diff --git a/components/scheduler/renderer/renderer_scheduler_impl.h b/components/scheduler/renderer/renderer_scheduler_impl.h deleted file mode 100644 index dad69ee..0000000 --- a/components/scheduler/renderer/renderer_scheduler_impl.h +++ /dev/null
@@ -1,492 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_RENDERER_RENDERER_SCHEDULER_IMPL_H_ -#define COMPONENTS_SCHEDULER_RENDERER_RENDERER_SCHEDULER_IMPL_H_ - -#include "base/atomicops.h" -#include "base/macros.h" -#include "base/synchronization/lock.h" -#include "components/scheduler/base/long_task_tracker.h" -#include "components/scheduler/base/pollable_thread_safe_flag.h" -#include "components/scheduler/base/queueing_time_estimator.h" -#include "components/scheduler/base/task_time_tracker.h" -#include "components/scheduler/child/idle_helper.h" -#include "components/scheduler/child/scheduler_helper.h" -#include "components/scheduler/renderer/deadline_task_runner.h" -#include "components/scheduler/renderer/idle_time_estimator.h" -#include "components/scheduler/renderer/render_widget_signals.h" -#include "components/scheduler/renderer/renderer_scheduler.h" -#include "components/scheduler/renderer/task_cost_estimator.h" -#include "components/scheduler/renderer/throttling_helper.h" -#include "components/scheduler/renderer/user_model.h" -#include "components/scheduler/renderer/web_view_scheduler_impl.h" -#include "components/scheduler/scheduler_export.h" - -namespace base { -namespace trace_event { -class ConvertableToTraceFormat; -} -} - -namespace scheduler { -class AutoAdvancingVirtualTimeDomain; -class RenderWidgetSchedulingState; -class WebViewSchedulerImpl; -class ThrottlingHelper; - -class SCHEDULER_EXPORT RendererSchedulerImpl - : public RendererScheduler, - public IdleHelper::Delegate, - public SchedulerHelper::Observer, - public RenderWidgetSignals::Observer, - public TaskTimeTracker, - public QueueingTimeEstimator::Client { - public: - // Keep RendererScheduler::UseCaseToString in sync with this enum. - enum class UseCase { - // No active use case detected. - NONE, - // A continuous gesture (e.g., scroll, pinch) which is being driven by the - // compositor thread. - COMPOSITOR_GESTURE, - // An unspecified touch gesture which is being handled by the main thread. - // Note that since we don't have a full view of the use case, we should be - // careful to prioritize all work equally. - MAIN_THREAD_CUSTOM_INPUT_HANDLING, - // A continuous gesture (e.g., scroll, pinch) which is being driven by the - // compositor thread but also observed by the main thread. An example is - // synchronized scrolling where a scroll listener on the main thread changes - // page layout based on the current scroll position. - SYNCHRONIZED_GESTURE, - // A gesture has recently started and we are about to run main thread touch - // listeners to find out the actual gesture type. To minimize touch latency, - // only input handling work should run in this state. - TOUCHSTART, - // The page is loading. - LOADING, - // A continuous gesture (e.g., scroll) which is being handled by the main - // thread. - MAIN_THREAD_GESTURE, - // Must be the last entry. - USE_CASE_COUNT, - FIRST_USE_CASE = NONE, - }; - static const char* UseCaseToString(UseCase use_case); - static const char* RAILModeToString(v8::RAILMode rail_mode); - - RendererSchedulerImpl(scoped_refptr<SchedulerTqmDelegate> main_task_runner); - ~RendererSchedulerImpl() override; - - // RendererScheduler implementation: - std::unique_ptr<blink::WebThread> CreateMainThread() override; - scoped_refptr<TaskQueue> DefaultTaskRunner() override; - scoped_refptr<SingleThreadIdleTaskRunner> IdleTaskRunner() override; - scoped_refptr<TaskQueue> CompositorTaskRunner() override; - scoped_refptr<TaskQueue> LoadingTaskRunner() override; - scoped_refptr<TaskQueue> TimerTaskRunner() override; - scoped_refptr<TaskQueue> NewLoadingTaskRunner(const char* name) override; - scoped_refptr<TaskQueue> NewTimerTaskRunner(const char* name) override; - scoped_refptr<TaskQueue> NewUnthrottledTaskRunner(const char* name) override; - std::unique_ptr<RenderWidgetSchedulingState> NewRenderWidgetSchedulingState() - override; - void WillBeginFrame(const cc::BeginFrameArgs& args) override; - void BeginFrameNotExpectedSoon() override; - void DidCommitFrameToCompositor() override; - void DidHandleInputEventOnCompositorThread( - const blink::WebInputEvent& web_input_event, - InputEventState event_state) override; - void DidHandleInputEventOnMainThread( - const blink::WebInputEvent& web_input_event) override; - void DidAnimateForInputOnCompositorThread() override; - void OnRendererBackgrounded() override; - void OnRendererForegrounded() override; - void SuspendRenderer() override; - void AddPendingNavigation( - blink::WebScheduler::NavigatingFrameType type) override; - void RemovePendingNavigation( - blink::WebScheduler::NavigatingFrameType type) override; - void OnNavigationStarted() override; - bool IsHighPriorityWorkAnticipated() override; - bool ShouldYieldForHighPriorityWork() override; - bool CanExceedIdleDeadlineIfRequired() const override; - void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer) override; - void RemoveTaskObserver( - base::MessageLoop::TaskObserver* task_observer) override; - void Shutdown() override; - void SuspendTimerQueue() override; - void ResumeTimerQueue() override; - void SetTimerQueueSuspensionWhenBackgroundedEnabled(bool enabled) override; - void SetTopLevelBlameContext( - base::trace_event::BlameContext* blame_context) override; - void SetRAILModeObserver(RAILModeObserver* observer) override; - - // RenderWidgetSignals::Observer implementation: - void SetAllRenderWidgetsHidden(bool hidden) override; - void SetHasVisibleRenderWidgetWithTouchHandler( - bool has_visible_render_widget_with_touch_handler) override; - - // SchedulerHelper::Observer implementation: - void OnUnregisterTaskQueue(const scoped_refptr<TaskQueue>& queue) override; - void OnTriedToExecuteBlockedTask(const TaskQueue& queue, - const base::PendingTask& task) override; - - // TaskTimeTracker implementation: - void ReportTaskTime(base::TimeTicks start_time, - base::TimeTicks end_time) override; - - // QueueingTimeEstimator::Client implementation: - void OnQueueingTimeForWindowEstimated(base::TimeDelta queueing_time) override; - - // Returns a task runner where tasks run at the highest possible priority. - scoped_refptr<TaskQueue> ControlTaskRunner(); - - void RegisterTimeDomain(TimeDomain* time_domain); - void UnregisterTimeDomain(TimeDomain* time_domain); - - // Tells the scheduler that all TaskQueues should use virtual time. - void EnableVirtualTime(); - - void SetExpensiveTaskBlockingAllowed(bool allowed); - - void AddWebViewScheduler(WebViewSchedulerImpl* web_view_scheduler); - void RemoveWebViewScheduler(WebViewSchedulerImpl* web_view_scheduler); - - LongTaskTracker::LongTaskTiming GetLongTaskTiming(); - - // Test helpers. - SchedulerHelper* GetSchedulerHelperForTesting(); - TaskCostEstimator* GetLoadingTaskCostEstimatorForTesting(); - TaskCostEstimator* GetTimerTaskCostEstimatorForTesting(); - IdleTimeEstimator* GetIdleTimeEstimatorForTesting(); - base::TimeTicks CurrentIdleTaskDeadlineForTesting() const; - void RunIdleTasksForTesting(const base::Closure& callback); - void EndIdlePeriodForTesting(const base::Closure& callback, - base::TimeTicks time_remaining); - bool PolicyNeedsUpdateForTesting(); - - base::TickClock* tick_clock() const; - - RealTimeDomain* real_time_domain() const { - return helper_.real_time_domain(); - } - - AutoAdvancingVirtualTimeDomain* GetVirtualTimeDomain(); - - ThrottlingHelper* throttling_helper() { return throttling_helper_.get(); } - - private: - friend class RendererSchedulerImplTest; - friend class RendererSchedulerImplForTest; - friend class RenderWidgetSchedulingState; - - enum class ExpensiveTaskPolicy { RUN, BLOCK, THROTTLE }; - - enum class TimeDomainType { - REAL, - THROTTLED, - VIRTUAL, - }; - - struct TaskQueuePolicy { - TaskQueuePolicy() - : is_enabled(true), - priority(TaskQueue::NORMAL_PRIORITY), - time_domain_type(TimeDomainType::REAL) {} - - bool is_enabled; - TaskQueue::QueuePriority priority; - TimeDomainType time_domain_type; - - bool operator==(const TaskQueuePolicy& other) const { - return is_enabled == other.is_enabled && priority == other.priority && - time_domain_type == other.time_domain_type; - } - }; - - struct Policy { - TaskQueuePolicy compositor_queue_policy; - TaskQueuePolicy loading_queue_policy; - TaskQueuePolicy timer_queue_policy; - TaskQueuePolicy default_queue_policy; - v8::RAILMode rail_mode = v8::PERFORMANCE_ANIMATION; - - bool operator==(const Policy& other) const { - return compositor_queue_policy == other.compositor_queue_policy && - loading_queue_policy == other.loading_queue_policy && - timer_queue_policy == other.timer_queue_policy && - default_queue_policy == other.default_queue_policy && - rail_mode == other.rail_mode; - } - }; - - class PollableNeedsUpdateFlag { - public: - PollableNeedsUpdateFlag(base::Lock* write_lock); - ~PollableNeedsUpdateFlag(); - - // Set the flag. May only be called if |write_lock| is held. - void SetWhileLocked(bool value); - - // Returns true iff the flag is set to true. - bool IsSet() const; - - private: - base::subtle::Atomic32 flag_; - base::Lock* write_lock_; // Not owned. - - DISALLOW_COPY_AND_ASSIGN(PollableNeedsUpdateFlag); - }; - - // IdleHelper::Delegate implementation: - bool CanEnterLongIdlePeriod( - base::TimeTicks now, - base::TimeDelta* next_long_idle_period_delay_out) override; - void IsNotQuiescent() override {} - void OnIdlePeriodStarted() override; - void OnIdlePeriodEnded() override; - - void EndIdlePeriod(); - - // Returns the serialized scheduler state for tracing. - std::unique_ptr<base::trace_event::ConvertableToTraceFormat> AsValue( - base::TimeTicks optional_now) const; - std::unique_ptr<base::trace_event::ConvertableToTraceFormat> AsValueLocked( - base::TimeTicks optional_now) const; - - static bool ShouldPrioritizeInputEvent( - const blink::WebInputEvent& web_input_event); - - // The amount of time which idle periods can continue being scheduled when the - // renderer has been hidden, before going to sleep for good. - static const int kEndIdleWhenHiddenDelayMillis = 10000; - - // The amount of time for which loading tasks will be prioritized over - // other tasks during the initial page load. - static const int kRailsInitialLoadingPrioritizationMillis = 1000; - - // The amount of time in milliseconds we have to respond to user input as - // defined by RAILS. - static const int kRailsResponseTimeMillis = 50; - - // For the purposes of deciding whether or not it's safe to turn timers and - // loading tasks on only in idle periods, we regard the system as being as - // being "idle period" starved if there hasn't been an idle period in the last - // 10 seconds. This was chosen to be long enough to cover most anticipated - // user gestures. - static const int kIdlePeriodStarvationThresholdMillis = 10000; - - // The amount of time to wait before suspending shared timers after the - // renderer has been backgrounded. This is used only if background suspension - // of shared timers is enabled. - static const int kSuspendTimersWhenBackgroundedDelayMillis = 5 * 60 * 1000; - - // The time we should stay in a priority-escalated mode after a call to - // DidAnimateForInputOnCompositorThread(). - static const int kFlingEscalationLimitMillis = 100; - - // Schedules an immediate PolicyUpdate, if there isn't one already pending and - // sets |policy_may_need_update_|. Note |any_thread_lock_| must be - // locked. - void EnsureUrgentPolicyUpdatePostedOnMainThread( - const tracked_objects::Location& from_here); - - // Update the policy if a new signal has arrived. Must be called from the main - // thread. - void MaybeUpdatePolicy(); - - // Locks |any_thread_lock_| and updates the scheduler policy. May early - // out if the policy is unchanged. Must be called from the main thread. - void UpdatePolicy(); - - // Like UpdatePolicy, except it doesn't early out. - void ForceUpdatePolicy(); - - enum class UpdateType { - MAY_EARLY_OUT_IF_POLICY_UNCHANGED, - FORCE_UPDATE, - }; - - // The implelemtation of UpdatePolicy & ForceUpdatePolicy. It is allowed to - // early out if |update_type| is MAY_EARLY_OUT_IF_POLICY_UNCHANGED. - virtual void UpdatePolicyLocked(UpdateType update_type); - - // Helper for computing the use case. |expected_usecase_duration| will be - // filled with the amount of time after which the use case should be updated - // again. If the duration is zero, a new use case update should not be - // scheduled. Must be called with |any_thread_lock_| held. Can be called from - // any thread. - UseCase ComputeCurrentUseCase( - base::TimeTicks now, - base::TimeDelta* expected_use_case_duration) const; - - // An input event of some sort happened, the policy may need updating. - void UpdateForInputEventOnCompositorThread(blink::WebInputEvent::Type type, - InputEventState input_event_state); - - // Returns true if there has been at least one idle period in the last - // |kIdlePeriodStarvationThresholdMillis|. - bool HadAnIdlePeriodRecently(base::TimeTicks now) const; - - // Helpers for safely suspending/resuming the timer queue after a - // background/foreground signal. - void SuspendTimerQueueWhenBackgrounded(); - void ResumeTimerQueueWhenForegrounded(); - - // The task cost estimators and the UserModel need to be reset upon page - // nagigation. This function does that. Must be called from the main thread. - void ResetForNavigationLocked(); - - // Estimates the maximum task length that won't cause a jank based on the - // current system state. Must be called from the main thread. - base::TimeDelta EstimateLongestJankFreeTaskDuration() const; - - // Log a console warning message to all WebViews in this process. - void BroadcastConsoleWarning(const std::string& message); - - void ApplyTaskQueuePolicy(TaskQueue* task_queue, - const TaskQueuePolicy& old_task_queue_policy, - const TaskQueuePolicy& new_task_queue_policy) const; - - static const char* ExpensiveTaskPolicyToString( - ExpensiveTaskPolicy expensive_task_policy); - - SchedulerHelper helper_; - IdleHelper idle_helper_; - std::unique_ptr<ThrottlingHelper> throttling_helper_; - RenderWidgetSignals render_widget_scheduler_signals_; - - const scoped_refptr<TaskQueue> control_task_runner_; - const scoped_refptr<TaskQueue> compositor_task_runner_; - std::set<scoped_refptr<TaskQueue>> loading_task_runners_; - std::set<scoped_refptr<TaskQueue>> timer_task_runners_; - std::set<scoped_refptr<TaskQueue>> unthrottled_task_runners_; - scoped_refptr<TaskQueue> default_loading_task_runner_; - scoped_refptr<TaskQueue> default_timer_task_runner_; - - // Note |virtual_time_domain_| is lazily created. - std::unique_ptr<AutoAdvancingVirtualTimeDomain> virtual_time_domain_; - - base::Closure update_policy_closure_; - DeadlineTaskRunner delayed_update_policy_runner_; - CancelableClosureHolder end_renderer_hidden_idle_period_closure_; - CancelableClosureHolder suspend_timers_when_backgrounded_closure_; - - // We have decided to improve thread safety at the cost of some boilerplate - // (the accessors) for the following data members. - - struct MainThreadOnly { - MainThreadOnly(RendererSchedulerImpl* renderer_scheduler_impl, - const scoped_refptr<TaskQueue>& compositor_task_runner, - base::TickClock* time_source); - ~MainThreadOnly(); - - TaskCostEstimator loading_task_cost_estimator; - TaskCostEstimator timer_task_cost_estimator; - QueueingTimeEstimator queueing_time_estimator; - LongTaskTracker long_task_tracker; - IdleTimeEstimator idle_time_estimator; - UseCase current_use_case; - Policy current_policy; - base::TimeTicks current_policy_expiration_time; - base::TimeTicks estimated_next_frame_begin; - base::TimeDelta compositor_frame_interval; - base::TimeDelta longest_jank_free_task_duration; - int timer_queue_suspend_count; // TIMER_TASK_QUEUE suspended if non-zero. - int navigation_task_expected_count; - ExpensiveTaskPolicy expensive_task_policy; - bool renderer_hidden; - bool renderer_backgrounded; - bool renderer_suspended; - bool timer_queue_suspension_when_backgrounded_enabled; - bool timer_queue_suspended_when_backgrounded; - bool was_shutdown; - bool loading_tasks_seem_expensive; - bool timer_tasks_seem_expensive; - bool touchstart_expected_soon; - bool have_seen_a_begin_main_frame; - bool have_reported_blocking_intervention_in_current_policy; - bool have_reported_blocking_intervention_since_navigation; - bool has_visible_render_widget_with_touch_handler; - bool begin_frame_not_expected_soon; - bool expensive_task_blocking_allowed; - bool in_idle_period_for_testing; - bool use_virtual_time; - std::set<WebViewSchedulerImpl*> web_view_schedulers; // Not owned. - RAILModeObserver* rail_mode_observer; // Not owned. - }; - - struct AnyThread { - AnyThread(); - ~AnyThread(); - - base::TimeTicks last_idle_period_end_time; - base::TimeTicks rails_loading_priority_deadline; - base::TimeTicks fling_compositor_escalation_deadline; - UserModel user_model; - bool awaiting_touch_start_response; - bool in_idle_period; - bool begin_main_frame_on_critical_path; - bool last_gesture_was_compositor_driven; - bool default_gesture_prevented; - bool have_seen_touchstart; - }; - - struct CompositorThreadOnly { - CompositorThreadOnly(); - ~CompositorThreadOnly(); - - blink::WebInputEvent::Type last_input_type; - std::unique_ptr<base::ThreadChecker> compositor_thread_checker; - - void CheckOnValidThread() { -#if DCHECK_IS_ON() - // We don't actually care which thread this called from, just so long as - // its consistent. - if (!compositor_thread_checker) - compositor_thread_checker.reset(new base::ThreadChecker()); - DCHECK(compositor_thread_checker->CalledOnValidThread()); -#endif - } - }; - - // Don't access main_thread_only_, instead use MainThreadOnly(). - MainThreadOnly main_thread_only_; - MainThreadOnly& MainThreadOnly() { - helper_.CheckOnValidThread(); - return main_thread_only_; - } - const struct MainThreadOnly& MainThreadOnly() const { - helper_.CheckOnValidThread(); - return main_thread_only_; - } - - mutable base::Lock any_thread_lock_; - // Don't access any_thread_, instead use AnyThread(). - AnyThread any_thread_; - AnyThread& AnyThread() { - any_thread_lock_.AssertAcquired(); - return any_thread_; - } - const struct AnyThread& AnyThread() const { - any_thread_lock_.AssertAcquired(); - return any_thread_; - } - - // Don't access compositor_thread_only_, instead use CompositorThreadOnly(). - CompositorThreadOnly compositor_thread_only_; - CompositorThreadOnly& CompositorThreadOnly() { - compositor_thread_only_.CheckOnValidThread(); - return compositor_thread_only_; - } - - PollableThreadSafeFlag policy_may_need_update_; - base::WeakPtrFactory<RendererSchedulerImpl> weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(RendererSchedulerImpl); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_RENDERER_RENDERER_SCHEDULER_IMPL_H_
diff --git a/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc b/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc deleted file mode 100644 index 0ee313bd..0000000 --- a/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc +++ /dev/null
@@ -1,3448 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/renderer/renderer_scheduler_impl.h" - -#include <utility> - -#include "base/callback.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/run_loop.h" -#include "base/test/simple_test_tick_clock.h" -#include "cc/output/begin_frame_args.h" -#include "cc/test/ordered_simple_task_runner.h" -#include "components/scheduler/base/test_time_source.h" -#include "components/scheduler/child/scheduler_tqm_delegate_for_test.h" -#include "components/scheduler/child/scheduler_tqm_delegate_impl.h" -#include "components/scheduler/renderer/auto_advancing_virtual_time_domain.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace scheduler { - -namespace { -class FakeInputEvent : public blink::WebInputEvent { - public: - explicit FakeInputEvent(blink::WebInputEvent::Type event_type) - : WebInputEvent(sizeof(FakeInputEvent)) { - type = event_type; - } - - FakeInputEvent(blink::WebInputEvent::Type event_type, int event_modifiers) - : WebInputEvent(sizeof(FakeInputEvent)) { - type = event_type; - modifiers = event_modifiers; - } -}; - -void AppendToVectorTestTask(std::vector<std::string>* vector, - std::string value) { - vector->push_back(value); -} - -void AppendToVectorIdleTestTask(std::vector<std::string>* vector, - std::string value, - base::TimeTicks deadline) { - AppendToVectorTestTask(vector, value); -} - -void NullTask() { -} - -void AppendToVectorReentrantTask(base::SingleThreadTaskRunner* task_runner, - std::vector<int>* vector, - int* reentrant_count, - int max_reentrant_count) { - vector->push_back((*reentrant_count)++); - if (*reentrant_count < max_reentrant_count) { - task_runner->PostTask( - FROM_HERE, - base::Bind(AppendToVectorReentrantTask, base::Unretained(task_runner), - vector, reentrant_count, max_reentrant_count)); - } -} - -void IdleTestTask(int* run_count, - base::TimeTicks* deadline_out, - base::TimeTicks deadline) { - (*run_count)++; - *deadline_out = deadline; -} - -int max_idle_task_reposts = 2; - -void RepostingIdleTestTask(SingleThreadIdleTaskRunner* idle_task_runner, - int* run_count, - base::TimeTicks deadline) { - if ((*run_count + 1) < max_idle_task_reposts) { - idle_task_runner->PostIdleTask( - FROM_HERE, base::Bind(&RepostingIdleTestTask, - base::Unretained(idle_task_runner), run_count)); - } - (*run_count)++; -} - -void RepostingUpdateClockIdleTestTask( - SingleThreadIdleTaskRunner* idle_task_runner, - int* run_count, - base::SimpleTestTickClock* clock, - base::TimeDelta advance_time, - std::vector<base::TimeTicks>* deadlines, - base::TimeTicks deadline) { - if ((*run_count + 1) < max_idle_task_reposts) { - idle_task_runner->PostIdleTask( - FROM_HERE, base::Bind(&RepostingUpdateClockIdleTestTask, - base::Unretained(idle_task_runner), run_count, - clock, advance_time, deadlines)); - } - deadlines->push_back(deadline); - (*run_count)++; - clock->Advance(advance_time); -} - -void WillBeginFrameIdleTask(RendererScheduler* scheduler, - base::SimpleTestTickClock* clock, - base::TimeTicks deadline) { - scheduler->WillBeginFrame(cc::BeginFrameArgs::Create( - BEGINFRAME_FROM_HERE, clock->NowTicks(), base::TimeTicks(), - base::TimeDelta::FromMilliseconds(1000), cc::BeginFrameArgs::NORMAL)); -} - -void UpdateClockToDeadlineIdleTestTask(base::SimpleTestTickClock* clock, - int* run_count, - base::TimeTicks deadline) { - clock->Advance(deadline - clock->NowTicks()); - (*run_count)++; -} - -void PostingYieldingTestTask(RendererSchedulerImpl* scheduler, - base::SingleThreadTaskRunner* task_runner, - bool simulate_input, - bool* should_yield_before, - bool* should_yield_after) { - *should_yield_before = scheduler->ShouldYieldForHighPriorityWork(); - task_runner->PostTask(FROM_HERE, base::Bind(NullTask)); - if (simulate_input) { - scheduler->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchMove), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - } - *should_yield_after = scheduler->ShouldYieldForHighPriorityWork(); -} - -enum class SimulateInputType { - None, - TouchStart, - TouchEnd, - GestureScrollBegin, - GestureScrollEnd -}; - -void AnticipationTestTask(RendererSchedulerImpl* scheduler, - SimulateInputType simulate_input, - bool* is_anticipated_before, - bool* is_anticipated_after) { - *is_anticipated_before = scheduler->IsHighPriorityWorkAnticipated(); - switch (simulate_input) { - case SimulateInputType::None: - break; - - case SimulateInputType::TouchStart: - scheduler->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchStart), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - break; - - case SimulateInputType::TouchEnd: - scheduler->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchEnd), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - break; - - case SimulateInputType::GestureScrollBegin: - scheduler->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureScrollBegin), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - break; - - case SimulateInputType::GestureScrollEnd: - scheduler->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureScrollEnd), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - break; - } - *is_anticipated_after = scheduler->IsHighPriorityWorkAnticipated(); -} - -}; // namespace - -class RendererSchedulerImplForTest : public RendererSchedulerImpl { - public: - using RendererSchedulerImpl::OnIdlePeriodEnded; - using RendererSchedulerImpl::OnIdlePeriodStarted; - using RendererSchedulerImpl::EstimateLongestJankFreeTaskDuration; - - RendererSchedulerImplForTest( - scoped_refptr<SchedulerTqmDelegate> main_task_runner) - : RendererSchedulerImpl(main_task_runner), update_policy_count_(0) {} - - void UpdatePolicyLocked(UpdateType update_type) override { - update_policy_count_++; - RendererSchedulerImpl::UpdatePolicyLocked(update_type); - - std::string use_case = RendererSchedulerImpl::UseCaseToString( - MainThreadOnly().current_use_case); - if (MainThreadOnly().touchstart_expected_soon) { - use_cases_.push_back(use_case + " touchstart expected"); - } else { - use_cases_.push_back(use_case); - } - } - - void EnsureUrgentPolicyUpdatePostedOnMainThread() { - base::AutoLock lock(any_thread_lock_); - RendererSchedulerImpl::EnsureUrgentPolicyUpdatePostedOnMainThread( - FROM_HERE); - } - - void ScheduleDelayedPolicyUpdate(base::TimeTicks now, base::TimeDelta delay) { - delayed_update_policy_runner_.SetDeadline(FROM_HERE, delay, now); - } - - bool BeginMainFrameOnCriticalPath() { - base::AutoLock lock(any_thread_lock_); - return AnyThread().begin_main_frame_on_critical_path; - } - - int update_policy_count_; - std::vector<std::string> use_cases_; -}; - -// Lets gtest print human readable Policy values. -::std::ostream& operator<<(::std::ostream& os, - const RendererSchedulerImpl::UseCase& use_case) { - return os << RendererSchedulerImpl::UseCaseToString(use_case); -} - -class RendererSchedulerImplTest : public testing::Test { - public: - using UseCase = RendererSchedulerImpl::UseCase; - - RendererSchedulerImplTest() : clock_(new base::SimpleTestTickClock()) { - clock_->Advance(base::TimeDelta::FromMicroseconds(5000)); - } - - RendererSchedulerImplTest(base::MessageLoop* message_loop) - : clock_(new base::SimpleTestTickClock()), message_loop_(message_loop) { - clock_->Advance(base::TimeDelta::FromMicroseconds(5000)); - } - - ~RendererSchedulerImplTest() override {} - - void SetUp() override { - if (message_loop_) { - main_task_runner_ = SchedulerTqmDelegateImpl::Create( - message_loop_.get(), - base::WrapUnique(new TestTimeSource(clock_.get()))); - } else { - mock_task_runner_ = make_scoped_refptr( - new cc::OrderedSimpleTaskRunner(clock_.get(), false)); - main_task_runner_ = SchedulerTqmDelegateForTest::Create( - mock_task_runner_, - base::WrapUnique(new TestTimeSource(clock_.get()))); - } - Initialize( - base::WrapUnique(new RendererSchedulerImplForTest(main_task_runner_))); - } - - void Initialize(std::unique_ptr<RendererSchedulerImplForTest> scheduler) { - scheduler_ = std::move(scheduler); - default_task_runner_ = scheduler_->DefaultTaskRunner(); - compositor_task_runner_ = scheduler_->CompositorTaskRunner(); - loading_task_runner_ = scheduler_->LoadingTaskRunner(); - idle_task_runner_ = scheduler_->IdleTaskRunner(); - timer_task_runner_ = scheduler_->TimerTaskRunner(); - } - - void TearDown() override { - DCHECK(!mock_task_runner_.get() || !message_loop_.get()); - scheduler_->Shutdown(); - if (mock_task_runner_.get()) { - // Check that all tests stop posting tasks. - mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true); - while (mock_task_runner_->RunUntilIdle()) { - } - } else { - base::RunLoop().RunUntilIdle(); - } - scheduler_.reset(); - } - - void RunUntilIdle() { - // Only one of mock_task_runner_ or message_loop_ should be set. - DCHECK(!mock_task_runner_.get() || !message_loop_.get()); - if (mock_task_runner_.get()) - mock_task_runner_->RunUntilIdle(); - else - base::RunLoop().RunUntilIdle(); - } - - void DoMainFrame() { - cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( - BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), - base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); - begin_frame_args.on_critical_path = false; - scheduler_->WillBeginFrame(begin_frame_args); - scheduler_->DidCommitFrameToCompositor(); - } - - void DoMainFrameOnCriticalPath() { - cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( - BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), - base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); - begin_frame_args.on_critical_path = true; - scheduler_->WillBeginFrame(begin_frame_args); - } - - void ForceTouchStartToBeExpectedSoon() { - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureScrollEnd), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - clock_->Advance(priority_escalation_after_input_duration() * 2); - scheduler_->ForceUpdatePolicy(); - } - - void SimulateExpensiveTasks( - const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) { - // RunUntilIdle won't actually run all of the SimpleTestTickClock::Advance - // tasks unless we set AutoAdvanceNow to true :/ - mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true); - - // Simulate a bunch of expensive tasks - for (int i = 0; i < 10; i++) { - task_runner->PostTask(FROM_HERE, - base::Bind(&base::SimpleTestTickClock::Advance, - base::Unretained(clock_.get()), - base::TimeDelta::FromMilliseconds(500))); - } - - RunUntilIdle(); - - // Switch back to not auto-advancing because we want to be in control of - // when time advances. - mock_task_runner_->SetAutoAdvanceNowToPendingTasks(false); - } - - enum class TouchEventPolicy { - SEND_TOUCH_START, - DONT_SEND_TOUCH_START, - }; - - void SimulateCompositorGestureStart(TouchEventPolicy touch_event_policy) { - if (touch_event_policy == TouchEventPolicy::SEND_TOUCH_START) { - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchStart), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchMove), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchMove), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - } - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureScrollBegin), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - } - - // Simulate a gesture where there is an active compositor scroll, but no - // scroll updates are generated. Instead, the main thread handles - // non-canceleable touch events, making this an effectively main thread - // driven gesture. - void SimulateMainThreadGestureWithoutScrollUpdates() { - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchStart), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchMove), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureScrollBegin), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchMove), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - } - - // Simulate a gesture where the main thread handles touch events but does not - // preventDefault(), allowing the gesture to turn into a compositor driven - // gesture. This function also verifies the necessary policy updates are - // scheduled. - void SimulateMainThreadGestureWithoutPreventDefault() { - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchStart), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - - // Touchstart policy update. - EXPECT_TRUE(scheduler_->PolicyNeedsUpdateForTesting()); - EXPECT_EQ(UseCase::TOUCHSTART, ForceUpdatePolicyAndGetCurrentUseCase()); - EXPECT_FALSE(scheduler_->PolicyNeedsUpdateForTesting()); - - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchMove), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureTapCancel), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureScrollBegin), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - - // Main thread gesture policy update. - EXPECT_TRUE(scheduler_->PolicyNeedsUpdateForTesting()); - EXPECT_EQ(UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, - ForceUpdatePolicyAndGetCurrentUseCase()); - EXPECT_FALSE(scheduler_->PolicyNeedsUpdateForTesting()); - - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchScrollStarted), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchMove), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - - // Compositor thread gesture policy update. - EXPECT_TRUE(scheduler_->PolicyNeedsUpdateForTesting()); - EXPECT_EQ(UseCase::COMPOSITOR_GESTURE, - ForceUpdatePolicyAndGetCurrentUseCase()); - EXPECT_FALSE(scheduler_->PolicyNeedsUpdateForTesting()); - } - - void SimulateMainThreadGestureStart(TouchEventPolicy touch_event_policy, - blink::WebInputEvent::Type gesture_type) { - if (touch_event_policy == TouchEventPolicy::SEND_TOUCH_START) { - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchStart), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - scheduler_->DidHandleInputEventOnMainThread( - FakeInputEvent(blink::WebInputEvent::TouchStart)); - - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchMove), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - scheduler_->DidHandleInputEventOnMainThread( - FakeInputEvent(blink::WebInputEvent::TouchMove)); - - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchMove), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - scheduler_->DidHandleInputEventOnMainThread( - FakeInputEvent(blink::WebInputEvent::TouchMove)); - } - if (gesture_type != blink::WebInputEvent::Undefined) { - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(gesture_type), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - scheduler_->DidHandleInputEventOnMainThread(FakeInputEvent(gesture_type)); - } - } - - void SimulateMainThreadInputHandlingCompositorTask( - base::TimeDelta begin_main_frame_duration) { - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchMove), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - clock_->Advance(begin_main_frame_duration); - scheduler_->DidHandleInputEventOnMainThread( - FakeInputEvent(blink::WebInputEvent::TouchMove)); - scheduler_->DidCommitFrameToCompositor(); - } - - void SimulateMainThreadCompositorTask( - base::TimeDelta begin_main_frame_duration) { - clock_->Advance(begin_main_frame_duration); - scheduler_->DidCommitFrameToCompositor(); - simulate_compositor_task_ran_ = true; - } - - bool SimulatedCompositorTaskPending() const { - return !simulate_compositor_task_ran_; - } - - void SimulateTimerTask(base::TimeDelta duration) { - clock_->Advance(duration); - simulate_timer_task_ran_ = true; - } - - void EnableIdleTasks() { DoMainFrame(); } - - UseCase CurrentUseCase() { - return scheduler_->MainThreadOnly().current_use_case; - } - - UseCase ForceUpdatePolicyAndGetCurrentUseCase() { - scheduler_->ForceUpdatePolicy(); - return scheduler_->MainThreadOnly().current_use_case; - } - - v8::RAILMode RAILMode() { - return scheduler_->MainThreadOnly().current_policy.rail_mode; - } - - bool BeginFrameNotExpectedSoon() { - return scheduler_->MainThreadOnly().begin_frame_not_expected_soon; - } - - bool TouchStartExpectedSoon() { - return scheduler_->MainThreadOnly().touchstart_expected_soon; - } - - bool HaveSeenABeginMainframe() { - return scheduler_->MainThreadOnly().have_seen_a_begin_main_frame; - } - - bool LoadingTasksSeemExpensive() { - return scheduler_->MainThreadOnly().loading_tasks_seem_expensive; - } - - bool TimerTasksSeemExpensive() { - return scheduler_->MainThreadOnly().timer_tasks_seem_expensive; - } - - base::TimeTicks EstimatedNextFrameBegin() { - return scheduler_->MainThreadOnly().estimated_next_frame_begin; - } - - int NavigationTaskExpectedCount() { - return scheduler_->MainThreadOnly().navigation_task_expected_count; - } - - // Helper for posting several tasks of specific types. |task_descriptor| is a - // string with space delimited task identifiers. The first letter of each - // task identifier specifies the task type: - // - 'D': Default task - // - 'C': Compositor task - // - 'L': Loading task - // - 'I': Idle task - // - 'T': Timer task - void PostTestTasks(std::vector<std::string>* run_order, - const std::string& task_descriptor) { - std::istringstream stream(task_descriptor); - while (!stream.eof()) { - std::string task; - stream >> task; - switch (task[0]) { - case 'D': - default_task_runner_->PostTask( - FROM_HERE, base::Bind(&AppendToVectorTestTask, run_order, task)); - break; - case 'C': - compositor_task_runner_->PostTask( - FROM_HERE, base::Bind(&AppendToVectorTestTask, run_order, task)); - break; - case 'L': - loading_task_runner_->PostTask( - FROM_HERE, base::Bind(&AppendToVectorTestTask, run_order, task)); - break; - case 'I': - idle_task_runner_->PostIdleTask( - FROM_HERE, - base::Bind(&AppendToVectorIdleTestTask, run_order, task)); - break; - case 'T': - timer_task_runner_->PostTask( - FROM_HERE, base::Bind(&AppendToVectorTestTask, run_order, task)); - break; - default: - NOTREACHED(); - } - } - } - - protected: - static base::TimeDelta priority_escalation_after_input_duration() { - return base::TimeDelta::FromMilliseconds( - UserModel::kGestureEstimationLimitMillis); - } - - static base::TimeDelta subsequent_input_expected_after_input_duration() { - return base::TimeDelta::FromMilliseconds( - UserModel::kExpectSubsequentGestureMillis); - } - - static base::TimeDelta maximum_idle_period_duration() { - return base::TimeDelta::FromMilliseconds( - IdleHelper::kMaximumIdlePeriodMillis); - } - - static base::TimeDelta end_idle_when_hidden_delay() { - return base::TimeDelta::FromMilliseconds( - RendererSchedulerImpl::kEndIdleWhenHiddenDelayMillis); - } - - static base::TimeDelta idle_period_starvation_threshold() { - return base::TimeDelta::FromMilliseconds( - RendererSchedulerImpl::kIdlePeriodStarvationThresholdMillis); - } - - static base::TimeDelta suspend_timers_when_backgrounded_delay() { - return base::TimeDelta::FromMilliseconds( - RendererSchedulerImpl::kSuspendTimersWhenBackgroundedDelayMillis); - } - - static base::TimeDelta rails_response_time() { - return base::TimeDelta::FromMilliseconds( - RendererSchedulerImpl::kRailsResponseTimeMillis); - } - - template <typename E> - static void CallForEachEnumValue(E first, - E last, - const char* (*function)(E)) { - for (E val = first; val < last; - val = static_cast<E>(static_cast<int>(val) + 1)) { - (*function)(val); - } - } - - static void CheckAllUseCaseToString() { - CallForEachEnumValue<RendererSchedulerImpl::UseCase>( - RendererSchedulerImpl::UseCase::FIRST_USE_CASE, - RendererSchedulerImpl::UseCase::USE_CASE_COUNT, - &RendererSchedulerImpl::UseCaseToString); - } - - std::unique_ptr<base::SimpleTestTickClock> clock_; - // Only one of mock_task_runner_ or message_loop_ will be set. - scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_; - std::unique_ptr<base::MessageLoop> message_loop_; - - scoped_refptr<SchedulerTqmDelegate> main_task_runner_; - std::unique_ptr<RendererSchedulerImplForTest> scheduler_; - scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_; - scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_; - scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner_; - scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_; - scoped_refptr<base::SingleThreadTaskRunner> timer_task_runner_; - bool simulate_timer_task_ran_; - bool simulate_compositor_task_ran_; - - DISALLOW_COPY_AND_ASSIGN(RendererSchedulerImplTest); -}; - -TEST_F(RendererSchedulerImplTest, TestPostDefaultTask) { - std::vector<std::string> run_order; - PostTestTasks(&run_order, "D1 D2 D3 D4"); - - RunUntilIdle(); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("D1"), std::string("D2"), - std::string("D3"), std::string("D4"))); -} - -TEST_F(RendererSchedulerImplTest, TestPostDefaultAndCompositor) { - std::vector<std::string> run_order; - PostTestTasks(&run_order, "D1 C1"); - RunUntilIdle(); - EXPECT_THAT(run_order, testing::Contains("D1")); - EXPECT_THAT(run_order, testing::Contains("C1")); -} - -TEST_F(RendererSchedulerImplTest, TestRentrantTask) { - int count = 0; - std::vector<int> run_order; - default_task_runner_->PostTask( - FROM_HERE, base::Bind(AppendToVectorReentrantTask, - base::RetainedRef(default_task_runner_), &run_order, - &count, 5)); - RunUntilIdle(); - - EXPECT_THAT(run_order, testing::ElementsAre(0, 1, 2, 3, 4)); -} - -TEST_F(RendererSchedulerImplTest, TestPostIdleTask) { - int run_count = 0; - base::TimeTicks expected_deadline = - clock_->NowTicks() + base::TimeDelta::FromMilliseconds(2300); - base::TimeTicks deadline_in_task; - - clock_->Advance(base::TimeDelta::FromMilliseconds(100)); - idle_task_runner_->PostIdleTask( - FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); - - RunUntilIdle(); - EXPECT_EQ(0, run_count); // Shouldn't run yet as no WillBeginFrame. - - scheduler_->WillBeginFrame(cc::BeginFrameArgs::Create( - BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), - base::TimeDelta::FromMilliseconds(1000), cc::BeginFrameArgs::NORMAL)); - RunUntilIdle(); - EXPECT_EQ(0, run_count); // Shouldn't run as no DidCommitFrameToCompositor. - - clock_->Advance(base::TimeDelta::FromMilliseconds(1200)); - scheduler_->DidCommitFrameToCompositor(); - RunUntilIdle(); - EXPECT_EQ(0, run_count); // We missed the deadline. - - scheduler_->WillBeginFrame(cc::BeginFrameArgs::Create( - BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), - base::TimeDelta::FromMilliseconds(1000), cc::BeginFrameArgs::NORMAL)); - clock_->Advance(base::TimeDelta::FromMilliseconds(800)); - scheduler_->DidCommitFrameToCompositor(); - RunUntilIdle(); - EXPECT_EQ(1, run_count); - EXPECT_EQ(expected_deadline, deadline_in_task); -} - -TEST_F(RendererSchedulerImplTest, TestRepostingIdleTask) { - int run_count = 0; - - max_idle_task_reposts = 2; - idle_task_runner_->PostIdleTask( - FROM_HERE, base::Bind(&RepostingIdleTestTask, - base::RetainedRef(idle_task_runner_), &run_count)); - EnableIdleTasks(); - RunUntilIdle(); - EXPECT_EQ(1, run_count); - - // Reposted tasks shouldn't run until next idle period. - RunUntilIdle(); - EXPECT_EQ(1, run_count); - - EnableIdleTasks(); - RunUntilIdle(); - EXPECT_EQ(2, run_count); -} - -TEST_F(RendererSchedulerImplTest, TestIdleTaskExceedsDeadline) { - mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true); - int run_count = 0; - - // Post two UpdateClockToDeadlineIdleTestTask tasks. - idle_task_runner_->PostIdleTask( - FROM_HERE, - base::Bind(&UpdateClockToDeadlineIdleTestTask, clock_.get(), &run_count)); - idle_task_runner_->PostIdleTask( - FROM_HERE, - base::Bind(&UpdateClockToDeadlineIdleTestTask, clock_.get(), &run_count)); - - EnableIdleTasks(); - RunUntilIdle(); - // Only the first idle task should execute since it's used up the deadline. - EXPECT_EQ(1, run_count); - - EnableIdleTasks(); - RunUntilIdle(); - // Second task should be run on the next idle period. - EXPECT_EQ(2, run_count); -} - -TEST_F(RendererSchedulerImplTest, TestPostIdleTaskAfterWakeup) { - base::TimeTicks deadline_in_task; - int run_count = 0; - - idle_task_runner_->PostIdleTaskAfterWakeup( - FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); - - EnableIdleTasks(); - RunUntilIdle(); - // Shouldn't run yet as no other task woke up the scheduler. - EXPECT_EQ(0, run_count); - - idle_task_runner_->PostIdleTaskAfterWakeup( - FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); - - EnableIdleTasks(); - RunUntilIdle(); - // Another after wakeup idle task shouldn't wake the scheduler. - EXPECT_EQ(0, run_count); - - default_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask)); - - RunUntilIdle(); - EnableIdleTasks(); // Must start a new idle period before idle task runs. - RunUntilIdle(); - // Execution of default task queue task should trigger execution of idle task. - EXPECT_EQ(2, run_count); -} - -TEST_F(RendererSchedulerImplTest, TestPostIdleTaskAfterWakeupWhileAwake) { - base::TimeTicks deadline_in_task; - int run_count = 0; - - idle_task_runner_->PostIdleTaskAfterWakeup( - FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); - default_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask)); - - RunUntilIdle(); - EnableIdleTasks(); // Must start a new idle period before idle task runs. - RunUntilIdle(); - // Should run as the scheduler was already awakened by the normal task. - EXPECT_EQ(1, run_count); -} - -TEST_F(RendererSchedulerImplTest, TestPostIdleTaskWakesAfterWakeupIdleTask) { - base::TimeTicks deadline_in_task; - int run_count = 0; - - idle_task_runner_->PostIdleTaskAfterWakeup( - FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); - idle_task_runner_->PostIdleTask( - FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); - - EnableIdleTasks(); - RunUntilIdle(); - // Must start a new idle period before after-wakeup idle task runs. - EnableIdleTasks(); - RunUntilIdle(); - // Normal idle task should wake up after-wakeup idle task. - EXPECT_EQ(2, run_count); -} - -TEST_F(RendererSchedulerImplTest, TestDelayedEndIdlePeriodCanceled) { - int run_count = 0; - - base::TimeTicks deadline_in_task; - idle_task_runner_->PostIdleTask( - FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); - - // Trigger the beginning of an idle period for 1000ms. - scheduler_->WillBeginFrame(cc::BeginFrameArgs::Create( - BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), - base::TimeDelta::FromMilliseconds(1000), cc::BeginFrameArgs::NORMAL)); - DoMainFrame(); - - // End the idle period early (after 500ms), and send a WillBeginFrame which - // specifies that the next idle period should end 1000ms from now. - clock_->Advance(base::TimeDelta::FromMilliseconds(500)); - scheduler_->WillBeginFrame(cc::BeginFrameArgs::Create( - BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), - base::TimeDelta::FromMilliseconds(1000), cc::BeginFrameArgs::NORMAL)); - - RunUntilIdle(); - EXPECT_EQ(0, run_count); // Not currently in an idle period. - - // Trigger the start of the idle period before the task to end the previous - // idle period has been triggered. - clock_->Advance(base::TimeDelta::FromMilliseconds(400)); - scheduler_->DidCommitFrameToCompositor(); - - // Post a task which simulates running until after the previous end idle - // period delayed task was scheduled for - scheduler_->DefaultTaskRunner()->PostTask(FROM_HERE, base::Bind(NullTask)); - clock_->Advance(base::TimeDelta::FromMilliseconds(300)); - - RunUntilIdle(); - EXPECT_EQ(1, run_count); // We should still be in the new idle period. -} - -TEST_F(RendererSchedulerImplTest, TestDefaultPolicy) { - std::vector<std::string> run_order; - PostTestTasks(&run_order, "L1 I1 D1 C1 D2 C2"); - - EnableIdleTasks(); - RunUntilIdle(); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("L1"), std::string("D1"), - std::string("C1"), std::string("D2"), - std::string("C2"), std::string("I1"))); - EXPECT_EQ(RendererSchedulerImpl::UseCase::NONE, CurrentUseCase()); -} - -TEST_F(RendererSchedulerImplTest, - TestCompositorPolicy_CompositorHandlesInput_WithTouchHandler) { - std::vector<std::string> run_order; - PostTestTasks(&run_order, "L1 I1 D1 C1 D2 C2"); - - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - EnableIdleTasks(); - SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START); - RunUntilIdle(); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("L1"), std::string("D1"), - std::string("D2"), std::string("I1"), - std::string("C1"), std::string("C2"))); - EXPECT_EQ(RendererSchedulerImpl::UseCase::COMPOSITOR_GESTURE, - CurrentUseCase()); -} - -TEST_F(RendererSchedulerImplTest, - TestCompositorPolicy_MainThreadHandlesInput_WithoutScrollUpdates) { - std::vector<std::string> run_order; - PostTestTasks(&run_order, "L1 I1 D1 C1 D2 C2"); - - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - EnableIdleTasks(); - SimulateMainThreadGestureWithoutScrollUpdates(); - RunUntilIdle(); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("C1"), std::string("C2"), - std::string("L1"), std::string("D1"), - std::string("D2"), std::string("I1"))); - EXPECT_EQ(RendererSchedulerImpl::UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, - CurrentUseCase()); -} - -TEST_F(RendererSchedulerImplTest, - TestCompositorPolicy_MainThreadHandlesInput_WithoutPreventDefault) { - std::vector<std::string> run_order; - PostTestTasks(&run_order, "L1 I1 D1 C1 D2 C2"); - - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - EnableIdleTasks(); - SimulateMainThreadGestureWithoutPreventDefault(); - RunUntilIdle(); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("L1"), std::string("D1"), - std::string("D2"), std::string("I1"), - std::string("C1"), std::string("C2"))); - EXPECT_EQ(RendererSchedulerImpl::UseCase::COMPOSITOR_GESTURE, - CurrentUseCase()); -} - -TEST_F(RendererSchedulerImplTest, - TestCompositorPolicy_CompositorHandlesInput_LongGestureDuration) { - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - EnableIdleTasks(); - SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START); - - base::TimeTicks loop_end_time = - clock_->NowTicks() + base::TimeDelta::FromMilliseconds( - UserModel::kMedianGestureDurationMillis * 2); - - // The UseCase::COMPOSITOR_GESTURE usecase initially deprioritizes compositor - // tasks (see TestCompositorPolicy_CompositorHandlesInput_WithTouchHandler) - // but if the gesture is long enough, compositor tasks get prioritized again. - while (clock_->NowTicks() < loop_end_time) { - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchMove), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - clock_->Advance(base::TimeDelta::FromMilliseconds(16)); - RunUntilIdle(); - } - - std::vector<std::string> run_order; - PostTestTasks(&run_order, "L1 I1 D1 C1 D2 C2"); - - RunUntilIdle(); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("C1"), std::string("C2"), - std::string("L1"), std::string("D1"), - std::string("D2"))); - EXPECT_EQ(RendererSchedulerImpl::UseCase::COMPOSITOR_GESTURE, - CurrentUseCase()); -} - -TEST_F(RendererSchedulerImplTest, - TestCompositorPolicy_CompositorHandlesInput_WithoutTouchHandler) { - std::vector<std::string> run_order; - PostTestTasks(&run_order, "L1 I1 D1 C1 D2 C2"); - - EnableIdleTasks(); - SimulateCompositorGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START); - RunUntilIdle(); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("L1"), std::string("D1"), - std::string("D2"), std::string("I1"), - std::string("C1"), std::string("C2"))); - EXPECT_EQ(RendererSchedulerImpl::UseCase::COMPOSITOR_GESTURE, - CurrentUseCase()); -} - -TEST_F(RendererSchedulerImplTest, - TestCompositorPolicy_MainThreadHandlesInput_WithTouchHandler) { - std::vector<std::string> run_order; - PostTestTasks(&run_order, "L1 I1 D1 C1 D2 C2"); - - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - EnableIdleTasks(); - SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START, - blink::WebInputEvent::GestureScrollBegin); - RunUntilIdle(); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("C1"), std::string("C2"), - std::string("L1"), std::string("D1"), - std::string("D2"), std::string("I1"))); - EXPECT_EQ(RendererSchedulerImpl::UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, - CurrentUseCase()); - scheduler_->DidHandleInputEventOnMainThread( - FakeInputEvent(blink::WebInputEvent::GestureFlingStart)); -} - -TEST_F(RendererSchedulerImplTest, - TestCompositorPolicy_MainThreadHandlesInput_WithoutTouchHandler) { - std::vector<std::string> run_order; - PostTestTasks(&run_order, "L1 I1 D1 C1 D2 C2"); - - EnableIdleTasks(); - SimulateMainThreadGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START, - blink::WebInputEvent::GestureScrollBegin); - RunUntilIdle(); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("C1"), std::string("C2"), - std::string("L1"), std::string("D1"), - std::string("D2"), std::string("I1"))); - EXPECT_EQ(RendererSchedulerImpl::UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, - CurrentUseCase()); - scheduler_->DidHandleInputEventOnMainThread( - FakeInputEvent(blink::WebInputEvent::GestureFlingStart)); -} - -TEST_F(RendererSchedulerImplTest, TestCompositorPolicy_DidAnimateForInput) { - std::vector<std::string> run_order; - PostTestTasks(&run_order, "I1 D1 C1 D2 C2"); - - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - scheduler_->DidAnimateForInputOnCompositorThread(); - // Note DidAnimateForInputOnCompositorThread does not by itself trigger a - // policy update. - EXPECT_EQ(RendererSchedulerImpl::UseCase::COMPOSITOR_GESTURE, - ForceUpdatePolicyAndGetCurrentUseCase()); - EnableIdleTasks(); - RunUntilIdle(); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("D1"), std::string("D2"), - std::string("I1"), std::string("C1"), - std::string("C2"))); - EXPECT_EQ(RendererSchedulerImpl::UseCase::COMPOSITOR_GESTURE, - CurrentUseCase()); -} - -TEST_F(RendererSchedulerImplTest, Navigation_ResetsTaskCostEstimations) { - std::vector<std::string> run_order; - - SimulateExpensiveTasks(timer_task_runner_); - scheduler_->OnNavigationStarted(); - PostTestTasks(&run_order, "C1 T1"); - - SimulateMainThreadGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START, - blink::WebInputEvent::GestureScrollBegin); - scheduler_->DidCommitFrameToCompositor(); // Starts Idle Period - RunUntilIdle(); - - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("C1"), std::string("T1"))); -} - -TEST_F(RendererSchedulerImplTest, - ExpensiveTimersDontRunWhenMainThreadScrolling) { - std::vector<std::string> run_order; - - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - SimulateExpensiveTasks(timer_task_runner_); - DoMainFrame(); - SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START, - blink::WebInputEvent::GestureScrollUpdate); - - PostTestTasks(&run_order, "C1 T1"); - - RunUntilIdle(); - EXPECT_FALSE(TouchStartExpectedSoon()); - EXPECT_EQ(RendererSchedulerImpl::UseCase::MAIN_THREAD_GESTURE, - CurrentUseCase()); - - EXPECT_THAT(run_order, testing::ElementsAre(std::string("C1"))); -} - -TEST_F(RendererSchedulerImplTest, - ExpensiveTimersDoRunWhenMainThreadInputHandling) { - std::vector<std::string> run_order; - - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - SimulateExpensiveTasks(timer_task_runner_); - DoMainFrame(); - SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START, - blink::WebInputEvent::Undefined); - - PostTestTasks(&run_order, "C1 T1"); - - RunUntilIdle(); - EXPECT_FALSE(TouchStartExpectedSoon()); - EXPECT_EQ(RendererSchedulerImpl::UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, - CurrentUseCase()); - - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("C1"), std::string("T1"))); -} - -TEST_F(RendererSchedulerImplTest, - ExpensiveTimersDoRunWhenMainThreadScrolling_AndOnCriticalPath) { - std::vector<std::string> run_order; - - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - SimulateExpensiveTasks(timer_task_runner_); - DoMainFrameOnCriticalPath(); - SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START, - blink::WebInputEvent::GestureScrollBegin); - - PostTestTasks(&run_order, "C1 T1"); - - RunUntilIdle(); - EXPECT_FALSE(TouchStartExpectedSoon()); - EXPECT_EQ(RendererSchedulerImpl::UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, - CurrentUseCase()); - - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("C1"), std::string("T1"))); -} - -TEST_F(RendererSchedulerImplTest, TestTouchstartPolicy_Compositor) { - std::vector<std::string> run_order; - PostTestTasks(&run_order, "L1 D1 C1 D2 C2 T1 T2"); - - // Observation of touchstart should defer execution of timer, idle and loading - // tasks. - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchStart), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - EnableIdleTasks(); - RunUntilIdle(); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("C1"), std::string("C2"), - std::string("D1"), std::string("D2"))); - - // Animation or meta events like TapDown/FlingCancel shouldn't affect the - // priority. - run_order.clear(); - scheduler_->DidAnimateForInputOnCompositorThread(); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureFlingCancel), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureTapDown), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); - - // Action events like ScrollBegin will kick us back into compositor priority, - // allowing service of the timer, loading and idle queues. - run_order.clear(); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureScrollBegin), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - RunUntilIdle(); - - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("L1"), std::string("T1"), - std::string("T2"))); -} - -TEST_F(RendererSchedulerImplTest, TestTouchstartPolicy_MainThread) { - std::vector<std::string> run_order; - PostTestTasks(&run_order, "L1 D1 C1 D2 C2 T1 T2"); - - // Observation of touchstart should defer execution of timer, idle and loading - // tasks. - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchStart), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - scheduler_->DidHandleInputEventOnMainThread( - FakeInputEvent(blink::WebInputEvent::TouchStart)); - EnableIdleTasks(); - RunUntilIdle(); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("C1"), std::string("C2"), - std::string("D1"), std::string("D2"))); - - // Meta events like TapDown/FlingCancel shouldn't affect the priority. - run_order.clear(); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureFlingCancel), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - scheduler_->DidHandleInputEventOnMainThread( - FakeInputEvent(blink::WebInputEvent::GestureFlingCancel)); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureTapDown), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - scheduler_->DidHandleInputEventOnMainThread( - FakeInputEvent(blink::WebInputEvent::GestureTapDown)); - RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); - - // Action events like ScrollBegin will kick us back into compositor priority, - // allowing service of the timer, loading and idle queues. - run_order.clear(); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureScrollBegin), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - scheduler_->DidHandleInputEventOnMainThread( - FakeInputEvent(blink::WebInputEvent::GestureScrollBegin)); - RunUntilIdle(); - - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("L1"), std::string("T1"), - std::string("T2"))); -} - -// TODO(alexclarke): Reenable once we've reinstaed the Loading UseCase. -TEST_F(RendererSchedulerImplTest, DISABLED_LoadingUseCase) { - std::vector<std::string> run_order; - PostTestTasks(&run_order, "I1 D1 C1 T1 L1 D2 C2 T2 L2"); - - scheduler_->OnNavigationStarted(); - EnableIdleTasks(); - RunUntilIdle(); - - // In loading policy, loading tasks are prioritized other others. - std::string loading_policy_expected[] = { - std::string("D1"), std::string("L1"), std::string("D2"), - std::string("L2"), std::string("C1"), std::string("T1"), - std::string("C2"), std::string("T2"), std::string("I1")}; - EXPECT_THAT(run_order, testing::ElementsAreArray(loading_policy_expected)); - EXPECT_EQ(RendererSchedulerImpl::UseCase::LOADING, CurrentUseCase()); - - // Advance 15s and try again, the loading policy should have ended and the - // task order should return to the NONE use case where loading tasks are no - // longer prioritized. - clock_->Advance(base::TimeDelta::FromMilliseconds(150000)); - run_order.clear(); - PostTestTasks(&run_order, "I1 D1 C1 T1 L1 D2 C2 T2 L2"); - EnableIdleTasks(); - RunUntilIdle(); - - std::string default_order_expected[] = { - std::string("D1"), std::string("C1"), std::string("T1"), - std::string("L1"), std::string("D2"), std::string("C2"), - std::string("T2"), std::string("L2"), std::string("I1")}; - EXPECT_THAT(run_order, testing::ElementsAreArray(default_order_expected)); - EXPECT_EQ(RendererSchedulerImpl::UseCase::NONE, CurrentUseCase()); -} - -TEST_F(RendererSchedulerImplTest, - EventConsumedOnCompositorThread_IgnoresMouseMove_WhenMouseUp) { - std::vector<std::string> run_order; - PostTestTasks(&run_order, "I1 D1 C1 D2 C2"); - - EnableIdleTasks(); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::MouseMove), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - RunUntilIdle(); - // Note compositor tasks are not prioritized. - EXPECT_EQ(RendererSchedulerImpl::UseCase::NONE, CurrentUseCase()); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("D1"), std::string("C1"), - std::string("D2"), std::string("C2"), - std::string("I1"))); -} - -TEST_F(RendererSchedulerImplTest, - EventForwardedToMainThread_IgnoresMouseMove_WhenMouseUp) { - std::vector<std::string> run_order; - PostTestTasks(&run_order, "I1 D1 C1 D2 C2"); - - EnableIdleTasks(); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::MouseMove), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - RunUntilIdle(); - // Note compositor tasks are not prioritized. - EXPECT_EQ(RendererSchedulerImpl::UseCase::NONE, CurrentUseCase()); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("D1"), std::string("C1"), - std::string("D2"), std::string("C2"), - std::string("I1"))); -} - -TEST_F(RendererSchedulerImplTest, - EventConsumedOnCompositorThread_MouseMove_WhenMouseDown) { - std::vector<std::string> run_order; - PostTestTasks(&run_order, "I1 D1 C1 D2 C2"); - - EnableIdleTasks(); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::MouseMove, - blink::WebInputEvent::LeftButtonDown), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - RunUntilIdle(); - // Note compositor tasks are prioritized. - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("C1"), std::string("C2"), - std::string("D1"), std::string("D2"), - std::string("I1"))); -} - -TEST_F(RendererSchedulerImplTest, - EventForwardedToMainThread_MouseMove_WhenMouseDown) { - std::vector<std::string> run_order; - PostTestTasks(&run_order, "I1 D1 C1 D2 C2"); - - EnableIdleTasks(); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::MouseMove, - blink::WebInputEvent::LeftButtonDown), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - RunUntilIdle(); - // Note compositor tasks are prioritized. - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("C1"), std::string("C2"), - std::string("D1"), std::string("D2"), - std::string("I1"))); - scheduler_->DidHandleInputEventOnMainThread(FakeInputEvent( - blink::WebInputEvent::MouseMove, blink::WebInputEvent::LeftButtonDown)); -} - -TEST_F(RendererSchedulerImplTest, EventConsumedOnCompositorThread_MouseWheel) { - std::vector<std::string> run_order; - PostTestTasks(&run_order, "I1 D1 C1 D2 C2"); - - EnableIdleTasks(); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::MouseWheel), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - RunUntilIdle(); - // Note compositor tasks are prioritized. - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("C1"), std::string("C2"), - std::string("D1"), std::string("D2"), - std::string("I1"))); -} - -TEST_F(RendererSchedulerImplTest, EventForwardedToMainThread_MouseWheel) { - std::vector<std::string> run_order; - PostTestTasks(&run_order, "I1 D1 C1 D2 C2"); - - EnableIdleTasks(); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::MouseWheel), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - RunUntilIdle(); - // Note compositor tasks are prioritized. - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("C1"), std::string("C2"), - std::string("D1"), std::string("D2"), - std::string("I1"))); - EXPECT_EQ(RendererSchedulerImpl::UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, - CurrentUseCase()); -} - -TEST_F(RendererSchedulerImplTest, - EventConsumedOnCompositorThread_IgnoresKeyboardEvents) { - std::vector<std::string> run_order; - PostTestTasks(&run_order, "I1 D1 C1 D2 C2"); - - EnableIdleTasks(); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::KeyDown), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - RunUntilIdle(); - // Note compositor tasks are not prioritized. - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("D1"), std::string("C1"), - std::string("D2"), std::string("C2"), - std::string("I1"))); - EXPECT_EQ(RendererSchedulerImpl::UseCase::NONE, CurrentUseCase()); -} - -TEST_F(RendererSchedulerImplTest, - EventForwardedToMainThread_IgnoresKeyboardEvents) { - std::vector<std::string> run_order; - PostTestTasks(&run_order, "I1 D1 C1 D2 C2"); - - EnableIdleTasks(); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::KeyDown), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - RunUntilIdle(); - // Note compositor tasks are not prioritized. - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("D1"), std::string("C1"), - std::string("D2"), std::string("C2"), - std::string("I1"))); - EXPECT_EQ(RendererSchedulerImpl::UseCase::NONE, CurrentUseCase()); - // Note compositor tasks are not prioritized. - scheduler_->DidHandleInputEventOnMainThread( - FakeInputEvent(blink::WebInputEvent::KeyDown)); -} - -TEST_F(RendererSchedulerImplTest, - TestMainthreadScrollingUseCaseDoesNotStarveDefaultTasks) { - SimulateMainThreadGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START, - blink::WebInputEvent::GestureScrollBegin); - EnableIdleTasks(); - - std::vector<std::string> run_order; - PostTestTasks(&run_order, "D1 C1"); - - for (int i = 0; i < 20; i++) { - compositor_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask)); - } - PostTestTasks(&run_order, "C2"); - - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureFlingStart), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - RunUntilIdle(); - // Ensure that the default D1 task gets to run at some point before the final - // C2 compositor task. - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("C1"), std::string("D1"), - std::string("C2"))); -} - -TEST_F(RendererSchedulerImplTest, - TestCompositorPolicyEnds_CompositorHandlesInput) { - SimulateCompositorGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START); - EXPECT_EQ(UseCase::COMPOSITOR_GESTURE, - ForceUpdatePolicyAndGetCurrentUseCase()); - - clock_->Advance(base::TimeDelta::FromMilliseconds(1000)); - EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); -} - -TEST_F(RendererSchedulerImplTest, - TestCompositorPolicyEnds_MainThreadHandlesInput) { - SimulateMainThreadGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START, - blink::WebInputEvent::GestureScrollBegin); - EXPECT_EQ(UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, - ForceUpdatePolicyAndGetCurrentUseCase()); - - clock_->Advance(base::TimeDelta::FromMilliseconds(1000)); - EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); -} - -TEST_F(RendererSchedulerImplTest, TestTouchstartPolicyEndsAfterTimeout) { - std::vector<std::string> run_order; - PostTestTasks(&run_order, "L1 D1 C1 D2 C2"); - - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchStart), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - RunUntilIdle(); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("C1"), std::string("C2"), - std::string("D1"), std::string("D2"))); - - run_order.clear(); - clock_->Advance(base::TimeDelta::FromMilliseconds(1000)); - - // Don't post any compositor tasks to simulate a very long running event - // handler. - PostTestTasks(&run_order, "D1 D2"); - - // Touchstart policy mode should have ended now that the clock has advanced. - RunUntilIdle(); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("L1"), std::string("D1"), - std::string("D2"))); -} - -TEST_F(RendererSchedulerImplTest, - TestTouchstartPolicyEndsAfterConsecutiveTouchmoves) { - std::vector<std::string> run_order; - PostTestTasks(&run_order, "L1 D1 C1 D2 C2"); - - // Observation of touchstart should defer execution of idle and loading tasks. - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchStart), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - RunUntilIdle(); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("C1"), std::string("C2"), - std::string("D1"), std::string("D2"))); - - // Receiving the first touchmove will not affect scheduler priority. - run_order.clear(); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchMove), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); - - // Receiving the second touchmove will kick us back into compositor priority. - run_order.clear(); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchMove), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - RunUntilIdle(); - EXPECT_THAT(run_order, testing::ElementsAre(std::string("L1"))); -} - -TEST_F(RendererSchedulerImplTest, TestIsHighPriorityWorkAnticipated) { - bool is_anticipated_before = false; - bool is_anticipated_after = false; - - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - default_task_runner_->PostTask( - FROM_HERE, base::Bind(&AnticipationTestTask, scheduler_.get(), - SimulateInputType::None, &is_anticipated_before, - &is_anticipated_after)); - RunUntilIdle(); - // In its default state, without input receipt, the scheduler should indicate - // that no high-priority is anticipated. - EXPECT_FALSE(is_anticipated_before); - EXPECT_FALSE(is_anticipated_after); - - default_task_runner_->PostTask( - FROM_HERE, base::Bind(&AnticipationTestTask, scheduler_.get(), - SimulateInputType::TouchStart, - &is_anticipated_before, &is_anticipated_after)); - bool dummy; - default_task_runner_->PostTask( - FROM_HERE, base::Bind(&AnticipationTestTask, scheduler_.get(), - SimulateInputType::TouchEnd, &dummy, &dummy)); - default_task_runner_->PostTask( - FROM_HERE, - base::Bind(&AnticipationTestTask, scheduler_.get(), - SimulateInputType::GestureScrollBegin, &dummy, &dummy)); - default_task_runner_->PostTask( - FROM_HERE, - base::Bind(&AnticipationTestTask, scheduler_.get(), - SimulateInputType::GestureScrollEnd, &dummy, &dummy)); - - RunUntilIdle(); - // When input is received, the scheduler should indicate that high-priority - // work is anticipated. - EXPECT_FALSE(is_anticipated_before); - EXPECT_TRUE(is_anticipated_after); - - clock_->Advance(priority_escalation_after_input_duration() * 2); - default_task_runner_->PostTask( - FROM_HERE, base::Bind(&AnticipationTestTask, scheduler_.get(), - SimulateInputType::None, &is_anticipated_before, - &is_anticipated_after)); - RunUntilIdle(); - // Without additional input, the scheduler should go into NONE - // use case but with scrolling expected where high-priority work is still - // anticipated. - EXPECT_EQ(UseCase::NONE, CurrentUseCase()); - EXPECT_TRUE(TouchStartExpectedSoon()); - EXPECT_TRUE(is_anticipated_before); - EXPECT_TRUE(is_anticipated_after); - - clock_->Advance(subsequent_input_expected_after_input_duration() * 2); - default_task_runner_->PostTask( - FROM_HERE, base::Bind(&AnticipationTestTask, scheduler_.get(), - SimulateInputType::None, &is_anticipated_before, - &is_anticipated_after)); - RunUntilIdle(); - // Eventually the scheduler should go into the default use case where - // high-priority work is no longer anticipated. - EXPECT_EQ(UseCase::NONE, CurrentUseCase()); - EXPECT_FALSE(TouchStartExpectedSoon()); - EXPECT_FALSE(is_anticipated_before); - EXPECT_FALSE(is_anticipated_after); -} - -TEST_F(RendererSchedulerImplTest, TestShouldYield) { - bool should_yield_before = false; - bool should_yield_after = false; - - default_task_runner_->PostTask( - FROM_HERE, base::Bind(&PostingYieldingTestTask, scheduler_.get(), - base::RetainedRef(default_task_runner_), false, - &should_yield_before, &should_yield_after)); - RunUntilIdle(); - // Posting to default runner shouldn't cause yielding. - EXPECT_FALSE(should_yield_before); - EXPECT_FALSE(should_yield_after); - - default_task_runner_->PostTask( - FROM_HERE, base::Bind(&PostingYieldingTestTask, scheduler_.get(), - base::RetainedRef(compositor_task_runner_), false, - &should_yield_before, &should_yield_after)); - RunUntilIdle(); - // Posting while not mainthread scrolling shouldn't cause yielding. - EXPECT_FALSE(should_yield_before); - EXPECT_FALSE(should_yield_after); - - default_task_runner_->PostTask( - FROM_HERE, base::Bind(&PostingYieldingTestTask, scheduler_.get(), - base::RetainedRef(compositor_task_runner_), true, - &should_yield_before, &should_yield_after)); - RunUntilIdle(); - // We should be able to switch to compositor priority mid-task. - EXPECT_FALSE(should_yield_before); - EXPECT_TRUE(should_yield_after); -} - -TEST_F(RendererSchedulerImplTest, TestShouldYield_TouchStart) { - // Receiving a touchstart should immediately trigger yielding, even if - // there's no immediately pending work in the compositor queue. - EXPECT_FALSE(scheduler_->ShouldYieldForHighPriorityWork()); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchStart), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - EXPECT_TRUE(scheduler_->ShouldYieldForHighPriorityWork()); - RunUntilIdle(); -} - -TEST_F(RendererSchedulerImplTest, SlowMainThreadInputEvent) { - EXPECT_EQ(UseCase::NONE, CurrentUseCase()); - - // An input event should bump us into input priority. - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureFlingStart), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - RunUntilIdle(); - EXPECT_EQ(UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, CurrentUseCase()); - - // Simulate the input event being queued for a very long time. The compositor - // task we post here represents the enqueued input task. - clock_->Advance(priority_escalation_after_input_duration() * 2); - scheduler_->DidHandleInputEventOnMainThread( - FakeInputEvent(blink::WebInputEvent::GestureFlingStart)); - RunUntilIdle(); - - // Even though we exceeded the input priority escalation period, we should - // still be in main thread gesture since the input remains queued. - EXPECT_EQ(UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, CurrentUseCase()); - - // After the escalation period ends we should go back into normal mode. - clock_->Advance(priority_escalation_after_input_duration() * 2); - RunUntilIdle(); - EXPECT_EQ(UseCase::NONE, CurrentUseCase()); -} - -class RendererSchedulerImplWithMockSchedulerTest - : public RendererSchedulerImplTest { - public: - void SetUp() override { - mock_task_runner_ = make_scoped_refptr( - new cc::OrderedSimpleTaskRunner(clock_.get(), false)); - main_task_runner_ = SchedulerTqmDelegateForTest::Create( - mock_task_runner_, base::WrapUnique(new TestTimeSource(clock_.get()))); - mock_scheduler_ = new RendererSchedulerImplForTest(main_task_runner_); - Initialize(base::WrapUnique(mock_scheduler_)); - } - - protected: - RendererSchedulerImplForTest* mock_scheduler_; -}; - -TEST_F(RendererSchedulerImplWithMockSchedulerTest, - OnlyOnePendingUrgentPolicyUpdatey) { - mock_scheduler_->EnsureUrgentPolicyUpdatePostedOnMainThread(); - mock_scheduler_->EnsureUrgentPolicyUpdatePostedOnMainThread(); - mock_scheduler_->EnsureUrgentPolicyUpdatePostedOnMainThread(); - mock_scheduler_->EnsureUrgentPolicyUpdatePostedOnMainThread(); - - RunUntilIdle(); - - EXPECT_EQ(1, mock_scheduler_->update_policy_count_); -} - -TEST_F(RendererSchedulerImplWithMockSchedulerTest, - OnePendingDelayedAndOneUrgentUpdatePolicy) { - mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true); - - mock_scheduler_->ScheduleDelayedPolicyUpdate( - clock_->NowTicks(), base::TimeDelta::FromMilliseconds(1)); - mock_scheduler_->EnsureUrgentPolicyUpdatePostedOnMainThread(); - - RunUntilIdle(); - - // We expect both the urgent and the delayed updates to run. - EXPECT_EQ(2, mock_scheduler_->update_policy_count_); -} - -TEST_F(RendererSchedulerImplWithMockSchedulerTest, - OneUrgentAndOnePendingDelayedUpdatePolicy) { - mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true); - - mock_scheduler_->EnsureUrgentPolicyUpdatePostedOnMainThread(); - mock_scheduler_->ScheduleDelayedPolicyUpdate( - clock_->NowTicks(), base::TimeDelta::FromMilliseconds(1)); - - RunUntilIdle(); - - // We expect both the urgent and the delayed updates to run. - EXPECT_EQ(2, mock_scheduler_->update_policy_count_); -} - -TEST_F(RendererSchedulerImplWithMockSchedulerTest, - UpdatePolicyCountTriggeredByOneInputEvent) { - // We expect DidHandleInputEventOnCompositorThread to post an urgent policy - // update. - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchStart), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - EXPECT_EQ(0, mock_scheduler_->update_policy_count_); - mock_task_runner_->RunPendingTasks(); - EXPECT_EQ(1, mock_scheduler_->update_policy_count_); - - scheduler_->DidHandleInputEventOnMainThread( - FakeInputEvent(blink::WebInputEvent::TouchStart)); - EXPECT_EQ(1, mock_scheduler_->update_policy_count_); - - clock_->Advance(base::TimeDelta::FromMilliseconds(1000)); - RunUntilIdle(); - - // We finally expect a delayed policy update 100ms later. - EXPECT_EQ(2, mock_scheduler_->update_policy_count_); -} - -TEST_F(RendererSchedulerImplWithMockSchedulerTest, - UpdatePolicyCountTriggeredByThreeInputEvents) { - // We expect DidHandleInputEventOnCompositorThread to post an urgent policy - // update. - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchStart), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - EXPECT_EQ(0, mock_scheduler_->update_policy_count_); - mock_task_runner_->RunPendingTasks(); - EXPECT_EQ(1, mock_scheduler_->update_policy_count_); - - scheduler_->DidHandleInputEventOnMainThread( - FakeInputEvent(blink::WebInputEvent::TouchStart)); - EXPECT_EQ(1, mock_scheduler_->update_policy_count_); - - // The second call to DidHandleInputEventOnCompositorThread should not post a - // policy update because we are already in compositor priority. - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchMove), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - mock_task_runner_->RunPendingTasks(); - EXPECT_EQ(1, mock_scheduler_->update_policy_count_); - - // We expect DidHandleInputEvent to trigger a policy update. - scheduler_->DidHandleInputEventOnMainThread( - FakeInputEvent(blink::WebInputEvent::TouchMove)); - EXPECT_EQ(1, mock_scheduler_->update_policy_count_); - - // The third call to DidHandleInputEventOnCompositorThread should post a - // policy update because the awaiting_touch_start_response_ flag changed. - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchMove), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - EXPECT_EQ(1, mock_scheduler_->update_policy_count_); - mock_task_runner_->RunPendingTasks(); - EXPECT_EQ(2, mock_scheduler_->update_policy_count_); - - // We expect DidHandleInputEvent to trigger a policy update. - scheduler_->DidHandleInputEventOnMainThread( - FakeInputEvent(blink::WebInputEvent::TouchMove)); - EXPECT_EQ(2, mock_scheduler_->update_policy_count_); - - clock_->Advance(base::TimeDelta::FromMilliseconds(1000)); - RunUntilIdle(); - - // We finally expect a delayed policy update. - EXPECT_EQ(3, mock_scheduler_->update_policy_count_); -} - -TEST_F(RendererSchedulerImplWithMockSchedulerTest, - UpdatePolicyCountTriggeredByTwoInputEventsWithALongSeparatingDelay) { - // We expect DidHandleInputEventOnCompositorThread to post an urgent policy - // update. - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchStart), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - EXPECT_EQ(0, mock_scheduler_->update_policy_count_); - mock_task_runner_->RunPendingTasks(); - EXPECT_EQ(1, mock_scheduler_->update_policy_count_); - - scheduler_->DidHandleInputEventOnMainThread( - FakeInputEvent(blink::WebInputEvent::TouchStart)); - EXPECT_EQ(1, mock_scheduler_->update_policy_count_); - - clock_->Advance(base::TimeDelta::FromMilliseconds(1000)); - RunUntilIdle(); - // We expect a delayed policy update. - EXPECT_EQ(2, mock_scheduler_->update_policy_count_); - - // We expect the second call to DidHandleInputEventOnCompositorThread to post - // an urgent policy update because we are no longer in compositor priority. - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchMove), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - EXPECT_EQ(2, mock_scheduler_->update_policy_count_); - mock_task_runner_->RunPendingTasks(); - EXPECT_EQ(3, mock_scheduler_->update_policy_count_); - - scheduler_->DidHandleInputEventOnMainThread( - FakeInputEvent(blink::WebInputEvent::TouchMove)); - EXPECT_EQ(3, mock_scheduler_->update_policy_count_); - - clock_->Advance(base::TimeDelta::FromMilliseconds(1000)); - RunUntilIdle(); - - // We finally expect a delayed policy update. - EXPECT_EQ(4, mock_scheduler_->update_policy_count_); -} - -TEST_F(RendererSchedulerImplWithMockSchedulerTest, - EnsureUpdatePolicyNotTriggeredTooOften) { - mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true); - - EXPECT_EQ(0, mock_scheduler_->update_policy_count_); - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - EXPECT_EQ(1, mock_scheduler_->update_policy_count_); - - SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START); - - // We expect the first call to IsHighPriorityWorkAnticipated to be called - // after receiving an input event (but before the UpdateTask was processed) to - // call UpdatePolicy. - EXPECT_EQ(1, mock_scheduler_->update_policy_count_); - scheduler_->IsHighPriorityWorkAnticipated(); - EXPECT_EQ(2, mock_scheduler_->update_policy_count_); - // Subsequent calls should not call UpdatePolicy. - scheduler_->IsHighPriorityWorkAnticipated(); - scheduler_->IsHighPriorityWorkAnticipated(); - scheduler_->IsHighPriorityWorkAnticipated(); - scheduler_->ShouldYieldForHighPriorityWork(); - scheduler_->ShouldYieldForHighPriorityWork(); - scheduler_->ShouldYieldForHighPriorityWork(); - scheduler_->ShouldYieldForHighPriorityWork(); - - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureScrollEnd), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchEnd), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - - scheduler_->DidHandleInputEventOnMainThread( - FakeInputEvent(blink::WebInputEvent::TouchStart)); - scheduler_->DidHandleInputEventOnMainThread( - FakeInputEvent(blink::WebInputEvent::TouchMove)); - scheduler_->DidHandleInputEventOnMainThread( - FakeInputEvent(blink::WebInputEvent::TouchMove)); - scheduler_->DidHandleInputEventOnMainThread( - FakeInputEvent(blink::WebInputEvent::TouchEnd)); - - EXPECT_EQ(2, mock_scheduler_->update_policy_count_); - - // We expect both the urgent and the delayed updates to run in addition to the - // earlier updated cause by IsHighPriorityWorkAnticipated, a final update - // transitions from 'not_scrolling touchstart expected' to 'not_scrolling'. - RunUntilIdle(); - EXPECT_THAT( - mock_scheduler_->use_cases_, - testing::ElementsAre( - std::string("none"), std::string("compositor_gesture"), - std::string("compositor_gesture touchstart expected"), - std::string("none touchstart expected"), std::string("none"))); -} - -class RendererSchedulerImplWithMessageLoopTest - : public RendererSchedulerImplTest { - public: - RendererSchedulerImplWithMessageLoopTest() - : RendererSchedulerImplTest(new base::MessageLoop()) {} - ~RendererSchedulerImplWithMessageLoopTest() override {} - - void PostFromNestedRunloop(std::vector< - std::pair<SingleThreadIdleTaskRunner::IdleTask, bool>>* tasks) { - base::MessageLoop::ScopedNestableTaskAllower allow(message_loop_.get()); - for (std::pair<SingleThreadIdleTaskRunner::IdleTask, bool>& pair : *tasks) { - if (pair.second) { - idle_task_runner_->PostIdleTask(FROM_HERE, pair.first); - } else { - idle_task_runner_->PostNonNestableIdleTask(FROM_HERE, pair.first); - } - } - EnableIdleTasks(); - base::RunLoop().RunUntilIdle(); - } - - private: - DISALLOW_COPY_AND_ASSIGN(RendererSchedulerImplWithMessageLoopTest); -}; - -TEST_F(RendererSchedulerImplWithMessageLoopTest, - NonNestableIdleTaskDoesntExecuteInNestedLoop) { - std::vector<std::string> order; - idle_task_runner_->PostIdleTask( - FROM_HERE, - base::Bind(&AppendToVectorIdleTestTask, &order, std::string("1"))); - idle_task_runner_->PostIdleTask( - FROM_HERE, - base::Bind(&AppendToVectorIdleTestTask, &order, std::string("2"))); - - std::vector<std::pair<SingleThreadIdleTaskRunner::IdleTask, bool>> - tasks_to_post_from_nested_loop; - tasks_to_post_from_nested_loop.push_back(std::make_pair( - base::Bind(&AppendToVectorIdleTestTask, &order, std::string("3")), - false)); - tasks_to_post_from_nested_loop.push_back(std::make_pair( - base::Bind(&AppendToVectorIdleTestTask, &order, std::string("4")), true)); - tasks_to_post_from_nested_loop.push_back(std::make_pair( - base::Bind(&AppendToVectorIdleTestTask, &order, std::string("5")), true)); - - default_task_runner_->PostTask( - FROM_HERE, - base::Bind( - &RendererSchedulerImplWithMessageLoopTest::PostFromNestedRunloop, - base::Unretained(this), - base::Unretained(&tasks_to_post_from_nested_loop))); - - EnableIdleTasks(); - RunUntilIdle(); - // Note we expect task 3 to run last because it's non-nestable. - EXPECT_THAT(order, testing::ElementsAre(std::string("1"), std::string("2"), - std::string("4"), std::string("5"), - std::string("3"))); -} - -TEST_F(RendererSchedulerImplTest, TestLongIdlePeriod) { - base::TimeTicks expected_deadline = - clock_->NowTicks() + maximum_idle_period_duration(); - base::TimeTicks deadline_in_task; - int run_count = 0; - - idle_task_runner_->PostIdleTask( - FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); - - RunUntilIdle(); - EXPECT_EQ(0, run_count); // Shouldn't run yet as no idle period. - - scheduler_->BeginFrameNotExpectedSoon(); - RunUntilIdle(); - EXPECT_EQ(1, run_count); // Should have run in a long idle time. - EXPECT_EQ(expected_deadline, deadline_in_task); -} - -TEST_F(RendererSchedulerImplTest, TestLongIdlePeriodWithPendingDelayedTask) { - base::TimeDelta pending_task_delay = base::TimeDelta::FromMilliseconds(30); - base::TimeTicks expected_deadline = clock_->NowTicks() + pending_task_delay; - base::TimeTicks deadline_in_task; - int run_count = 0; - - idle_task_runner_->PostIdleTask( - FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); - default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask), - pending_task_delay); - - scheduler_->BeginFrameNotExpectedSoon(); - RunUntilIdle(); - EXPECT_EQ(1, run_count); // Should have run in a long idle time. - EXPECT_EQ(expected_deadline, deadline_in_task); -} - -TEST_F(RendererSchedulerImplTest, - TestLongIdlePeriodWithLatePendingDelayedTask) { - base::TimeDelta pending_task_delay = base::TimeDelta::FromMilliseconds(10); - base::TimeTicks deadline_in_task; - int run_count = 0; - - default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask), - pending_task_delay); - - // Advance clock until after delayed task was meant to be run. - clock_->Advance(base::TimeDelta::FromMilliseconds(20)); - - // Post an idle task and BeginFrameNotExpectedSoon to initiate a long idle - // period. Since there is a late pending delayed task this shouldn't actually - // start an idle period. - idle_task_runner_->PostIdleTask( - FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); - scheduler_->BeginFrameNotExpectedSoon(); - RunUntilIdle(); - EXPECT_EQ(0, run_count); - - // After the delayed task has been run we should trigger an idle period. - clock_->Advance(maximum_idle_period_duration()); - RunUntilIdle(); - EXPECT_EQ(1, run_count); -} - -TEST_F(RendererSchedulerImplTest, TestLongIdlePeriodRepeating) { - mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true); - std::vector<base::TimeTicks> actual_deadlines; - int run_count = 0; - - max_idle_task_reposts = 3; - base::TimeTicks clock_before(clock_->NowTicks()); - base::TimeDelta idle_task_runtime(base::TimeDelta::FromMilliseconds(10)); - idle_task_runner_->PostIdleTask( - FROM_HERE, - base::Bind(&RepostingUpdateClockIdleTestTask, - base::RetainedRef(idle_task_runner_), &run_count, clock_.get(), - idle_task_runtime, &actual_deadlines)); - scheduler_->BeginFrameNotExpectedSoon(); - RunUntilIdle(); - EXPECT_EQ(3, run_count); - EXPECT_THAT( - actual_deadlines, - testing::ElementsAre( - clock_before + maximum_idle_period_duration(), - clock_before + idle_task_runtime + maximum_idle_period_duration(), - clock_before + (2 * idle_task_runtime) + - maximum_idle_period_duration())); - - // Check that idle tasks don't run after the idle period ends with a - // new BeginMainFrame. - max_idle_task_reposts = 5; - idle_task_runner_->PostIdleTask( - FROM_HERE, - base::Bind(&RepostingUpdateClockIdleTestTask, - base::RetainedRef(idle_task_runner_), &run_count, clock_.get(), - idle_task_runtime, &actual_deadlines)); - idle_task_runner_->PostIdleTask( - FROM_HERE, base::Bind(&WillBeginFrameIdleTask, - base::Unretained(scheduler_.get()), clock_.get())); - RunUntilIdle(); - EXPECT_EQ(4, run_count); -} - -TEST_F(RendererSchedulerImplTest, TestLongIdlePeriodDoesNotWakeScheduler) { - base::TimeTicks deadline_in_task; - int run_count = 0; - - // Start a long idle period and get the time it should end. - scheduler_->BeginFrameNotExpectedSoon(); - // The scheduler should not run the initiate_next_long_idle_period task if - // there are no idle tasks and no other task woke up the scheduler, thus - // the idle period deadline shouldn't update at the end of the current long - // idle period. - base::TimeTicks idle_period_deadline = - scheduler_->CurrentIdleTaskDeadlineForTesting(); - clock_->Advance(maximum_idle_period_duration()); - RunUntilIdle(); - - base::TimeTicks new_idle_period_deadline = - scheduler_->CurrentIdleTaskDeadlineForTesting(); - EXPECT_EQ(idle_period_deadline, new_idle_period_deadline); - - // Posting a after-wakeup idle task also shouldn't wake the scheduler or - // initiate the next long idle period. - idle_task_runner_->PostIdleTaskAfterWakeup( - FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); - RunUntilIdle(); - new_idle_period_deadline = scheduler_->CurrentIdleTaskDeadlineForTesting(); - EXPECT_EQ(idle_period_deadline, new_idle_period_deadline); - EXPECT_EQ(0, run_count); - - // Running a normal task should initiate a new long idle period though. - default_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask)); - RunUntilIdle(); - new_idle_period_deadline = scheduler_->CurrentIdleTaskDeadlineForTesting(); - EXPECT_EQ(idle_period_deadline + maximum_idle_period_duration(), - new_idle_period_deadline); - - EXPECT_EQ(1, run_count); -} - -TEST_F(RendererSchedulerImplTest, TestLongIdlePeriodInTouchStartPolicy) { - base::TimeTicks deadline_in_task; - int run_count = 0; - - idle_task_runner_->PostIdleTask( - FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); - - // Observation of touchstart should defer the start of the long idle period. - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchStart), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - scheduler_->BeginFrameNotExpectedSoon(); - RunUntilIdle(); - EXPECT_EQ(0, run_count); - - // The long idle period should start after the touchstart policy has finished. - clock_->Advance(priority_escalation_after_input_duration()); - RunUntilIdle(); - EXPECT_EQ(1, run_count); -} - -void TestCanExceedIdleDeadlineIfRequiredTask(RendererScheduler* scheduler, - bool* can_exceed_idle_deadline_out, - int* run_count, - base::TimeTicks deadline) { - *can_exceed_idle_deadline_out = scheduler->CanExceedIdleDeadlineIfRequired(); - (*run_count)++; -} - -TEST_F(RendererSchedulerImplTest, CanExceedIdleDeadlineIfRequired) { - int run_count = 0; - bool can_exceed_idle_deadline = false; - - // Should return false if not in an idle period. - EXPECT_FALSE(scheduler_->CanExceedIdleDeadlineIfRequired()); - - // Should return false for short idle periods. - idle_task_runner_->PostIdleTask( - FROM_HERE, - base::Bind(&TestCanExceedIdleDeadlineIfRequiredTask, scheduler_.get(), - &can_exceed_idle_deadline, &run_count)); - EnableIdleTasks(); - RunUntilIdle(); - EXPECT_EQ(1, run_count); - EXPECT_FALSE(can_exceed_idle_deadline); - - // Should return false for a long idle period which is shortened due to a - // pending delayed task. - default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask), - base::TimeDelta::FromMilliseconds(10)); - idle_task_runner_->PostIdleTask( - FROM_HERE, - base::Bind(&TestCanExceedIdleDeadlineIfRequiredTask, scheduler_.get(), - &can_exceed_idle_deadline, &run_count)); - scheduler_->BeginFrameNotExpectedSoon(); - RunUntilIdle(); - EXPECT_EQ(2, run_count); - EXPECT_FALSE(can_exceed_idle_deadline); - - // Next long idle period will be for the maximum time, so - // CanExceedIdleDeadlineIfRequired should return true. - clock_->Advance(maximum_idle_period_duration()); - idle_task_runner_->PostIdleTask( - FROM_HERE, - base::Bind(&TestCanExceedIdleDeadlineIfRequiredTask, scheduler_.get(), - &can_exceed_idle_deadline, &run_count)); - RunUntilIdle(); - EXPECT_EQ(3, run_count); - EXPECT_TRUE(can_exceed_idle_deadline); - - // Next long idle period will be for the maximum time, so - // CanExceedIdleDeadlineIfRequired should return true. - scheduler_->WillBeginFrame(cc::BeginFrameArgs::Create( - BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), - base::TimeDelta::FromMilliseconds(1000), cc::BeginFrameArgs::NORMAL)); - EXPECT_FALSE(scheduler_->CanExceedIdleDeadlineIfRequired()); -} - -TEST_F(RendererSchedulerImplTest, TestRendererHiddenIdlePeriod) { - int run_count = 0; - - max_idle_task_reposts = 2; - idle_task_runner_->PostIdleTask( - FROM_HERE, base::Bind(&RepostingIdleTestTask, - base::RetainedRef(idle_task_runner_), &run_count)); - - // Renderer should start in visible state. - RunUntilIdle(); - EXPECT_EQ(0, run_count); - - // When we hide the renderer it should start a max deadline idle period, which - // will run an idle task and then immediately start a new idle period, which - // runs the second idle task. - scheduler_->SetAllRenderWidgetsHidden(true); - RunUntilIdle(); - EXPECT_EQ(2, run_count); - - // Advance time by amount of time by the maximum amount of time we execute - // idle tasks when hidden (plus some slack) - idle period should have ended. - max_idle_task_reposts = 3; - idle_task_runner_->PostIdleTask( - FROM_HERE, base::Bind(&RepostingIdleTestTask, - base::RetainedRef(idle_task_runner_), &run_count)); - clock_->Advance(end_idle_when_hidden_delay() + - base::TimeDelta::FromMilliseconds(10)); - RunUntilIdle(); - EXPECT_EQ(2, run_count); -} - -TEST_F(RendererSchedulerImplTest, TimerQueueEnabledByDefault) { - std::vector<std::string> run_order; - PostTestTasks(&run_order, "T1 T2"); - RunUntilIdle(); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("T1"), std::string("T2"))); -} - -TEST_F(RendererSchedulerImplTest, SuspendAndResumeTimerQueue) { - std::vector<std::string> run_order; - PostTestTasks(&run_order, "T1 T2"); - - scheduler_->SuspendTimerQueue(); - RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); - - scheduler_->ResumeTimerQueue(); - RunUntilIdle(); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("T1"), std::string("T2"))); -} - -TEST_F(RendererSchedulerImplTest, SuspendAndThrottleTimerQueue) { - std::vector<std::string> run_order; - PostTestTasks(&run_order, "T1 T2"); - - scheduler_->SuspendTimerQueue(); - RunUntilIdle(); - scheduler_->throttling_helper()->IncreaseThrottleRefCount( - static_cast<TaskQueue*>(timer_task_runner_.get())); - RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); -} - -TEST_F(RendererSchedulerImplTest, ThrottleAndSuspendTimerQueue) { - std::vector<std::string> run_order; - PostTestTasks(&run_order, "T1 T2"); - - scheduler_->throttling_helper()->IncreaseThrottleRefCount( - static_cast<TaskQueue*>(timer_task_runner_.get())); - RunUntilIdle(); - scheduler_->SuspendTimerQueue(); - RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); -} - -TEST_F(RendererSchedulerImplTest, MultipleSuspendsNeedMultipleResumes) { - std::vector<std::string> run_order; - PostTestTasks(&run_order, "T1 T2"); - - scheduler_->SuspendTimerQueue(); - scheduler_->SuspendTimerQueue(); - scheduler_->SuspendTimerQueue(); - RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); - - scheduler_->ResumeTimerQueue(); - RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); - - scheduler_->ResumeTimerQueue(); - RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); - - scheduler_->ResumeTimerQueue(); - RunUntilIdle(); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("T1"), std::string("T2"))); -} - -TEST_F(RendererSchedulerImplTest, SuspendRenderer) { - // Assume that the renderer is backgrounded. - scheduler_->OnRendererBackgrounded(); - - // Tasks in some queues don't fire when the renderer is suspended. - std::vector<std::string> run_order; - PostTestTasks(&run_order, "D1 C1 L1 I1 T1"); - scheduler_->SuspendRenderer(); - EnableIdleTasks(); - RunUntilIdle(); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("D1"), std::string("C1"), - std::string("I1"))); - - // The rest queued tasks fire when the tab goes foregrounded. - run_order.clear(); - scheduler_->OnRendererForegrounded(); - RunUntilIdle(); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("L1"), std::string("T1"))); -} - -TEST_F(RendererSchedulerImplTest, UseCaseToString) { - CheckAllUseCaseToString(); -} - -TEST_F(RendererSchedulerImplTest, MismatchedDidHandleInputEventOnMainThread) { - // This should not DCHECK because there was no corresponding compositor side - // call to DidHandleInputEventOnCompositorThread with - // INPUT_EVENT_ACK_STATE_NOT_CONSUMED. There are legitimate reasons for the - // compositor to not be there and we don't want to make debugging impossible. - scheduler_->DidHandleInputEventOnMainThread( - FakeInputEvent(blink::WebInputEvent::GestureFlingStart)); -} - -TEST_F(RendererSchedulerImplTest, BeginMainFrameOnCriticalPath) { - ASSERT_FALSE(scheduler_->BeginMainFrameOnCriticalPath()); - - cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( - BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), - base::TimeDelta::FromMilliseconds(1000), cc::BeginFrameArgs::NORMAL); - scheduler_->WillBeginFrame(begin_frame_args); - ASSERT_TRUE(scheduler_->BeginMainFrameOnCriticalPath()); - - begin_frame_args.on_critical_path = false; - scheduler_->WillBeginFrame(begin_frame_args); - ASSERT_FALSE(scheduler_->BeginMainFrameOnCriticalPath()); -} - -TEST_F(RendererSchedulerImplTest, ShutdownPreventsPostingOfNewTasks) { - scheduler_->Shutdown(); - std::vector<std::string> run_order; - PostTestTasks(&run_order, "D1 C1"); - RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); -} - -TEST_F(RendererSchedulerImplTest, TestRendererBackgroundedTimerSuspension) { - scheduler_->SetTimerQueueSuspensionWhenBackgroundedEnabled(true); - - std::vector<std::string> run_order; - PostTestTasks(&run_order, "T1 T2"); - - // The background signal will not immediately suspend the timer queue. - scheduler_->OnRendererBackgrounded(); - RunUntilIdle(); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("T1"), std::string("T2"))); - - run_order.clear(); - PostTestTasks(&run_order, "T3"); - RunUntilIdle(); - EXPECT_THAT(run_order, testing::ElementsAre(std::string("T3"))); - - // Advance the time until after the scheduled timer queue suspension. - run_order.clear(); - clock_->Advance(suspend_timers_when_backgrounded_delay() + - base::TimeDelta::FromMilliseconds(10)); - RunUntilIdle(); - ASSERT_TRUE(run_order.empty()); - - // Timer tasks should be suspended until the foregrounded signal. - PostTestTasks(&run_order, "T4 T5"); - RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); - - scheduler_->OnRendererForegrounded(); - RunUntilIdle(); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("T4"), std::string("T5"))); - - // Subsequent timer tasks should fire as usual. - run_order.clear(); - PostTestTasks(&run_order, "T6"); - RunUntilIdle(); - EXPECT_THAT(run_order, testing::ElementsAre(std::string("T6"))); -} - -TEST_F(RendererSchedulerImplTest, - ExpensiveLoadingTasksNotBlockedTillFirstBeginMainFrame) { - std::vector<std::string> run_order; - - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - SimulateExpensiveTasks(loading_task_runner_); - ForceTouchStartToBeExpectedSoon(); - PostTestTasks(&run_order, "L1 D1"); - RunUntilIdle(); - - EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); - EXPECT_FALSE(HaveSeenABeginMainframe()); - EXPECT_TRUE(LoadingTasksSeemExpensive()); - EXPECT_FALSE(TimerTasksSeemExpensive()); - EXPECT_TRUE(TouchStartExpectedSoon()); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("L1"), std::string("D1"))); - - // Emit a BeginMainFrame, and the loading task should get blocked. - DoMainFrame(); - run_order.clear(); - - PostTestTasks(&run_order, "L1 D1"); - RunUntilIdle(); - - EXPECT_EQ(RendererSchedulerImpl::UseCase::NONE, CurrentUseCase()); - EXPECT_TRUE(HaveSeenABeginMainframe()); - EXPECT_TRUE(LoadingTasksSeemExpensive()); - EXPECT_FALSE(TimerTasksSeemExpensive()); - EXPECT_TRUE(TouchStartExpectedSoon()); - EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1"))); - EXPECT_EQ(v8::PERFORMANCE_RESPONSE, RAILMode()); -} - -TEST_F(RendererSchedulerImplTest, - ExpensiveLoadingTasksNotBlockedIfNoTouchHandler) { - std::vector<std::string> run_order; - - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(false); - DoMainFrame(); - SimulateExpensiveTasks(loading_task_runner_); - ForceTouchStartToBeExpectedSoon(); - PostTestTasks(&run_order, "L1 D1"); - RunUntilIdle(); - - EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); - EXPECT_TRUE(HaveSeenABeginMainframe()); - EXPECT_TRUE(LoadingTasksSeemExpensive()); - EXPECT_FALSE(TimerTasksSeemExpensive()); - EXPECT_FALSE(TouchStartExpectedSoon()); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("L1"), std::string("D1"))); - EXPECT_EQ(v8::PERFORMANCE_ANIMATION, RAILMode()); -} - -TEST_F(RendererSchedulerImplTest, - ExpensiveTimerTaskBlocked_UseCase_NONE_PreviousCompositorGesture) { - std::vector<std::string> run_order; - - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - DoMainFrame(); - SimulateExpensiveTasks(timer_task_runner_); - ForceTouchStartToBeExpectedSoon(); - - PostTestTasks(&run_order, "T1 D1"); - RunUntilIdle(); - - EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); - EXPECT_TRUE(HaveSeenABeginMainframe()); - EXPECT_FALSE(LoadingTasksSeemExpensive()); - EXPECT_TRUE(TimerTasksSeemExpensive()); - EXPECT_TRUE(TouchStartExpectedSoon()); - EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1"))); - EXPECT_EQ(v8::PERFORMANCE_RESPONSE, RAILMode()); -} - -TEST_F(RendererSchedulerImplTest, - ExpensiveTimerTaskNotBlocked_UseCase_NONE_PreviousMainThreadGesture) { - std::vector<std::string> run_order; - - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - DoMainFrame(); - SimulateExpensiveTasks(timer_task_runner_); - - SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START, - blink::WebInputEvent::GestureScrollBegin); - EXPECT_EQ(UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, - ForceUpdatePolicyAndGetCurrentUseCase()); - - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchEnd), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - scheduler_->DidHandleInputEventOnMainThread( - FakeInputEvent(blink::WebInputEvent::TouchEnd)); - - clock_->Advance(priority_escalation_after_input_duration() * 2); - EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); - - PostTestTasks(&run_order, "T1 D1"); - RunUntilIdle(); - - EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); - EXPECT_TRUE(HaveSeenABeginMainframe()); - EXPECT_FALSE(LoadingTasksSeemExpensive()); - EXPECT_TRUE(TimerTasksSeemExpensive()); - EXPECT_TRUE(TouchStartExpectedSoon()); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("T1"), std::string("D1"))); - EXPECT_EQ(v8::PERFORMANCE_ANIMATION, RAILMode()); -} - -TEST_F(RendererSchedulerImplTest, - ExpensiveTimerTaskBlocked_UseCase_COMPOSITOR_GESTURE) { - std::vector<std::string> run_order; - - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - DoMainFrame(); - SimulateExpensiveTasks(timer_task_runner_); - ForceTouchStartToBeExpectedSoon(); - scheduler_->DidAnimateForInputOnCompositorThread(); - - PostTestTasks(&run_order, "T1 D1"); - RunUntilIdle(); - - EXPECT_EQ(UseCase::COMPOSITOR_GESTURE, - ForceUpdatePolicyAndGetCurrentUseCase()); - EXPECT_TRUE(HaveSeenABeginMainframe()); - EXPECT_FALSE(LoadingTasksSeemExpensive()); - EXPECT_TRUE(TimerTasksSeemExpensive()); - EXPECT_TRUE(TouchStartExpectedSoon()); - EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1"))); - EXPECT_EQ(v8::PERFORMANCE_RESPONSE, RAILMode()); -} - -TEST_F(RendererSchedulerImplTest, - ExpensiveTimerTaskNotBlockedIfDisallowed_UseCase_COMPOSITOR_GESTURE) { - std::vector<std::string> run_order; - - scheduler_->SetExpensiveTaskBlockingAllowed(false); - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - DoMainFrame(); - SimulateExpensiveTasks(timer_task_runner_); - ForceTouchStartToBeExpectedSoon(); - scheduler_->DidAnimateForInputOnCompositorThread(); - - PostTestTasks(&run_order, "T1 D1"); - RunUntilIdle(); - - EXPECT_EQ(UseCase::COMPOSITOR_GESTURE, - ForceUpdatePolicyAndGetCurrentUseCase()); - EXPECT_TRUE(HaveSeenABeginMainframe()); - EXPECT_FALSE(LoadingTasksSeemExpensive()); - EXPECT_TRUE(TimerTasksSeemExpensive()); - EXPECT_TRUE(TouchStartExpectedSoon()); - EXPECT_THAT(run_order, testing::ElementsAre(std::string("T1"), - std::string("D1"))); - EXPECT_EQ(v8::PERFORMANCE_RESPONSE, RAILMode()); -} - -TEST_F(RendererSchedulerImplTest, - ExpensiveTimerTaskBlocked_EvenIfBeginMainFrameNotExpectedSoon) { - std::vector<std::string> run_order; - - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - DoMainFrame(); - SimulateExpensiveTasks(timer_task_runner_); - ForceTouchStartToBeExpectedSoon(); - scheduler_->BeginFrameNotExpectedSoon(); - - PostTestTasks(&run_order, "T1 D1"); - RunUntilIdle(); - - EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); - EXPECT_TRUE(HaveSeenABeginMainframe()); - EXPECT_FALSE(LoadingTasksSeemExpensive()); - EXPECT_TRUE(TimerTasksSeemExpensive()); - EXPECT_TRUE(TouchStartExpectedSoon()); - EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1"))); - EXPECT_EQ(v8::PERFORMANCE_RESPONSE, RAILMode()); -} - -TEST_F(RendererSchedulerImplTest, - ExpensiveLoadingTasksBlockedIfChildFrameNavigationExpected) { - std::vector<std::string> run_order; - - DoMainFrame(); - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - SimulateExpensiveTasks(loading_task_runner_); - ForceTouchStartToBeExpectedSoon(); - scheduler_->AddPendingNavigation( - blink::WebScheduler::NavigatingFrameType::kChildFrame); - - PostTestTasks(&run_order, "L1 D1"); - RunUntilIdle(); - - // The expensive loading task gets blocked. - EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1"))); - EXPECT_EQ(v8::PERFORMANCE_RESPONSE, RAILMode()); -} - -TEST_F(RendererSchedulerImplTest, - ExpensiveLoadingTasksNotBlockedIfMainFrameNavigationExpected) { - std::vector<std::string> run_order; - - DoMainFrame(); - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - SimulateExpensiveTasks(loading_task_runner_); - ForceTouchStartToBeExpectedSoon(); - scheduler_->AddPendingNavigation( - blink::WebScheduler::NavigatingFrameType::kMainFrame); - - PostTestTasks(&run_order, "L1 D1"); - RunUntilIdle(); - - EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); - EXPECT_TRUE(HaveSeenABeginMainframe()); - EXPECT_TRUE(LoadingTasksSeemExpensive()); - EXPECT_FALSE(TimerTasksSeemExpensive()); - EXPECT_TRUE(TouchStartExpectedSoon()); - EXPECT_EQ(1, NavigationTaskExpectedCount()); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("L1"), std::string("D1"))); - - // After the nagigation has been cancelled, the expensive loading tasks should - // get blocked. - scheduler_->RemovePendingNavigation( - blink::WebScheduler::NavigatingFrameType::kMainFrame); - run_order.clear(); - - PostTestTasks(&run_order, "L1 D1"); - RunUntilIdle(); - - EXPECT_EQ(RendererSchedulerImpl::UseCase::NONE, CurrentUseCase()); - EXPECT_TRUE(HaveSeenABeginMainframe()); - EXPECT_TRUE(LoadingTasksSeemExpensive()); - EXPECT_FALSE(TimerTasksSeemExpensive()); - EXPECT_TRUE(TouchStartExpectedSoon()); - EXPECT_EQ(0, NavigationTaskExpectedCount()); - EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1"))); - EXPECT_EQ(v8::PERFORMANCE_RESPONSE, RAILMode()); -} - -TEST_F( - RendererSchedulerImplTest, - ExpensiveLoadingTasksNotBlockedIfMainFrameNavigationExpected_Multiple) { - std::vector<std::string> run_order; - - DoMainFrame(); - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - SimulateExpensiveTasks(loading_task_runner_); - ForceTouchStartToBeExpectedSoon(); - scheduler_->AddPendingNavigation( - blink::WebScheduler::NavigatingFrameType::kMainFrame); - scheduler_->AddPendingNavigation( - blink::WebScheduler::NavigatingFrameType::kMainFrame); - - PostTestTasks(&run_order, "L1 D1"); - RunUntilIdle(); - - EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); - EXPECT_TRUE(HaveSeenABeginMainframe()); - EXPECT_TRUE(LoadingTasksSeemExpensive()); - EXPECT_FALSE(TimerTasksSeemExpensive()); - EXPECT_TRUE(TouchStartExpectedSoon()); - EXPECT_EQ(2, NavigationTaskExpectedCount()); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("L1"), std::string("D1"))); - - - run_order.clear(); - scheduler_->RemovePendingNavigation( - blink::WebScheduler::NavigatingFrameType::kMainFrame); - // Navigation task expected ref count non-zero so expensive tasks still not - // blocked. - PostTestTasks(&run_order, "L1 D1"); - RunUntilIdle(); - - EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); - EXPECT_TRUE(HaveSeenABeginMainframe()); - EXPECT_TRUE(LoadingTasksSeemExpensive()); - EXPECT_FALSE(TimerTasksSeemExpensive()); - EXPECT_TRUE(TouchStartExpectedSoon()); - EXPECT_EQ(1, NavigationTaskExpectedCount()); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("L1"), std::string("D1"))); - - - run_order.clear(); - scheduler_->RemovePendingNavigation( - blink::WebScheduler::NavigatingFrameType::kMainFrame); - // Navigation task expected ref count is now zero, the expensive loading tasks - // should get blocked. - PostTestTasks(&run_order, "L1 D1"); - RunUntilIdle(); - - EXPECT_EQ(RendererSchedulerImpl::UseCase::NONE, CurrentUseCase()); - EXPECT_TRUE(HaveSeenABeginMainframe()); - EXPECT_TRUE(LoadingTasksSeemExpensive()); - EXPECT_FALSE(TimerTasksSeemExpensive()); - EXPECT_TRUE(TouchStartExpectedSoon()); - EXPECT_EQ(0, NavigationTaskExpectedCount()); - EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1"))); - EXPECT_EQ(v8::PERFORMANCE_RESPONSE, RAILMode()); -} - -TEST_F(RendererSchedulerImplTest, - ExpensiveLoadingTasksNotBlockedDuringMainThreadGestures) { - std::vector<std::string> run_order; - - SimulateExpensiveTasks(loading_task_runner_); - - // Loading tasks should not be disabled during main thread user interactions. - PostTestTasks(&run_order, "C1 L1"); - - // Trigger main_thread_gesture UseCase - SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START, - blink::WebInputEvent::GestureScrollBegin); - RunUntilIdle(); - EXPECT_EQ(RendererSchedulerImpl::UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, - CurrentUseCase()); - - EXPECT_TRUE(LoadingTasksSeemExpensive()); - EXPECT_FALSE(TimerTasksSeemExpensive()); - EXPECT_THAT(run_order, - testing::ElementsAre(std::string("C1"), std::string("L1"))); - EXPECT_EQ(v8::PERFORMANCE_ANIMATION, RAILMode()); -} - -TEST_F(RendererSchedulerImplTest, ModeratelyExpensiveTimer_NotBlocked) { - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START, - blink::WebInputEvent::TouchMove); - RunUntilIdle(); - for (int i = 0; i < 20; i++) { - simulate_timer_task_ran_ = false; - - cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( - BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), - base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); - begin_frame_args.on_critical_path = false; - scheduler_->WillBeginFrame(begin_frame_args); - - compositor_task_runner_->PostTask( - FROM_HERE, base::Bind(&RendererSchedulerImplTest:: - SimulateMainThreadInputHandlingCompositorTask, - base::Unretained(this), - base::TimeDelta::FromMilliseconds(8))); - timer_task_runner_->PostTask( - FROM_HERE, base::Bind(&RendererSchedulerImplTest::SimulateTimerTask, - base::Unretained(this), - base::TimeDelta::FromMilliseconds(4))); - - RunUntilIdle(); - EXPECT_TRUE(simulate_timer_task_ran_) << " i = " << i; - EXPECT_EQ(RendererSchedulerImpl::UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, - CurrentUseCase()) - << " i = " << i; - EXPECT_FALSE(LoadingTasksSeemExpensive()) << " i = " << i; - EXPECT_FALSE(TimerTasksSeemExpensive()) << " i = " << i; - - base::TimeDelta time_till_next_frame = - EstimatedNextFrameBegin() - clock_->NowTicks(); - if (time_till_next_frame > base::TimeDelta()) - clock_->Advance(time_till_next_frame); - } -} - -TEST_F(RendererSchedulerImplTest, - FourtyMsTimer_NotBlocked_CompositorScrolling) { - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - RunUntilIdle(); - for (int i = 0; i < 20; i++) { - simulate_timer_task_ran_ = false; - - cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( - BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), - base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); - begin_frame_args.on_critical_path = false; - scheduler_->WillBeginFrame(begin_frame_args); - scheduler_->DidAnimateForInputOnCompositorThread(); - - compositor_task_runner_->PostTask( - FROM_HERE, - base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask, - base::Unretained(this), - base::TimeDelta::FromMilliseconds(8))); - timer_task_runner_->PostTask( - FROM_HERE, base::Bind(&RendererSchedulerImplTest::SimulateTimerTask, - base::Unretained(this), - base::TimeDelta::FromMilliseconds(40))); - - RunUntilIdle(); - EXPECT_TRUE(simulate_timer_task_ran_) << " i = " << i; - EXPECT_EQ(RendererSchedulerImpl::UseCase::COMPOSITOR_GESTURE, - CurrentUseCase()) - << " i = " << i; - EXPECT_FALSE(LoadingTasksSeemExpensive()) << " i = " << i; - EXPECT_FALSE(TimerTasksSeemExpensive()) << " i = " << i; - - base::TimeDelta time_till_next_frame = - EstimatedNextFrameBegin() - clock_->NowTicks(); - if (time_till_next_frame > base::TimeDelta()) - clock_->Advance(time_till_next_frame); - } -} - -TEST_F(RendererSchedulerImplTest, - ExpensiveTimer_NotBlocked_UseCase_MAIN_THREAD_CUSTOM_INPUT_HANDLING) { - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START, - blink::WebInputEvent::TouchMove); - RunUntilIdle(); - for (int i = 0; i < 20; i++) { - simulate_timer_task_ran_ = false; - - cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( - BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), - base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); - begin_frame_args.on_critical_path = false; - scheduler_->WillBeginFrame(begin_frame_args); - - compositor_task_runner_->PostTask( - FROM_HERE, base::Bind(&RendererSchedulerImplTest:: - SimulateMainThreadInputHandlingCompositorTask, - base::Unretained(this), - base::TimeDelta::FromMilliseconds(8))); - timer_task_runner_->PostTask( - FROM_HERE, base::Bind(&RendererSchedulerImplTest::SimulateTimerTask, - base::Unretained(this), - base::TimeDelta::FromMilliseconds(10))); - - RunUntilIdle(); - EXPECT_EQ(RendererSchedulerImpl::UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, - CurrentUseCase()) - << " i = " << i; - EXPECT_FALSE(LoadingTasksSeemExpensive()) << " i = " << i; - if (i == 0) { - EXPECT_FALSE(TimerTasksSeemExpensive()) << " i = " << i; - } else { - EXPECT_TRUE(TimerTasksSeemExpensive()) << " i = " << i; - } - EXPECT_TRUE(simulate_timer_task_ran_) << " i = " << i; - - base::TimeDelta time_till_next_frame = - EstimatedNextFrameBegin() - clock_->NowTicks(); - if (time_till_next_frame > base::TimeDelta()) - clock_->Advance(time_till_next_frame); - } -} - -TEST_F(RendererSchedulerImplTest, - EstimateLongestJankFreeTaskDuration_UseCase_NONE) { - EXPECT_EQ(UseCase::NONE, CurrentUseCase()); - EXPECT_EQ(rails_response_time(), - scheduler_->EstimateLongestJankFreeTaskDuration()); -} - -TEST_F(RendererSchedulerImplTest, - EstimateLongestJankFreeTaskDuration_UseCase_COMPOSITOR_GESTURE) { - SimulateCompositorGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START); - EXPECT_EQ(UseCase::COMPOSITOR_GESTURE, - ForceUpdatePolicyAndGetCurrentUseCase()); - EXPECT_EQ(rails_response_time(), - scheduler_->EstimateLongestJankFreeTaskDuration()); -} - -// TODO(alexclarke): Reenable once we've reinstaed the Loading UseCase. -TEST_F(RendererSchedulerImplTest, - DISABLED_EstimateLongestJankFreeTaskDuration_UseCase_) { - scheduler_->OnNavigationStarted(); - EXPECT_EQ(UseCase::LOADING, ForceUpdatePolicyAndGetCurrentUseCase()); - EXPECT_EQ(rails_response_time(), - scheduler_->EstimateLongestJankFreeTaskDuration()); -} - -TEST_F(RendererSchedulerImplTest, - EstimateLongestJankFreeTaskDuration_UseCase_MAIN_THREAD_GESTURE) { - SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START, - blink::WebInputEvent::GestureScrollUpdate); - cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( - BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), - base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); - begin_frame_args.on_critical_path = false; - scheduler_->WillBeginFrame(begin_frame_args); - - compositor_task_runner_->PostTask( - FROM_HERE, - base::Bind(&RendererSchedulerImplTest:: - SimulateMainThreadInputHandlingCompositorTask, - base::Unretained(this), base::TimeDelta::FromMilliseconds(5))); - - RunUntilIdle(); - EXPECT_EQ(UseCase::MAIN_THREAD_GESTURE, CurrentUseCase()); - - // 16ms frame - 5ms compositor work = 11ms for other stuff. - EXPECT_EQ(base::TimeDelta::FromMilliseconds(11), - scheduler_->EstimateLongestJankFreeTaskDuration()); -} - -TEST_F( - RendererSchedulerImplTest, - EstimateLongestJankFreeTaskDuration_UseCase_MAIN_THREAD_CUSTOM_INPUT_HANDLING) { - cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( - BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), - base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); - begin_frame_args.on_critical_path = false; - scheduler_->WillBeginFrame(begin_frame_args); - - compositor_task_runner_->PostTask( - FROM_HERE, - base::Bind(&RendererSchedulerImplTest:: - SimulateMainThreadInputHandlingCompositorTask, - base::Unretained(this), base::TimeDelta::FromMilliseconds(5))); - - RunUntilIdle(); - EXPECT_EQ(UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, CurrentUseCase()); - - // 16ms frame - 5ms compositor work = 11ms for other stuff. - EXPECT_EQ(base::TimeDelta::FromMilliseconds(11), - scheduler_->EstimateLongestJankFreeTaskDuration()); -} - -TEST_F(RendererSchedulerImplTest, - EstimateLongestJankFreeTaskDuration_UseCase_SYNCHRONIZED_GESTURE) { - SimulateCompositorGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START); - - cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( - BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), - base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); - begin_frame_args.on_critical_path = true; - scheduler_->WillBeginFrame(begin_frame_args); - - compositor_task_runner_->PostTask( - FROM_HERE, - base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask, - base::Unretained(this), base::TimeDelta::FromMilliseconds(5))); - - RunUntilIdle(); - EXPECT_EQ(UseCase::SYNCHRONIZED_GESTURE, CurrentUseCase()); - - // 16ms frame - 5ms compositor work = 11ms for other stuff. - EXPECT_EQ(base::TimeDelta::FromMilliseconds(11), - scheduler_->EstimateLongestJankFreeTaskDuration()); -} - -class WebViewSchedulerImplForTest : public WebViewSchedulerImpl { - public: - WebViewSchedulerImplForTest(RendererSchedulerImpl* scheduler) - : WebViewSchedulerImpl(nullptr, scheduler, false) {} - ~WebViewSchedulerImplForTest() override {} - - void AddConsoleWarning(const std::string& message) override { - console_warnings_.push_back(message); - } - - const std::vector<std::string>& console_warnings() const { - return console_warnings_; - } - - private: - std::vector<std::string> console_warnings_; - - DISALLOW_COPY_AND_ASSIGN(WebViewSchedulerImplForTest); -}; - -TEST_F(RendererSchedulerImplTest, BlockedTimerNotification) { - // Make sure we see one (and just one) console warning about an expensive - // timer being deferred. - WebViewSchedulerImplForTest web_view_scheduler(scheduler_.get()); - - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - scheduler_->SetExpensiveTaskBlockingAllowed(true); - DoMainFrame(); - SimulateExpensiveTasks(timer_task_runner_); - SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START); - ForceTouchStartToBeExpectedSoon(); - - std::vector<std::string> run_order; - PostTestTasks(&run_order, "T1 T2"); - RunUntilIdle(); - - EXPECT_EQ(0u, run_order.size()); - EXPECT_EQ(1u, web_view_scheduler.console_warnings().size()); - EXPECT_NE(std::string::npos, - web_view_scheduler.console_warnings()[0].find("crbug.com/574343")); -} - -TEST_F(RendererSchedulerImplTest, - BlockedTimerNotification_ExpensiveTaskBlockingNotAllowed) { - // Make sure we don't report warnings about blocked tasks when expensive task - // blocking is not allowed. - WebViewSchedulerImplForTest web_view_scheduler(scheduler_.get()); - - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - scheduler_->SetExpensiveTaskBlockingAllowed(false); - scheduler_->SuspendTimerQueue(); - DoMainFrame(); - SimulateExpensiveTasks(timer_task_runner_); - SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START); - ForceTouchStartToBeExpectedSoon(); - - std::vector<std::string> run_order; - PostTestTasks(&run_order, "T1 T2"); - RunUntilIdle(); - - EXPECT_EQ(0u, run_order.size()); - EXPECT_EQ(0u, web_view_scheduler.console_warnings().size()); -} - -TEST_F(RendererSchedulerImplTest, BlockedTimerNotification_TimersSuspended) { - // Make sure we don't report warnings about blocked tasks when timers are - // being blocked for other reasons. - WebViewSchedulerImplForTest web_view_scheduler(scheduler_.get()); - - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - scheduler_->SetExpensiveTaskBlockingAllowed(true); - scheduler_->SuspendTimerQueue(); - DoMainFrame(); - SimulateExpensiveTasks(timer_task_runner_); - SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START); - ForceTouchStartToBeExpectedSoon(); - - std::vector<std::string> run_order; - PostTestTasks(&run_order, "T1 T2"); - RunUntilIdle(); - - EXPECT_EQ(0u, run_order.size()); - EXPECT_EQ(0u, web_view_scheduler.console_warnings().size()); -} - -TEST_F(RendererSchedulerImplTest, BlockedTimerNotification_TOUCHSTART) { - // Make sure we don't report warnings about blocked tasks during TOUCHSTART. - WebViewSchedulerImplForTest web_view_scheduler(scheduler_.get()); - - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - DoMainFrame(); - SimulateExpensiveTasks(timer_task_runner_); - SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchStart), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - EXPECT_EQ(UseCase::TOUCHSTART, ForceUpdatePolicyAndGetCurrentUseCase()); - - std::vector<std::string> run_order; - PostTestTasks(&run_order, "T1 T2"); - RunUntilIdle(); - - EXPECT_EQ(0u, run_order.size()); - EXPECT_EQ(0u, web_view_scheduler.console_warnings().size()); -} - -TEST_F(RendererSchedulerImplTest, - BlockedTimerNotification_SYNCHRONIZED_GESTURE) { - // Make sure we only report warnings during a high blocking threshold. - WebViewSchedulerImplForTest web_view_scheduler(scheduler_.get()); - - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - DoMainFrame(); - SimulateExpensiveTasks(timer_task_runner_); - SimulateCompositorGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START); - - cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( - BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), - base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); - begin_frame_args.on_critical_path = true; - scheduler_->WillBeginFrame(begin_frame_args); - - EXPECT_EQ(UseCase::SYNCHRONIZED_GESTURE, - ForceUpdatePolicyAndGetCurrentUseCase()); - - std::vector<std::string> run_order; - PostTestTasks(&run_order, "T1 T2"); - RunUntilIdle(); - - EXPECT_EQ(0u, run_order.size()); - EXPECT_EQ(0u, web_view_scheduler.console_warnings().size()); -} - -namespace { -void SlowCountingTask(size_t* count, - base::SimpleTestTickClock* clock, - int task_duration, - scoped_refptr<base::SingleThreadTaskRunner> timer_queue) { - clock->Advance(base::TimeDelta::FromMilliseconds(task_duration)); - if (++(*count) < 500) { - timer_queue->PostTask(FROM_HERE, base::Bind(SlowCountingTask, count, clock, - task_duration, timer_queue)); - } -} -} - -TEST_F(RendererSchedulerImplTest, - SYNCHRONIZED_GESTURE_TimerTaskThrottling_task_expensive) { - SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START); - - base::TimeTicks first_throttled_run_time = - ThrottlingHelper::ThrottledRunTime(clock_->NowTicks()); - - size_t count = 0; - // With the compositor task taking 10ms, there is not enough time to run this - // 7ms timer task in the 16ms frame. - scheduler_->TimerTaskRunner()->PostTask( - FROM_HERE, base::Bind(SlowCountingTask, &count, clock_.get(), 7, - scheduler_->TimerTaskRunner())); - - for (int i = 0; i < 1000; i++) { - cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( - BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), - base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); - begin_frame_args.on_critical_path = true; - scheduler_->WillBeginFrame(begin_frame_args); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - - simulate_compositor_task_ran_ = false; - compositor_task_runner_->PostTask( - FROM_HERE, - base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask, - base::Unretained(this), - base::TimeDelta::FromMilliseconds(10))); - - mock_task_runner_->RunTasksWhile( - base::Bind(&RendererSchedulerImplTest::SimulatedCompositorTaskPending, - base::Unretained(this))); - EXPECT_EQ(UseCase::SYNCHRONIZED_GESTURE, CurrentUseCase()) << "i = " << i; - - // Before the policy is updated the queue will be enabled. Subsequently it - // will be disabled until the throttled queue is pumped. - bool expect_queue_enabled = - (i == 0) || (clock_->NowTicks() > first_throttled_run_time); - EXPECT_EQ(expect_queue_enabled, - scheduler_->TimerTaskRunner()->IsQueueEnabled()) - << "i = " << i; - } - - // Task is throttled but not completely blocked. - EXPECT_EQ(12u, count); -} - -TEST_F(RendererSchedulerImplTest, - SYNCHRONIZED_GESTURE_TimerTaskThrottling_TimersSuspended) { - SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START); - - base::TimeTicks first_throttled_run_time = - ThrottlingHelper::ThrottledRunTime(clock_->NowTicks()); - - size_t count = 0; - // With the compositor task taking 10ms, there is not enough time to run this - // 7ms timer task in the 16ms frame. - scheduler_->TimerTaskRunner()->PostTask( - FROM_HERE, base::Bind(SlowCountingTask, &count, clock_.get(), 7, - scheduler_->TimerTaskRunner())); - - bool suspended = false; - for (int i = 0; i < 1000; i++) { - cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( - BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), - base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); - begin_frame_args.on_critical_path = true; - scheduler_->WillBeginFrame(begin_frame_args); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - - simulate_compositor_task_ran_ = false; - compositor_task_runner_->PostTask( - FROM_HERE, - base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask, - base::Unretained(this), - base::TimeDelta::FromMilliseconds(10))); - - mock_task_runner_->RunTasksWhile( - base::Bind(&RendererSchedulerImplTest::SimulatedCompositorTaskPending, - base::Unretained(this))); - EXPECT_EQ(UseCase::SYNCHRONIZED_GESTURE, CurrentUseCase()) << "i = " << i; - - // Before the policy is updated the queue will be enabled. Subsequently it - // will be disabled until the throttled queue is pumped. - bool expect_queue_enabled = - (i == 0) || (clock_->NowTicks() > first_throttled_run_time); - if (suspended) - expect_queue_enabled = false; - EXPECT_EQ(expect_queue_enabled, - scheduler_->TimerTaskRunner()->IsQueueEnabled()) - << "i = " << i; - - // After we've run any expensive tasks suspend the queue. The throttling - // helper should /not/ re-enable this queue under any circumstances while - // timers are suspended. - if (count > 0 && !suspended) { - EXPECT_EQ(2u, count); - scheduler_->SuspendTimerQueue(); - suspended = true; - } - } - - // Make sure the timer queue stayed suspended! - EXPECT_EQ(2u, count); -} - -TEST_F(RendererSchedulerImplTest, - SYNCHRONIZED_GESTURE_TimerTaskThrottling_task_not_expensive) { - SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START); - - size_t count = 0; - // With the compositor task taking 10ms, there is enough time to run this 6ms - // timer task in the 16ms frame. - scheduler_->TimerTaskRunner()->PostTask( - FROM_HERE, base::Bind(SlowCountingTask, &count, clock_.get(), 6, - scheduler_->TimerTaskRunner())); - - for (int i = 0; i < 1000; i++) { - cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( - BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), - base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); - begin_frame_args.on_critical_path = true; - scheduler_->WillBeginFrame(begin_frame_args); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - - simulate_compositor_task_ran_ = false; - compositor_task_runner_->PostTask( - FROM_HERE, - base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask, - base::Unretained(this), - base::TimeDelta::FromMilliseconds(10))); - - mock_task_runner_->RunTasksWhile( - base::Bind(&RendererSchedulerImplTest::SimulatedCompositorTaskPending, - base::Unretained(this))); - EXPECT_EQ(UseCase::SYNCHRONIZED_GESTURE, CurrentUseCase()) << "i = " << i; - EXPECT_TRUE(scheduler_->TimerTaskRunner()->IsQueueEnabled()) << "i = " << i; - } - - // Task is not throttled. - EXPECT_EQ(500u, count); -} - -TEST_F(RendererSchedulerImplTest, - ExpensiveTimerTaskBlocked_SYNCHRONIZED_GESTURE_TouchStartExpected) { - SimulateExpensiveTasks(timer_task_runner_); - SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START); - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - ForceTouchStartToBeExpectedSoon(); - - // Bump us into SYNCHRONIZED_GESTURE. - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - - cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( - BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), - base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); - begin_frame_args.on_critical_path = true; - scheduler_->WillBeginFrame(begin_frame_args); - - EXPECT_EQ(UseCase::SYNCHRONIZED_GESTURE, - ForceUpdatePolicyAndGetCurrentUseCase()); - - EXPECT_TRUE(TimerTasksSeemExpensive()); - EXPECT_TRUE(TouchStartExpectedSoon()); - EXPECT_FALSE(scheduler_->TimerTaskRunner()->IsQueueEnabled()); -} - -TEST_F(RendererSchedulerImplTest, DenyLongIdleDuringTouchStart) { - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchStart), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - EXPECT_EQ(UseCase::TOUCHSTART, ForceUpdatePolicyAndGetCurrentUseCase()); - - // First check that long idle is denied during the TOUCHSTART use case. - IdleHelper::Delegate* idle_delegate = scheduler_.get(); - base::TimeTicks now; - base::TimeDelta next_time_to_check; - EXPECT_FALSE(idle_delegate->CanEnterLongIdlePeriod(now, &next_time_to_check)); - EXPECT_GE(next_time_to_check, base::TimeDelta()); - - // Check again at a time past the TOUCHSTART expiration. We should still get a - // non-negative delay to when to check again. - now += base::TimeDelta::FromMilliseconds(500); - EXPECT_FALSE(idle_delegate->CanEnterLongIdlePeriod(now, &next_time_to_check)); - EXPECT_GE(next_time_to_check, base::TimeDelta()); -} - -TEST_F(RendererSchedulerImplTest, TestCompositorPolicy_TouchStartDuringFling) { - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - scheduler_->DidAnimateForInputOnCompositorThread(); - // Note DidAnimateForInputOnCompositorThread does not by itself trigger a - // policy update. - EXPECT_EQ(RendererSchedulerImpl::UseCase::COMPOSITOR_GESTURE, - ForceUpdatePolicyAndGetCurrentUseCase()); - - // Make sure TouchStart causes a policy change. - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchStart), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - EXPECT_EQ(RendererSchedulerImpl::UseCase::TOUCHSTART, - ForceUpdatePolicyAndGetCurrentUseCase()); -} - -TEST_F(RendererSchedulerImplTest, SYNCHRONIZED_GESTURE_CompositingExpensive) { - SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START); - - // With the compositor task taking 20ms, there is not enough time to run - // other tasks in the same 16ms frame. To avoid starvation, compositing tasks - // should therefore not get prioritized. - std::vector<std::string> run_order; - for (int i = 0; i < 1000; i++) - PostTestTasks(&run_order, "T1"); - - for (int i = 0; i < 100; i++) { - cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( - BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), - base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); - begin_frame_args.on_critical_path = true; - scheduler_->WillBeginFrame(begin_frame_args); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - - simulate_compositor_task_ran_ = false; - compositor_task_runner_->PostTask( - FROM_HERE, - base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask, - base::Unretained(this), - base::TimeDelta::FromMilliseconds(20))); - - mock_task_runner_->RunTasksWhile( - base::Bind(&RendererSchedulerImplTest::SimulatedCompositorTaskPending, - base::Unretained(this))); - EXPECT_EQ(UseCase::SYNCHRONIZED_GESTURE, CurrentUseCase()) << "i = " << i; - } - - // Timer tasks should not have been starved by the expensive compositor - // tasks. - EXPECT_EQ(TaskQueue::NORMAL_PRIORITY, - scheduler_->CompositorTaskRunner()->GetQueuePriority()); - EXPECT_EQ(1000u, run_order.size()); -} - -TEST_F(RendererSchedulerImplTest, MAIN_THREAD_CUSTOM_INPUT_HANDLING) { - SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START, - blink::WebInputEvent::GestureScrollBegin); - - // With the compositor task taking 20ms, there is not enough time to run - // other tasks in the same 16ms frame. To avoid starvation, compositing tasks - // should therefore not get prioritized. - std::vector<std::string> run_order; - for (int i = 0; i < 1000; i++) - PostTestTasks(&run_order, "T1"); - - for (int i = 0; i < 100; i++) { - cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( - BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), - base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); - begin_frame_args.on_critical_path = true; - scheduler_->WillBeginFrame(begin_frame_args); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchMove), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - - simulate_compositor_task_ran_ = false; - compositor_task_runner_->PostTask( - FROM_HERE, - base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask, - base::Unretained(this), - base::TimeDelta::FromMilliseconds(20))); - - mock_task_runner_->RunTasksWhile( - base::Bind(&RendererSchedulerImplTest::SimulatedCompositorTaskPending, - base::Unretained(this))); - EXPECT_EQ(UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, CurrentUseCase()) - << "i = " << i; - } - - // Timer tasks should not have been starved by the expensive compositor - // tasks. - EXPECT_EQ(TaskQueue::NORMAL_PRIORITY, - scheduler_->CompositorTaskRunner()->GetQueuePriority()); - EXPECT_EQ(1000u, run_order.size()); -} - -TEST_F(RendererSchedulerImplTest, MAIN_THREAD_GESTURE) { - SimulateMainThreadGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START, - blink::WebInputEvent::GestureScrollBegin); - - // With the compositor task taking 20ms, there is not enough time to run - // other tasks in the same 16ms frame. However because this is a main thread - // gesture instead of custom main thread input handling, we allow the timer - // tasks to be starved. - std::vector<std::string> run_order; - for (int i = 0; i < 1000; i++) - PostTestTasks(&run_order, "T1"); - - for (int i = 0; i < 100; i++) { - cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( - BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), - base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); - begin_frame_args.on_critical_path = true; - scheduler_->WillBeginFrame(begin_frame_args); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - - simulate_compositor_task_ran_ = false; - compositor_task_runner_->PostTask( - FROM_HERE, - base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask, - base::Unretained(this), - base::TimeDelta::FromMilliseconds(20))); - - mock_task_runner_->RunTasksWhile( - base::Bind(&RendererSchedulerImplTest::SimulatedCompositorTaskPending, - base::Unretained(this))); - EXPECT_EQ(UseCase::MAIN_THREAD_GESTURE, CurrentUseCase()) << "i = " << i; - } - - EXPECT_EQ(TaskQueue::HIGH_PRIORITY, - scheduler_->CompositorTaskRunner()->GetQueuePriority()); - EXPECT_EQ(279u, run_order.size()); -} - -class MockRAILModeObserver : public RendererScheduler::RAILModeObserver { - public: - MOCK_METHOD1(OnRAILModeChanged, void(v8::RAILMode rail_mode)); -}; - -TEST_F(RendererSchedulerImplTest, TestResponseRAILMode) { - MockRAILModeObserver observer; - scheduler_->SetRAILModeObserver(&observer); - EXPECT_CALL(observer, OnRAILModeChanged(v8::PERFORMANCE_RESPONSE)); - - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - ForceTouchStartToBeExpectedSoon(); - EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); - EXPECT_EQ(v8::PERFORMANCE_RESPONSE, RAILMode()); - scheduler_->SetRAILModeObserver(nullptr); -} - -TEST_F(RendererSchedulerImplTest, TestAnimateRAILMode) { - MockRAILModeObserver observer; - scheduler_->SetRAILModeObserver(&observer); - EXPECT_CALL(observer, OnRAILModeChanged(v8::PERFORMANCE_ANIMATION)).Times(0); - - EXPECT_FALSE(BeginFrameNotExpectedSoon()); - EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); - EXPECT_EQ(v8::PERFORMANCE_ANIMATION, RAILMode()); - scheduler_->SetRAILModeObserver(nullptr); -} - -TEST_F(RendererSchedulerImplTest, TestIdleRAILMode) { - MockRAILModeObserver observer; - scheduler_->SetRAILModeObserver(&observer); - EXPECT_CALL(observer, OnRAILModeChanged(v8::PERFORMANCE_ANIMATION)); - EXPECT_CALL(observer, OnRAILModeChanged(v8::PERFORMANCE_IDLE)); - - scheduler_->SetAllRenderWidgetsHidden(true); - EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); - EXPECT_EQ(v8::PERFORMANCE_IDLE, RAILMode()); - scheduler_->SetAllRenderWidgetsHidden(false); - EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); - EXPECT_EQ(v8::PERFORMANCE_ANIMATION, RAILMode()); - scheduler_->SetRAILModeObserver(nullptr); -} - -TEST_F(RendererSchedulerImplTest, UnthrottledTaskRunner) { - // Ensure neither suspension nor timer task throttling affects an unthrottled - // task runner. - SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START); - scoped_refptr<TaskQueue> unthrottled_task_runner = - scheduler_->NewUnthrottledTaskRunner("unthrottled_tq"); - - size_t timer_count = 0; - size_t unthrottled_count = 0; - scheduler_->TimerTaskRunner()->PostTask( - FROM_HERE, base::Bind(SlowCountingTask, &timer_count, clock_.get(), 7, - scheduler_->TimerTaskRunner())); - unthrottled_task_runner->PostTask( - FROM_HERE, base::Bind(SlowCountingTask, &unthrottled_count, clock_.get(), - 7, unthrottled_task_runner)); - scheduler_->SuspendTimerQueue(); - - for (int i = 0; i < 1000; i++) { - cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( - BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), - base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); - begin_frame_args.on_critical_path = true; - scheduler_->WillBeginFrame(begin_frame_args); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - - simulate_compositor_task_ran_ = false; - compositor_task_runner_->PostTask( - FROM_HERE, - base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask, - base::Unretained(this), - base::TimeDelta::FromMilliseconds(10))); - - mock_task_runner_->RunTasksWhile( - base::Bind(&RendererSchedulerImplTest::SimulatedCompositorTaskPending, - base::Unretained(this))); - EXPECT_EQ(UseCase::SYNCHRONIZED_GESTURE, CurrentUseCase()) << "i = " << i; - } - - EXPECT_EQ(0u, timer_count); - EXPECT_EQ(500u, unthrottled_count); -} - -TEST_F(RendererSchedulerImplTest, EnableVirtualTime) { - scheduler_->EnableVirtualTime(); - - scoped_refptr<TaskQueue> loading_tq = - scheduler_->NewLoadingTaskRunner("test"); - scoped_refptr<TaskQueue> timer_tq = scheduler_->NewTimerTaskRunner("test"); - scoped_refptr<TaskQueue> unthrottled_tq = - scheduler_->NewUnthrottledTaskRunner("test"); - - EXPECT_EQ(scheduler_->DefaultTaskRunner()->GetTimeDomain(), - scheduler_->GetVirtualTimeDomain()); - EXPECT_EQ(scheduler_->CompositorTaskRunner()->GetTimeDomain(), - scheduler_->GetVirtualTimeDomain()); - EXPECT_EQ(scheduler_->LoadingTaskRunner()->GetTimeDomain(), - scheduler_->GetVirtualTimeDomain()); - EXPECT_EQ(scheduler_->TimerTaskRunner()->GetTimeDomain(), - scheduler_->GetVirtualTimeDomain()); - - EXPECT_EQ(loading_tq->GetTimeDomain(), scheduler_->GetVirtualTimeDomain()); - EXPECT_EQ(timer_tq->GetTimeDomain(), scheduler_->GetVirtualTimeDomain()); - EXPECT_EQ(unthrottled_tq->GetTimeDomain(), - scheduler_->GetVirtualTimeDomain()); - - EXPECT_EQ(scheduler_->NewLoadingTaskRunner("test")->GetTimeDomain(), - scheduler_->GetVirtualTimeDomain()); - EXPECT_EQ(scheduler_->NewTimerTaskRunner("test")->GetTimeDomain(), - scheduler_->GetVirtualTimeDomain()); - EXPECT_EQ(scheduler_->NewUnthrottledTaskRunner("test")->GetTimeDomain(), - scheduler_->GetVirtualTimeDomain()); -} - -} // namespace scheduler
diff --git a/components/scheduler/renderer/renderer_web_scheduler_impl.cc b/components/scheduler/renderer/renderer_web_scheduler_impl.cc deleted file mode 100644 index e53e01d..0000000 --- a/components/scheduler/renderer/renderer_web_scheduler_impl.cc +++ /dev/null
@@ -1,49 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/renderer/renderer_web_scheduler_impl.h" - -#include <memory> - -#include "base/command_line.h" -#include "base/memory/ptr_util.h" -#include "components/scheduler/base/task_queue.h" -#include "components/scheduler/common/scheduler_switches.h" -#include "components/scheduler/renderer/renderer_scheduler_impl.h" -#include "components/scheduler/renderer/web_view_scheduler_impl.h" - -namespace scheduler { - -RendererWebSchedulerImpl::RendererWebSchedulerImpl( - RendererSchedulerImpl* renderer_scheduler) - : WebSchedulerImpl(renderer_scheduler, - renderer_scheduler->IdleTaskRunner(), - renderer_scheduler->LoadingTaskRunner(), - renderer_scheduler->TimerTaskRunner()), - renderer_scheduler_(renderer_scheduler) {} - -RendererWebSchedulerImpl::~RendererWebSchedulerImpl() { -} - -void RendererWebSchedulerImpl::suspendTimerQueue() { - renderer_scheduler_->SuspendTimerQueue(); -} - -void RendererWebSchedulerImpl::resumeTimerQueue() { - renderer_scheduler_->ResumeTimerQueue(); -} - -std::unique_ptr<blink::WebViewScheduler> -RendererWebSchedulerImpl::createWebViewScheduler(blink::WebView* web_view) { - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - return base::WrapUnique(new WebViewSchedulerImpl( - web_view, renderer_scheduler_, - command_line->HasSwitch(switches::kDisableBackgroundTimerThrottling))); -} - -void RendererWebSchedulerImpl::onNavigationStarted() { - renderer_scheduler_->OnNavigationStarted(); -} - -} // namespace scheduler
diff --git a/components/scheduler/renderer/renderer_web_scheduler_impl.h b/components/scheduler/renderer/renderer_web_scheduler_impl.h deleted file mode 100644 index 9cb4cbd..0000000 --- a/components/scheduler/renderer/renderer_web_scheduler_impl.h +++ /dev/null
@@ -1,33 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_RENDERER_RENDERER_WEB_SCHEDULER_IMPL_H_ -#define COMPONENTS_SCHEDULER_RENDERER_RENDERER_WEB_SCHEDULER_IMPL_H_ - -#include "components/scheduler/child/web_scheduler_impl.h" - -namespace scheduler { - -class RendererSchedulerImpl; - -class SCHEDULER_EXPORT RendererWebSchedulerImpl : public WebSchedulerImpl { - public: - explicit RendererWebSchedulerImpl(RendererSchedulerImpl* renderer_scheduler); - - ~RendererWebSchedulerImpl() override; - - // blink::WebScheduler implementation: - void suspendTimerQueue() override; - void resumeTimerQueue() override; - std::unique_ptr<blink::WebViewScheduler> createWebViewScheduler( - blink::WebView* web_view) override; - void onNavigationStarted() override; - - private: - RendererSchedulerImpl* renderer_scheduler_; // NOT OWNED -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_RENDERER_RENDERER_WEB_SCHEDULER_IMPL_H_
diff --git a/components/scheduler/renderer/task_cost_estimator.cc b/components/scheduler/renderer/task_cost_estimator.cc deleted file mode 100644 index ce8dee9..0000000 --- a/components/scheduler/renderer/task_cost_estimator.cc +++ /dev/null
@@ -1,43 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/renderer/task_cost_estimator.h" - -#include "base/time/default_tick_clock.h" - -namespace scheduler { - -TaskCostEstimator::TaskCostEstimator(base::TickClock* time_source, - int sample_count, - double estimation_percentile) - : rolling_time_delta_history_(sample_count), - time_source_(time_source), - outstanding_task_count_(0), - estimation_percentile_(estimation_percentile) {} - -TaskCostEstimator::~TaskCostEstimator() {} - -void TaskCostEstimator::WillProcessTask(const base::PendingTask& pending_task) { - // Avoid measuring the duration in nested run loops. - if (++outstanding_task_count_ == 1) - task_start_time_ = time_source_->NowTicks(); -} - -void TaskCostEstimator::DidProcessTask(const base::PendingTask& pending_task) { - if (--outstanding_task_count_ == 0) { - base::TimeDelta duration = time_source_->NowTicks() - task_start_time_; - rolling_time_delta_history_.InsertSample(duration); - } -} - -base::TimeDelta TaskCostEstimator::expected_task_duration() const { - return rolling_time_delta_history_.Percentile(estimation_percentile_); -} - -void TaskCostEstimator::Clear() { - rolling_time_delta_history_.Clear(); - expected_task_duration_ = base::TimeDelta(); -} - -} // namespace scheduler
diff --git a/components/scheduler/renderer/task_cost_estimator.h b/components/scheduler/renderer/task_cost_estimator.h deleted file mode 100644 index c4e43c4..0000000 --- a/components/scheduler/renderer/task_cost_estimator.h +++ /dev/null
@@ -1,50 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_RENDERER_TASK_COST_ESTIMATOR_H_ -#define COMPONENTS_SCHEDULER_RENDERER_TASK_COST_ESTIMATOR_H_ - -#include "base/macros.h" -#include "base/message_loop/message_loop.h" -#include "base/time/time.h" -#include "cc/base/rolling_time_delta_history.h" -#include "components/scheduler/scheduler_export.h" - -namespace base { -class TickClock; -} - -namespace scheduler { - -// Estimates the cost of running tasks based on historical timing data. -class SCHEDULER_EXPORT TaskCostEstimator - : public base::MessageLoop::TaskObserver { - public: - TaskCostEstimator(base::TickClock* time_source, - int sample_count, - double estimation_percentile); - ~TaskCostEstimator() override; - - base::TimeDelta expected_task_duration() const; - - // TaskObserver implementation: - void WillProcessTask(const base::PendingTask& pending_task) override; - void DidProcessTask(const base::PendingTask& pending_task) override; - - void Clear(); - - private: - cc::RollingTimeDeltaHistory rolling_time_delta_history_; - base::TickClock* time_source_; // NOT OWNED - int outstanding_task_count_; - double estimation_percentile_; - base::TimeTicks task_start_time_; - base::TimeDelta expected_task_duration_; - - DISALLOW_COPY_AND_ASSIGN(TaskCostEstimator); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_RENDERER_TASK_COST_ESTIMATOR_H_
diff --git a/components/scheduler/renderer/task_cost_estimator_unittest.cc b/components/scheduler/renderer/task_cost_estimator_unittest.cc deleted file mode 100644 index a8297daf4..0000000 --- a/components/scheduler/renderer/task_cost_estimator_unittest.cc +++ /dev/null
@@ -1,80 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/renderer/task_cost_estimator.h" - -#include <memory> - -#include "base/test/simple_test_tick_clock.h" -#include "components/scheduler/base/test_time_source.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace scheduler { - -class TaskCostEstimatorTest : public testing::Test { - public: - TaskCostEstimatorTest() {} - ~TaskCostEstimatorTest() override {} - - void SetUp() override { - test_time_source_.reset(new TestTimeSource(&clock_)); - } - - base::SimpleTestTickClock clock_; - std::unique_ptr<TestTimeSource> test_time_source_; -}; - -class TaskCostEstimatorForTest : public TaskCostEstimator { - public: - TaskCostEstimatorForTest(TestTimeSource* test_time_source, - int sample_count, - double estimation_percentile) - : TaskCostEstimator(test_time_source, - sample_count, - estimation_percentile) {} -}; - -TEST_F(TaskCostEstimatorTest, BasicEstimation) { - TaskCostEstimatorForTest estimator(test_time_source_.get(), 1, 100); - base::PendingTask task(FROM_HERE, base::Closure()); - - estimator.WillProcessTask(task); - clock_.Advance(base::TimeDelta::FromMilliseconds(500)); - estimator.DidProcessTask(task); - - EXPECT_EQ(base::TimeDelta::FromMilliseconds(500), - estimator.expected_task_duration()); -} - -TEST_F(TaskCostEstimatorTest, Clear) { - TaskCostEstimatorForTest estimator(test_time_source_.get(), 1, 100); - base::PendingTask task(FROM_HERE, base::Closure()); - - estimator.WillProcessTask(task); - clock_.Advance(base::TimeDelta::FromMilliseconds(500)); - estimator.DidProcessTask(task); - - estimator.Clear(); - - EXPECT_EQ(base::TimeDelta(), estimator.expected_task_duration()); -} - -TEST_F(TaskCostEstimatorTest, NestedRunLoop) { - TaskCostEstimatorForTest estimator(test_time_source_.get(), 1, 100); - base::PendingTask task(FROM_HERE, base::Closure()); - - // Make sure we ignore the tasks inside the nested run loop. - estimator.WillProcessTask(task); - estimator.WillProcessTask(task); - clock_.Advance(base::TimeDelta::FromMilliseconds(500)); - estimator.DidProcessTask(task); - clock_.Advance(base::TimeDelta::FromMilliseconds(500)); - estimator.DidProcessTask(task); - - EXPECT_EQ(base::TimeDelta::FromMilliseconds(1000), - estimator.expected_task_duration()); -} - -} // namespace scheduler
diff --git a/components/scheduler/renderer/throttled_time_domain.cc b/components/scheduler/renderer/throttled_time_domain.cc deleted file mode 100644 index b66c8208..0000000 --- a/components/scheduler/renderer/throttled_time_domain.cc +++ /dev/null
@@ -1,39 +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 "components/scheduler/renderer/throttled_time_domain.h" - -namespace scheduler { - -ThrottledTimeDomain::ThrottledTimeDomain(TimeDomain::Observer* observer, - const char* tracing_category) - : RealTimeDomain(observer, tracing_category) {} - -ThrottledTimeDomain::~ThrottledTimeDomain() {} - -const char* ThrottledTimeDomain::GetName() const { - return "ThrottledTimeDomain"; -} - -void ThrottledTimeDomain::RequestWakeup(base::TimeTicks now, - base::TimeDelta delay) { - // We assume the owner (i.e. ThrottlingHelper) will manage wakeups on our - // behalf. -} - -bool ThrottledTimeDomain::MaybeAdvanceTime() { - base::TimeTicks next_run_time; - if (!NextScheduledRunTime(&next_run_time)) - return false; - - base::TimeTicks now = Now(); - if (now >= next_run_time) - return true; // Causes DoWork to post a continuation. - - // Unlike RealTimeDomain::MaybeAdvanceTime we don't request a wake up here, we - // assume the owner (i.e. ThrottlingHelper) will manage wakeups on our behalf. - return false; -} - -} // namespace scheduler
diff --git a/components/scheduler/renderer/throttled_time_domain.h b/components/scheduler/renderer/throttled_time_domain.h deleted file mode 100644 index e334c90..0000000 --- a/components/scheduler/renderer/throttled_time_domain.h +++ /dev/null
@@ -1,34 +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 COMPONENTS_SCHEDULER_RENDERER_THROTTLED_TIME_DOMAIN_H_ -#define COMPONENTS_SCHEDULER_RENDERER_THROTTLED_TIME_DOMAIN_H_ - -#include "base/macros.h" -#include "components/scheduler/base/real_time_domain.h" - -namespace scheduler { - -// A time domain for throttled tasks. behaves like an RealTimeDomain except it -// relies on the owner (ThrottlingHelper) to schedule wakeups. -class SCHEDULER_EXPORT ThrottledTimeDomain : public RealTimeDomain { - public: - ThrottledTimeDomain(TimeDomain::Observer* observer, - const char* tracing_category); - ~ThrottledTimeDomain() override; - - // TimeDomain implementation: - const char* GetName() const override; - void RequestWakeup(base::TimeTicks now, base::TimeDelta delay) override; - bool MaybeAdvanceTime() override; - - using TimeDomain::ClearExpiredWakeups; - - private: - DISALLOW_COPY_AND_ASSIGN(ThrottledTimeDomain); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_RENDERER_THROTTLED_TIME_DOMAIN_H_
diff --git a/components/scheduler/renderer/throttling_helper.cc b/components/scheduler/renderer/throttling_helper.cc deleted file mode 100644 index 034a161..0000000 --- a/components/scheduler/renderer/throttling_helper.cc +++ /dev/null
@@ -1,219 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/renderer/throttling_helper.h" - -#include "base/logging.h" -#include "components/scheduler/base/real_time_domain.h" -#include "components/scheduler/child/scheduler_tqm_delegate.h" -#include "components/scheduler/renderer/auto_advancing_virtual_time_domain.h" -#include "components/scheduler/renderer/renderer_scheduler_impl.h" -#include "components/scheduler/renderer/throttled_time_domain.h" -#include "components/scheduler/renderer/web_frame_scheduler_impl.h" -#include "third_party/WebKit/public/platform/WebFrameScheduler.h" - -namespace scheduler { - -ThrottlingHelper::ThrottlingHelper(RendererSchedulerImpl* renderer_scheduler, - const char* tracing_category) - : task_runner_(renderer_scheduler->ControlTaskRunner()), - renderer_scheduler_(renderer_scheduler), - tick_clock_(renderer_scheduler->tick_clock()), - tracing_category_(tracing_category), - time_domain_(new ThrottledTimeDomain(this, tracing_category)), - virtual_time_(false), - weak_factory_(this) { - pump_throttled_tasks_closure_.Reset(base::Bind( - &ThrottlingHelper::PumpThrottledTasks, weak_factory_.GetWeakPtr())); - forward_immediate_work_closure_ = - base::Bind(&ThrottlingHelper::OnTimeDomainHasImmediateWork, - weak_factory_.GetWeakPtr()); - - renderer_scheduler_->RegisterTimeDomain(time_domain_.get()); -} - -ThrottlingHelper::~ThrottlingHelper() { - // It's possible for queues to be still throttled, so we need to tidy up - // before unregistering the time domain. - for (const TaskQueueMap::value_type& map_entry : throttled_queues_) { - TaskQueue* task_queue = map_entry.first; - task_queue->SetTimeDomain(renderer_scheduler_->real_time_domain()); - task_queue->SetPumpPolicy(TaskQueue::PumpPolicy::AUTO); - } - - renderer_scheduler_->UnregisterTimeDomain(time_domain_.get()); -} - -void ThrottlingHelper::SetQueueEnabled(TaskQueue* task_queue, bool enabled) { - TaskQueueMap::iterator find_it = throttled_queues_.find(task_queue); - - if (find_it == throttled_queues_.end()) { - task_queue->SetQueueEnabled(enabled); - return; - } - - find_it->second.enabled = enabled; - - // We don't enable the queue here because it's throttled and there might be - // tasks in it's work queue that would execute immediatly rather than after - // PumpThrottledTasks runs. - if (!enabled) - task_queue->SetQueueEnabled(false); -} - -void ThrottlingHelper::IncreaseThrottleRefCount(TaskQueue* task_queue) { - DCHECK_NE(task_queue, task_runner_.get()); - - if (virtual_time_) - return; - - std::pair<TaskQueueMap::iterator, bool> insert_result = - throttled_queues_.insert(std::make_pair( - task_queue, Metadata(1, task_queue->IsQueueEnabled()))); - - if (insert_result.second) { - // The insert was succesful so we need to throttle the queue. - task_queue->SetTimeDomain(time_domain_.get()); - task_queue->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL); - task_queue->SetQueueEnabled(false); - - if (!task_queue->IsEmpty()) { - if (task_queue->HasPendingImmediateWork()) { - OnTimeDomainHasImmediateWork(); - } else { - OnTimeDomainHasDelayedWork(); - } - } - } else { - // An entry already existed in the map so we need to increment the refcount. - insert_result.first->second.throttling_ref_count++; - } -} - -void ThrottlingHelper::DecreaseThrottleRefCount(TaskQueue* task_queue) { - if (virtual_time_) - return; - - TaskQueueMap::iterator iter = throttled_queues_.find(task_queue); - - if (iter != throttled_queues_.end() && - --iter->second.throttling_ref_count == 0) { - bool enabled = iter->second.enabled; - // The refcount has become zero, we need to unthrottle the queue. - throttled_queues_.erase(iter); - - task_queue->SetTimeDomain(renderer_scheduler_->real_time_domain()); - task_queue->SetPumpPolicy(TaskQueue::PumpPolicy::AUTO); - task_queue->SetQueueEnabled(enabled); - } -} - -void ThrottlingHelper::UnregisterTaskQueue(TaskQueue* task_queue) { - throttled_queues_.erase(task_queue); -} - -void ThrottlingHelper::OnTimeDomainHasImmediateWork() { - // Forward to the main thread if called from another thread. - if (!task_runner_->RunsTasksOnCurrentThread()) { - task_runner_->PostTask(FROM_HERE, forward_immediate_work_closure_); - return; - } - TRACE_EVENT0(tracing_category_, - "ThrottlingHelper::OnTimeDomainHasImmediateWork"); - base::TimeTicks now = tick_clock_->NowTicks(); - MaybeSchedulePumpThrottledTasksLocked(FROM_HERE, now, now); -} - -void ThrottlingHelper::OnTimeDomainHasDelayedWork() { - TRACE_EVENT0(tracing_category_, - "ThrottlingHelper::OnTimeDomainHasDelayedWork"); - base::TimeTicks next_scheduled_delayed_task; - bool has_delayed_task = - time_domain_->NextScheduledRunTime(&next_scheduled_delayed_task); - DCHECK(has_delayed_task); - base::TimeTicks now = tick_clock_->NowTicks(); - MaybeSchedulePumpThrottledTasksLocked(FROM_HERE, now, - next_scheduled_delayed_task); -} - -void ThrottlingHelper::PumpThrottledTasks() { - TRACE_EVENT0(tracing_category_, "ThrottlingHelper::PumpThrottledTasks"); - pending_pump_throttled_tasks_runtime_ = base::TimeTicks(); - - LazyNow lazy_low(tick_clock_); - for (const TaskQueueMap::value_type& map_entry : throttled_queues_) { - TaskQueue* task_queue = map_entry.first; - if (task_queue->IsEmpty()) - continue; - - task_queue->SetQueueEnabled(map_entry.second.enabled); - task_queue->PumpQueue(&lazy_low, false); - } - // Make sure NextScheduledRunTime gives us an up-to date result. - time_domain_->ClearExpiredWakeups(); - - base::TimeTicks next_scheduled_delayed_task; - // Maybe schedule a call to ThrottlingHelper::PumpThrottledTasks if there is - // a pending delayed task. NOTE posting a non-delayed task in the future will - // result in ThrottlingHelper::OnTimeDomainHasImmediateWork being called. - if (time_domain_->NextScheduledRunTime(&next_scheduled_delayed_task)) { - MaybeSchedulePumpThrottledTasksLocked(FROM_HERE, lazy_low.Now(), - next_scheduled_delayed_task); - } -} - -/* static */ -base::TimeTicks ThrottlingHelper::ThrottledRunTime( - base::TimeTicks unthrottled_runtime) { - const base::TimeDelta one_second = base::TimeDelta::FromSeconds(1); - return unthrottled_runtime + one_second - - ((unthrottled_runtime - base::TimeTicks()) % one_second); -} - -void ThrottlingHelper::MaybeSchedulePumpThrottledTasksLocked( - const tracked_objects::Location& from_here, - base::TimeTicks now, - base::TimeTicks unthrottled_runtime) { - if (virtual_time_) - return; - - base::TimeTicks throttled_runtime = - ThrottledRunTime(std::max(now, unthrottled_runtime)); - // If there is a pending call to PumpThrottledTasks and it's sooner than - // |unthrottled_runtime| then return. - if (!pending_pump_throttled_tasks_runtime_.is_null() && - throttled_runtime >= pending_pump_throttled_tasks_runtime_) { - return; - } - - pending_pump_throttled_tasks_runtime_ = throttled_runtime; - - pump_throttled_tasks_closure_.Cancel(); - - base::TimeDelta delay = pending_pump_throttled_tasks_runtime_ - now; - TRACE_EVENT1(tracing_category_, - "ThrottlingHelper::MaybeSchedulePumpThrottledTasksLocked", - "delay_till_next_pump_ms", delay.InMilliseconds()); - task_runner_->PostDelayedTask( - from_here, pump_throttled_tasks_closure_.callback(), delay); -} - -void ThrottlingHelper::EnableVirtualTime() { - virtual_time_ = true; - - pump_throttled_tasks_closure_.Cancel(); - - while (!throttled_queues_.empty()) { - TaskQueue* task_queue = throttled_queues_.begin()->first; - bool enabled = throttled_queues_.begin()->second.enabled; - - throttled_queues_.erase(throttled_queues_.begin()); - - task_queue->SetTimeDomain(renderer_scheduler_->GetVirtualTimeDomain()); - task_queue->SetPumpPolicy(TaskQueue::PumpPolicy::AUTO); - task_queue->SetQueueEnabled(enabled); - } -} - -} // namespace scheduler
diff --git a/components/scheduler/renderer/throttling_helper.h b/components/scheduler/renderer/throttling_helper.h deleted file mode 100644 index d2b34c20..0000000 --- a/components/scheduler/renderer/throttling_helper.h +++ /dev/null
@@ -1,104 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_RENDERER_THROTTLING_HELPER_H_ -#define COMPONENTS_SCHEDULER_RENDERER_THROTTLING_HELPER_H_ - -#include <set> - -#include "base/macros.h" -#include "components/scheduler/base/cancelable_closure_holder.h" -#include "components/scheduler/base/time_domain.h" -#include "components/scheduler/scheduler_export.h" -#include "third_party/WebKit/public/platform/WebViewScheduler.h" - -namespace scheduler { - -class RendererSchedulerImpl; -class ThrottledTimeDomain; -class WebFrameSchedulerImpl; - -class SCHEDULER_EXPORT ThrottlingHelper : public TimeDomain::Observer { - public: - ThrottlingHelper(RendererSchedulerImpl* renderer_scheduler, - const char* tracing_category); - - ~ThrottlingHelper() override; - - // TimeDomain::Observer implementation: - void OnTimeDomainHasImmediateWork() override; - void OnTimeDomainHasDelayedWork() override; - - // The purpose of this method is to make sure throttling doesn't conflict with - // enabling/disabling the queue for policy reasons. - // If |task_queue| is throttled then the ThrottlingHelper remembers the - // |enabled| setting. In addition if |enabled| is false then the queue is - // immediatly disabled. Otherwise if |task_queue| not throttled then - // TaskQueue::SetEnabled(enabled) is called. - void SetQueueEnabled(TaskQueue* task_queue, bool enabled); - - // Increments the throttled refcount and causes |task_queue| to be throttled - // if its not already throttled. - void IncreaseThrottleRefCount(TaskQueue* task_queue); - - // If the refcouint is non-zero it's decremented. If the throttled refcount - // becomes zero then |task_queue| is unthrottled. If the refcount was already - // zero this function does nothing. - void DecreaseThrottleRefCount(TaskQueue* task_queue); - - // Removes |task_queue| from |throttled_queues_|. - void UnregisterTaskQueue(TaskQueue* task_queue); - - // Tells the ThrottlingHelper we're using virtual time, which disables all - // throttling. - void EnableVirtualTime(); - - const ThrottledTimeDomain* time_domain() const { return time_domain_.get(); } - - static base::TimeTicks ThrottledRunTime(base::TimeTicks unthrottled_runtime); - - const scoped_refptr<TaskQueue>& task_runner() const { return task_runner_; } - - private: - struct Metadata { - Metadata() : throttling_ref_count(0), enabled(false) {} - - Metadata(size_t ref_count, bool is_enabled) - : throttling_ref_count(ref_count), enabled(is_enabled) {} - - size_t throttling_ref_count; - bool enabled; - }; - using TaskQueueMap = std::map<TaskQueue*, Metadata>; - - void PumpThrottledTasks(); - - // Note |unthrottled_runtime| might be in the past. When this happens we - // compute the delay to the next runtime based on now rather than - // unthrottled_runtime. - void MaybeSchedulePumpThrottledTasksLocked( - const tracked_objects::Location& from_here, - base::TimeTicks now, - base::TimeTicks unthrottled_runtime); - - TaskQueueMap throttled_queues_; - base::Closure forward_immediate_work_closure_; - scoped_refptr<TaskQueue> task_runner_; - RendererSchedulerImpl* renderer_scheduler_; // NOT OWNED - base::TickClock* tick_clock_; // NOT OWNED - const char* tracing_category_; // NOT OWNED - std::unique_ptr<ThrottledTimeDomain> time_domain_; - - CancelableClosureHolder pump_throttled_tasks_closure_; - base::TimeTicks pending_pump_throttled_tasks_runtime_; - bool virtual_time_; - - base::WeakPtrFactory<ThrottlingHelper> weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(ThrottlingHelper); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_RENDERER_THROTTLING_HELPER_H_
diff --git a/components/scheduler/renderer/throttling_helper_unittest.cc b/components/scheduler/renderer/throttling_helper_unittest.cc deleted file mode 100644 index a43a00e..0000000 --- a/components/scheduler/renderer/throttling_helper_unittest.cc +++ /dev/null
@@ -1,480 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/renderer/throttling_helper.h" - -#include <stddef.h> - -#include <memory> - -#include "base/callback.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/test/simple_test_tick_clock.h" -#include "cc/test/ordered_simple_task_runner.h" -#include "components/scheduler/base/test_time_source.h" -#include "components/scheduler/child/scheduler_tqm_delegate_for_test.h" -#include "components/scheduler/renderer/auto_advancing_virtual_time_domain.h" -#include "components/scheduler/renderer/renderer_scheduler_impl.h" -#include "components/scheduler/renderer/web_frame_scheduler_impl.h" -#include "components/scheduler/renderer/web_view_scheduler_impl.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using testing::ElementsAre; - -namespace scheduler { - -namespace { -void CountingTask(size_t* count, scoped_refptr<TaskQueue> timer_queue) { - if (++(*count) < 10) { - timer_queue->PostTask(FROM_HERE, - base::Bind(&CountingTask, count, timer_queue)); - } -} -} - -class ThrottlingHelperTest : public testing::Test { - public: - ThrottlingHelperTest() {} - ~ThrottlingHelperTest() override {} - - void SetUp() override { - clock_.reset(new base::SimpleTestTickClock()); - clock_->Advance(base::TimeDelta::FromMicroseconds(5000)); - mock_task_runner_ = - make_scoped_refptr(new cc::OrderedSimpleTaskRunner(clock_.get(), true)); - delegate_ = SchedulerTqmDelegateForTest::Create( - mock_task_runner_, base::WrapUnique(new TestTimeSource(clock_.get()))); - scheduler_.reset(new RendererSchedulerImpl(delegate_)); - throttling_helper_ = scheduler_->throttling_helper(); - timer_queue_ = scheduler_->NewTimerTaskRunner("test_queue"); - } - - void TearDown() override { - scheduler_->Shutdown(); - scheduler_.reset(); - } - - void ExpectThrottled(scoped_refptr<TaskQueue> timer_queue) { - size_t count = 0; - timer_queue->PostTask(FROM_HERE, - base::Bind(&CountingTask, &count, timer_queue)); - - mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1)); - EXPECT_LT(count, 10u); - mock_task_runner_->RunUntilIdle(); - } - - void ExpectUnthrottled(scoped_refptr<TaskQueue> timer_queue) { - size_t count = 0; - timer_queue->PostTask(FROM_HERE, - base::Bind(&CountingTask, &count, timer_queue)); - - mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1)); - EXPECT_EQ(count, 10u); - mock_task_runner_->RunUntilIdle(); - } - - protected: - std::unique_ptr<base::SimpleTestTickClock> clock_; - scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_; - scoped_refptr<SchedulerTqmDelegate> delegate_; - std::unique_ptr<RendererSchedulerImpl> scheduler_; - scoped_refptr<TaskQueue> timer_queue_; - ThrottlingHelper* throttling_helper_; // NOT OWNED - - DISALLOW_COPY_AND_ASSIGN(ThrottlingHelperTest); -}; - -TEST_F(ThrottlingHelperTest, ThrottledRunTime) { - EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(1.0), - ThrottlingHelper::ThrottledRunTime( - base::TimeTicks() + base::TimeDelta::FromSecondsD(0.0))); - - EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(1.0), - ThrottlingHelper::ThrottledRunTime( - base::TimeTicks() + base::TimeDelta::FromSecondsD(0.1))); - - EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(1.0), - ThrottlingHelper::ThrottledRunTime( - base::TimeTicks() + base::TimeDelta::FromSecondsD(0.2))); - - EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(1.0), - ThrottlingHelper::ThrottledRunTime( - base::TimeTicks() + base::TimeDelta::FromSecondsD(0.5))); - - EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(1.0), - ThrottlingHelper::ThrottledRunTime( - base::TimeTicks() + base::TimeDelta::FromSecondsD(0.8))); - - EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(1.0), - ThrottlingHelper::ThrottledRunTime( - base::TimeTicks() + base::TimeDelta::FromSecondsD(0.9))); - - EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(2.0), - ThrottlingHelper::ThrottledRunTime( - base::TimeTicks() + base::TimeDelta::FromSecondsD(1.0))); - - EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(2.0), - ThrottlingHelper::ThrottledRunTime( - base::TimeTicks() + base::TimeDelta::FromSecondsD(1.1))); - - EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(9.0), - ThrottlingHelper::ThrottledRunTime( - base::TimeTicks() + base::TimeDelta::FromSecondsD(8.0))); - - EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(9.0), - ThrottlingHelper::ThrottledRunTime( - base::TimeTicks() + base::TimeDelta::FromSecondsD(8.1))); -} - -namespace { -void TestTask(std::vector<base::TimeTicks>* run_times, - base::SimpleTestTickClock* clock) { - run_times->push_back(clock->NowTicks()); -} -} // namespace - -TEST_F(ThrottlingHelperTest, TimerAlignment) { - std::vector<base::TimeTicks> run_times; - timer_queue_->PostDelayedTask(FROM_HERE, - base::Bind(&TestTask, &run_times, clock_.get()), - base::TimeDelta::FromMilliseconds(200.0)); - - timer_queue_->PostDelayedTask(FROM_HERE, - base::Bind(&TestTask, &run_times, clock_.get()), - base::TimeDelta::FromMilliseconds(800.0)); - - timer_queue_->PostDelayedTask(FROM_HERE, - base::Bind(&TestTask, &run_times, clock_.get()), - base::TimeDelta::FromMilliseconds(1200.0)); - - timer_queue_->PostDelayedTask(FROM_HERE, - base::Bind(&TestTask, &run_times, clock_.get()), - base::TimeDelta::FromMilliseconds(8300.0)); - - throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); - - mock_task_runner_->RunUntilIdle(); - - // Times are aligned to a multipple of 1000 milliseconds. - EXPECT_THAT( - run_times, - ElementsAre( - base::TimeTicks() + base::TimeDelta::FromMilliseconds(1000.0), - base::TimeTicks() + base::TimeDelta::FromMilliseconds(1000.0), - base::TimeTicks() + base::TimeDelta::FromMilliseconds(2000.0), - base::TimeTicks() + base::TimeDelta::FromMilliseconds(9000.0))); -} - -TEST_F(ThrottlingHelperTest, TimerAlignment_Unthrottled) { - std::vector<base::TimeTicks> run_times; - base::TimeTicks start_time = clock_->NowTicks(); - timer_queue_->PostDelayedTask(FROM_HERE, - base::Bind(&TestTask, &run_times, clock_.get()), - base::TimeDelta::FromMilliseconds(200.0)); - - timer_queue_->PostDelayedTask(FROM_HERE, - base::Bind(&TestTask, &run_times, clock_.get()), - base::TimeDelta::FromMilliseconds(800.0)); - - timer_queue_->PostDelayedTask(FROM_HERE, - base::Bind(&TestTask, &run_times, clock_.get()), - base::TimeDelta::FromMilliseconds(1200.0)); - - timer_queue_->PostDelayedTask(FROM_HERE, - base::Bind(&TestTask, &run_times, clock_.get()), - base::TimeDelta::FromMilliseconds(8300.0)); - - throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); - throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get()); - - mock_task_runner_->RunUntilIdle(); - - // Times are not aligned. - EXPECT_THAT( - run_times, - ElementsAre(start_time + base::TimeDelta::FromMilliseconds(200.0), - start_time + base::TimeDelta::FromMilliseconds(800.0), - start_time + base::TimeDelta::FromMilliseconds(1200.0), - start_time + base::TimeDelta::FromMilliseconds(8300.0))); -} - -TEST_F(ThrottlingHelperTest, Refcount) { - ExpectUnthrottled(timer_queue_.get()); - - throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); - ExpectThrottled(timer_queue_); - - throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); - ExpectThrottled(timer_queue_); - - throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get()); - ExpectThrottled(timer_queue_); - - throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get()); - ExpectUnthrottled(timer_queue_); - - // Should be a NOP. - throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get()); - ExpectUnthrottled(timer_queue_); - - throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); - ExpectThrottled(timer_queue_); -} - -TEST_F(ThrottlingHelperTest, - ThrotlingAnEmptyQueueDoesNotPostPumpThrottledTasksLocked) { - throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); - - EXPECT_TRUE(throttling_helper_->task_runner()->IsEmpty()); -} - -TEST_F(ThrottlingHelperTest, WakeUpForNonDelayedTask) { - std::vector<base::TimeTicks> run_times; - - // Nothing is posted on timer_queue_ so PumpThrottledTasks will not tick. - throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); - - // Posting a task should trigger the pump. - timer_queue_->PostTask(FROM_HERE, - base::Bind(&TestTask, &run_times, clock_.get())); - - mock_task_runner_->RunUntilIdle(); - EXPECT_THAT(run_times, - ElementsAre(base::TimeTicks() + - base::TimeDelta::FromMilliseconds(1000.0))); -} - -TEST_F(ThrottlingHelperTest, WakeUpForDelayedTask) { - std::vector<base::TimeTicks> run_times; - - // Nothing is posted on timer_queue_ so PumpThrottledTasks will not tick. - throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); - - // Posting a task should trigger the pump. - timer_queue_->PostDelayedTask(FROM_HERE, - base::Bind(&TestTask, &run_times, clock_.get()), - base::TimeDelta::FromMilliseconds(1200.0)); - - mock_task_runner_->RunUntilIdle(); - EXPECT_THAT(run_times, - ElementsAre(base::TimeTicks() + - base::TimeDelta::FromMilliseconds(2000.0))); -} - -namespace { -bool MessageLoopTaskCounter(size_t* count) { - *count = *count + 1; - return true; -} - -void NopTask() {} - -} // namespace - -TEST_F(ThrottlingHelperTest, - SingleThrottledTaskPumpedAndRunWithNoExtraneousMessageLoopTasks) { - throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); - - base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10)); - timer_queue_->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), delay); - - size_t task_count = 0; - mock_task_runner_->RunTasksWhile( - base::Bind(&MessageLoopTaskCounter, &task_count)); - - EXPECT_EQ(1u, task_count); -} - -TEST_F(ThrottlingHelperTest, - SingleFutureThrottledTaskPumpedAndRunWithNoExtraneousMessageLoopTasks) { - throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); - - base::TimeDelta delay(base::TimeDelta::FromSecondsD(15.5)); - timer_queue_->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), delay); - - size_t task_count = 0; - mock_task_runner_->RunTasksWhile( - base::Bind(&MessageLoopTaskCounter, &task_count)); - - EXPECT_EQ(1u, task_count); -} - -TEST_F(ThrottlingHelperTest, - TwoFutureThrottledTaskPumpedAndRunWithNoExtraneousMessageLoopTasks) { - throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); - std::vector<base::TimeTicks> run_times; - - base::TimeDelta delay(base::TimeDelta::FromSecondsD(15.5)); - timer_queue_->PostDelayedTask(FROM_HERE, - base::Bind(&TestTask, &run_times, clock_.get()), - delay); - - base::TimeDelta delay2(base::TimeDelta::FromSecondsD(5.5)); - timer_queue_->PostDelayedTask(FROM_HERE, - base::Bind(&TestTask, &run_times, clock_.get()), - delay2); - - size_t task_count = 0; - mock_task_runner_->RunTasksWhile( - base::Bind(&MessageLoopTaskCounter, &task_count)); - - EXPECT_EQ(2u, task_count); // There are two since the cancelled task runs in - // the same DoWork batch. - - EXPECT_THAT( - run_times, - ElementsAre(base::TimeTicks() + base::TimeDelta::FromSeconds(6), - base::TimeTicks() + base::TimeDelta::FromSeconds(16))); -} - -TEST_F(ThrottlingHelperTest, TaskDelayIsBasedOnRealTime) { - std::vector<base::TimeTicks> run_times; - - throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); - - // Post an initial task that should run at the first aligned time period. - timer_queue_->PostDelayedTask(FROM_HERE, - base::Bind(&TestTask, &run_times, clock_.get()), - base::TimeDelta::FromMilliseconds(900.0)); - - mock_task_runner_->RunUntilIdle(); - - // Advance realtime. - clock_->Advance(base::TimeDelta::FromMilliseconds(250)); - - // Post a task that due to real time + delay must run in the third aligned - // time period. - timer_queue_->PostDelayedTask(FROM_HERE, - base::Bind(&TestTask, &run_times, clock_.get()), - base::TimeDelta::FromMilliseconds(900.0)); - - mock_task_runner_->RunUntilIdle(); - - EXPECT_THAT( - run_times, - ElementsAre( - base::TimeTicks() + base::TimeDelta::FromMilliseconds(1000.0), - base::TimeTicks() + base::TimeDelta::FromMilliseconds(3000.0))); -} - -TEST_F(ThrottlingHelperTest, ThrottledTasksReportRealTime) { - EXPECT_EQ(timer_queue_->GetTimeDomain()->Now(), clock_->NowTicks()); - - throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); - EXPECT_EQ(timer_queue_->GetTimeDomain()->Now(), clock_->NowTicks()); - - clock_->Advance(base::TimeDelta::FromMilliseconds(250)); - // Make sure the throttled time domain's Now() reports the same as the - // underlying clock. - EXPECT_EQ(timer_queue_->GetTimeDomain()->Now(), clock_->NowTicks()); -} - -TEST_F(ThrottlingHelperTest, TaskQueueDisabledTillPump) { - timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask)); - - EXPECT_TRUE(timer_queue_->IsQueueEnabled()); - throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); - EXPECT_FALSE(timer_queue_->IsQueueEnabled()); - - mock_task_runner_->RunUntilIdle(); // Wait until the pump. - EXPECT_TRUE(timer_queue_->IsQueueEnabled()); -} - -TEST_F(ThrottlingHelperTest, TaskQueueUnthrottle_InitiallyEnabled) { - timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask)); - - timer_queue_->SetQueueEnabled(true); // NOP - throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); - EXPECT_FALSE(timer_queue_->IsQueueEnabled()); - - throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get()); - EXPECT_TRUE(timer_queue_->IsQueueEnabled()); -} - -TEST_F(ThrottlingHelperTest, TaskQueueUnthrottle_InitiallyDisabled) { - timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask)); - - timer_queue_->SetQueueEnabled(false); - throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); - EXPECT_FALSE(timer_queue_->IsQueueEnabled()); - - throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get()); - EXPECT_FALSE(timer_queue_->IsQueueEnabled()); -} - -TEST_F(ThrottlingHelperTest, SetQueueEnabled_Unthrottled) { - timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask)); - - throttling_helper_->SetQueueEnabled(timer_queue_.get(), false); - EXPECT_FALSE(timer_queue_->IsQueueEnabled()); - - throttling_helper_->SetQueueEnabled(timer_queue_.get(), true); - EXPECT_TRUE(timer_queue_->IsQueueEnabled()); -} - -TEST_F(ThrottlingHelperTest, SetQueueEnabled_DisabledWhileThrottled) { - timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask)); - - throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); - EXPECT_FALSE(timer_queue_->IsQueueEnabled()); - - throttling_helper_->SetQueueEnabled(timer_queue_.get(), false); - throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get()); - EXPECT_FALSE(timer_queue_->IsQueueEnabled()); -} - -TEST_F(ThrottlingHelperTest, TaskQueueDisabledTillPump_ThenManuallyDisabled) { - timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask)); - - EXPECT_TRUE(timer_queue_->IsQueueEnabled()); - throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); - EXPECT_FALSE(timer_queue_->IsQueueEnabled()); - - mock_task_runner_->RunUntilIdle(); // Wait until the pump. - EXPECT_TRUE(timer_queue_->IsQueueEnabled()); - - throttling_helper_->SetQueueEnabled(timer_queue_.get(), false); - EXPECT_FALSE(timer_queue_->IsQueueEnabled()); -} - -TEST_F(ThrottlingHelperTest, DoubleIncrementDoubleDecrement) { - timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask)); - - EXPECT_TRUE(timer_queue_->IsQueueEnabled()); - throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); - throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); - EXPECT_FALSE(timer_queue_->IsQueueEnabled()); - throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get()); - throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get()); - EXPECT_TRUE(timer_queue_->IsQueueEnabled()); -} - -TEST_F(ThrottlingHelperTest, EnableVirtualTimeThenIncrement) { - timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask)); - - scheduler_->EnableVirtualTime(); - EXPECT_EQ(timer_queue_->GetTimeDomain(), scheduler_->GetVirtualTimeDomain()); - - EXPECT_TRUE(timer_queue_->IsQueueEnabled()); - throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); - EXPECT_TRUE(timer_queue_->IsQueueEnabled()); - EXPECT_EQ(timer_queue_->GetTimeDomain(), scheduler_->GetVirtualTimeDomain()); -} - -TEST_F(ThrottlingHelperTest, IncrementThenEnableVirtualTime) { - timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask)); - - EXPECT_TRUE(timer_queue_->IsQueueEnabled()); - throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); - EXPECT_FALSE(timer_queue_->IsQueueEnabled()); - - scheduler_->EnableVirtualTime(); - EXPECT_TRUE(timer_queue_->IsQueueEnabled()); - EXPECT_EQ(timer_queue_->GetTimeDomain(), scheduler_->GetVirtualTimeDomain()); -} - -} // namespace scheduler
diff --git a/components/scheduler/renderer/user_model.cc b/components/scheduler/renderer/user_model.cc deleted file mode 100644 index c71e86c..0000000 --- a/components/scheduler/renderer/user_model.cc +++ /dev/null
@@ -1,222 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/renderer/user_model.h" - -#include "base/metrics/histogram_macros.h" - -namespace scheduler { - -namespace { -// This enum is used to back a histogram, and should therefore be treated as -// append-only. -enum GesturePredictionResult { - GESTURE_OCCURED_WAS_PREDICTED = 0, - GESTURE_OCCURED_BUT_NOT_PREDICTED = 1, - GESTURE_PREDICTED_BUT_DID_NOT_OCCUR = 2, - GESTURE_PREDICTION_RESULT_COUNT = 3 -}; - -void RecordGesturePrediction(GesturePredictionResult result) { - UMA_HISTOGRAM_ENUMERATION( - "RendererScheduler.UserModel.GesturePredictedCorrectly", result, - GESTURE_PREDICTION_RESULT_COUNT); -} - -} // namespace - -UserModel::UserModel() - : pending_input_event_count_(0), - is_gesture_active_(false), - is_gesture_expected_(false) {} -UserModel::~UserModel() {} - -void UserModel::DidStartProcessingInputEvent(blink::WebInputEvent::Type type, - const base::TimeTicks now) { - last_input_signal_time_ = now; - if (type == blink::WebInputEvent::TouchStart || - type == blink::WebInputEvent::GestureScrollBegin || - type == blink::WebInputEvent::GesturePinchBegin) { - // Only update stats once per gesture. - if (!is_gesture_active_) { - last_gesture_start_time_ = now; - - RecordGesturePrediction(is_gesture_expected_ - ? GESTURE_OCCURED_WAS_PREDICTED - : GESTURE_OCCURED_BUT_NOT_PREDICTED); - - if (!last_reset_time_.is_null()) { - base::TimeDelta time_since_reset = now - last_reset_time_; - UMA_HISTOGRAM_MEDIUM_TIMES( - "RendererScheduler.UserModel.GestureStartTimeSinceModelReset", - time_since_reset); - } - - // If there has been a previous gesture, record a UMA metric for the time - // interval between then and now. - if (!last_continuous_gesture_time_.is_null()) { - base::TimeDelta time_since_last_gesture = - now - last_continuous_gesture_time_; - UMA_HISTOGRAM_MEDIUM_TIMES( - "RendererScheduler.UserModel.TimeBetweenGestures", - time_since_last_gesture); - } - } - - is_gesture_active_ = true; - } - - // We need to track continuous gestures seperatly for scroll detection - // because taps should not be confused with scrolls. - if (type == blink::WebInputEvent::GestureScrollBegin || - type == blink::WebInputEvent::GestureScrollEnd || - type == blink::WebInputEvent::GestureScrollUpdate || - type == blink::WebInputEvent::GestureFlingStart || - type == blink::WebInputEvent::GestureFlingCancel || - type == blink::WebInputEvent::GesturePinchBegin || - type == blink::WebInputEvent::GesturePinchEnd || - type == blink::WebInputEvent::GesturePinchUpdate) { - last_continuous_gesture_time_ = now; - } - - // If the gesture has ended, clear |is_gesture_active_| and record a UMA - // metric that tracks its duration. - if (type == blink::WebInputEvent::GestureScrollEnd || - type == blink::WebInputEvent::GesturePinchEnd || - type == blink::WebInputEvent::GestureFlingStart || - type == blink::WebInputEvent::TouchEnd) { - // Only update stats once per gesture. - if (is_gesture_active_) { - base::TimeDelta duration = now - last_gesture_start_time_; - UMA_HISTOGRAM_TIMES("RendererScheduler.UserModel.GestureDuration", - duration); - } - is_gesture_active_ = false; - } - - TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), - "is_gesture_active", is_gesture_active_); - - pending_input_event_count_++; -} - -void UserModel::DidFinishProcessingInputEvent(const base::TimeTicks now) { - last_input_signal_time_ = now; - if (pending_input_event_count_ > 0) - pending_input_event_count_--; -} - -base::TimeDelta UserModel::TimeLeftInUserGesture(base::TimeTicks now) const { - base::TimeDelta escalated_priority_duration = - base::TimeDelta::FromMilliseconds(kGestureEstimationLimitMillis); - - // If the input event is still pending, go into input prioritized policy and - // check again later. - if (pending_input_event_count_ > 0) - return escalated_priority_duration; - if (last_input_signal_time_.is_null() || - last_input_signal_time_ + escalated_priority_duration < now) { - return base::TimeDelta(); - } - return last_input_signal_time_ + escalated_priority_duration - now; -} - -bool UserModel::IsGestureExpectedSoon( - const base::TimeTicks now, - base::TimeDelta* prediction_valid_duration) { - bool was_gesture_expected = is_gesture_expected_; - is_gesture_expected_ = - IsGestureExpectedSoonImpl(now, prediction_valid_duration); - - // Track when we start expecting a gesture so we can work out later if a - // gesture actually happened. - if (!was_gesture_expected && is_gesture_expected_) - last_gesture_expected_start_time_ = now; - - if (was_gesture_expected && !is_gesture_expected_ && - last_gesture_expected_start_time_ > last_gesture_start_time_) { - RecordGesturePrediction(GESTURE_PREDICTED_BUT_DID_NOT_OCCUR); - } - return is_gesture_expected_; -} - -bool UserModel::IsGestureExpectedSoonImpl( - const base::TimeTicks now, - base::TimeDelta* prediction_valid_duration) const { - if (is_gesture_active_) { - if (IsGestureExpectedToContinue(now, prediction_valid_duration)) { - return false; - } else { - // If a gesture is not expected to continue then we expect a subsequent - // gesture soon. - *prediction_valid_duration = - base::TimeDelta::FromMilliseconds(kExpectSubsequentGestureMillis); - return true; - } - } else { - // If we've have a finished a gesture then a subsequent gesture is deemed - // likely. - base::TimeDelta expect_subsequent_gesture_for = - base::TimeDelta::FromMilliseconds(kExpectSubsequentGestureMillis); - if (last_continuous_gesture_time_.is_null() || - last_continuous_gesture_time_ + expect_subsequent_gesture_for <= now) { - return false; - } - *prediction_valid_duration = - last_continuous_gesture_time_ + expect_subsequent_gesture_for - now; - return true; - } -} - -bool UserModel::IsGestureExpectedToContinue( - const base::TimeTicks now, - base::TimeDelta* prediction_valid_duration) const { - if (!is_gesture_active_) - return false; - - base::TimeDelta median_gesture_duration = - base::TimeDelta::FromMilliseconds(kMedianGestureDurationMillis); - base::TimeTicks expected_gesture_end_time = - last_gesture_start_time_ + median_gesture_duration; - - if (expected_gesture_end_time > now) { - *prediction_valid_duration = expected_gesture_end_time - now; - return true; - } - return false; -} - -void UserModel::Reset(base::TimeTicks now) { - last_input_signal_time_ = base::TimeTicks(); - last_gesture_start_time_ = base::TimeTicks(); - last_continuous_gesture_time_ = base::TimeTicks(); - last_gesture_expected_start_time_ = base::TimeTicks(); - last_reset_time_ = now; - is_gesture_active_ = false; - is_gesture_expected_ = false; -} - -void UserModel::AsValueInto(base::trace_event::TracedValue* state) const { - state->BeginDictionary("user_model"); - state->SetInteger("pending_input_event_count", pending_input_event_count_); - state->SetDouble( - "last_input_signal_time", - (last_input_signal_time_ - base::TimeTicks()).InMillisecondsF()); - state->SetDouble( - "last_gesture_start_time", - (last_gesture_start_time_ - base::TimeTicks()).InMillisecondsF()); - state->SetDouble( - "last_continuous_gesture_time", - (last_continuous_gesture_time_ - base::TimeTicks()).InMillisecondsF()); - state->SetDouble("last_gesture_expected_start_time", - (last_gesture_expected_start_time_ - base::TimeTicks()) - .InMillisecondsF()); - state->SetDouble("last_reset_time", - (last_reset_time_ - base::TimeTicks()).InMillisecondsF()); - state->SetBoolean("is_gesture_expected", is_gesture_expected_); - state->SetBoolean("is_gesture_active", is_gesture_active_); - state->EndDictionary(); -} - -} // namespace scheduler
diff --git a/components/scheduler/renderer/user_model.h b/components/scheduler/renderer/user_model.h deleted file mode 100644 index f93b10b..0000000 --- a/components/scheduler/renderer/user_model.h +++ /dev/null
@@ -1,84 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_RENDERER_USER_MODEL_H_ -#define COMPONENTS_SCHEDULER_RENDERER_USER_MODEL_H_ - -#include "base/macros.h" -#include "base/trace_event/trace_event.h" -#include "base/trace_event/trace_event_argument.h" -#include "components/scheduler/renderer/renderer_scheduler.h" -#include "components/scheduler/scheduler_export.h" -#include "third_party/WebKit/public/web/WebInputEvent.h" - -namespace scheduler { - -class SCHEDULER_EXPORT UserModel { - public: - UserModel(); - ~UserModel(); - - // Tells us that the system started processing an input event. Must be paired - // with a call to DidFinishProcessingInputEvent. - void DidStartProcessingInputEvent(blink::WebInputEvent::Type type, - const base::TimeTicks now); - - // Tells us that the system finished processing an input event. - void DidFinishProcessingInputEvent(const base::TimeTicks now); - - // Returns the estimated amount of time left in the current user gesture, to a - // maximum of |kGestureEstimationLimitMillis|. After that time has elapased - // this function should be called again. - base::TimeDelta TimeLeftInUserGesture(base::TimeTicks now) const; - - // Tries to guess if a user gesture is expected soon. Currently this is - // very simple, but one day I hope to do something more sophisticated here. - // The prediction may change after |prediction_valid_duration| has elapsed. - bool IsGestureExpectedSoon(const base::TimeTicks now, - base::TimeDelta* prediction_valid_duration); - - // Returns true if a gesture has been in progress for less than the median - // gesture duration. The prediction may change after - // |prediction_valid_duration| has elapsed. - bool IsGestureExpectedToContinue( - const base::TimeTicks now, - base::TimeDelta* prediction_valid_duration) const; - - void AsValueInto(base::trace_event::TracedValue* state) const; - - // The time we should stay in a priority-escalated mode after an input event. - static const int kGestureEstimationLimitMillis = 100; - - // This is based on two weeks of Android usage data. - static const int kMedianGestureDurationMillis = 300; - - // We consider further gesture start events to be likely if the user has - // interacted with the device in the past two seconds. - // Based on Android usage data, 2000ms between gestures is the 75th percentile - // with 700ms being the 50th. - static const int kExpectSubsequentGestureMillis = 2000; - - // Clears input signals. - void Reset(base::TimeTicks now); - - private: - bool IsGestureExpectedSoonImpl( - const base::TimeTicks now, - base::TimeDelta* prediction_valid_duration) const; - - int pending_input_event_count_; - base::TimeTicks last_input_signal_time_; - base::TimeTicks last_gesture_start_time_; - base::TimeTicks last_continuous_gesture_time_; // Doesn't include Taps. - base::TimeTicks last_gesture_expected_start_time_; - base::TimeTicks last_reset_time_; - bool is_gesture_active_; // This typically means the user's finger is down. - bool is_gesture_expected_; - - DISALLOW_COPY_AND_ASSIGN(UserModel); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_RENDERER_USER_MODEL_H_
diff --git a/components/scheduler/renderer/user_model_unittest.cc b/components/scheduler/renderer/user_model_unittest.cc deleted file mode 100644 index 87afc72..0000000 --- a/components/scheduler/renderer/user_model_unittest.cc +++ /dev/null
@@ -1,254 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/renderer/user_model.h" - -#include "base/test/simple_test_tick_clock.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace scheduler { - -class UserModelTest : public testing::Test { - public: - UserModelTest() {} - ~UserModelTest() override {} - - void SetUp() override { - clock_.reset(new base::SimpleTestTickClock()); - clock_->Advance(base::TimeDelta::FromMicroseconds(5000)); - - user_model_.reset(new UserModel()); - } - - protected: - static base::TimeDelta priority_escalation_after_input_duration() { - return base::TimeDelta::FromMilliseconds( - UserModel::kGestureEstimationLimitMillis); - } - - static base::TimeDelta subsequent_input_expected_after_input_duration() { - return base::TimeDelta::FromMilliseconds( - UserModel::kExpectSubsequentGestureMillis); - } - - std::unique_ptr<base::SimpleTestTickClock> clock_; - std::unique_ptr<UserModel> user_model_; -}; - -TEST_F(UserModelTest, TimeLeftInUserGesture_NoInput) { - EXPECT_EQ(base::TimeDelta(), - user_model_->TimeLeftInUserGesture(clock_->NowTicks())); -} - -TEST_F(UserModelTest, TimeLeftInUserGesture_ImmediatelyAfterInput) { - user_model_->DidStartProcessingInputEvent( - blink::WebInputEvent::Type::TouchStart, clock_->NowTicks()); - user_model_->DidFinishProcessingInputEvent(clock_->NowTicks()); - EXPECT_EQ(priority_escalation_after_input_duration(), - user_model_->TimeLeftInUserGesture(clock_->NowTicks())); -} - -TEST_F(UserModelTest, TimeLeftInUserGesture_ShortlyAfterInput) { - user_model_->DidStartProcessingInputEvent( - blink::WebInputEvent::Type::TouchStart, clock_->NowTicks()); - user_model_->DidFinishProcessingInputEvent(clock_->NowTicks()); - base::TimeDelta delta(base::TimeDelta::FromMilliseconds(10)); - clock_->Advance(delta); - EXPECT_EQ(priority_escalation_after_input_duration() - delta, - user_model_->TimeLeftInUserGesture(clock_->NowTicks())); -} - -TEST_F(UserModelTest, TimeLeftInUserGesture_LongAfterInput) { - user_model_->DidStartProcessingInputEvent( - blink::WebInputEvent::Type::TouchStart, clock_->NowTicks()); - user_model_->DidFinishProcessingInputEvent(clock_->NowTicks()); - clock_->Advance(priority_escalation_after_input_duration() * 2); - EXPECT_EQ(base::TimeDelta(), - user_model_->TimeLeftInUserGesture(clock_->NowTicks())); -} - -TEST_F(UserModelTest, DidFinishProcessingInputEvent_Delayed) { - user_model_->DidStartProcessingInputEvent( - blink::WebInputEvent::Type::TouchStart, clock_->NowTicks()); - clock_->Advance(priority_escalation_after_input_duration() * 10); - - EXPECT_EQ(priority_escalation_after_input_duration(), - user_model_->TimeLeftInUserGesture(clock_->NowTicks())); - - user_model_->DidFinishProcessingInputEvent(clock_->NowTicks()); - base::TimeDelta delta(base::TimeDelta::FromMilliseconds(10)); - clock_->Advance(delta); - - EXPECT_EQ(priority_escalation_after_input_duration() - delta, - user_model_->TimeLeftInUserGesture(clock_->NowTicks())); -} - -TEST_F(UserModelTest, GestureExpectedSoon_NoRecentInput) { - base::TimeDelta prediction_valid_duration; - EXPECT_FALSE(user_model_->IsGestureExpectedSoon(clock_->NowTicks(), - &prediction_valid_duration)); - EXPECT_EQ(base::TimeDelta(), prediction_valid_duration); -} - -TEST_F(UserModelTest, GestureExpectedSoon_ShortlyAfter_GestureScrollBegin) { - user_model_->DidStartProcessingInputEvent( - blink::WebInputEvent::Type::GestureScrollBegin, clock_->NowTicks()); - user_model_->DidFinishProcessingInputEvent(clock_->NowTicks()); - - base::TimeDelta delta(base::TimeDelta::FromMilliseconds(10)); - clock_->Advance(delta); - - base::TimeDelta prediction_valid_duration; - EXPECT_FALSE(user_model_->IsGestureExpectedSoon(clock_->NowTicks(), - &prediction_valid_duration)); - EXPECT_EQ(base::TimeDelta::FromMilliseconds( - UserModel::kMedianGestureDurationMillis) - - delta, - prediction_valid_duration); -} - -TEST_F(UserModelTest, GestureExpectedSoon_LongAfter_GestureScrollBegin) { - user_model_->DidStartProcessingInputEvent( - blink::WebInputEvent::Type::GestureScrollBegin, clock_->NowTicks()); - user_model_->DidFinishProcessingInputEvent(clock_->NowTicks()); - - base::TimeDelta delta(base::TimeDelta::FromMilliseconds( - UserModel::kMedianGestureDurationMillis * 2)); - clock_->Advance(delta); - - base::TimeDelta prediction_valid_duration; - EXPECT_TRUE(user_model_->IsGestureExpectedSoon(clock_->NowTicks(), - &prediction_valid_duration)); - EXPECT_EQ(base::TimeDelta::FromMilliseconds( - UserModel::kExpectSubsequentGestureMillis), - prediction_valid_duration); -} - -TEST_F(UserModelTest, GestureExpectedSoon_ImmediatelyAfter_GestureScrollEnd) { - user_model_->DidStartProcessingInputEvent( - blink::WebInputEvent::Type::GestureScrollEnd, clock_->NowTicks()); - user_model_->DidFinishProcessingInputEvent(clock_->NowTicks()); - - base::TimeDelta prediction_valid_duration; - EXPECT_TRUE(user_model_->IsGestureExpectedSoon(clock_->NowTicks(), - &prediction_valid_duration)); - EXPECT_EQ(subsequent_input_expected_after_input_duration(), - prediction_valid_duration); -} - -TEST_F(UserModelTest, GestureExpectedSoon_ShortlyAfter_GestureScrollEnd) { - user_model_->DidStartProcessingInputEvent( - blink::WebInputEvent::Type::GestureScrollEnd, clock_->NowTicks()); - user_model_->DidFinishProcessingInputEvent(clock_->NowTicks()); - - base::TimeDelta delta(base::TimeDelta::FromMilliseconds(10)); - clock_->Advance(delta); - - base::TimeDelta prediction_valid_duration; - EXPECT_TRUE(user_model_->IsGestureExpectedSoon(clock_->NowTicks(), - &prediction_valid_duration)); - EXPECT_EQ(subsequent_input_expected_after_input_duration() - delta, - prediction_valid_duration); -} - -TEST_F(UserModelTest, GestureExpectedSoon_LongAfter_GestureScrollEnd) { - user_model_->DidStartProcessingInputEvent( - blink::WebInputEvent::Type::GestureScrollEnd, clock_->NowTicks()); - user_model_->DidFinishProcessingInputEvent(clock_->NowTicks()); - clock_->Advance(subsequent_input_expected_after_input_duration() * 2); - - base::TimeDelta prediction_valid_duration; - EXPECT_FALSE(user_model_->IsGestureExpectedSoon(clock_->NowTicks(), - &prediction_valid_duration)); - EXPECT_EQ(base::TimeDelta(), prediction_valid_duration); -} - -TEST_F(UserModelTest, GestureExpectedSoon_ShortlyAfter_GesturePinchEnd) { - user_model_->DidStartProcessingInputEvent( - blink::WebInputEvent::Type::GesturePinchEnd, clock_->NowTicks()); - user_model_->DidFinishProcessingInputEvent(clock_->NowTicks()); - - base::TimeDelta delta(base::TimeDelta::FromMilliseconds(10)); - clock_->Advance(delta); - - base::TimeDelta prediction_valid_duration; - EXPECT_TRUE(user_model_->IsGestureExpectedSoon(clock_->NowTicks(), - &prediction_valid_duration)); - EXPECT_EQ(subsequent_input_expected_after_input_duration() - delta, - prediction_valid_duration); -} - -TEST_F(UserModelTest, GestureExpectedSoon_ShortlyAfterInput_GestureTap) { - user_model_->DidStartProcessingInputEvent( - blink::WebInputEvent::Type::GestureTap, clock_->NowTicks()); - user_model_->DidFinishProcessingInputEvent(clock_->NowTicks()); - - base::TimeDelta delta(base::TimeDelta::FromMilliseconds(10)); - clock_->Advance(delta); - - base::TimeDelta prediction_valid_duration; - EXPECT_FALSE(user_model_->IsGestureExpectedSoon(clock_->NowTicks(), - &prediction_valid_duration)); - EXPECT_EQ(base::TimeDelta(), prediction_valid_duration); -} - -TEST_F(UserModelTest, IsGestureExpectedToContinue_NoGesture) { - base::TimeDelta prediction_valid_duration; - EXPECT_FALSE(user_model_->IsGestureExpectedToContinue( - clock_->NowTicks(), &prediction_valid_duration)); - EXPECT_EQ(base::TimeDelta(), prediction_valid_duration); -} - -TEST_F(UserModelTest, IsGestureExpectedToContinue_GestureJustStarted) { - user_model_->DidStartProcessingInputEvent( - blink::WebInputEvent::Type::GestureScrollBegin, clock_->NowTicks()); - base::TimeDelta prediction_valid_duration; - EXPECT_TRUE(user_model_->IsGestureExpectedToContinue( - clock_->NowTicks(), &prediction_valid_duration)); - EXPECT_EQ(base::TimeDelta::FromMilliseconds( - UserModel::kMedianGestureDurationMillis), - prediction_valid_duration); -} - -TEST_F(UserModelTest, IsGestureExpectedToContinue_GestureJustEnded) { - user_model_->DidStartProcessingInputEvent( - blink::WebInputEvent::Type::GestureScrollEnd, clock_->NowTicks()); - base::TimeDelta prediction_valid_duration; - EXPECT_FALSE(user_model_->IsGestureExpectedToContinue( - clock_->NowTicks(), &prediction_valid_duration)); - EXPECT_EQ(base::TimeDelta(), prediction_valid_duration); -} - -TEST_F(UserModelTest, IsGestureExpectedToContinue_ShortlyAfterGestureStarted) { - user_model_->DidStartProcessingInputEvent( - blink::WebInputEvent::Type::GestureScrollBegin, clock_->NowTicks()); - - base::TimeDelta delta(base::TimeDelta::FromMilliseconds(10)); - clock_->Advance(delta); - - base::TimeDelta prediction_valid_duration; - EXPECT_TRUE(user_model_->IsGestureExpectedToContinue( - clock_->NowTicks(), &prediction_valid_duration)); - EXPECT_EQ(base::TimeDelta::FromMilliseconds( - UserModel::kMedianGestureDurationMillis) - - delta, - prediction_valid_duration); -} - -TEST_F(UserModelTest, IsGestureExpectedToContinue_LongAfterGestureStarted) { - user_model_->DidStartProcessingInputEvent( - blink::WebInputEvent::Type::GestureScrollBegin, clock_->NowTicks()); - - base::TimeDelta delta(base::TimeDelta::FromMilliseconds( - UserModel::kMedianGestureDurationMillis * 2)); - clock_->Advance(delta); - - base::TimeDelta prediction_valid_duration; - EXPECT_FALSE(user_model_->IsGestureExpectedToContinue( - clock_->NowTicks(), &prediction_valid_duration)); - EXPECT_EQ(base::TimeDelta(), prediction_valid_duration); -} - -} // namespace scheduler
diff --git a/components/scheduler/renderer/web_frame_scheduler_impl.cc b/components/scheduler/renderer/web_frame_scheduler_impl.cc deleted file mode 100644 index cbf6677..0000000 --- a/components/scheduler/renderer/web_frame_scheduler_impl.cc +++ /dev/null
@@ -1,137 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/renderer/web_frame_scheduler_impl.h" - -#include "base/trace_event/blame_context.h" -#include "components/scheduler/base/real_time_domain.h" -#include "components/scheduler/base/virtual_time_domain.h" -#include "components/scheduler/child/web_task_runner_impl.h" -#include "components/scheduler/renderer/auto_advancing_virtual_time_domain.h" -#include "components/scheduler/renderer/renderer_scheduler_impl.h" -#include "components/scheduler/renderer/web_view_scheduler_impl.h" -#include "third_party/WebKit/public/platform/BlameContext.h" -#include "third_party/WebKit/public/platform/WebString.h" - -namespace scheduler { - -WebFrameSchedulerImpl::WebFrameSchedulerImpl( - RendererSchedulerImpl* renderer_scheduler, - WebViewSchedulerImpl* parent_web_view_scheduler, - base::trace_event::BlameContext* blame_context) - : renderer_scheduler_(renderer_scheduler), - parent_web_view_scheduler_(parent_web_view_scheduler), - blame_context_(blame_context), - frame_visible_(true), - page_visible_(true) {} - -WebFrameSchedulerImpl::~WebFrameSchedulerImpl() { - if (loading_task_queue_) { - loading_task_queue_->UnregisterTaskQueue(); - loading_task_queue_->SetBlameContext(nullptr); - } - - if (timer_task_queue_) { - timer_task_queue_->UnregisterTaskQueue(); - timer_task_queue_->SetBlameContext(nullptr); - } - - if (unthrottled_task_queue_) { - unthrottled_task_queue_->UnregisterTaskQueue(); - unthrottled_task_queue_->SetBlameContext(nullptr); - } - - if (parent_web_view_scheduler_) - parent_web_view_scheduler_->Unregister(this); -} - -void WebFrameSchedulerImpl::DetachFromWebViewScheduler() { - parent_web_view_scheduler_ = nullptr; -} - -void WebFrameSchedulerImpl::setFrameVisible(bool frame_visible) { - frame_visible_ = frame_visible; - // TODO(alexclarke): Do something with this flag. -} - -blink::WebTaskRunner* WebFrameSchedulerImpl::loadingTaskRunner() { - DCHECK(parent_web_view_scheduler_); - if (!loading_web_task_runner_) { - loading_task_queue_ = - renderer_scheduler_->NewLoadingTaskRunner("frame_loading_tq"); - loading_task_queue_->SetBlameContext(blame_context_); - loading_web_task_runner_.reset(new WebTaskRunnerImpl(loading_task_queue_)); - } - return loading_web_task_runner_.get(); -} - -blink::WebTaskRunner* WebFrameSchedulerImpl::timerTaskRunner() { - DCHECK(parent_web_view_scheduler_); - if (!timer_web_task_runner_) { - timer_task_queue_ = - renderer_scheduler_->NewTimerTaskRunner("frame_timer_tq"); - timer_task_queue_->SetBlameContext(blame_context_); - if (!page_visible_) { - renderer_scheduler_->throttling_helper()->IncreaseThrottleRefCount( - timer_task_queue_.get()); - } - timer_web_task_runner_.reset(new WebTaskRunnerImpl(timer_task_queue_)); - } - return timer_web_task_runner_.get(); -} - -blink::WebTaskRunner* WebFrameSchedulerImpl::unthrottledTaskRunner() { - DCHECK(parent_web_view_scheduler_); - if (!unthrottled_web_task_runner_) { - unthrottled_task_queue_ = - renderer_scheduler_->NewUnthrottledTaskRunner("frame_unthrottled_tq"); - unthrottled_task_queue_->SetBlameContext(blame_context_); - unthrottled_web_task_runner_.reset( - new WebTaskRunnerImpl(unthrottled_task_queue_)); - } - return unthrottled_web_task_runner_.get(); -} - -blink::WebViewScheduler* WebFrameSchedulerImpl::webViewScheduler() { - return parent_web_view_scheduler_; -} - -void WebFrameSchedulerImpl::didStartLoading(unsigned long identifier) { - if (parent_web_view_scheduler_) - parent_web_view_scheduler_->DidStartLoading(identifier); -} - -void WebFrameSchedulerImpl::didStopLoading(unsigned long identifier) { - if (parent_web_view_scheduler_) - parent_web_view_scheduler_->DidStopLoading(identifier); -} - -void WebFrameSchedulerImpl::setDocumentParsingInBackground( - bool background_parser_active) { - if (background_parser_active) - parent_web_view_scheduler_->IncrementBackgroundParserCount(); - else - parent_web_view_scheduler_->DecrementBackgroundParserCount(); -} - -void WebFrameSchedulerImpl::setPageVisible(bool page_visible) { - DCHECK(parent_web_view_scheduler_); - if (page_visible_ == page_visible) - return; - - page_visible_ = page_visible; - - if (!timer_web_task_runner_) - return; - - if (page_visible_) { - renderer_scheduler_->throttling_helper()->DecreaseThrottleRefCount( - timer_task_queue_.get()); - } else { - renderer_scheduler_->throttling_helper()->IncreaseThrottleRefCount( - timer_task_queue_.get()); - } -} - -} // namespace scheduler
diff --git a/components/scheduler/renderer/web_frame_scheduler_impl.h b/components/scheduler/renderer/web_frame_scheduler_impl.h deleted file mode 100644 index ecf1f7d..0000000 --- a/components/scheduler/renderer/web_frame_scheduler_impl.h +++ /dev/null
@@ -1,75 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_RENDERER_WEB_FRAME_SCHEDULER_IMPL_H_ -#define COMPONENTS_SCHEDULER_RENDERER_WEB_FRAME_SCHEDULER_IMPL_H_ - -#include <memory> - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/trace_event/trace_event.h" -#include "components/scheduler/base/task_queue.h" -#include "components/scheduler/scheduler_export.h" -#include "third_party/WebKit/public/platform/WebFrameScheduler.h" - -namespace base { -namespace trace_event { -class BlameContext; -} // namespace trace_event -class SingleThreadTaskRunner; -} // namespace base - -namespace scheduler { - -class AutoAdvancingVirtualTimeDomain; -class RendererSchedulerImpl; -class TaskQueue; -class WebTaskRunnerImpl; -class WebViewSchedulerImpl; - -class SCHEDULER_EXPORT WebFrameSchedulerImpl : public blink::WebFrameScheduler { - public: - WebFrameSchedulerImpl(RendererSchedulerImpl* renderer_scheduler, - WebViewSchedulerImpl* parent_web_view_scheduler, - base::trace_event::BlameContext* blame_context); - - ~WebFrameSchedulerImpl() override; - - // blink::WebFrameScheduler implementation: - void setFrameVisible(bool frame_visible) override; - void setPageVisible(bool page_visible) override; - blink::WebTaskRunner* loadingTaskRunner() override; - blink::WebTaskRunner* timerTaskRunner() override; - blink::WebTaskRunner* unthrottledTaskRunner() override; - blink::WebViewScheduler* webViewScheduler() override; - void didStartLoading(unsigned long identifier) override; - void didStopLoading(unsigned long identifier) override; - void setDocumentParsingInBackground(bool background_parser_active) override; - - private: - friend class WebViewSchedulerImpl; - - void DetachFromWebViewScheduler(); - void ApplyPolicyToTimerQueue(); - - scoped_refptr<TaskQueue> loading_task_queue_; - scoped_refptr<TaskQueue> timer_task_queue_; - scoped_refptr<TaskQueue> unthrottled_task_queue_; - std::unique_ptr<WebTaskRunnerImpl> loading_web_task_runner_; - std::unique_ptr<WebTaskRunnerImpl> timer_web_task_runner_; - std::unique_ptr<WebTaskRunnerImpl> unthrottled_web_task_runner_; - RendererSchedulerImpl* renderer_scheduler_; // NOT OWNED - WebViewSchedulerImpl* parent_web_view_scheduler_; // NOT OWNED - base::trace_event::BlameContext* blame_context_; // NOT OWNED - TaskQueue::PumpPolicy virtual_time_pump_policy_; - bool frame_visible_; - bool page_visible_; - - DISALLOW_COPY_AND_ASSIGN(WebFrameSchedulerImpl); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_RENDERER_WEB_FRAME_SCHEDULER_IMPL_H_
diff --git a/components/scheduler/renderer/web_view_scheduler_impl.cc b/components/scheduler/renderer/web_view_scheduler_impl.cc deleted file mode 100644 index 888a34b..0000000 --- a/components/scheduler/renderer/web_view_scheduler_impl.cc +++ /dev/null
@@ -1,165 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/renderer/web_view_scheduler_impl.h" - -#include "base/logging.h" -#include "components/scheduler/base/real_time_domain.h" -#include "components/scheduler/base/virtual_time_domain.h" -#include "components/scheduler/child/scheduler_tqm_delegate.h" -#include "components/scheduler/renderer/auto_advancing_virtual_time_domain.h" -#include "components/scheduler/renderer/renderer_scheduler_impl.h" -#include "components/scheduler/renderer/web_frame_scheduler_impl.h" -#include "third_party/WebKit/public/platform/WebFrameScheduler.h" -#include "third_party/WebKit/public/web/WebConsoleMessage.h" -#include "third_party/WebKit/public/web/WebFrame.h" -#include "third_party/WebKit/public/web/WebView.h" - -namespace scheduler { - -WebViewSchedulerImpl::WebViewSchedulerImpl( - blink::WebView* web_view, - RendererSchedulerImpl* renderer_scheduler, - bool disable_background_timer_throttling) - : web_view_(web_view), - renderer_scheduler_(renderer_scheduler), - virtual_time_policy_(VirtualTimePolicy::ADVANCE), - background_parser_count_(0), - page_visible_(true), - disable_background_timer_throttling_(disable_background_timer_throttling), - allow_virtual_time_to_advance_(true), - have_seen_loading_task_(false), - virtual_time_(false) { - renderer_scheduler->AddWebViewScheduler(this); -} - -WebViewSchedulerImpl::~WebViewSchedulerImpl() { - // TODO(alexclarke): Find out why we can't rely on the web view outliving the - // frame. - for (WebFrameSchedulerImpl* frame_scheduler : frame_schedulers_) { - frame_scheduler->DetachFromWebViewScheduler(); - } - renderer_scheduler_->RemoveWebViewScheduler(this); -} - -void WebViewSchedulerImpl::setPageVisible(bool page_visible) { - if (disable_background_timer_throttling_ || page_visible_ == page_visible) - return; - - page_visible_ = page_visible; - - for (WebFrameSchedulerImpl* frame_scheduler : frame_schedulers_) { - frame_scheduler->setPageVisible(page_visible_); - } -} - -std::unique_ptr<WebFrameSchedulerImpl> -WebViewSchedulerImpl::createWebFrameSchedulerImpl( - base::trace_event::BlameContext* blame_context) { - std::unique_ptr<WebFrameSchedulerImpl> frame_scheduler( - new WebFrameSchedulerImpl(renderer_scheduler_, this, blame_context)); - frame_scheduler->setPageVisible(page_visible_); - frame_schedulers_.insert(frame_scheduler.get()); - return frame_scheduler; -} - -std::unique_ptr<blink::WebFrameScheduler> -WebViewSchedulerImpl::createFrameScheduler(blink::BlameContext* blame_context) { - return createWebFrameSchedulerImpl(blame_context); -} - -void WebViewSchedulerImpl::Unregister(WebFrameSchedulerImpl* frame_scheduler) { - DCHECK(frame_schedulers_.find(frame_scheduler) != frame_schedulers_.end()); - frame_schedulers_.erase(frame_scheduler); -} - -void WebViewSchedulerImpl::AddConsoleWarning(const std::string& message) { - if (!web_view_ || !web_view_->mainFrame()) - return; - blink::WebConsoleMessage console_message( - blink::WebConsoleMessage::LevelWarning, - blink::WebString::fromUTF8(message)); - web_view_->mainFrame()->addMessageToConsole(console_message); -} - -void WebViewSchedulerImpl::enableVirtualTime() { - if (virtual_time_) - return; - - virtual_time_ = true; - renderer_scheduler_->GetVirtualTimeDomain()->SetCanAdvanceVirtualTime( - allow_virtual_time_to_advance_); - - renderer_scheduler_->EnableVirtualTime(); -} - -void WebViewSchedulerImpl::setAllowVirtualTimeToAdvance( - bool allow_virtual_time_to_advance) { - allow_virtual_time_to_advance_ = allow_virtual_time_to_advance; - - if (!virtual_time_) - return; - - renderer_scheduler_->GetVirtualTimeDomain()->SetCanAdvanceVirtualTime( - allow_virtual_time_to_advance); -} - -bool WebViewSchedulerImpl::virtualTimeAllowedToAdvance() const { - return allow_virtual_time_to_advance_; -} - -void WebViewSchedulerImpl::DidStartLoading(unsigned long identifier) { - pending_loads_.insert(identifier); - have_seen_loading_task_ = true; - ApplyVirtualTimePolicy(); -} - -void WebViewSchedulerImpl::DidStopLoading(unsigned long identifier) { - pending_loads_.erase(identifier); - ApplyVirtualTimePolicy(); -} - -void WebViewSchedulerImpl::IncrementBackgroundParserCount() { - background_parser_count_++; - ApplyVirtualTimePolicy(); -} - -void WebViewSchedulerImpl::DecrementBackgroundParserCount() { - background_parser_count_--; - DCHECK_GE(background_parser_count_, 0); - ApplyVirtualTimePolicy(); -} - -void WebViewSchedulerImpl::setVirtualTimePolicy(VirtualTimePolicy policy) { - virtual_time_policy_ = policy; - - switch (virtual_time_policy_) { - case VirtualTimePolicy::ADVANCE: - setAllowVirtualTimeToAdvance(true); - break; - - case VirtualTimePolicy::PAUSE: - setAllowVirtualTimeToAdvance(false); - break; - - case VirtualTimePolicy::DETERMINISTIC_LOADING: - ApplyVirtualTimePolicy(); - break; - } -} - -void WebViewSchedulerImpl::ApplyVirtualTimePolicy() { - if (virtual_time_policy_ != VirtualTimePolicy::DETERMINISTIC_LOADING) { - return; - } - - // We pause virtual time until we've seen a loading task posted, because - // otherwise we could advance virtual time arbitarially far before the - // first load arrives. - setAllowVirtualTimeToAdvance(pending_loads_.size() == 0 && - background_parser_count_ == 0 && - have_seen_loading_task_); -} - -} // namespace scheduler
diff --git a/components/scheduler/renderer/web_view_scheduler_impl.h b/components/scheduler/renderer/web_view_scheduler_impl.h deleted file mode 100644 index 6f69845a..0000000 --- a/components/scheduler/renderer/web_view_scheduler_impl.h +++ /dev/null
@@ -1,82 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_RENDERER_WEB_VIEW_SCHEDULER_IMPL_H_ -#define COMPONENTS_SCHEDULER_RENDERER_WEB_VIEW_SCHEDULER_IMPL_H_ - -#include <memory> -#include <set> -#include <string> - -#include "base/macros.h" -#include "components/scheduler/base/task_queue.h" -#include "components/scheduler/scheduler_export.h" -#include "third_party/WebKit/public/platform/WebViewScheduler.h" - -namespace base { -namespace trace_event { -class BlameContext; -} // namespace trace_event -class SingleThreadTaskRunner; -} // namespace base - -namespace blink { -class WebView; -} // namespace blink - -namespace scheduler { - -class RendererSchedulerImpl; -class WebFrameSchedulerImpl; - -class SCHEDULER_EXPORT WebViewSchedulerImpl : public blink::WebViewScheduler { - public: - WebViewSchedulerImpl(blink::WebView* web_view, - RendererSchedulerImpl* renderer_scheduler, - bool disable_background_timer_throttling); - - ~WebViewSchedulerImpl() override; - - // blink::WebViewScheduler implementation: - void setPageVisible(bool page_visible) override; - std::unique_ptr<blink::WebFrameScheduler> createFrameScheduler( - blink::BlameContext* blame_context) override; - void enableVirtualTime() override; - bool virtualTimeAllowedToAdvance() const override; - void setVirtualTimePolicy(VirtualTimePolicy virtual_time_policy) override; - - // Virtual for testing. - virtual void AddConsoleWarning(const std::string& message); - - std::unique_ptr<WebFrameSchedulerImpl> createWebFrameSchedulerImpl( - base::trace_event::BlameContext* blame_context); - - void DidStartLoading(unsigned long identifier); - void DidStopLoading(unsigned long identifier); - void IncrementBackgroundParserCount(); - void DecrementBackgroundParserCount(); - void Unregister(WebFrameSchedulerImpl* frame_scheduler); - - private: - void setAllowVirtualTimeToAdvance(bool allow_virtual_time_to_advance); - void ApplyVirtualTimePolicy(); - - std::set<WebFrameSchedulerImpl*> frame_schedulers_; - std::set<unsigned long> pending_loads_; - blink::WebView* web_view_; - RendererSchedulerImpl* renderer_scheduler_; - VirtualTimePolicy virtual_time_policy_; - int background_parser_count_; - bool page_visible_; - bool disable_background_timer_throttling_; - bool allow_virtual_time_to_advance_; - bool have_seen_loading_task_; - bool virtual_time_; - - DISALLOW_COPY_AND_ASSIGN(WebViewSchedulerImpl); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_RENDERER_WEB_VIEW_SCHEDULER_IMPL_H_
diff --git a/components/scheduler/renderer/web_view_scheduler_impl_unittest.cc b/components/scheduler/renderer/web_view_scheduler_impl_unittest.cc deleted file mode 100644 index 403df53..0000000 --- a/components/scheduler/renderer/web_view_scheduler_impl_unittest.cc +++ /dev/null
@@ -1,592 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/renderer/web_view_scheduler_impl.h" - -#include <memory> - -#include "base/callback.h" -#include "base/memory/ptr_util.h" -#include "base/test/simple_test_tick_clock.h" -#include "cc/test/ordered_simple_task_runner.h" -#include "components/scheduler/base/test_time_source.h" -#include "components/scheduler/child/scheduler_tqm_delegate_for_test.h" -#include "components/scheduler/renderer/renderer_scheduler_impl.h" -#include "components/scheduler/renderer/web_frame_scheduler_impl.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/WebKit/public/platform/WebTaskRunner.h" -#include "third_party/WebKit/public/platform/WebTraceLocation.h" - -using testing::ElementsAre; -using VirtualTimePolicy = blink::WebViewScheduler::VirtualTimePolicy; - -namespace scheduler { - -class WebViewSchedulerImplTest : public testing::Test { - public: - WebViewSchedulerImplTest() {} - ~WebViewSchedulerImplTest() override {} - - void SetUp() override { - clock_.reset(new base::SimpleTestTickClock()); - clock_->Advance(base::TimeDelta::FromMicroseconds(5000)); - mock_task_runner_ = - make_scoped_refptr(new cc::OrderedSimpleTaskRunner(clock_.get(), true)); - delegate_ = SchedulerTqmDelegateForTest::Create( - mock_task_runner_, base::WrapUnique(new TestTimeSource(clock_.get()))); - scheduler_.reset(new RendererSchedulerImpl(delegate_)); - web_view_scheduler_.reset(new WebViewSchedulerImpl( - nullptr, scheduler_.get(), DisableBackgroundTimerThrottling())); - web_frame_scheduler_ = - web_view_scheduler_->createWebFrameSchedulerImpl(nullptr); - } - - void TearDown() override { - web_frame_scheduler_.reset(); - web_view_scheduler_.reset(); - scheduler_->Shutdown(); - scheduler_.reset(); - } - - virtual bool DisableBackgroundTimerThrottling() const { return false; } - - std::unique_ptr<base::SimpleTestTickClock> clock_; - scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_; - scoped_refptr<SchedulerTqmDelegate> delegate_; - std::unique_ptr<RendererSchedulerImpl> scheduler_; - std::unique_ptr<WebViewSchedulerImpl> web_view_scheduler_; - std::unique_ptr<WebFrameSchedulerImpl> web_frame_scheduler_; -}; - -TEST_F(WebViewSchedulerImplTest, TestDestructionOfFrameSchedulersBefore) { - std::unique_ptr<blink::WebFrameScheduler> frame1( - web_view_scheduler_->createFrameScheduler(nullptr)); - std::unique_ptr<blink::WebFrameScheduler> frame2( - web_view_scheduler_->createFrameScheduler(nullptr)); -} - -TEST_F(WebViewSchedulerImplTest, TestDestructionOfFrameSchedulersAfter) { - std::unique_ptr<blink::WebFrameScheduler> frame1( - web_view_scheduler_->createFrameScheduler(nullptr)); - std::unique_ptr<blink::WebFrameScheduler> frame2( - web_view_scheduler_->createFrameScheduler(nullptr)); - web_view_scheduler_.reset(); -} - -namespace { -class RepeatingTask : public blink::WebTaskRunner::Task { - public: - RepeatingTask(blink::WebTaskRunner* web_task_runner, int* run_count) - : web_task_runner_(web_task_runner), run_count_(run_count) {} - - ~RepeatingTask() override {} - - void run() override { - (*run_count_)++; - web_task_runner_->postDelayedTask( - BLINK_FROM_HERE, new RepeatingTask(web_task_runner_, run_count_), 1.0); - } - - private: - blink::WebTaskRunner* web_task_runner_; // NOT OWNED - int* run_count_; // NOT OWNED -}; -} // namespace - -TEST_F(WebViewSchedulerImplTest, RepeatingTimer_PageInForeground) { - web_view_scheduler_->setPageVisible(true); - - int run_count = 0; - web_frame_scheduler_->timerTaskRunner()->postDelayedTask( - BLINK_FROM_HERE, - new RepeatingTask(web_frame_scheduler_->timerTaskRunner(), &run_count), - 1.0); - - mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1)); - EXPECT_EQ(1000, run_count); -} - -TEST_F(WebViewSchedulerImplTest, RepeatingTimer_PageInBackground) { - web_view_scheduler_->setPageVisible(false); - - int run_count = 0; - web_frame_scheduler_->timerTaskRunner()->postDelayedTask( - BLINK_FROM_HERE, - new RepeatingTask(web_frame_scheduler_->timerTaskRunner(), &run_count), - 1.0); - - mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1)); - EXPECT_EQ(1, run_count); -} - -TEST_F(WebViewSchedulerImplTest, RepeatingLoadingTask_PageInBackground) { - web_view_scheduler_->setPageVisible(false); - - int run_count = 0; - web_frame_scheduler_->loadingTaskRunner()->postDelayedTask( - BLINK_FROM_HERE, - new RepeatingTask(web_frame_scheduler_->loadingTaskRunner(), &run_count), - 1.0); - - mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1)); - EXPECT_EQ(1000, run_count); // Loading tasks should not be throttled -} - -TEST_F(WebViewSchedulerImplTest, RepeatingTimers_OneBackgroundOneForeground) { - std::unique_ptr<WebViewSchedulerImpl> web_view_scheduler2( - new WebViewSchedulerImpl(nullptr, scheduler_.get(), false)); - std::unique_ptr<WebFrameSchedulerImpl> web_frame_scheduler2 = - web_view_scheduler2->createWebFrameSchedulerImpl(nullptr); - - web_view_scheduler_->setPageVisible(true); - web_view_scheduler2->setPageVisible(false); - - int run_count1 = 0; - int run_count2 = 0; - web_frame_scheduler_->timerTaskRunner()->postDelayedTask( - BLINK_FROM_HERE, - new RepeatingTask(web_frame_scheduler_->timerTaskRunner(), &run_count1), - 1.0); - web_frame_scheduler2->timerTaskRunner()->postDelayedTask( - BLINK_FROM_HERE, - new RepeatingTask(web_frame_scheduler2->timerTaskRunner(), &run_count2), - 1.0); - - mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1)); - EXPECT_EQ(1000, run_count1); - EXPECT_EQ(1, run_count2); -} - -namespace { -class VirtualTimeRecorderTask : public blink::WebTaskRunner::Task { - public: - VirtualTimeRecorderTask(base::SimpleTestTickClock* clock, - blink::WebTaskRunner* web_task_runner, - std::vector<base::TimeTicks>* out_real_times, - std::vector<size_t>* out_virtual_times_ms) - : clock_(clock), - web_task_runner_(web_task_runner), - out_real_times_(out_real_times), - out_virtual_times_ms_(out_virtual_times_ms) {} - - ~VirtualTimeRecorderTask() override {} - - void run() override { - out_real_times_->push_back(clock_->NowTicks()); - out_virtual_times_ms_->push_back( - web_task_runner_->monotonicallyIncreasingVirtualTimeSeconds() * 1000.0); - } - - private: - base::SimpleTestTickClock* clock_; // NOT OWNED - blink::WebTaskRunner* web_task_runner_; // NOT OWNED - std::vector<base::TimeTicks>* out_real_times_; // NOT OWNED - std::vector<size_t>* out_virtual_times_ms_; // NOT OWNED -}; -} - -TEST_F(WebViewSchedulerImplTest, VirtualTime_TimerFastForwarding) { - std::vector<base::TimeTicks> real_times; - std::vector<size_t> virtual_times_ms; - base::TimeTicks initial_real_time = scheduler_->tick_clock()->NowTicks(); - size_t initial_virtual_time_ms = - web_frame_scheduler_->timerTaskRunner() - ->monotonicallyIncreasingVirtualTimeSeconds() * - 1000.0; - - web_view_scheduler_->enableVirtualTime(); - - web_frame_scheduler_->timerTaskRunner()->postDelayedTask( - BLINK_FROM_HERE, - new VirtualTimeRecorderTask(clock_.get(), - web_frame_scheduler_->timerTaskRunner(), - &real_times, &virtual_times_ms), - 2.0); - - web_frame_scheduler_->timerTaskRunner()->postDelayedTask( - BLINK_FROM_HERE, - new VirtualTimeRecorderTask(clock_.get(), - web_frame_scheduler_->timerTaskRunner(), - &real_times, &virtual_times_ms), - 20.0); - - web_frame_scheduler_->timerTaskRunner()->postDelayedTask( - BLINK_FROM_HERE, - new VirtualTimeRecorderTask(clock_.get(), - web_frame_scheduler_->timerTaskRunner(), - &real_times, &virtual_times_ms), - 200.0); - - mock_task_runner_->RunUntilIdle(); - - EXPECT_THAT(real_times, ElementsAre(initial_real_time, - initial_real_time, initial_real_time)); - EXPECT_THAT(virtual_times_ms, - ElementsAre(initial_virtual_time_ms + 2, - initial_virtual_time_ms + 20, - initial_virtual_time_ms + 200)); -} - -TEST_F(WebViewSchedulerImplTest, VirtualTime_LoadingTaskFastForwarding) { - std::vector<base::TimeTicks> real_times; - std::vector<size_t> virtual_times_ms; - base::TimeTicks initial_real_time = scheduler_->tick_clock()->NowTicks(); - size_t initial_virtual_time_ms = - web_frame_scheduler_->timerTaskRunner() - ->monotonicallyIncreasingVirtualTimeSeconds() * - 1000.0; - - web_view_scheduler_->enableVirtualTime(); - - web_frame_scheduler_->loadingTaskRunner()->postDelayedTask( - BLINK_FROM_HERE, - new VirtualTimeRecorderTask(clock_.get(), - web_frame_scheduler_->loadingTaskRunner(), - &real_times, &virtual_times_ms), - 2.0); - - web_frame_scheduler_->loadingTaskRunner()->postDelayedTask( - BLINK_FROM_HERE, - new VirtualTimeRecorderTask(clock_.get(), - web_frame_scheduler_->loadingTaskRunner(), - &real_times, &virtual_times_ms), - 20.0); - - web_frame_scheduler_->loadingTaskRunner()->postDelayedTask( - BLINK_FROM_HERE, - new VirtualTimeRecorderTask(clock_.get(), - web_frame_scheduler_->loadingTaskRunner(), - &real_times, &virtual_times_ms), - 200.0); - - mock_task_runner_->RunUntilIdle(); - - EXPECT_THAT(real_times, ElementsAre(initial_real_time, - initial_real_time, initial_real_time)); - EXPECT_THAT(virtual_times_ms, - ElementsAre(initial_virtual_time_ms + 2, - initial_virtual_time_ms + 20, - initial_virtual_time_ms + 200)); -} - -TEST_F(WebViewSchedulerImplTest, - RepeatingTimer_PageInBackground_MeansNothingForVirtualTime) { - web_view_scheduler_->enableVirtualTime(); - web_view_scheduler_->setPageVisible(false); - base::TimeTicks initial_real_time = scheduler_->tick_clock()->NowTicks(); - - int run_count = 0; - web_frame_scheduler_->timerTaskRunner()->postDelayedTask( - BLINK_FROM_HERE, - new RepeatingTask(web_frame_scheduler_->timerTaskRunner(), &run_count), - 1.0); - - mock_task_runner_->RunTasksWhile(mock_task_runner_->TaskRunCountBelow(2000)); - // Virtual time means page visibility is ignored. - EXPECT_EQ(1999, run_count); - - // The global tick clock has not moved, yet we ran a large number of "delayed" - // tasks despite calling setPageVisible(false). - EXPECT_EQ(initial_real_time, scheduler_->tick_clock()->NowTicks()); -} - -namespace { -class RunOrderTask : public blink::WebTaskRunner::Task { - public: - RunOrderTask(int index, std::vector<int>* out_run_order) - : index_(index), - out_run_order_(out_run_order) {} - - ~RunOrderTask() override {} - - void run() override { - out_run_order_->push_back(index_); - } - - private: - int index_; - std::vector<int>* out_run_order_; // NOT OWNED -}; - -class DelayedRunOrderTask : public blink::WebTaskRunner::Task { - public: - DelayedRunOrderTask(int index, blink::WebTaskRunner* task_runner, - std::vector<int>* out_run_order) - : index_(index), - task_runner_(task_runner), - out_run_order_(out_run_order) {} - - ~DelayedRunOrderTask() override {} - - void run() override { - out_run_order_->push_back(index_); - task_runner_->postTask( - BLINK_FROM_HERE, new RunOrderTask(index_ + 1, out_run_order_)); - } - - private: - int index_; - blink::WebTaskRunner* task_runner_; // NOT OWNED - std::vector<int>* out_run_order_; // NOT OWNED -}; -} - -TEST_F(WebViewSchedulerImplTest, VirtualTime_NotAllowedToAdvance) { - std::vector<int> run_order; - - web_view_scheduler_->setVirtualTimePolicy(VirtualTimePolicy::PAUSE); - web_view_scheduler_->enableVirtualTime(); - - web_frame_scheduler_->timerTaskRunner()->postTask( - BLINK_FROM_HERE, new RunOrderTask(0, &run_order)); - - web_frame_scheduler_->timerTaskRunner()->postDelayedTask( - BLINK_FROM_HERE, - new DelayedRunOrderTask(1, web_frame_scheduler_->timerTaskRunner(), - &run_order), - 2.0); - - web_frame_scheduler_->timerTaskRunner()->postDelayedTask( - BLINK_FROM_HERE, - new DelayedRunOrderTask(3, web_frame_scheduler_->timerTaskRunner(), - &run_order), - 4.0); - - mock_task_runner_->RunUntilIdle(); - - // Immediate tasks are allowed to run even if delayed tasks are not. - EXPECT_THAT(run_order, ElementsAre(0)); -} - -TEST_F(WebViewSchedulerImplTest, VirtualTime_AllowedToAdvance) { - std::vector<int> run_order; - - web_view_scheduler_->setVirtualTimePolicy(VirtualTimePolicy::ADVANCE); - web_view_scheduler_->enableVirtualTime(); - - web_frame_scheduler_->timerTaskRunner()->postTask( - BLINK_FROM_HERE, new RunOrderTask(0, &run_order)); - - web_frame_scheduler_->timerTaskRunner()->postDelayedTask( - BLINK_FROM_HERE, - new DelayedRunOrderTask(1, web_frame_scheduler_->timerTaskRunner(), - &run_order), - 2.0); - - web_frame_scheduler_->timerTaskRunner()->postDelayedTask( - BLINK_FROM_HERE, - new DelayedRunOrderTask(3, web_frame_scheduler_->timerTaskRunner(), - &run_order), - 4.0); - - mock_task_runner_->RunUntilIdle(); - - EXPECT_THAT(run_order, ElementsAre(0, 1, 2, 3, 4)); -} - -class WebViewSchedulerImplTestWithDisabledBackgroundTimerThrottling - : public WebViewSchedulerImplTest { - public: - WebViewSchedulerImplTestWithDisabledBackgroundTimerThrottling() {} - ~WebViewSchedulerImplTestWithDisabledBackgroundTimerThrottling() override {} - - bool DisableBackgroundTimerThrottling() const override { return true; } -}; - -TEST_F(WebViewSchedulerImplTestWithDisabledBackgroundTimerThrottling, - RepeatingTimer_PageInBackground) { - web_view_scheduler_->setPageVisible(false); - - int run_count = 0; - web_frame_scheduler_->timerTaskRunner()->postDelayedTask( - BLINK_FROM_HERE, - new RepeatingTask(web_frame_scheduler_->timerTaskRunner(), &run_count), - 1.0); - - mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1)); - EXPECT_EQ(1000, run_count); -} - -TEST_F(WebViewSchedulerImplTest, VirtualTimeSettings_NewWebFrameScheduler) { - std::vector<int> run_order; - - web_view_scheduler_->setVirtualTimePolicy(VirtualTimePolicy::PAUSE); - web_view_scheduler_->enableVirtualTime(); - - std::unique_ptr<WebFrameSchedulerImpl> web_frame_scheduler = - web_view_scheduler_->createWebFrameSchedulerImpl(nullptr); - - web_frame_scheduler->timerTaskRunner()->postDelayedTask( - BLINK_FROM_HERE, new RunOrderTask(1, &run_order), 0.1); - - mock_task_runner_->RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); - - web_view_scheduler_->setVirtualTimePolicy(VirtualTimePolicy::ADVANCE); - mock_task_runner_->RunUntilIdle(); - - EXPECT_THAT(run_order, ElementsAre(1)); -} - -namespace { -class DeleteWebFrameSchedulerTask : public blink::WebTaskRunner::Task { - public: - explicit DeleteWebFrameSchedulerTask(WebViewSchedulerImpl* web_view_scheduler) - : web_frame_scheduler_( - web_view_scheduler->createWebFrameSchedulerImpl(nullptr)) {} - - ~DeleteWebFrameSchedulerTask() override {} - - void run() override { web_frame_scheduler_.reset(); } - - WebFrameSchedulerImpl* web_frame_scheduler() const { - return web_frame_scheduler_.get(); - } - - private: - std::unique_ptr<WebFrameSchedulerImpl> web_frame_scheduler_; -}; - -class DeleteWebViewSchedulerTask : public blink::WebTaskRunner::Task { - public: - explicit DeleteWebViewSchedulerTask(WebViewSchedulerImpl* web_view_scheduler) - : web_view_scheduler_(web_view_scheduler) {} - - ~DeleteWebViewSchedulerTask() override {} - - void run() override { web_view_scheduler_.reset(); } - - private: - std::unique_ptr<WebViewSchedulerImpl> web_view_scheduler_; -}; -} // namespace - -TEST_F(WebViewSchedulerImplTest, DeleteWebFrameSchedulers_InTask) { - for (int i = 0; i < 10; i++) { - DeleteWebFrameSchedulerTask* task = - new DeleteWebFrameSchedulerTask(web_view_scheduler_.get()); - task->web_frame_scheduler()->timerTaskRunner()->postDelayedTask( - BLINK_FROM_HERE, task, 1.0); - } - mock_task_runner_->RunUntilIdle(); -} - -TEST_F(WebViewSchedulerImplTest, DeleteWebViewScheduler_InTask) { - web_frame_scheduler_->timerTaskRunner()->postTask( - BLINK_FROM_HERE, - new DeleteWebViewSchedulerTask(web_view_scheduler_.release())); - mock_task_runner_->RunUntilIdle(); -} - -TEST_F(WebViewSchedulerImplTest, DeleteThrottledQueue_InTask) { - web_view_scheduler_->setPageVisible(false); - - DeleteWebFrameSchedulerTask* delete_frame_task = - new DeleteWebFrameSchedulerTask(web_view_scheduler_.get()); - blink::WebTaskRunner* timer_task_runner = - delete_frame_task->web_frame_scheduler()->timerTaskRunner(); - - int run_count = 0; - timer_task_runner->postDelayedTask( - BLINK_FROM_HERE, new RepeatingTask(timer_task_runner, &run_count), 1.0); - - // Note this will run at time t = 10s since we start at time t = 5000us, and - // it will prevent further tasks from running (i.e. the RepeatingTask) by - // deleting the WebFrameScheduler. - timer_task_runner->postDelayedTask(BLINK_FROM_HERE, delete_frame_task, - 9990.0); - - mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(100)); - EXPECT_EQ(10, run_count); -} - -TEST_F(WebViewSchedulerImplTest, VirtualTimePolicy_DETERMINISTIC_LOADING) { - web_view_scheduler_->setVirtualTimePolicy( - VirtualTimePolicy::DETERMINISTIC_LOADING); - // Initially virtual time is not allowed to advance until we have seen at - // least one load. - EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); - - web_view_scheduler_->DidStartLoading(1u); - EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); - - web_view_scheduler_->DidStartLoading(2u); - EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); - - web_view_scheduler_->DidStopLoading(2u); - EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); - - web_view_scheduler_->DidStartLoading(3u); - EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); - - web_view_scheduler_->DidStopLoading(1u); - EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); - - web_view_scheduler_->DidStopLoading(3u); - EXPECT_TRUE(web_view_scheduler_->virtualTimeAllowedToAdvance()); - - web_view_scheduler_->DidStartLoading(4u); - EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); - - web_view_scheduler_->DidStopLoading(4u); - EXPECT_TRUE(web_view_scheduler_->virtualTimeAllowedToAdvance()); -} - -TEST_F(WebViewSchedulerImplTest, RedundantDidStopLoadingCallsAreHarmless) { - web_view_scheduler_->setVirtualTimePolicy( - VirtualTimePolicy::DETERMINISTIC_LOADING); - - web_view_scheduler_->DidStartLoading(1u); - EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); - - web_view_scheduler_->DidStopLoading(1u); - EXPECT_TRUE(web_view_scheduler_->virtualTimeAllowedToAdvance()); - - web_view_scheduler_->DidStopLoading(1u); - EXPECT_TRUE(web_view_scheduler_->virtualTimeAllowedToAdvance()); - - web_view_scheduler_->DidStopLoading(1u); - EXPECT_TRUE(web_view_scheduler_->virtualTimeAllowedToAdvance()); - - web_view_scheduler_->DidStartLoading(2u); - EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); - - web_view_scheduler_->DidStopLoading(2u); - EXPECT_TRUE(web_view_scheduler_->virtualTimeAllowedToAdvance()); -} - -TEST_F(WebViewSchedulerImplTest, BackgroundParser_DETERMINISTIC_LOADING) { - web_view_scheduler_->setVirtualTimePolicy( - VirtualTimePolicy::DETERMINISTIC_LOADING); - // Initially virtual time is not allowed to advance until we have seen at - // least one load. - EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); - - web_view_scheduler_->IncrementBackgroundParserCount(); - EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); - - web_view_scheduler_->DidStartLoading(1u); - EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); - - web_view_scheduler_->DidStopLoading(1u); - EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); - - web_view_scheduler_->IncrementBackgroundParserCount(); - EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); - - web_view_scheduler_->DecrementBackgroundParserCount(); - EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); - - web_view_scheduler_->DecrementBackgroundParserCount(); - EXPECT_TRUE(web_view_scheduler_->virtualTimeAllowedToAdvance()); - - web_view_scheduler_->IncrementBackgroundParserCount(); - EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); - - web_view_scheduler_->DecrementBackgroundParserCount(); - EXPECT_TRUE(web_view_scheduler_->virtualTimeAllowedToAdvance()); -} - -} // namespace scheduler
diff --git a/components/scheduler/renderer/webthread_impl_for_renderer_scheduler.cc b/components/scheduler/renderer/webthread_impl_for_renderer_scheduler.cc deleted file mode 100644 index b2419b4..0000000 --- a/components/scheduler/renderer/webthread_impl_for_renderer_scheduler.cc +++ /dev/null
@@ -1,59 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/renderer/webthread_impl_for_renderer_scheduler.h" - -#include "components/scheduler/base/task_queue.h" -#include "components/scheduler/child/web_task_runner_impl.h" -#include "components/scheduler/renderer/renderer_scheduler_impl.h" -#include "components/scheduler/renderer/renderer_web_scheduler_impl.h" -#include "third_party/WebKit/public/platform/WebTraceLocation.h" - -namespace scheduler { - -WebThreadImplForRendererScheduler::WebThreadImplForRendererScheduler( - RendererSchedulerImpl* scheduler) - : web_scheduler_(new RendererWebSchedulerImpl(scheduler)), - task_runner_(scheduler->DefaultTaskRunner()), - idle_task_runner_(scheduler->IdleTaskRunner()), - scheduler_(scheduler), - thread_id_(base::PlatformThread::CurrentId()), - web_task_runner_(new WebTaskRunnerImpl(scheduler->DefaultTaskRunner())) {} - -WebThreadImplForRendererScheduler::~WebThreadImplForRendererScheduler() { -} - -blink::PlatformThreadId WebThreadImplForRendererScheduler::threadId() const { - return thread_id_; -} - -blink::WebScheduler* WebThreadImplForRendererScheduler::scheduler() const { - return web_scheduler_.get(); -} - -base::SingleThreadTaskRunner* WebThreadImplForRendererScheduler::GetTaskRunner() - const { - return task_runner_.get(); -} - -SingleThreadIdleTaskRunner* -WebThreadImplForRendererScheduler::GetIdleTaskRunner() const { - return idle_task_runner_.get(); -} - -blink::WebTaskRunner* WebThreadImplForRendererScheduler::getWebTaskRunner() { - return web_task_runner_.get(); -} - -void WebThreadImplForRendererScheduler::AddTaskObserverInternal( - base::MessageLoop::TaskObserver* observer) { - scheduler_->AddTaskObserver(observer); -} - -void WebThreadImplForRendererScheduler::RemoveTaskObserverInternal( - base::MessageLoop::TaskObserver* observer) { - scheduler_->RemoveTaskObserver(observer); -} - -} // namespace scheduler
diff --git a/components/scheduler/renderer/webthread_impl_for_renderer_scheduler.h b/components/scheduler/renderer/webthread_impl_for_renderer_scheduler.h deleted file mode 100644 index 04b0ece2..0000000 --- a/components/scheduler/renderer/webthread_impl_for_renderer_scheduler.h +++ /dev/null
@@ -1,51 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_RENDERER_WEBTHREAD_IMPL_FOR_RENDERER_SCHEDULER_H_ -#define COMPONENTS_SCHEDULER_RENDERER_WEBTHREAD_IMPL_FOR_RENDERER_SCHEDULER_H_ - -#include "base/containers/scoped_ptr_hash_map.h" -#include "components/scheduler/child/webthread_base.h" - -namespace blink { -class WebScheduler; -}; - -namespace scheduler { -class RendererSchedulerImpl; -class WebSchedulerImpl; -class WebTaskRunnerImpl; - -class SCHEDULER_EXPORT WebThreadImplForRendererScheduler - : public WebThreadBase { - public: - explicit WebThreadImplForRendererScheduler(RendererSchedulerImpl* scheduler); - ~WebThreadImplForRendererScheduler() override; - - // blink::WebThread implementation. - blink::WebScheduler* scheduler() const override; - blink::PlatformThreadId threadId() const override; - blink::WebTaskRunner* getWebTaskRunner() override; - - // WebThreadBase implementation. - base::SingleThreadTaskRunner* GetTaskRunner() const override; - SingleThreadIdleTaskRunner* GetIdleTaskRunner() const override; - - private: - void AddTaskObserverInternal( - base::MessageLoop::TaskObserver* observer) override; - void RemoveTaskObserverInternal( - base::MessageLoop::TaskObserver* observer) override; - - std::unique_ptr<WebSchedulerImpl> web_scheduler_; - scoped_refptr<base::SingleThreadTaskRunner> task_runner_; - scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_; - RendererSchedulerImpl* scheduler_; // Not owned. - blink::PlatformThreadId thread_id_; - std::unique_ptr<WebTaskRunnerImpl> web_task_runner_; -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_RENDERER_WEBTHREAD_IMPL_FOR_RENDERER_SCHEDULER_H_
diff --git a/components/scheduler/renderer/webthread_impl_for_renderer_scheduler_unittest.cc b/components/scheduler/renderer/webthread_impl_for_renderer_scheduler_unittest.cc deleted file mode 100644 index 1d29f24..0000000 --- a/components/scheduler/renderer/webthread_impl_for_renderer_scheduler_unittest.cc +++ /dev/null
@@ -1,213 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/renderer/webthread_impl_for_renderer_scheduler.h" - -#include <stddef.h> - -#include "base/location.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/run_loop.h" -#include "base/single_thread_task_runner.h" -#include "base/test/simple_test_tick_clock.h" -#include "components/scheduler/base/test_time_source.h" -#include "components/scheduler/child/scheduler_tqm_delegate_impl.h" -#include "components/scheduler/renderer/renderer_scheduler_impl.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/WebKit/public/platform/WebTaskRunner.h" -#include "third_party/WebKit/public/platform/WebTraceLocation.h" - -namespace scheduler { -namespace { - -const int kWorkBatchSize = 2; - -class MockTask : public blink::WebTaskRunner::Task { - public: - MOCK_METHOD0(run, void()); -}; - -class MockTaskObserver : public blink::WebThread::TaskObserver { - public: - MOCK_METHOD0(willProcessTask, void()); - MOCK_METHOD0(didProcessTask, void()); -}; -} // namespace - -class WebThreadImplForRendererSchedulerTest : public testing::Test { - public: - WebThreadImplForRendererSchedulerTest() {} - - void SetUp() override { - clock_.reset(new base::SimpleTestTickClock()); - clock_->Advance(base::TimeDelta::FromMicroseconds(5000)); - scheduler_.reset(new RendererSchedulerImpl(SchedulerTqmDelegateImpl::Create( - &message_loop_, base::WrapUnique(new TestTimeSource(clock_.get()))))); - default_task_runner_ = scheduler_->DefaultTaskRunner(); - thread_ = scheduler_->CreateMainThread(); - } - - ~WebThreadImplForRendererSchedulerTest() override {} - - void SetWorkBatchSizeForTesting(size_t work_batch_size) { - scheduler_->GetSchedulerHelperForTesting()->SetWorkBatchSizeForTesting( - work_batch_size); - } - - void TearDown() override { scheduler_->Shutdown(); } - - protected: - base::MessageLoop message_loop_; - std::unique_ptr<base::SimpleTestTickClock> clock_; - std::unique_ptr<RendererSchedulerImpl> scheduler_; - scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_; - std::unique_ptr<blink::WebThread> thread_; - - DISALLOW_COPY_AND_ASSIGN(WebThreadImplForRendererSchedulerTest); -}; - -TEST_F(WebThreadImplForRendererSchedulerTest, TestTaskObserver) { - MockTaskObserver observer; - thread_->addTaskObserver(&observer); - std::unique_ptr<MockTask> task(new MockTask()); - - { - testing::InSequence sequence; - EXPECT_CALL(observer, willProcessTask()); - EXPECT_CALL(*task, run()); - EXPECT_CALL(observer, didProcessTask()); - } - - thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(), - task.release()); - base::RunLoop().RunUntilIdle(); - thread_->removeTaskObserver(&observer); -} - -TEST_F(WebThreadImplForRendererSchedulerTest, TestWorkBatchWithOneTask) { - MockTaskObserver observer; - thread_->addTaskObserver(&observer); - std::unique_ptr<MockTask> task(new MockTask()); - - SetWorkBatchSizeForTesting(kWorkBatchSize); - { - testing::InSequence sequence; - EXPECT_CALL(observer, willProcessTask()); - EXPECT_CALL(*task, run()); - EXPECT_CALL(observer, didProcessTask()); - } - - thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(), - task.release()); - base::RunLoop().RunUntilIdle(); - thread_->removeTaskObserver(&observer); -} - -TEST_F(WebThreadImplForRendererSchedulerTest, TestWorkBatchWithTwoTasks) { - MockTaskObserver observer; - thread_->addTaskObserver(&observer); - std::unique_ptr<MockTask> task1(new MockTask()); - std::unique_ptr<MockTask> task2(new MockTask()); - - SetWorkBatchSizeForTesting(kWorkBatchSize); - { - testing::InSequence sequence; - EXPECT_CALL(observer, willProcessTask()); - EXPECT_CALL(*task1, run()); - EXPECT_CALL(observer, didProcessTask()); - - EXPECT_CALL(observer, willProcessTask()); - EXPECT_CALL(*task2, run()); - EXPECT_CALL(observer, didProcessTask()); - } - - thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(), - task1.release()); - thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(), - task2.release()); - base::RunLoop().RunUntilIdle(); - thread_->removeTaskObserver(&observer); -} - -TEST_F(WebThreadImplForRendererSchedulerTest, TestWorkBatchWithThreeTasks) { - MockTaskObserver observer; - thread_->addTaskObserver(&observer); - std::unique_ptr<MockTask> task1(new MockTask()); - std::unique_ptr<MockTask> task2(new MockTask()); - std::unique_ptr<MockTask> task3(new MockTask()); - - SetWorkBatchSizeForTesting(kWorkBatchSize); - { - testing::InSequence sequence; - EXPECT_CALL(observer, willProcessTask()); - EXPECT_CALL(*task1, run()); - EXPECT_CALL(observer, didProcessTask()); - - EXPECT_CALL(observer, willProcessTask()); - EXPECT_CALL(*task2, run()); - EXPECT_CALL(observer, didProcessTask()); - - EXPECT_CALL(observer, willProcessTask()); - EXPECT_CALL(*task3, run()); - EXPECT_CALL(observer, didProcessTask()); - } - - thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(), - task1.release()); - thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(), - task2.release()); - thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(), - task3.release()); - base::RunLoop().RunUntilIdle(); - thread_->removeTaskObserver(&observer); -} - -class ExitRunLoopTask : public blink::WebTaskRunner::Task { - public: - ExitRunLoopTask(base::RunLoop* run_loop) : run_loop_(run_loop) {} - - void run() override { run_loop_->Quit(); } - - private: - base::RunLoop* run_loop_; -}; - -void EnterRunLoop(base::MessageLoop* message_loop, blink::WebThread* thread) { - // Note: WebThreads do not support nested run loops, which is why we use a - // run loop directly. - base::RunLoop run_loop; - thread->getWebTaskRunner()->postTask(blink::WebTraceLocation(), - new ExitRunLoopTask(&run_loop)); - message_loop->SetNestableTasksAllowed(true); - run_loop.Run(); -} - -TEST_F(WebThreadImplForRendererSchedulerTest, TestNestedRunLoop) { - MockTaskObserver observer; - thread_->addTaskObserver(&observer); - - { - testing::InSequence sequence; - - // One callback for EnterRunLoop. - EXPECT_CALL(observer, willProcessTask()); - - // A pair for ExitRunLoopTask. - EXPECT_CALL(observer, willProcessTask()); - EXPECT_CALL(observer, didProcessTask()); - - // A final callback for EnterRunLoop. - EXPECT_CALL(observer, didProcessTask()); - } - - message_loop_.task_runner()->PostTask( - FROM_HERE, base::Bind(&EnterRunLoop, base::Unretained(&message_loop_), - base::Unretained(thread_.get()))); - base::RunLoop().RunUntilIdle(); - thread_->removeTaskObserver(&observer); -} - -} // namespace scheduler
diff --git a/components/scheduler/scheduler.gyp b/components/scheduler/scheduler.gyp deleted file mode 100644 index 5afb0d9..0000000 --- a/components/scheduler/scheduler.gyp +++ /dev/null
@@ -1,68 +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. - -{ - 'variables': { - # This turns on e.g. the filename-based detection of which - # platforms to include source files on (e.g. files ending in - # _mac.h or _mac.cc are only compiled on MacOSX). - 'chromium_code': 1, - }, - 'includes': [ - 'scheduler.gypi', - ], - 'targets': [ - { - # GN version: //components/scheduler:common - 'target_name': 'scheduler_common', - 'type': 'static_library', - 'include_dirs': [ - '../..', - ], - 'sources': [ - '<@(scheduler_common_sources)', - ], - }, - { - # GN version: //components/scheduler:scheduler - 'target_name': 'scheduler', - 'type': '<(component)', - 'dependencies': [ - 'scheduler_common', - '../../base/base.gyp:base', - '../../cc/cc.gyp:cc', - '../../third_party/WebKit/public/blink.gyp:blink', - '../../ui/gfx/gfx.gyp:gfx', - ], - 'include_dirs': [ - '../..', - ], - 'defines': [ - 'SCHEDULER_IMPLEMENTATION', - ], - # Disable c4267 warnings until we fix size_t to int truncations. - 'msvs_disabled_warnings': [ 4267, ], - 'sources': [ - '<@(scheduler_sources)', - ], - 'export_dependent_settings': [ - '../../third_party/WebKit/public/blink.gyp:blink', - ], - }, - { - # GN version: //components/scheduler:test_support - 'target_name': 'scheduler_test_support', - 'type': 'static_library', - 'dependencies': [ - '../../third_party/WebKit/public/blink.gyp:blink', - ], - 'include_dirs': [ - '../..', - ], - 'sources': [ - '<@(scheduler_test_support_sources)', - ], - }, - ], -}
diff --git a/components/scheduler/scheduler.gypi b/components/scheduler/scheduler.gypi deleted file mode 100644 index c157f342..0000000 --- a/components/scheduler/scheduler.gypi +++ /dev/null
@@ -1,109 +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. - -{ - 'variables': { - 'scheduler_common_sources': [ - # Sources list duplicated in GN build. - 'common/scheduler_switches.cc', - 'common/scheduler_switches.h', - ], - 'scheduler_sources': [ - # Sources list duplicated in GN build. - 'base/cancelable_closure_holder.cc', - 'base/cancelable_closure_holder.h', - 'base/lazy_now.cc', - 'base/lazy_now.h', - 'base/long_task_tracker.cc', - 'base/long_task_tracker.h', - 'base/queueing_time_estimator.cc', - 'base/queueing_time_estimator.h', - 'base/real_time_domain.cc', - 'base/real_time_domain.h', - 'base/task_queue.h', - 'base/task_queue_impl.cc', - 'base/task_queue_impl.h', - 'base/task_queue_manager.cc', - 'base/task_queue_manager.h', - 'base/task_queue_manager_delegate.h', - 'base/task_queue_selector.cc', - 'base/task_queue_selector.h', - 'base/task_time_tracker.h', - 'base/time_domain.cc', - 'base/time_domain.h', - 'base/work_queue.cc', - 'base/work_queue.h', - 'base/work_queue_sets.cc', - 'base/work_queue_sets.h', - 'base/pollable_thread_safe_flag.cc', - 'base/pollable_thread_safe_flag.h', - 'base/virtual_time_domain.cc', - 'base/virtual_time_domain.h', - 'base/enqueue_order.h', - 'base/enqueue_order.cc', - 'child/child_scheduler.h', - 'child/compositor_worker_scheduler.cc', - 'child/compositor_worker_scheduler.h', - 'child/idle_helper.cc', - 'child/idle_helper.h', - 'child/scheduler_helper.cc', - 'child/scheduler_helper.h', - 'child/scheduler_tqm_delegate.h', - 'child/scheduler_tqm_delegate_impl.cc', - 'child/scheduler_tqm_delegate_impl.h', - 'child/single_thread_idle_task_runner.cc', - 'child/single_thread_idle_task_runner.h', - 'child/web_scheduler_impl.cc', - 'child/web_scheduler_impl.h', - 'child/web_task_runner_impl.cc', - 'child/web_task_runner_impl.h', - 'child/webthread_base.cc', - 'child/webthread_base.h', - 'child/webthread_impl_for_worker_scheduler.cc', - 'child/webthread_impl_for_worker_scheduler.h', - 'child/worker_scheduler.cc', - 'child/worker_scheduler.h', - 'child/worker_scheduler_impl.cc', - 'child/worker_scheduler_impl.h', - 'renderer/auto_advancing_virtual_time_domain.cc', - 'renderer/auto_advancing_virtual_time_domain.h', - 'renderer/deadline_task_runner.cc', - 'renderer/deadline_task_runner.h', - 'renderer/idle_time_estimator.cc', - 'renderer/idle_time_estimator.h', - 'renderer/renderer_scheduler.cc', - 'renderer/renderer_scheduler.h', - 'renderer/renderer_scheduler_impl.cc', - 'renderer/renderer_scheduler_impl.h', - 'renderer/renderer_web_scheduler_impl.cc', - 'renderer/renderer_web_scheduler_impl.h', - 'renderer/render_widget_scheduling_state.cc', - 'renderer/render_widget_scheduling_state.h', - 'renderer/render_widget_signals.cc', - 'renderer/render_widget_signals.h', - 'renderer/task_cost_estimator.cc', - 'renderer/task_cost_estimator.h', - 'renderer/throttled_time_domain.cc', - 'renderer/throttled_time_domain.h', - 'renderer/throttling_helper.cc', - 'renderer/throttling_helper.h', - 'renderer/web_frame_scheduler_impl.cc', - 'renderer/web_frame_scheduler_impl.h', - 'renderer/web_view_scheduler_impl.cc', - 'renderer/web_view_scheduler_impl.h', - 'renderer/user_model.cc', - 'renderer/user_model.h', - 'renderer/webthread_impl_for_renderer_scheduler.cc', - 'renderer/webthread_impl_for_renderer_scheduler.h', - 'scheduler_export.h', - ], - 'scheduler_test_support_sources': [ - # Sources list duplicated in GN build. - 'test/lazy_scheduler_message_loop_delegate_for_tests.cc', - 'test/lazy_scheduler_message_loop_delegate_for_tests.h', - 'test/renderer_scheduler_test_support.h', - 'test/renderer_scheduler_test_support.cc', - ], - }, -}
diff --git a/components/scheduler/scheduler_export.h b/components/scheduler/scheduler_export.h deleted file mode 100644 index b441b84..0000000 --- a/components/scheduler/scheduler_export.h +++ /dev/null
@@ -1,29 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_SCHEDULER_EXPORT_H_ -#define COMPONENTS_SCHEDULER_SCHEDULER_EXPORT_H_ - -#if defined(COMPONENT_BUILD) -#if defined(WIN32) - -#if defined(SCHEDULER_IMPLEMENTATION) -#define SCHEDULER_EXPORT __declspec(dllexport) -#else -#define SCHEDULER_EXPORT __declspec(dllimport) -#endif // defined(SCHEDULER_IMPLEMENTATION) - -#else // defined(WIN32) -#if defined(SCHEDULER_IMPLEMENTATION) -#define SCHEDULER_EXPORT __attribute__((visibility("default"))) -#else -#define SCHEDULER_EXPORT -#endif -#endif - -#else // defined(COMPONENT_BUILD) -#define SCHEDULER_EXPORT -#endif - -#endif // COMPONENTS_SCHEDULER_SCHEDULER_EXPORT_H_
diff --git a/components/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.cc b/components/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.cc deleted file mode 100644 index 7075754..0000000 --- a/components/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.cc +++ /dev/null
@@ -1,95 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.h" - -#include <utility> - -#include "base/memory/ptr_util.h" -#include "base/time/default_tick_clock.h" - -namespace scheduler { - -// static -scoped_refptr<LazySchedulerMessageLoopDelegateForTests> -LazySchedulerMessageLoopDelegateForTests::Create() { - return make_scoped_refptr(new LazySchedulerMessageLoopDelegateForTests()); -} - -LazySchedulerMessageLoopDelegateForTests:: - LazySchedulerMessageLoopDelegateForTests() - : message_loop_(base::MessageLoop::current()), - thread_id_(base::PlatformThread::CurrentId()), - time_source_(base::WrapUnique(new base::DefaultTickClock())) { - if (message_loop_) - original_task_runner_ = message_loop_->task_runner(); -} - -LazySchedulerMessageLoopDelegateForTests:: - ~LazySchedulerMessageLoopDelegateForTests() { - RestoreDefaultTaskRunner(); -} - -base::MessageLoop* LazySchedulerMessageLoopDelegateForTests::EnsureMessageLoop() - const { - if (message_loop_) - return message_loop_; - DCHECK(RunsTasksOnCurrentThread()); - message_loop_ = base::MessageLoop::current(); - DCHECK(message_loop_); - original_task_runner_ = message_loop_->task_runner(); - if (pending_task_runner_) - message_loop_->SetTaskRunner(std::move(pending_task_runner_)); - return message_loop_; -} - -void LazySchedulerMessageLoopDelegateForTests::SetDefaultTaskRunner( - scoped_refptr<base::SingleThreadTaskRunner> task_runner) { - if (!HasMessageLoop()) { - pending_task_runner_ = std::move(task_runner); - return; - } - message_loop_->SetTaskRunner(std::move(task_runner)); -} - -void LazySchedulerMessageLoopDelegateForTests::RestoreDefaultTaskRunner() { - if (HasMessageLoop() && base::MessageLoop::current() == message_loop_) - message_loop_->SetTaskRunner(original_task_runner_); -} - -bool LazySchedulerMessageLoopDelegateForTests::HasMessageLoop() const { - return message_loop_ != nullptr; -} - -bool LazySchedulerMessageLoopDelegateForTests::PostDelayedTask( - const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) { - EnsureMessageLoop(); - return original_task_runner_->PostDelayedTask(from_here, task, delay); -} - -bool LazySchedulerMessageLoopDelegateForTests::PostNonNestableDelayedTask( - const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) { - EnsureMessageLoop(); - return original_task_runner_->PostNonNestableDelayedTask(from_here, task, - delay); -} - -bool LazySchedulerMessageLoopDelegateForTests::RunsTasksOnCurrentThread() - const { - return thread_id_ == base::PlatformThread::CurrentId(); -} - -bool LazySchedulerMessageLoopDelegateForTests::IsNested() const { - return EnsureMessageLoop()->IsNested(); -} - -base::TimeTicks LazySchedulerMessageLoopDelegateForTests::NowTicks() { - return time_source_->NowTicks(); -} - -} // namespace scheduler
diff --git a/components/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.h b/components/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.h deleted file mode 100644 index 377231f..0000000 --- a/components/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.h +++ /dev/null
@@ -1,62 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SCHEDULER_TEST_LAZY_SCHEDULER_MESSAGE_LOOP_DELEGATE_FOR_TESTS_H_ -#define COMPONENTS_SCHEDULER_TEST_LAZY_SCHEDULER_MESSAGE_LOOP_DELEGATE_FOR_TESTS_H_ - -#include <memory> - -#include "base/macros.h" -#include "base/message_loop/message_loop.h" -#include "base/time/tick_clock.h" -#include "components/scheduler/child/scheduler_tqm_delegate.h" - -namespace scheduler { - -// This class connects the scheduler to a MessageLoop, but unlike -// SchedulerMessageLoopDelegate it allows the message loop to be created lazily -// after the scheduler has been brought up. This is needed in testing scenarios -// where Blink is initialized before a MessageLoop has been created. -// -// TODO(skyostil): Fix the relevant test suites and remove this class -// (crbug.com/495659). -class LazySchedulerMessageLoopDelegateForTests : public SchedulerTqmDelegate { - public: - static scoped_refptr<LazySchedulerMessageLoopDelegateForTests> Create(); - - // SchedulerTqmDelegate implementation - void SetDefaultTaskRunner( - scoped_refptr<base::SingleThreadTaskRunner> task_runner) override; - void RestoreDefaultTaskRunner() override; - bool PostDelayedTask(const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) override; - bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) override; - bool RunsTasksOnCurrentThread() const override; - bool IsNested() const override; - base::TimeTicks NowTicks() override; - - private: - LazySchedulerMessageLoopDelegateForTests(); - ~LazySchedulerMessageLoopDelegateForTests() override; - - bool HasMessageLoop() const; - base::MessageLoop* EnsureMessageLoop() const; - - mutable base::MessageLoop* message_loop_; - base::PlatformThreadId thread_id_; - - // A task runner which hasn't yet been overridden in the message loop. - mutable scoped_refptr<base::SingleThreadTaskRunner> pending_task_runner_; - mutable scoped_refptr<base::SingleThreadTaskRunner> original_task_runner_; - std::unique_ptr<base::TickClock> time_source_; - - DISALLOW_COPY_AND_ASSIGN(LazySchedulerMessageLoopDelegateForTests); -}; - -} // namespace scheduler - -#endif // COMPONENTS_SCHEDULER_TEST_LAZY_SCHEDULER_MESSAGE_LOOP_DELEGATE_FOR_TESTS_H_
diff --git a/components/scheduler/test/renderer_scheduler_test_support.cc b/components/scheduler/test/renderer_scheduler_test_support.cc deleted file mode 100644 index 013485c..0000000 --- a/components/scheduler/test/renderer_scheduler_test_support.cc +++ /dev/null
@@ -1,19 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/scheduler/test/renderer_scheduler_test_support.h" - -#include "components/scheduler/renderer/renderer_scheduler_impl.h" - -namespace scheduler { - -void RunIdleTasksForTesting( - RendererScheduler* scheduler, - const base::Closure& callback) { - RendererSchedulerImpl* scheduler_impl = static_cast<RendererSchedulerImpl*>( - scheduler); - scheduler_impl->RunIdleTasksForTesting(callback); -} - -} // namespace scheduler
diff --git a/components/scheduler/test/renderer_scheduler_test_support.h b/components/scheduler/test/renderer_scheduler_test_support.h deleted file mode 100644 index aee29f1..0000000 --- a/components/scheduler/test/renderer_scheduler_test_support.h +++ /dev/null
@@ -1,14 +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 "base/bind.h" - -namespace scheduler { - -class RendererScheduler; - -extern void RunIdleTasksForTesting(RendererScheduler* scheduler, - const base::Closure& callback); - -}
diff --git a/components/security_state/security_state_model.cc b/components/security_state/security_state_model.cc index 4084402f..9b8288f 100644 --- a/components/security_state/security_state_model.cc +++ b/components/security_state/security_state_model.cc
@@ -93,7 +93,14 @@ const scoped_refptr<net::X509Certificate>& cert, SecurityStateModel::SHA1DeprecationStatus sha1_status, SecurityStateModel::MixedContentStatus mixed_content_status) { - DCHECK(visible_security_state.initialized); + DCHECK(visible_security_state.connection_info_initialized || + visible_security_state.fails_malware_check); + + // Override the connection security information if the website failed the + // browser's malware checks. + if (visible_security_state.fails_malware_check) + return SecurityStateModel::SECURITY_ERROR; + GURL url = visible_security_state.url; switch (visible_security_state.initial_security_level) { case SecurityStateModel::NONE: { @@ -170,8 +177,16 @@ const SecurityStateModel::VisibleSecurityState& visible_security_state, const scoped_refptr<net::X509Certificate>& cert, SecurityStateModel::SecurityInfo* security_info) { - if (!visible_security_state.initialized) { + if (!visible_security_state.connection_info_initialized) { *security_info = SecurityStateModel::SecurityInfo(); + security_info->fails_malware_check = + visible_security_state.fails_malware_check; + if (security_info->fails_malware_check) { + security_info->security_level = + GetSecurityLevelForRequest(visible_security_state, client, cert, + SecurityStateModel::UNKNOWN_SHA1, + SecurityStateModel::UNKNOWN_MIXED_CONTENT); + } return; } security_info->cert_id = visible_security_state.cert_id; @@ -194,6 +209,9 @@ security_info->sct_verify_statuses = visible_security_state.sct_verify_statuses; + security_info->fails_malware_check = + visible_security_state.fails_malware_check; + security_info->security_level = GetSecurityLevelForRequest(visible_security_state, client, cert, security_info->sha1_deprecation_status, @@ -211,6 +229,7 @@ SecurityStateModel::SecurityInfo::SecurityInfo() : security_level(SecurityStateModel::NONE), + fails_malware_check(false), sha1_deprecation_status(SecurityStateModel::NO_DEPRECATED_SHA1), mixed_content_status(SecurityStateModel::NO_MIXED_CONTENT), scheme_is_cryptographic(false), @@ -258,8 +277,9 @@ } SecurityStateModel::VisibleSecurityState::VisibleSecurityState() - : initialized(false), - initial_security_level(SecurityStateModel::NONE), + : initial_security_level(SecurityStateModel::NONE), + fails_malware_check(false), + connection_info_initialized(false), cert_id(0), cert_status(0), connection_status(0), @@ -274,6 +294,7 @@ const SecurityStateModel::VisibleSecurityState& other) const { return (url == other.url && initial_security_level == other.initial_security_level && + fails_malware_check == other.fails_malware_check && cert_id == other.cert_id && cert_status == other.cert_status && connection_status == other.connection_status && security_bits == other.security_bits &&
diff --git a/components/security_state/security_state_model.h b/components/security_state/security_state_model.h index b4ff3e9c..180891df 100644 --- a/components/security_state/security_state_model.h +++ b/components/security_state/security_state_model.h
@@ -34,30 +34,32 @@ // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.security_state // GENERATED_JAVA_CLASS_NAME_OVERRIDE: ConnectionSecurityLevel enum SecurityLevel { - // HTTP/no URL/HTTPS but with insecure passive content on the page + // HTTP/no URL/HTTPS but with insecure passive content on the page. NONE, - // HTTPS with valid EV cert + // HTTPS with valid EV cert. EV_SECURE, - // HTTPS (non-EV) with valid cert + // HTTPS (non-EV) with valid cert. SECURE, - // HTTPS, but with an outdated protocol version + // HTTPS, but with an outdated protocol version. SECURITY_WARNING, // HTTPS, but the certificate verification chain is anchored on a - // certificate that was installed by the system administrator + // certificate that was installed by the system administrator. SECURITY_POLICY_WARNING, - // Attempted HTTPS and failed, page not authenticated, or HTTPS with - // insecure active content on the page + // Attempted HTTPS and failed, page not authenticated, HTTPS with + // insecure active content on the page, malware, phishing, or any other + // serious security issue. SECURITY_ERROR, }; // Describes how the SHA1 deprecation policy applies to an HTTPS // connection. enum SHA1DeprecationStatus { + UNKNOWN_SHA1, // No SHA1 deprecation policy applies. NO_DEPRECATED_SHA1, // The connection used a certificate with a SHA1 signature in the @@ -73,6 +75,7 @@ // Describes the type of mixed content (if any) that a site // displayed/ran. enum MixedContentStatus { + UNKNOWN_MIXED_CONTENT, NO_MIXED_CONTENT, // The site displayed insecure resources (passive mixed content). DISPLAYED_MIXED_CONTENT, @@ -88,6 +91,8 @@ SecurityInfo(); ~SecurityInfo(); SecurityLevel security_level; + // True if the page fails the browser's malware or phishing checks. + bool fails_malware_check; SHA1DeprecationStatus sha1_deprecation_status; MixedContentStatus mixed_content_status; // The verification statuses of the signed certificate timestamps @@ -107,7 +112,6 @@ // True if the protocol version and ciphersuite for the connection // are considered secure. bool is_secure_protocol_and_ciphersuite; - // True if pinning was bypassed due to a local trust anchor. bool pkp_bypassed; }; @@ -119,11 +123,16 @@ VisibleSecurityState(); ~VisibleSecurityState(); bool operator==(const VisibleSecurityState& other) const; - bool initialized; GURL url; // The baseline SecurityLevel describing the page or request before // any SecurityStateModel policies have been applied. SecurityLevel initial_security_level; + // True if the page fails the browser's malware or phishing checks. + bool fails_malware_check; + + // CONNECTION SECURITY FIELDS + // Whether the connection security fields are initialized. + bool connection_info_initialized; // The following fields contain information about the connection // used to load the page or request. int cert_id;
diff --git a/components/security_state/security_state_model_unittest.cc b/components/security_state/security_state_model_unittest.cc index 1a21b85..c2580f9 100644 --- a/components/security_state/security_state_model_unittest.cc +++ b/components/security_state/security_state_model_unittest.cc
@@ -28,7 +28,8 @@ << net::SSL_CONNECTION_VERSION_SHIFT), cert_status_(net::CERT_STATUS_SHA1_SIGNATURE_PRESENT), displayed_mixed_content_(false), - ran_mixed_content_(false) { + ran_mixed_content_(false), + fails_malware_check_(false) { cert_ = net::ImportCertFromFile(net::GetTestCertsDirectory(), "sha1_2016.pem"); } @@ -49,6 +50,9 @@ void SetRanMixedContent(bool ran_mixed_content) { ran_mixed_content_ = ran_mixed_content; } + void set_fails_malware_check(bool fails_malware_check) { + fails_malware_check_ = fails_malware_check; + } void set_initial_security_level( SecurityStateModel::SecurityLevel security_level) { initial_security_level_ = security_level; @@ -57,7 +61,7 @@ // SecurityStateModelClient: void GetVisibleSecurityState( SecurityStateModel::VisibleSecurityState* state) override { - state->initialized = true; + state->connection_info_initialized = true; state->url = GURL(kUrl); state->initial_security_level = initial_security_level_; state->cert_id = 1; @@ -66,6 +70,7 @@ state->security_bits = 256; state->displayed_mixed_content = displayed_mixed_content_; state->ran_mixed_content = ran_mixed_content_; + state->fails_malware_check = fails_malware_check_; } bool RetrieveCert(scoped_refptr<net::X509Certificate>* cert) override { @@ -86,6 +91,7 @@ net::CertStatus cert_status_; bool displayed_mixed_content_; bool ran_mixed_content_; + bool fails_malware_check_; }; // Tests that SHA1-signed certificates expiring in 2016 downgrade the @@ -190,6 +196,37 @@ EXPECT_FALSE(security_info.is_secure_protocol_and_ciphersuite); } +// Tests that the malware/phishing status is set, and it overrides valid HTTPS. +TEST(SecurityStateModelTest, MalwareOverride) { + TestSecurityStateModelClient client; + SecurityStateModel model; + model.SetClient(&client); + // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 from + // http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-4 + const uint16_t ciphersuite = 0xc02f; + client.set_connection_status(net::SSL_CONNECTION_VERSION_TLS1_2 + << net::SSL_CONNECTION_VERSION_SHIFT); + client.SetCipherSuite(ciphersuite); + client.set_fails_malware_check(true); + const SecurityStateModel::SecurityInfo& security_info = + model.GetSecurityInfo(); + EXPECT_TRUE(security_info.fails_malware_check); + EXPECT_EQ(SecurityStateModel::SECURITY_ERROR, security_info.security_level); +} + +// Tests that the malware/phishing status is set, even if other connection info +// is not available. +TEST(SecurityStateModelTest, MalwareWithoutCOnnectionState) { + TestSecurityStateModelClient client; + SecurityStateModel model; + model.SetClient(&client); + client.set_fails_malware_check(true); + const SecurityStateModel::SecurityInfo& security_info = + model.GetSecurityInfo(); + EXPECT_TRUE(security_info.fails_malware_check); + EXPECT_EQ(SecurityStateModel::SECURITY_ERROR, security_info.security_level); +} + } // namespace } // namespace security_state
diff --git a/components/sessions/BUILD.gn b/components/sessions/BUILD.gn index 9ea64abc..dd09990 100644 --- a/components/sessions/BUILD.gn +++ b/components/sessions/BUILD.gn
@@ -162,7 +162,6 @@ "core/serialized_navigation_entry_unittest.cc", "core/session_backend_unittest.cc", "core/session_types_unittest.cc", - "core/tab_restore_service_unittest.cc", "ios/ios_serialized_navigation_builder_unittest.mm", "ios/ios_serialized_navigation_driver_unittest.cc", ]
diff --git a/components/sessions/content/content_live_tab.cc b/components/sessions/content/content_live_tab.cc index f8a7940..7b1dff0 100644 --- a/components/sessions/content/content_live_tab.cc +++ b/components/sessions/content/content_live_tab.cc
@@ -58,8 +58,8 @@ std::unique_ptr<sessions::PlatformSpecificTabData> ContentLiveTab::GetPlatformSpecificTabData() { - return base::WrapUnique( - new sessions::ContentPlatformSpecificTabData(web_contents())); + return base::MakeUnique<sessions::ContentPlatformSpecificTabData>( + web_contents()); } void ContentLiveTab::LoadIfNecessary() {
diff --git a/components/sessions/content/content_platform_specific_tab_data.cc b/components/sessions/content/content_platform_specific_tab_data.cc index 755f5cf..bca42b8 100644 --- a/components/sessions/content/content_platform_specific_tab_data.cc +++ b/components/sessions/content/content_platform_specific_tab_data.cc
@@ -21,11 +21,4 @@ ContentPlatformSpecificTabData::~ContentPlatformSpecificTabData() {} -std::unique_ptr<PlatformSpecificTabData> -ContentPlatformSpecificTabData::Clone() { - ContentPlatformSpecificTabData* clone = new ContentPlatformSpecificTabData(); - clone->session_storage_namespace_ = session_storage_namespace_; - return base::WrapUnique(clone); -} - } // namespace sessions
diff --git a/components/sessions/content/content_platform_specific_tab_data.h b/components/sessions/content/content_platform_specific_tab_data.h index 1ccc6dd7..711a444 100644 --- a/components/sessions/content/content_platform_specific_tab_data.h +++ b/components/sessions/content/content_platform_specific_tab_data.h
@@ -32,9 +32,6 @@ } private: - // PlatformSpecificTabData: - std::unique_ptr<PlatformSpecificTabData> Clone() override; - scoped_refptr<content::SessionStorageNamespace> session_storage_namespace_; };
diff --git a/components/sessions/core/in_memory_tab_restore_service.cc b/components/sessions/core/in_memory_tab_restore_service.cc index 5caf576..902d008 100644 --- a/components/sessions/core/in_memory_tab_restore_service.cc +++ b/components/sessions/core/in_memory_tab_restore_service.cc
@@ -55,8 +55,8 @@ return helper_.RestoreMostRecentEntry(context); } -TabRestoreService::Tab* InMemoryTabRestoreService::RemoveTabEntryById( - SessionID::id_type id) { +std::unique_ptr<TabRestoreService::Tab> +InMemoryTabRestoreService::RemoveTabEntryById(SessionID::id_type id) { return helper_.RemoveTabEntryById(id); }
diff --git a/components/sessions/core/in_memory_tab_restore_service.h b/components/sessions/core/in_memory_tab_restore_service.h index eeb4904..784d6c6 100644 --- a/components/sessions/core/in_memory_tab_restore_service.h +++ b/components/sessions/core/in_memory_tab_restore_service.h
@@ -42,7 +42,7 @@ const Entries& entries() const override; std::vector<LiveTab*> RestoreMostRecentEntry( LiveTabContext* context) override; - Tab* RemoveTabEntryById(SessionID::id_type id) override; + std::unique_ptr<Tab> RemoveTabEntryById(SessionID::id_type id) override; std::vector<LiveTab*> RestoreEntryById( LiveTabContext* context, SessionID::id_type id,
diff --git a/components/sessions/core/persistent_tab_restore_service.cc b/components/sessions/core/persistent_tab_restore_service.cc index 984c3af2..7548edb 100644 --- a/components/sessions/core/persistent_tab_restore_service.cc +++ b/components/sessions/core/persistent_tab_restore_service.cc
@@ -15,8 +15,8 @@ #include "base/files/file_path.h" #include "base/logging.h" #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "base/memory/ref_counted.h" -#include "base/memory/scoped_vector.h" #include "base/stl_util.h" #include "base/task/cancelable_task_tracker.h" #include "base/time/time.h" @@ -35,8 +35,6 @@ typedef int32_t RestoredEntryPayload; -typedef std::map<SessionID::id_type, TabRestoreService::Entry*> IDToEntry; - // Payload used for the start of a tab close. This is the old struct that is // used for backwards compat when it comes to reading the session files. struct SelectedNavigationInTabPayload { @@ -111,6 +109,32 @@ const size_t kMaxEntries = TabRestoreServiceHelper::kMaxEntries; +void RemoveEntryByID( + SessionID::id_type id, + std::vector<std::unique_ptr<TabRestoreService::Entry>>* entries) { + // Look for the entry in the top-level collection. + for (auto it = entries->begin(); it != entries->end(); ++it) { + TabRestoreService::Entry& entry = **it; + // Erase it if it's our target. + if (entry.id == id) { + entries->erase(it); + return; + } + // If this entry is a window, look through its tabs. + if (entry.type == TabRestoreService::WINDOW) { + auto& window = static_cast<TabRestoreService::Window&>(entry); + for (auto it = window.tabs.begin(); it != window.tabs.end(); ++it) { + const TabRestoreService::Tab& tab = **it; + // Erase it if it's our target. + if (tab.id == id) { + window.tabs.erase(it); + return; + } + } + } + } +} + } // namespace // PersistentTabRestoreService::Delegate --------------------------------------- @@ -148,8 +172,9 @@ bool IsLoaded() const; // Creates and add entries to |entries| for each of the windows in |windows|. - static void CreateEntriesFromWindows(std::vector<SessionWindow*>* windows, - std::vector<Entry*>* entries); + static void CreateEntriesFromWindows( + std::vector<SessionWindow*>* windows, + std::vector<std::unique_ptr<Entry>>* entries); void Shutdown(); @@ -189,12 +214,14 @@ void OnGotLastSessionCommands(ScopedVector<SessionCommand> commands); // Populates |loaded_entries| with Entries from |commands|. - void CreateEntriesFromCommands(const std::vector<SessionCommand*>& commands, - std::vector<Entry*>* loaded_entries); + void CreateEntriesFromCommands( + const std::vector<SessionCommand*>& commands, + std::vector<std::unique_ptr<Entry>>* loaded_entries); // Validates all entries in |entries|, deleting any with no navigations. This // also deletes any entries beyond the max number of entries we can hold. - static void ValidateAndDeleteEmptyEntries(std::vector<Entry*>* entries); + static void ValidateAndDeleteEmptyEntries( + std::vector<std::unique_ptr<Entry>>* entries); // Callback from BaseSessionService when we've received the windows from the // previous session. This creates and add entries to |staging_entries_| and @@ -213,13 +240,6 @@ // observers are notified. void LoadStateChanged(); - // If |id_to_entry| contains an entry for |id| the corresponding entry is - // deleted and removed from both |id_to_entry| and |entries|. This is used - // when creating entries from the backend file. - void RemoveEntryByID(SessionID::id_type id, - IDToEntry* id_to_entry, - std::vector<TabRestoreService::Entry*>* entries); - private: // The associated client. TabRestoreServiceClient* client_; @@ -240,7 +260,7 @@ // Results from previously closed tabs/sessions is first added here. When the // results from both us and the session restore service have finished loading // LoadStateChanged is invoked, which adds these entries to entries_. - ScopedVector<Entry> staging_entries_; + std::vector<std::unique_ptr<Entry>> staging_entries_; // Used when loading previous tabs/session and open tabs/session. base::CancelableTaskTracker cancelable_task_tracker_; @@ -287,14 +307,18 @@ DCHECK(static_cast<size_t>(to_write_count) <= entries.size()); std::advance(i, entries.size() - static_cast<int>(to_write_count)); for (; i != entries.rend(); ++i) { - Entry* entry = *i; - if (entry->type == TAB) { - Tab* tab = static_cast<Tab*>(entry); - int selected_index = GetSelectedNavigationIndexToPersist(*tab); - if (selected_index != -1) - ScheduleCommandsForTab(*tab, selected_index); - } else { - ScheduleCommandsForWindow(*static_cast<Window*>(entry)); + Entry& entry = **i; + switch (entry.type) { + case TAB: { + Tab& tab = static_cast<Tab&>(entry); + int selected_index = GetSelectedNavigationIndexToPersist(tab); + if (selected_index != -1) + ScheduleCommandsForTab(tab, selected_index); + break; + } + case WINDOW: + ScheduleCommandsForWindow(static_cast<Window&>(entry)); + break; } entries_written_++; } @@ -380,11 +404,11 @@ // static void PersistentTabRestoreService::Delegate::CreateEntriesFromWindows( std::vector<SessionWindow*>* windows, - std::vector<Entry*>* entries) { + std::vector<std::unique_ptr<Entry>>* entries) { for (size_t i = 0; i < windows->size(); ++i) { std::unique_ptr<Window> window(new Window()); if (ConvertSessionWindowToWindow((*windows)[i], window.get())) - entries->push_back(window.release()); + entries->push_back(std::move(window)); } } @@ -399,7 +423,7 @@ int valid_tab_count = 0; int real_selected_tab = selected_tab; for (size_t i = 0; i < window.tabs.size(); ++i) { - if (GetSelectedNavigationIndexToPersist(window.tabs[i]) != -1) { + if (GetSelectedNavigationIndexToPersist(*window.tabs[i]) != -1) { valid_tab_count++; } else if (static_cast<int>(i) < selected_tab) { real_selected_tab--; @@ -418,9 +442,9 @@ } for (size_t i = 0; i < window.tabs.size(); ++i) { - int selected_index = GetSelectedNavigationIndexToPersist(window.tabs[i]); + int selected_index = GetSelectedNavigationIndexToPersist(*window.tabs[i]); if (selected_index != -1) - ScheduleCommandsForTab(window.tabs[i], selected_index); + ScheduleCommandsForTab(*window.tabs[i], selected_index); } } @@ -555,28 +579,28 @@ void PersistentTabRestoreService::Delegate::OnGotLastSessionCommands( ScopedVector<SessionCommand> commands) { - std::vector<Entry*> entries; + std::vector<std::unique_ptr<TabRestoreService::Entry>> entries; CreateEntriesFromCommands(commands.get(), &entries); // Closed tabs always go to the end. - staging_entries_.insert(staging_entries_.end(), entries.begin(), - entries.end()); + staging_entries_.insert(staging_entries_.end(), + make_move_iterator(entries.begin()), + make_move_iterator(entries.end())); load_state_ |= LOADED_LAST_TABS; LoadStateChanged(); } void PersistentTabRestoreService::Delegate::CreateEntriesFromCommands( const std::vector<SessionCommand*>& commands, - std::vector<Entry*>* loaded_entries) { + std::vector<std::unique_ptr<Entry>>* loaded_entries) { if (tab_restore_service_helper_->entries().size() == kMaxEntries) return; - // Iterate through the commands populating entries and id_to_entry. - ScopedVector<Entry> entries; - IDToEntry id_to_entry; + // Iterate through the commands, populating |entries|. + std::vector<std::unique_ptr<Entry>> entries; // If non-null we're processing the navigations of this tab. - Tab* current_tab = NULL; + Tab* current_tab = nullptr; // If non-null we're processing the tabs of this window. - Window* current_window = NULL; + Window* current_window = nullptr; // If > 0, we've gotten a window command but not all the tabs yet. int pending_window_tabs = 0; for (std::vector<SessionCommand*>::const_iterator i = commands.begin(); @@ -590,13 +614,13 @@ return; } - current_tab = NULL; - current_window = NULL; + current_tab = nullptr; + current_window = nullptr; RestoredEntryPayload payload; if (!command.GetPayload(&payload, sizeof(payload))) return; - RemoveEntryByID(payload, &id_to_entry, &(entries.get())); + RemoveEntryByID(payload, &entries); break; } @@ -630,14 +654,13 @@ return; } - RemoveEntryByID(payload.window_id, &id_to_entry, &(entries.get())); + RemoveEntryByID(payload.window_id, &entries); - current_window = new Window(); + entries.push_back(base::MakeUnique<Window>()); + current_window = static_cast<Window*>(entries.back().get()); current_window->selected_tab_index = payload.selected_tab_index; current_window->timestamp = base::Time::FromInternalValue(payload.timestamp); - entries.push_back(current_window); - id_to_entry[payload.window_id] = current_window; break; } @@ -660,17 +683,16 @@ NOTREACHED(); return; } - current_window->tabs.resize(current_window->tabs.size() + 1); - current_tab = &(current_window->tabs.back()); + current_window->tabs.push_back(base::MakeUnique<Tab>()); + current_tab = current_window->tabs.back().get(); if (--pending_window_tabs == 0) - current_window = NULL; + current_window = nullptr; } else { - RemoveEntryByID(payload.id, &id_to_entry, &(entries.get())); - current_tab = new Tab(); - id_to_entry[payload.id] = current_tab; + RemoveEntryByID(payload.id, &entries); + entries.push_back(base::MakeUnique<Tab>()); + current_tab = static_cast<Tab*>(entries.back().get()); current_tab->timestamp = base::Time::FromInternalValue(payload.timestamp); - entries.push_back(current_tab); } current_tab->current_navigation_index = payload.index; break; @@ -757,40 +779,34 @@ } // If there was corruption some of the entries won't be valid. - ValidateAndDeleteEmptyEntries(&(entries.get())); + ValidateAndDeleteEmptyEntries(&entries); - loaded_entries->swap(entries.get()); + loaded_entries->swap(entries); } // static void PersistentTabRestoreService::Delegate::ValidateAndDeleteEmptyEntries( - std::vector<Entry*>* entries) { - std::vector<Entry*> valid_entries; - std::vector<Entry*> invalid_entries; + std::vector<std::unique_ptr<Entry>>* entries) { + std::vector<std::unique_ptr<Entry>> valid_entries; // Iterate from the back so that we keep the most recently closed entries. - for (std::vector<Entry*>::reverse_iterator i = entries->rbegin(); - i != entries->rend(); ++i) { - if (TabRestoreServiceHelper::ValidateEntry(*i)) - valid_entries.push_back(*i); - else - invalid_entries.push_back(*i); + for (auto i = entries->rbegin(); i != entries->rend(); ++i) { + if (TabRestoreServiceHelper::ValidateEntry(**i)) + valid_entries.push_back(std::move(*i)); } // NOTE: at this point the entries are ordered with newest at the front. entries->swap(valid_entries); - - // Delete the remaining entries. - STLDeleteElements(&invalid_entries); } void PersistentTabRestoreService::Delegate::OnGotPreviousSession( ScopedVector<SessionWindow> windows, SessionID::id_type ignored_active_window) { - std::vector<Entry*> entries; + std::vector<std::unique_ptr<Entry>> entries; CreateEntriesFromWindows(&windows.get(), &entries); // Previous session tabs go first. - staging_entries_.insert(staging_entries_.begin(), entries.begin(), - entries.end()); + staging_entries_.insert(staging_entries_.begin(), + make_move_iterator(entries.begin()), + make_move_iterator(entries.end())); load_state_ |= LOADED_LAST_SESSION; LoadStateChanged(); } @@ -800,8 +816,8 @@ Window* window) { for (size_t i = 0; i < session_window->tabs.size(); ++i) { if (!session_window->tabs[i]->navigations.empty()) { - window->tabs.resize(window->tabs.size() + 1); - Tab& tab = window->tabs.back(); + window->tabs.push_back(base::MakeUnique<Tab>()); + Tab& tab = *window->tabs.back(); tab.pinned = session_window->tabs[i]->pinned; tab.navigations.swap(session_window->tabs[i]->navigations); tab.current_navigation_index = @@ -850,19 +866,14 @@ } // And add them. - for (size_t i = 0; i < staging_entries_.size(); ++i) { - staging_entries_[i]->from_last_session = true; - tab_restore_service_helper_->AddEntry(staging_entries_[i], false, false); + for (auto& staging_entry : staging_entries_) { + staging_entry->from_last_session = true; + tab_restore_service_helper_->AddEntry(std::move(staging_entry), false, + false); } - // AddEntry takes ownership of the entry, need to clear out entries so that - // it doesn't delete them. - staging_entries_.weak_clear(); - - // Make it so we rewrite all the tabs. We need to do this otherwise we won't - // correctly write out the entries when Save is invoked (Save starts from - // the front, not the end and we just added the entries to the end). - entries_to_write_ = staging_entries_.size(); + staging_entries_.clear(); + entries_to_write_ = 0; tab_restore_service_helper_->PruneEntries(); tab_restore_service_helper_->NotifyTabsChanged(); @@ -870,40 +881,6 @@ tab_restore_service_helper_->NotifyLoaded(); } -void PersistentTabRestoreService::Delegate::RemoveEntryByID( - SessionID::id_type id, - IDToEntry* id_to_entry, - std::vector<TabRestoreService::Entry*>* entries) { - // Look for the entry in the map. If it is present, erase it from both - // collections and return. - IDToEntry::iterator i = id_to_entry->find(id); - if (i != id_to_entry->end()) { - entries->erase(std::find(entries->begin(), entries->end(), i->second)); - delete i->second; - id_to_entry->erase(i); - return; - } - - // Otherwise, loop over all items in the map and see if any of the Windows - // have Tabs with the |id|. - for (IDToEntry::iterator i = id_to_entry->begin(); i != id_to_entry->end(); - ++i) { - if (i->second->type == TabRestoreService::WINDOW) { - TabRestoreService::Window* window = - static_cast<TabRestoreService::Window*>(i->second); - std::vector<TabRestoreService::Tab>::iterator j = window->tabs.begin(); - for ( ; j != window->tabs.end(); ++j) { - // If the ID matches one of this window's tabs, remove it from the - // list. - if ((*j).id == id) { - window->tabs.erase(j); - return; - } - } - } - } -} - // PersistentTabRestoreService ------------------------------------------------- PersistentTabRestoreService::PersistentTabRestoreService( @@ -953,8 +930,8 @@ return helper_.RestoreMostRecentEntry(context); } -TabRestoreService::Tab* PersistentTabRestoreService::RemoveTabEntryById( - SessionID::id_type id) { +std::unique_ptr<TabRestoreService::Tab> +PersistentTabRestoreService::RemoveTabEntryById(SessionID::id_type id) { return helper_.RemoveTabEntryById(id); }
diff --git a/components/sessions/core/persistent_tab_restore_service.h b/components/sessions/core/persistent_tab_restore_service.h index ac3ffd4..5e2a165 100644 --- a/components/sessions/core/persistent_tab_restore_service.h +++ b/components/sessions/core/persistent_tab_restore_service.h
@@ -38,7 +38,7 @@ const Entries& entries() const override; std::vector<LiveTab*> RestoreMostRecentEntry( LiveTabContext* context) override; - Tab* RemoveTabEntryById(SessionID::id_type id) override; + std::unique_ptr<Tab> RemoveTabEntryById(SessionID::id_type id) override; std::vector<LiveTab*> RestoreEntryById( LiveTabContext* context, SessionID::id_type id,
diff --git a/components/sessions/core/tab_restore_service.cc b/components/sessions/core/tab_restore_service.cc index c440faf3..8bf3195 100644 --- a/components/sessions/core/tab_restore_service.cc +++ b/components/sessions/core/tab_restore_service.cc
@@ -15,71 +15,14 @@ // ID of the next Entry. static SessionID::id_type next_entry_id = 1; -TabRestoreService::Entry::Entry() - : id(next_entry_id++), - type(TAB), - from_last_session(false) {} +TabRestoreService::Entry::~Entry() = default; +TabRestoreService::Entry::Entry(Type type) : id(next_entry_id++), type(type) {} -TabRestoreService::Entry::Entry(Type type) - : id(next_entry_id++), - type(type), - from_last_session(false) {} +TabRestoreService::Tab::Tab() : Entry(TAB) {} +TabRestoreService::Tab::~Tab() = default; -TabRestoreService::Entry::~Entry() {} - -// Tab ------------------------------------------------------------------------ - -TabRestoreService::Tab::Tab() - : Entry(TAB), - current_navigation_index(-1), - browser_id(0), - tabstrip_index(-1), - pinned(false) { -} - -TabRestoreService::Tab::Tab(const TabRestoreService::Tab& tab) - : Entry(tab), - navigations(tab.navigations), - current_navigation_index(tab.current_navigation_index), - browser_id(tab.browser_id), - tabstrip_index(tab.tabstrip_index), - pinned(tab.pinned), - extension_app_id(tab.extension_app_id), - user_agent_override(tab.user_agent_override) { - if (tab.platform_data) - platform_data = tab.platform_data->Clone(); -} - -TabRestoreService::Tab::~Tab() { -} - -TabRestoreService::Tab& TabRestoreService::Tab::operator=( - const TabRestoreService::Tab& tab) { - id = tab.id; - type = tab.type; - timestamp = tab.timestamp; - from_last_session = tab.from_last_session; - navigations = tab.navigations; - current_navigation_index = tab.current_navigation_index; - browser_id = tab.browser_id; - tabstrip_index = tab.tabstrip_index; - pinned = tab.pinned; - extension_app_id = tab.extension_app_id; - user_agent_override = tab.user_agent_override; - - if (tab.platform_data) - platform_data = tab.platform_data->Clone(); - - return *this; -} - -// Window --------------------------------------------------------------------- - -TabRestoreService::Window::Window() : Entry(WINDOW), selected_tab_index(-1) { -} - -TabRestoreService::Window::~Window() { -} +TabRestoreService::Window::Window() : Entry(WINDOW) {} +TabRestoreService::Window::~Window() = default; // TabRestoreService ----------------------------------------------------------
diff --git a/components/sessions/core/tab_restore_service.h b/components/sessions/core/tab_restore_service.h index f9eda99..8f68b9f0 100644 --- a/components/sessions/core/tab_restore_service.h +++ b/components/sessions/core/tab_restore_service.h
@@ -52,8 +52,6 @@ }; struct SESSIONS_EXPORT Entry { - Entry(); - explicit Entry(Type type); virtual ~Entry(); // Unique id for this entry. The id is guaranteed to be unique for a @@ -61,7 +59,7 @@ SessionID::id_type id; // The type of the entry. - Type type; + const Type type; // The time when the window or tab was closed. base::Time timestamp; @@ -69,34 +67,35 @@ // Is this entry from the last session? This is set to true for entries that // were closed during the last session, and false for entries that were // closed during this session. - bool from_last_session; + bool from_last_session = false; + + protected: + explicit Entry(Type type); + + private: + DISALLOW_COPY_AND_ASSIGN(Entry); }; // Represents a previously open tab. struct SESSIONS_EXPORT Tab : public Entry { Tab(); - Tab(const Tab& tab); ~Tab() override; - Tab& operator=(const Tab& tab); - - bool has_browser() const { return browser_id > 0; } - // The navigations. std::vector<SerializedNavigationEntry> navigations; // Index of the selected navigation in navigations. - int current_navigation_index; + int current_navigation_index = -1; // The ID of the browser to which this tab belonged, so it can be restored // there. May be 0 (an invalid SessionID) when restoring an entire session. - SessionID::id_type browser_id; + SessionID::id_type browser_id = 0; // Index within the tab strip. May be -1 for an unknown index. - int tabstrip_index; + int tabstrip_index = -1; // True if the tab was pinned. - bool pinned; + bool pinned = false; // If non-empty gives the id of the extension for the tab. std::string extension_app_id; @@ -114,16 +113,16 @@ ~Window() override; // The tabs that comprised the window, in order. - std::vector<Tab> tabs; + std::vector<std::unique_ptr<Tab>> tabs; // Index of the selected tab. - int selected_tab_index; + int selected_tab_index = -1; // If an application window, the name of the app. std::string app_name; }; - typedef std::list<Entry*> Entries; + typedef std::list<std::unique_ptr<Entry>> Entries; ~TabRestoreService() override; @@ -160,9 +159,8 @@ virtual std::vector<LiveTab*> RestoreMostRecentEntry( LiveTabContext* context) = 0; - // Removes the Tab with id |id| from the list and returns it; ownership is - // passed to the caller. - virtual Tab* RemoveTabEntryById(SessionID::id_type id) = 0; + // Removes the Tab with id |id| from the list and returns it. + virtual std::unique_ptr<Tab> RemoveTabEntryById(SessionID::id_type id) = 0; // Restores an entry by id. If there is no entry with an id matching |id|, // this does nothing. If |context| is NULL, this creates a new window for the @@ -188,16 +186,9 @@ // A class that is used to associate platform-specific data with // TabRestoreService::Tab. See LiveTab::GetPlatformSpecificTabData(). -// Subclasses of this class must be copyable by implementing the Clone() method -// for usage by the Tab struct, which is itself copyable and assignable. class SESSIONS_EXPORT PlatformSpecificTabData { public: virtual ~PlatformSpecificTabData(); - - private: - friend TabRestoreService::Tab; - - virtual std::unique_ptr<PlatformSpecificTabData> Clone() = 0; }; } // namespace sessions
diff --git a/components/sessions/core/tab_restore_service_helper.cc b/components/sessions/core/tab_restore_service_helper.cc index 73a4c72..cc3f2ae 100644 --- a/components/sessions/core/tab_restore_service_helper.cc +++ b/components/sessions/core/tab_restore_service_helper.cc
@@ -10,6 +10,7 @@ #include <iterator> #include "base/logging.h" +#include "base/memory/ptr_util.h" #include "base/metrics/histogram.h" #include "base/stl_util.h" #include "components/sessions/core/live_tab.h" @@ -52,7 +53,6 @@ TabRestoreServiceHelper::~TabRestoreServiceHelper() { FOR_EACH_OBSERVER(TabRestoreServiceObserver, observer_list_, TabRestoreServiceDestroyed(tab_restore_service_)); - STLDeleteElements(&entries_); } void TabRestoreServiceHelper::AddObserver( @@ -74,48 +74,39 @@ if (closing_contexts_.find(context) != closing_contexts_.end()) return; - std::unique_ptr<Tab> local_tab(new Tab()); + auto local_tab = base::MakeUnique<Tab>(); PopulateTab(local_tab.get(), index, context, live_tab); if (local_tab->navigations.empty()) return; - AddEntry(local_tab.release(), true, true); + AddEntry(std::move(local_tab), true, true); } void TabRestoreServiceHelper::BrowserClosing(LiveTabContext* context) { closing_contexts_.insert(context); - std::unique_ptr<Window> window(new Window()); + auto window = base::MakeUnique<Window>(); window->selected_tab_index = context->GetSelectedIndex(); window->timestamp = TimeNow(); window->app_name = context->GetAppName(); - // Don't use std::vector::resize() because it will push copies of an empty tab - // into the vector, which will give all tabs in a window the same ID. - for (int i = 0; i < context->GetTabCount(); ++i) { - window->tabs.push_back(Tab()); - } - size_t entry_index = 0; for (int tab_index = 0; tab_index < context->GetTabCount(); ++tab_index) { - PopulateTab(&(window->tabs[entry_index]), tab_index, context, + auto tab = base::MakeUnique<Tab>(); + PopulateTab(tab.get(), tab_index, context, context->GetLiveTabAt(tab_index)); - if (window->tabs[entry_index].navigations.empty()) { - window->tabs.erase(window->tabs.begin() + entry_index); - } else { - window->tabs[entry_index].browser_id = context->GetSessionID().id(); - entry_index++; + if (!tab->navigations.empty()) { + tab->browser_id = context->GetSessionID().id(); + window->tabs.push_back(std::move(tab)); } } if (window->tabs.size() == 1 && window->app_name.empty()) { // Short-circuit creating a Window if only 1 tab was present. This fixes - // http://crbug.com/56744. Copy the Tab because it's owned by an object on - // the stack. - AddEntry(new Tab(window->tabs[0]), true, true); + // http://crbug.com/56744. + AddEntry(std::move(window->tabs[0]), true, true); } else if (!window->tabs.empty()) { - window->selected_tab_index = - std::min(static_cast<int>(window->tabs.size() - 1), - window->selected_tab_index); - AddEntry(window.release(), true, true); + window->selected_tab_index = std::min( + static_cast<int>(window->tabs.size() - 1), window->selected_tab_index); + AddEntry(std::move(window), true, true); } } @@ -126,7 +117,7 @@ void TabRestoreServiceHelper::ClearEntries() { if (observer_) observer_->OnClearEntries(); - STLDeleteElements(&entries_); + entries_.clear(); NotifyTabsChanged(); } @@ -141,17 +132,16 @@ return RestoreEntryById(context, entries_.front()->id, UNKNOWN); } -TabRestoreService::Tab* TabRestoreServiceHelper::RemoveTabEntryById( - SessionID::id_type id) { - Entries::iterator it = GetEntryIteratorById(id); +std::unique_ptr<TabRestoreService::Tab> +TabRestoreServiceHelper::RemoveTabEntryById(SessionID::id_type id) { + auto it = GetEntryIteratorById(id); if (it == entries_.end()) return nullptr; - Entry* entry = *it; - if (entry->type != TabRestoreService::TAB) + if ((*it)->type != TabRestoreService::TAB) return nullptr; - Tab* tab = static_cast<Tab*>(entry); + auto tab = std::unique_ptr<Tab>(static_cast<Tab*>(it->release())); entries_.erase(it); return tab; } @@ -169,97 +159,99 @@ if (observer_) observer_->OnRestoreEntryById(id, entry_iterator); restoring_ = true; - Entry* entry = *entry_iterator; + auto& entry = **entry_iterator; // If the entry's ID does not match the ID that is being restored, then the // entry is a window from which a single tab will be restored. - bool restoring_tab_in_window = entry->id != id; - - if (!restoring_tab_in_window) { - entries_.erase(entry_iterator); - entry_iterator = entries_.end(); - } + bool restoring_tab_in_window = entry.id != id; // |context| will be NULL in cases where one isn't already available (eg, // when invoked on Mac OS X with no windows open). In this case, create a // new browser into which we restore the tabs. std::vector<LiveTab*> live_tabs; - if (entry->type == TabRestoreService::TAB) { - Tab* tab = static_cast<Tab*>(entry); - LiveTab* restored_tab = nullptr; - context = RestoreTab(*tab, context, disposition, &restored_tab); - live_tabs.push_back(restored_tab); - context->ShowBrowserWindow(); - } else if (entry->type == TabRestoreService::WINDOW) { - LiveTabContext* current_context = context; - Window* window = static_cast<Window*>(entry); + switch (entry.type) { + case TabRestoreService::TAB: { + auto& tab = static_cast<const Tab&>(entry); + LiveTab* restored_tab = nullptr; + context = RestoreTab(tab, context, disposition, &restored_tab); + live_tabs.push_back(restored_tab); + context->ShowBrowserWindow(); + break; + } + case TabRestoreService::WINDOW: { + LiveTabContext* current_context = context; + auto& window = static_cast<Window&>(entry); - // When restoring a window, either the entire window can be restored, or a - // single tab within it. If the entry's ID matches the one to restore, then - // the entire window will be restored. - if (!restoring_tab_in_window) { - context = client_->CreateLiveTabContext(window->app_name); - for (size_t tab_i = 0; tab_i < window->tabs.size(); ++tab_i) { - const Tab& tab = window->tabs[tab_i]; - LiveTab* restored_tab = context->AddRestoredTab( - tab.navigations, context->GetTabCount(), - tab.current_navigation_index, tab.extension_app_id, - static_cast<int>(tab_i) == window->selected_tab_index, tab.pinned, - tab.from_last_session, tab.platform_data.get(), - tab.user_agent_override); - if (restored_tab) { - restored_tab->LoadIfNecessary(); - client_->OnTabRestored( - tab.navigations.at(tab.current_navigation_index).virtual_url()); - live_tabs.push_back(restored_tab); + // When restoring a window, either the entire window can be restored, or a + // single tab within it. If the entry's ID matches the one to restore, + // then the entire window will be restored. + if (!restoring_tab_in_window) { + context = client_->CreateLiveTabContext(window.app_name); + for (size_t tab_i = 0; tab_i < window.tabs.size(); ++tab_i) { + const Tab& tab = *window.tabs[tab_i]; + LiveTab* restored_tab = context->AddRestoredTab( + tab.navigations, context->GetTabCount(), + tab.current_navigation_index, tab.extension_app_id, + static_cast<int>(tab_i) == window.selected_tab_index, tab.pinned, + tab.from_last_session, tab.platform_data.get(), + tab.user_agent_override); + if (restored_tab) { + restored_tab->LoadIfNecessary(); + client_->OnTabRestored( + tab.navigations.at(tab.current_navigation_index).virtual_url()); + live_tabs.push_back(restored_tab); + } + } + // All the window's tabs had the same former browser_id. + if (auto browser_id = window.tabs[0]->browser_id) { + UpdateTabBrowserIDs(browser_id, context->GetSessionID().id()); + } + } else { + // Restore a single tab from the window. Find the tab that matches the + // ID + // in the window and restore it. + for (auto tab_i = window.tabs.begin(); tab_i != window.tabs.end(); + ++tab_i) { + SessionID::id_type restored_tab_browser_id; + { + const Tab& tab = **tab_i; + if (tab.id != id) + continue; + + restored_tab_browser_id = tab.browser_id; + LiveTab* restored_tab = nullptr; + context = RestoreTab(tab, context, disposition, &restored_tab); + live_tabs.push_back(restored_tab); + window.tabs.erase(tab_i); + } + // If restoring the tab leaves the window with nothing else, delete it + // as well. + if (window.tabs.empty()) { + entries_.erase(entry_iterator); + } else { + // Update the browser ID of the rest of the tabs in the window so if + // any one is restored, it goes into the same window as the tab + // being restored now. + UpdateTabBrowserIDs(restored_tab_browser_id, + context->GetSessionID().id()); + for (auto& tab_j : window.tabs) + tab_j->browser_id = context->GetSessionID().id(); + } + break; } } - // All the window's tabs had the same former browser_id. - if (window->tabs[0].has_browser()) { - UpdateTabBrowserIDs(window->tabs[0].browser_id, - context->GetSessionID().id()); - } - } else { - // Restore a single tab from the window. Find the tab that matches the ID - // in the window and restore it. - for (std::vector<Tab>::iterator tab_i = window->tabs.begin(); - tab_i != window->tabs.end(); ++tab_i) { - const Tab& tab = *tab_i; - if (tab.id != id) - continue; + context->ShowBrowserWindow(); - LiveTab* restored_tab = nullptr; - context = RestoreTab(tab, context, disposition, &restored_tab); - live_tabs.push_back(restored_tab); - window->tabs.erase(tab_i); - // If restoring the tab leaves the window with nothing else, delete it - // as well. - if (window->tabs.empty()) { - entries_.erase(entry_iterator); - delete entry; - } else { - // Update the browser ID of the rest of the tabs in the window so if - // any one is restored, it goes into the same window as the tab - // being restored now. - UpdateTabBrowserIDs(tab.browser_id, context->GetSessionID().id()); - for (Tab& tab_j : window->tabs) - tab_j.browser_id = context->GetSessionID().id(); - } - break; + if (disposition == CURRENT_TAB && current_context && + current_context->GetActiveLiveTab()) { + current_context->CloseTab(); } + break; } - context->ShowBrowserWindow(); - - if (disposition == CURRENT_TAB && current_context && - current_context->GetActiveLiveTab()) { - current_context->CloseTab(); - } - } else { - NOTREACHED(); } if (!restoring_tab_in_window) { - delete entry; + entries_.erase(entry_iterator); } restoring_ = false; @@ -277,18 +269,17 @@ TabRestoreServiceLoaded(tab_restore_service_)); } -void TabRestoreServiceHelper::AddEntry(Entry* entry, +void TabRestoreServiceHelper::AddEntry(std::unique_ptr<Entry> entry, bool notify, bool to_front) { - if (!FilterEntry(entry) || (entries_.size() >= kMaxEntries && !to_front)) { - delete entry; + if (!FilterEntry(*entry) || (entries_.size() >= kMaxEntries && !to_front)) { return; } if (to_front) - entries_.push_front(entry); + entries_.push_front(std::move(entry)); else - entries_.push_back(entry); + entries_.push_back(std::move(entry)); PruneEntries(); @@ -302,19 +293,13 @@ void TabRestoreServiceHelper::PruneEntries() { Entries new_entries; - for (TabRestoreService::Entries::const_iterator iter = entries_.begin(); - iter != entries_.end(); ++iter) { - TabRestoreService::Entry* entry = *iter; - - if (FilterEntry(entry) && - new_entries.size() < kMaxEntries) { - new_entries.push_back(entry); - } else { - delete entry; + for (auto& entry : entries_) { + if (FilterEntry(*entry) && new_entries.size() < kMaxEntries) { + new_entries.push_back(std::move(entry)); } } - entries_ = new_entries; + entries_ = std::move(new_entries); } TabRestoreService::Entries::iterator @@ -326,10 +311,9 @@ // For Window entries, see if the ID matches a tab. If so, report the window // as the Entry. if ((*i)->type == TabRestoreService::WINDOW) { - std::vector<Tab>& tabs = static_cast<Window*>(*i)->tabs; - for (std::vector<Tab>::iterator j = tabs.begin(); - j != tabs.end(); ++j) { - if ((*j).id == id) { + auto& window = static_cast<const Window&>(**i); + for (const auto& tab : window.tabs) { + if (tab->id == id) { return i; } } @@ -339,13 +323,13 @@ } // static -bool TabRestoreServiceHelper::ValidateEntry(Entry* entry) { - if (entry->type == TabRestoreService::TAB) - return ValidateTab(static_cast<Tab*>(entry)); - - if (entry->type == TabRestoreService::WINDOW) - return ValidateWindow(static_cast<Window*>(entry)); - +bool TabRestoreServiceHelper::ValidateEntry(const Entry& entry) { + switch (entry.type) { + case TabRestoreService::TAB: + return ValidateTab(static_cast<const Tab&>(entry)); + case TabRestoreService::WINDOW: + return ValidateWindow(static_cast<const Window&>(entry)); + } NOTREACHED(); return false; } @@ -368,8 +352,6 @@ } tab->timestamp = TimeNow(); tab->current_navigation_index = live_tab->GetCurrentEntryIndex(); - if (tab->current_navigation_index == -1 && entry_count > 0) - tab->current_navigation_index = 0; tab->tabstrip_index = index; tab->extension_app_id = client_->GetExtensionAppIDForTab(live_tab); @@ -397,7 +379,7 @@ tab.extension_app_id, tab.platform_data.get(), tab.user_agent_override); } else { // We only respsect the tab's original browser if there's no disposition. - if (disposition == UNKNOWN && tab.has_browser()) { + if (disposition == UNKNOWN && tab.browser_id) { context = client_->FindLiveTabContextWithID(tab.browser_id); } @@ -410,7 +392,7 @@ tab_index = tab.tabstrip_index; } else { context = client_->CreateLiveTabContext(std::string()); - if (tab.has_browser()) + if (tab.browser_id) UpdateTabBrowserIDs(tab.browser_id, context->GetSessionID().id()); } @@ -436,86 +418,68 @@ return context; } - -bool TabRestoreServiceHelper::ValidateTab(Tab* tab) { - if (tab->navigations.empty()) - return false; - - tab->current_navigation_index = - std::max(0, std::min(tab->current_navigation_index, - static_cast<int>(tab->navigations.size()) - 1)); - - return true; +bool TabRestoreServiceHelper::ValidateTab(const Tab& tab) { + return !tab.navigations.empty() && + static_cast<size_t>(tab.current_navigation_index) < + tab.navigations.size(); } -bool TabRestoreServiceHelper::ValidateWindow(Window* window) { - window->selected_tab_index = - std::max(0, std::min(window->selected_tab_index, - static_cast<int>(window->tabs.size() - 1))); +bool TabRestoreServiceHelper::ValidateWindow(const Window& window) { + if (static_cast<size_t>(window.selected_tab_index) >= window.tabs.size()) { + return false; + } - int i = 0; - for (std::vector<Tab>::iterator tab_i = window->tabs.begin(); - tab_i != window->tabs.end();) { - if (!ValidateTab(&(*tab_i))) { - tab_i = window->tabs.erase(tab_i); - if (i < window->selected_tab_index) - window->selected_tab_index--; - else if (i == window->selected_tab_index) - window->selected_tab_index = 0; - } else { - ++tab_i; - ++i; + for (const auto& tab : window.tabs) { + if (!ValidateTab(*tab)) { + return false; } } - if (window->tabs.empty()) - return false; - return true; } -bool TabRestoreServiceHelper::IsTabInteresting(const Tab* tab) { - if (tab->navigations.empty()) +bool TabRestoreServiceHelper::IsTabInteresting(const Tab& tab) { + if (tab.navigations.empty()) return false; - if (tab->navigations.size() > 1) + if (tab.navigations.size() > 1) return true; - return tab->pinned || - tab->navigations.at(0).virtual_url() != client_->GetNewTabURL(); + return tab.pinned || + tab.navigations.at(0).virtual_url() != client_->GetNewTabURL(); } -bool TabRestoreServiceHelper::IsWindowInteresting(const Window* window) { - if (window->tabs.empty()) +bool TabRestoreServiceHelper::IsWindowInteresting(const Window& window) { + if (window.tabs.empty()) return false; - if (window->tabs.size() > 1) + if (window.tabs.size() > 1) return true; - return IsTabInteresting(&window->tabs[0]); + return IsTabInteresting(*window.tabs[0]); } -bool TabRestoreServiceHelper::FilterEntry(Entry* entry) { +bool TabRestoreServiceHelper::FilterEntry(const Entry& entry) { if (!ValidateEntry(entry)) return false; - if (entry->type == TabRestoreService::TAB) - return IsTabInteresting(static_cast<Tab*>(entry)); - else if (entry->type == TabRestoreService::WINDOW) - return IsWindowInteresting(static_cast<Window*>(entry)); - + switch (entry.type) { + case TabRestoreService::TAB: + return IsTabInteresting(static_cast<const Tab&>(entry)); + case TabRestoreService::WINDOW: + return IsWindowInteresting(static_cast<const Window&>(entry)); + } NOTREACHED(); return false; } void TabRestoreServiceHelper::UpdateTabBrowserIDs(SessionID::id_type old_id, SessionID::id_type new_id) { - for (Entries::iterator i = entries_.begin(); i != entries_.end(); ++i) { - Entry* entry = *i; + for (const auto& entry : entries_) { if (entry->type == TabRestoreService::TAB) { - Tab* tab = static_cast<Tab*>(entry); - if (tab->browser_id == old_id) - tab->browser_id = new_id; + auto& tab = static_cast<Tab&>(*entry); + if (tab.browser_id == old_id) + tab.browser_id = new_id; } } }
diff --git a/components/sessions/core/tab_restore_service_helper.h b/components/sessions/core/tab_restore_service_helper.h index 8a9ed48..b6c3a47 100644 --- a/components/sessions/core/tab_restore_service_helper.h +++ b/components/sessions/core/tab_restore_service_helper.h
@@ -78,7 +78,7 @@ void ClearEntries(); const Entries& entries() const; std::vector<LiveTab*> RestoreMostRecentEntry(LiveTabContext* context); - Tab* RemoveTabEntryById(SessionID::id_type id); + std::unique_ptr<Tab> RemoveTabEntryById(SessionID::id_type id); std::vector<LiveTab*> RestoreEntryById(LiveTabContext* context, SessionID::id_type id, WindowOpenDisposition disposition); @@ -89,11 +89,11 @@ // Notifies observers the service has loaded. void NotifyLoaded(); - // Adds |entry| to the list of entries and takes ownership. If |prune| is true - // |PruneAndNotify| is invoked. If |to_front| is true the entry is added to - // the front, otherwise the back. Normal closes go to the front, but - // tab/window closes from the previous session are added to the back. - void AddEntry(Entry* entry, bool prune, bool to_front); + // Adds |entry| to the list of entries. If |prune| is true |PruneAndNotify| is + // invoked. If |to_front| is true the entry is added to the front, otherwise + // the back. Normal closes go to the front, but tab/window closes from the + // previous session are added to the back. + void AddEntry(std::unique_ptr<Entry> entry, bool prune, bool to_front); // Prunes |entries_| to contain only kMaxEntries, and removes uninteresting // entries. @@ -106,7 +106,7 @@ Entries::iterator GetEntryIteratorById(SessionID::id_type id); // Calls either ValidateTab or ValidateWindow as appropriate. - static bool ValidateEntry(Entry* entry); + static bool ValidateEntry(const Entry& entry); private: friend class PersistentTabRestoreService; @@ -130,23 +130,22 @@ WindowOpenDisposition disposition, LiveTab** live_tab); - // Returns true if |tab| has more than one navigation. If |tab| has more - // than one navigation |tab->current_navigation_index| is constrained based - // on the number of navigations. - static bool ValidateTab(Tab* tab); + // Returns true if |tab| has at least one navigation and + // |tab->current_navigation_index| is in bounds. + static bool ValidateTab(const Tab& tab); // Validates all the tabs in a window, plus the window's active tab index. - static bool ValidateWindow(Window* window); + static bool ValidateWindow(const Window& window); // Returns true if |tab| is one we care about restoring. - bool IsTabInteresting(const Tab* tab); + bool IsTabInteresting(const Tab& tab); // Checks whether |window| is interesting --- if it only contains a single, // uninteresting tab, it's not interesting. - bool IsWindowInteresting(const Window* window); + bool IsWindowInteresting(const Window& window); // Validates and checks |entry| for interesting. - bool FilterEntry(Entry* entry); + bool FilterEntry(const Entry& entry); // Finds tab entries with the old browser_id and sets it to the new one. void UpdateTabBrowserIDs(SessionID::id_type old_id,
diff --git a/components/sessions/core/tab_restore_service_unittest.cc b/components/sessions/core/tab_restore_service_unittest.cc deleted file mode 100644 index a896bfb1..0000000 --- a/components/sessions/core/tab_restore_service_unittest.cc +++ /dev/null
@@ -1,63 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/sessions/core/tab_restore_service.h" - -#include "testing/gtest/include/gtest/gtest.h" - -namespace sessions { - -namespace { - -void PopulateTab(TabRestoreService::Tab* tab) { - tab->timestamp = base::Time::FromDoubleT(100.0); - tab->from_last_session = true; - tab->current_navigation_index = 42; - tab->browser_id = 1; - tab->tabstrip_index = 5; - tab->pinned = true; - tab->extension_app_id = "dummy"; - tab->user_agent_override = "override"; -} - -void TestEntryEquality(TabRestoreService::Entry* expected, - TabRestoreService::Entry* actual) { - EXPECT_EQ(expected->id, actual->id); - EXPECT_EQ(expected->type, actual->type); - EXPECT_EQ(expected->timestamp, actual->timestamp); - EXPECT_EQ(expected->from_last_session, actual->from_last_session); -} - -void TestTabEquality(TabRestoreService::Tab* expected, - TabRestoreService::Tab* actual) { - TestEntryEquality(expected, actual); - EXPECT_EQ(expected->current_navigation_index, - actual->current_navigation_index); - EXPECT_EQ(expected->browser_id, actual->browser_id); - EXPECT_EQ(expected->tabstrip_index, actual->tabstrip_index); - EXPECT_EQ(expected->pinned, actual->pinned); - EXPECT_EQ(expected->extension_app_id, actual->extension_app_id); - EXPECT_EQ(expected->user_agent_override, actual->user_agent_override); -} - -TEST(Tab, CopyConstructor) { - TabRestoreService::Tab tab_to_copy; - PopulateTab(&tab_to_copy); - - TabRestoreService::Tab copied_tab(tab_to_copy); - TestTabEquality(&tab_to_copy, &copied_tab); -} - -TEST(Tab, AssignmentOperator) { - TabRestoreService::Tab tab_to_assign; - PopulateTab(&tab_to_assign); - - TabRestoreService::Tab assigned_tab; - assigned_tab = tab_to_assign; - TestTabEquality(&tab_to_assign, &assigned_tab); -} - -} // namespace - -} // namespace sessions
diff --git a/components/subresource_filter.gypi b/components/subresource_filter.gypi index eecfeb4..06960a39 100644 --- a/components/subresource_filter.gypi +++ b/components/subresource_filter.gypi
@@ -23,6 +23,7 @@ 'subresource_filter/core/browser/ruleset_distributor.h', 'subresource_filter/core/browser/ruleset_service.cc', 'subresource_filter/core/browser/ruleset_service.h', + 'subresource_filter/core/browser/subresource_filter_client.h', 'subresource_filter/core/browser/subresource_filter_constants.cc', 'subresource_filter/core/browser/subresource_filter_constants.h', 'subresource_filter/core/browser/subresource_filter_features.cc',
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc index 1d98723..d8ab2ca51 100644 --- a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc +++ b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc
@@ -6,6 +6,7 @@ #include "components/safe_browsing_db/util.h" #include "components/subresource_filter/content/browser/content_subresource_filter_driver.h" +#include "components/subresource_filter/core/browser/subresource_filter_client.h" #include "components/subresource_filter/core/browser/subresource_filter_features.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" @@ -19,12 +20,13 @@ // static void ContentSubresourceFilterDriverFactory::CreateForWebContents( - content::WebContents* web_contents) { + content::WebContents* web_contents, + std::unique_ptr<SubresourceFilterClient> client) { if (FromWebContents(web_contents)) return; - web_contents->SetUserData( - kWebContentsUserDataKey, - new ContentSubresourceFilterDriverFactory(web_contents)); + web_contents->SetUserData(kWebContentsUserDataKey, + new ContentSubresourceFilterDriverFactory( + web_contents, std::move(client))); } // static @@ -36,8 +38,9 @@ } ContentSubresourceFilterDriverFactory::ContentSubresourceFilterDriverFactory( - content::WebContents* web_contents) - : content::WebContentsObserver(web_contents) { + content::WebContents* web_contents, + std::unique_ptr<SubresourceFilterClient> client) + : content::WebContentsObserver(web_contents), client_(std::move(client)) { content::RenderFrameHost* main_frame_host = web_contents->GetMainFrame(); if (main_frame_host && main_frame_host->IsRenderFrameLive()) CreateDriverForFrameHostIfNeeded(main_frame_host); @@ -63,31 +66,45 @@ safe_browsing::ThreatPatternType threat_type) { if (threat_type != safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS) return; - AddOriginOfURLToActivationSet(url); + AddHostOfURLToActivationSet(url); for (const auto& url : redirect_urls) - AddOriginOfURLToActivationSet(url); + AddHostOfURLToActivationSet(url); } bool ContentSubresourceFilterDriverFactory::ShouldActivateForURL( const GURL& url) const { - return activation_set().find(url.host()) != activation_set().end(); + return whitelisted_set().find(url.host()) == whitelisted_set().end() && + activation_set().find(url.host()) != activation_set().end(); } -void ContentSubresourceFilterDriverFactory::AddOriginOfURLToActivationSet( +void ContentSubresourceFilterDriverFactory::AddHostOfURLToWhitelistSet( const GURL& url) { if (!url.host().empty() && url.SchemeIsHTTPOrHTTPS()) - activate_on_origins_.insert(url.host()); + whitelisted_hosts_.insert(url.host()); +} + +void ContentSubresourceFilterDriverFactory::AddHostOfURLToActivationSet( + const GURL& url) { + if (!url.host().empty() && url.SchemeIsHTTPOrHTTPS()) + activate_on_hosts_.insert(url.host()); } void ContentSubresourceFilterDriverFactory::ActivateForFrameHostIfNeeded( content::RenderFrameHost* render_frame_host, const GURL& url) { if (GetCurrentActivationScope() != ActivationScope::ACTIVATION_LIST || - !ShouldActivateForURL(url)) + !ShouldActivateForURL(url)) { + client_->ToggleNotificationVisibility(false /* visible */); return; - ContentSubresourceFilterDriver* driver = - DriverFromFrameHost(render_frame_host); - driver->ActivateForProvisionalLoad(GetMaximumActivationState()); + } + SendActivationStateAndPromptUser(render_frame_host); +} + +void ContentSubresourceFilterDriverFactory::OnReloadRequested() { + // TODO(melandory): Collect metrics. + const GURL whitelist_url(web_contents()->GetLastCommittedURL()); + AddHostOfURLToWhitelistSet(whitelist_url); + web_contents()->GetController().Reload(true); } void ContentSubresourceFilterDriverFactory::SetDriverForFrameHostForTesting( @@ -123,9 +140,17 @@ bool is_error_page, bool is_iframe_srcdoc) { if (GetCurrentActivationScope() == ActivationScope::ALL_SITES) { - DriverFromFrameHost(render_frame_host) - ->ActivateForProvisionalLoad(GetMaximumActivationState()); + SendActivationStateAndPromptUser(render_frame_host); } } +void ContentSubresourceFilterDriverFactory::SendActivationStateAndPromptUser( + content::RenderFrameHost* render_frame_host) { + ContentSubresourceFilterDriver* driver = + DriverFromFrameHost(render_frame_host); + driver->ActivateForProvisionalLoad(GetMaximumActivationState()); + if (GetMaximumActivationState() == ActivationState::ENABLED) + client_->ToggleNotificationVisibility(true /* visible */); +} + } // namespace subresource_filter
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h index 7890bcd..ceb0d8a 100644 --- a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h +++ b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h
@@ -27,9 +27,10 @@ namespace subresource_filter { -using OriginSet = std::set<std::string>; +using HostSet = std::set<std::string>; class ContentSubresourceFilterDriver; +class SubresourceFilterClient; // Controls the activation of subresource filtering for each page load in a // WebContents and manufactures the per-frame ContentSubresourceFilterDrivers. @@ -40,21 +41,33 @@ : public base::SupportsUserData::Data, public content::WebContentsObserver { public: - static void CreateForWebContents(content::WebContents* web_contents); + static void CreateForWebContents( + content::WebContents* web_contents, + std::unique_ptr<SubresourceFilterClient> client); static ContentSubresourceFilterDriverFactory* FromWebContents( content::WebContents* web_contents); explicit ContentSubresourceFilterDriverFactory( - content::WebContents* web_contents); + content::WebContents* web_contents, + std::unique_ptr<SubresourceFilterClient> client); ~ContentSubresourceFilterDriverFactory() override; void OnMainResourceMatchedSafeBrowsingBlacklist( const GURL& url, const std::vector<GURL>& redirect_urls, safe_browsing::ThreatPatternType threat_type); - const OriginSet& activation_set() const { return activate_on_origins_; } + const HostSet& activation_set() const { return activate_on_hosts_; } bool ShouldActivateForURL(const GURL& url) const; - void AddOriginOfURLToActivationSet(const GURL& url); + const HostSet& whitelisted_set() const { return whitelisted_hosts_; } + void AddHostOfURLToActivationSet(const GURL& url); + + // Whitelists the host of |url|, so that page loads with the main-frame + // document being loaded from this host will be exempted from subresource + // filtering for the lifetime of this WebContents. + void AddHostOfURLToWhitelistSet(const GURL& url); + + // Reloads the page and inserts the url to the whitelist. + void OnReloadRequested(); ContentSubresourceFilterDriver* DriverFromFrameHost( content::RenderFrameHost* render_frame_host); @@ -89,11 +102,18 @@ bool is_error_page, bool is_iframe_srcdoc) override; + // Sends the current maximum activation state to the given |render_frame_host| + // and prompts the user if needed. + void SendActivationStateAndPromptUser( + content::RenderFrameHost* render_frame_host); + static const char kWebContentsUserDataKey[]; FrameHostToOwnedDriverMap frame_drivers_; + std::unique_ptr<SubresourceFilterClient> client_; - OriginSet activate_on_origins_; + HostSet activate_on_hosts_; + HostSet whitelisted_hosts_; DISALLOW_COPY_AND_ASSIGN(ContentSubresourceFilterDriverFactory); };
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc index f19421a..5a45e84 100644 --- a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc +++ b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc
@@ -8,6 +8,7 @@ #include "components/safe_browsing_db/util.h" #include "components/subresource_filter/content/browser/content_subresource_filter_driver.h" #include "components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h" +#include "components/subresource_filter/core/browser/subresource_filter_client.h" #include "components/subresource_filter/core/browser/subresource_filter_features.h" #include "components/subresource_filter/core/browser/subresource_filter_features_test_support.h" #include "content/public/browser/web_contents.h" @@ -32,6 +33,18 @@ DISALLOW_COPY_AND_ASSIGN(MockSubresourceFilterDriver); }; +class MockSubresourceFilterClient : public SubresourceFilterClient { + public: + MockSubresourceFilterClient() {} + + ~MockSubresourceFilterClient() override = default; + + MOCK_METHOD1(ToggleNotificationVisibility, void(bool)); + + private: + DISALLOW_COPY_AND_ASSIGN(MockSubresourceFilterClient); +}; + class ContentSubresourceFilterDriverFactoryTest : public content::RenderViewHostTestHarness { public: @@ -42,10 +55,16 @@ void SetUp() override { RenderViewHostTestHarness::SetUp(); - ContentSubresourceFilterDriverFactory::CreateForWebContents(web_contents()); + client_ = new MockSubresourceFilterClient(); + ContentSubresourceFilterDriverFactory::CreateForWebContents( + web_contents(), base::WrapUnique(client())); driver_ = new MockSubresourceFilterDriver(web_contents()->GetMainFrame()); factory()->SetDriverForFrameHostForTesting(main_rfh(), - base::WrapUnique(driver_)); + base::WrapUnique(driver())); + } + + void SendActivationStateAndPromptUser() { + factory()->SendActivationStateAndPromptUser(main_rfh()); } ContentSubresourceFilterDriverFactory* factory() { @@ -53,10 +72,12 @@ web_contents()); } + MockSubresourceFilterClient* client() { return client_; } MockSubresourceFilterDriver* driver() { return driver_; } private: // Owned by the factory. + MockSubresourceFilterClient* client_; MockSubresourceFilterDriver* driver_; DISALLOW_COPY_AND_ASSIGN(ContentSubresourceFilterDriverFactoryTest); @@ -78,6 +99,7 @@ GURL("https://example.com/soceng?q=engsoc"), std::vector<GURL>(), safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS); EXPECT_EQ(1U, factory()->activation_set().size()); + EXPECT_TRUE(factory()->ShouldActivateForURL(GURL("https://example.com"))); EXPECT_TRUE(factory()->ShouldActivateForURL(GURL("http://example.com"))); EXPECT_TRUE( @@ -86,6 +108,10 @@ factory()->ShouldActivateForURL(GURL("https://example.com/42?q=42!"))); EXPECT_TRUE( factory()->ShouldActivateForURL(GURL("http://example.com/awesomepath"))); + const GURL whitelisted("http://example.com/page?q=whitelisted"); + EXPECT_TRUE(factory()->ShouldActivateForURL(whitelisted)); + factory()->AddHostOfURLToWhitelistSet(whitelisted); + EXPECT_FALSE(factory()->ShouldActivateForURL(whitelisted)); } TEST_F(ContentSubresourceFilterDriverFactoryTest, SocEngHitWithRedirects) { @@ -98,6 +124,7 @@ safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS); EXPECT_EQ(4U, factory()->activation_set().size()); EXPECT_TRUE(factory()->ShouldActivateForURL(GURL("https://example.com"))); + for (const auto& redirect : redirects) { EXPECT_TRUE(factory()->ShouldActivateForURL(redirect)); EXPECT_TRUE(factory()->ShouldActivateForURL(redirect.GetWithEmptyPath())); @@ -106,6 +133,10 @@ EXPECT_TRUE(factory()->ShouldActivateForURL( GURL("http://" + redirect.host() + "/path?q=q"))); } + const GURL whitelisted("http://example.com/page?q=42"); + EXPECT_TRUE(factory()->ShouldActivateForURL(whitelisted)); + factory()->AddHostOfURLToWhitelistSet(whitelisted); + EXPECT_FALSE(factory()->ShouldActivateForURL(whitelisted)); } TEST_F(ContentSubresourceFilterDriverFactoryTest, @@ -115,17 +146,21 @@ base::FeatureList::OVERRIDE_DISABLE_FEATURE, kActivationStateEnabled, kActivationScopeNoSites); EXPECT_CALL(*driver(), ActivateForProvisionalLoad(::testing::_)).Times(0); + EXPECT_CALL(*client(), ToggleNotificationVisibility(false)).Times(1); factory()->ActivateForFrameHostIfNeeded(main_rfh(), GURL("https://test.com")); ::testing::Mock::VerifyAndClearExpectations(driver()); + ::testing::Mock::VerifyAndClearExpectations(client()); factory()->OnMainResourceMatchedSafeBrowsingBlacklist( GURL("https://example.com/soceng?q=engsoc"), std::vector<GURL>(), safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS); EXPECT_CALL(*driver(), ActivateForProvisionalLoad(::testing::_)).Times(0); + EXPECT_CALL(*client(), ToggleNotificationVisibility(false)).Times(1); factory()->ActivateForFrameHostIfNeeded(main_rfh(), GURL("https://example.com")); ::testing::Mock::VerifyAndClearExpectations(driver()); + ::testing::Mock::VerifyAndClearExpectations(client()); } TEST_F(ContentSubresourceFilterDriverFactoryTest, ActivateForFrameHostNeeded) { @@ -139,13 +174,16 @@ safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS); EXPECT_CALL(*driver(), ActivateForProvisionalLoad(::testing::_)).Times(0); + EXPECT_CALL(*client(), ToggleNotificationVisibility(false)).Times(1); factory()->ActivateForFrameHostIfNeeded(main_rfh(), GURL("https://test.com")); ::testing::Mock::VerifyAndClearExpectations(driver()); EXPECT_CALL(*driver(), ActivateForProvisionalLoad(::testing::_)).Times(1); + EXPECT_CALL(*client(), ToggleNotificationVisibility(true)).Times(1); factory()->ActivateForFrameHostIfNeeded(main_rfh(), GURL("https://example.com")); ::testing::Mock::VerifyAndClearExpectations(driver()); + ::testing::Mock::VerifyAndClearExpectations(client()); } TEST_P(ContentSubresourceFilterDriverFactoryThreatTypeTest, NonSocEngHit) { @@ -173,6 +211,39 @@ } }; +TEST_F(ContentSubresourceFilterDriverFactoryTest, + ActivationPromptNotShownWhenExperimentDisabled) { + base::FieldTrialList field_trial_list(nullptr); + testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle( + base::FeatureList::OVERRIDE_DISABLE_FEATURE, kActivationStateEnabled, + kActivationScopeActivationList); + EXPECT_CALL(*client(), ToggleNotificationVisibility(::testing::_)).Times(0); + SendActivationStateAndPromptUser(); + ::testing::Mock::VerifyAndClearExpectations(client()); +} + +TEST_F(ContentSubresourceFilterDriverFactoryTest, + ActivationPromptNotShownWhenExperimentDryRun) { + base::FieldTrialList field_trial_list(nullptr); + testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle( + base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationStateDryRun, + kActivationScopeActivationList); + EXPECT_CALL(*client(), ToggleNotificationVisibility(::testing::_)).Times(0); + SendActivationStateAndPromptUser(); + ::testing::Mock::VerifyAndClearExpectations(client()); +} + +TEST_F(ContentSubresourceFilterDriverFactoryTest, + ActivationPromptShownWhenExperimentEnabled) { + base::FieldTrialList field_trial_list(nullptr); + testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle( + base::FeatureList::OVERRIDE_ENABLE_FEATURE, kActivationStateEnabled, + kActivationScopeActivationList); + EXPECT_CALL(*client(), ToggleNotificationVisibility(true)).Times(1); + SendActivationStateAndPromptUser(); + ::testing::Mock::VerifyAndClearExpectations(client()); +} + INSTANTIATE_TEST_CASE_P( NoSonEngHit, ContentSubresourceFilterDriverFactoryThreatTypeTest,
diff --git a/components/subresource_filter/content/browser/subresource_filter_navigation_throttle.cc b/components/subresource_filter/content/browser/subresource_filter_navigation_throttle.cc index 24ef82d..7e0fa01 100644 --- a/components/subresource_filter/content/browser/subresource_filter_navigation_throttle.cc +++ b/components/subresource_filter/content/browser/subresource_filter_navigation_throttle.cc
@@ -39,8 +39,7 @@ // the information about the activation set. But if the Safe Browsing check in // asynchronous, then we night miss some redirects. if (driver_factory->ShouldActivateForURL(initial_url_)) { - driver_factory->AddOriginOfURLToActivationSet( - navigation_handle()->GetURL()); + driver_factory->AddHostOfURLToActivationSet(navigation_handle()->GetURL()); } return NavigationThrottle::PROCEED;
diff --git a/components/subresource_filter/content/browser/subresource_filter_navigation_throttle_unittests.cc b/components/subresource_filter/content/browser/subresource_filter_navigation_throttle_unittests.cc index 547abb3..a3d3222 100644 --- a/components/subresource_filter/content/browser/subresource_filter_navigation_throttle_unittests.cc +++ b/components/subresource_filter/content/browser/subresource_filter_navigation_throttle_unittests.cc
@@ -12,6 +12,7 @@ #include "components/safe_browsing_db/util.h" #include "components/subresource_filter/content/browser/content_subresource_filter_driver.h" #include "components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h" +#include "components/subresource_filter/core/browser/subresource_filter_client.h" #include "components/subresource_filter/core/browser/subresource_filter_features.h" #include "components/subresource_filter/core/browser/subresource_filter_features_test_support.h" #include "content/public/browser/navigation_handle.h" @@ -49,6 +50,18 @@ DISALLOW_COPY_AND_ASSIGN(MockSubresourceFilterDriver); }; +class MockSubresourceFilterClient : public SubresourceFilterClient { + public: + MockSubresourceFilterClient() {} + + ~MockSubresourceFilterClient() override = default; + + MOCK_METHOD1(ToggleNotificationVisibility, void(bool)); + + private: + DISALLOW_COPY_AND_ASSIGN(MockSubresourceFilterClient); +}; + class SubresourceFilterNavigationThrottleTest : public content::RenderViewHostTestHarness { public: @@ -57,7 +70,8 @@ // content::RenderViewHostTestHarness: void SetUp() override { RenderViewHostTestHarness::SetUp(); - ContentSubresourceFilterDriverFactory::CreateForWebContents(web_contents()); + ContentSubresourceFilterDriverFactory::CreateForWebContents( + web_contents(), base::WrapUnique(new MockSubresourceFilterClient())); driver_ = new MockSubresourceFilterDriver(main_rfh()); factory()->SetDriverForFrameHostForTesting(main_rfh(),
diff --git a/components/subresource_filter/content/renderer/BUILD.gn b/components/subresource_filter/content/renderer/BUILD.gn index 9699c2e..e50e46d 100644 --- a/components/subresource_filter/content/renderer/BUILD.gn +++ b/components/subresource_filter/content/renderer/BUILD.gn
@@ -35,7 +35,6 @@ "//components/subresource_filter/content/common", "//components/subresource_filter/core/common", "//components/subresource_filter/core/common:test_support", - "//components/test_runner", "//content/public/renderer", "//testing/gmock", "//testing/gtest",
diff --git a/components/subresource_filter/content/renderer/document_subresource_filter_unittest.cc b/components/subresource_filter/content/renderer/document_subresource_filter_unittest.cc index c02acb1..f54f77da 100644 --- a/components/subresource_filter/content/renderer/document_subresource_filter_unittest.cc +++ b/components/subresource_filter/content/renderer/document_subresource_filter_unittest.cc
@@ -10,7 +10,6 @@ #include "base/strings/string_piece.h" #include "components/subresource_filter/core/common/memory_mapped_ruleset.h" #include "components/subresource_filter/core/common/test_ruleset_creator.h" -#include "components/test_runner/test_common.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/WebKit/public/platform/WebURL.h" #include "third_party/WebKit/public/platform/WebURLRequest.h" @@ -28,7 +27,7 @@ class DocumentSubresourceFilterTest : public ::testing::Test { public: - DocumentSubresourceFilterTest() { test_runner::EnsureBlinkInitialized(); } + DocumentSubresourceFilterTest() {} protected: void SetUp() override {
diff --git a/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc b/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc index c6f34e2..9ac2656 100644 --- a/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc +++ b/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc
@@ -14,7 +14,6 @@ #include "components/subresource_filter/content/common/subresource_filter_messages.h" #include "components/subresource_filter/content/renderer/ruleset_dealer.h" #include "components/subresource_filter/core/common/test_ruleset_creator.h" -#include "components/test_runner/test_common.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/WebKit/public/platform/WebDocumentSubresourceFilter.h" @@ -70,7 +69,7 @@ class SubresourceFilterAgentTest : public ::testing::Test { public: - SubresourceFilterAgentTest() { test_runner::EnsureBlinkInitialized(); } + SubresourceFilterAgentTest() {} protected: void SetUp() override {
diff --git a/components/subresource_filter/core/browser/BUILD.gn b/components/subresource_filter/core/browser/BUILD.gn index eb5cfc7..9e3ba6f 100644 --- a/components/subresource_filter/core/browser/BUILD.gn +++ b/components/subresource_filter/core/browser/BUILD.gn
@@ -7,6 +7,7 @@ "ruleset_distributor.h", "ruleset_service.cc", "ruleset_service.h", + "subresource_filter_client.h", "subresource_filter_constants.cc", "subresource_filter_constants.h", "subresource_filter_features.cc",
diff --git a/components/subresource_filter/core/browser/subresource_filter_client.h b/components/subresource_filter/core/browser/subresource_filter_client.h new file mode 100644 index 0000000..f834a102 --- /dev/null +++ b/components/subresource_filter/core/browser/subresource_filter_client.h
@@ -0,0 +1,25 @@ +// 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 COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_SUBRESOURCE_FILTER_CLIENT_H_ +#define COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_SUBRESOURCE_FILTER_CLIENT_H_ + +namespace subresource_filter { + +class SubresourceFilterClient { + public: + virtual ~SubresourceFilterClient() = default; + + // Changes the visibility of the prompt that informs the user that potentially + // deceptive content has been blocked on the page according to the passed + // |visibility| parameter. When |visibility| is set to true, an icon on the + // right side of the omnibox is displayed. If the user clicks on the icon then + // a bubble is shown that explains the feature and alalows the user to turn it + // off. + virtual void ToggleNotificationVisibility(bool visibility) = 0; +}; + +} // namespace subresource_filter + +#endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_SUBRESOURCE_FILTER_CLIENT_H_
diff --git a/components/sync_driver/BUILD.gn b/components/sync_driver/BUILD.gn index 1f82819..9d610f4 100644 --- a/components/sync_driver/BUILD.gn +++ b/components/sync_driver/BUILD.gn
@@ -79,8 +79,6 @@ "non_ui_model_type_controller.h", "pref_names.cc", "pref_names.h", - "profile_sync_auth_provider.cc", - "profile_sync_auth_provider.h", "protocol_event_observer.cc", "protocol_event_observer.h", "proxy_data_type_controller.cc", @@ -225,7 +223,6 @@ "non_blocking_data_type_controller_unittest.cc", "non_ui_data_type_controller_unittest.cc", "non_ui_model_type_controller_unittest.cc", - "profile_sync_auth_provider_unittest.cc", "shared_change_processor_unittest.cc", "startup_controller_unittest.cc", "sync_prefs_unittest.cc",
diff --git a/components/sync_driver/profile_sync_auth_provider.cc b/components/sync_driver/profile_sync_auth_provider.cc deleted file mode 100644 index 622d69f..0000000 --- a/components/sync_driver/profile_sync_auth_provider.cc +++ /dev/null
@@ -1,138 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/sync_driver/profile_sync_auth_provider.h" - -#include "base/bind.h" -#include "base/location.h" -#include "base/macros.h" -#include "base/single_thread_task_runner.h" -#include "base/threading/thread_task_runner_handle.h" -#include "components/signin/core/browser/profile_oauth2_token_service.h" -#include "google_apis/gaia/gaia_constants.h" - -// This is thin proxy class for forwarding calls between sync and UI threads. -// The main purpose is to hide the fact that ProfileSyncAuthProvider and -// SyncThreadProxy have independent lifetimes. If ProfileSyncAuthProvider is -// destroyed first calls to RequestAccessToken will never complete. This is fine -// since sync thread is not blocked and is in the process of shutdown anyway. -class ProfileSyncAuthProvider::SyncThreadProxy - : public syncer::SyncAuthProvider, - public base::NonThreadSafe { - public: - SyncThreadProxy( - base::WeakPtr<ProfileSyncAuthProvider> provider_impl, - scoped_refptr<base::SingleThreadTaskRunner> provider_task_runner); - - // syncer::SyncAuthProvider implementation. - void RequestAccessToken(const RequestTokenCallback& callback) override; - void InvalidateAccessToken(const std::string& token) override; - - private: - base::WeakPtr<ProfileSyncAuthProvider> provider_impl_; - scoped_refptr<base::SingleThreadTaskRunner> provider_task_runner_; - - DISALLOW_COPY_AND_ASSIGN(SyncThreadProxy); -}; - -ProfileSyncAuthProvider::SyncThreadProxy::SyncThreadProxy( - base::WeakPtr<ProfileSyncAuthProvider> provider_impl, - scoped_refptr<base::SingleThreadTaskRunner> provider_task_runner) - : provider_impl_(provider_impl), - provider_task_runner_(provider_task_runner) { - // SyncThreadProxy is created on UI thread but used on sync thread. - // Detach NonThreadSafe from UI thread so that it can reattach to sync thread - // on first invocation. - DetachFromThread(); -} - -void ProfileSyncAuthProvider::SyncThreadProxy::RequestAccessToken( - const RequestTokenCallback& callback) { - DCHECK(CalledOnValidThread()); - provider_task_runner_->PostTask( - FROM_HERE, - base::Bind(&ProfileSyncAuthProvider::RequestAccessToken, - provider_impl_, - callback, - base::ThreadTaskRunnerHandle::Get())); -} - -void ProfileSyncAuthProvider::SyncThreadProxy::InvalidateAccessToken( - const std::string& token) { - DCHECK(CalledOnValidThread()); - provider_task_runner_->PostTask( - FROM_HERE, - base::Bind(&ProfileSyncAuthProvider::InvalidateAccessToken, - provider_impl_, - token)); -} - -ProfileSyncAuthProvider::ProfileSyncAuthProvider( - ProfileOAuth2TokenService* token_service, - const std::string& account_id, - const std::string& scope) - : OAuth2TokenService::Consumer("sync_auth_provider"), - token_service_(token_service), - account_id_(account_id), - weak_factory_(this) { - oauth2_scope_.insert(scope); -} - -ProfileSyncAuthProvider::~ProfileSyncAuthProvider() { - DCHECK(CalledOnValidThread()); -} - -void ProfileSyncAuthProvider::RequestAccessToken( - const syncer::SyncAuthProvider::RequestTokenCallback& callback, - scoped_refptr<base::SingleThreadTaskRunner> task_runner) { - DCHECK(CalledOnValidThread()); - if (access_token_request_ != NULL) { - // If there is already pending request report it as cancelled. - GoogleServiceAuthError error(GoogleServiceAuthError::REQUEST_CANCELED); - RespondToTokenRequest(error, std::string()); - } - request_token_callback_ = callback; - callback_task_runner_ = task_runner; - access_token_request_ = - token_service_->StartRequest(account_id_, oauth2_scope_, this); -} - -void ProfileSyncAuthProvider::OnGetTokenSuccess( - const OAuth2TokenService::Request* request, - const std::string& access_token, - const base::Time& expiration_time) { - DCHECK_EQ(access_token_request_.get(), request); - RespondToTokenRequest(GoogleServiceAuthError::AuthErrorNone(), access_token); -} - -void ProfileSyncAuthProvider::OnGetTokenFailure( - const OAuth2TokenService::Request* request, - const GoogleServiceAuthError& error) { - DCHECK_EQ(access_token_request_.get(), request); - RespondToTokenRequest(error, std::string()); -} - -void ProfileSyncAuthProvider::RespondToTokenRequest( - const GoogleServiceAuthError& error, - const std::string& token) { - DCHECK(CalledOnValidThread()); - callback_task_runner_->PostTask( - FROM_HERE, base::Bind(request_token_callback_, error, token)); - access_token_request_.reset(); - request_token_callback_.Reset(); - callback_task_runner_ = NULL; -} - -void ProfileSyncAuthProvider::InvalidateAccessToken(const std::string& token) { - DCHECK(CalledOnValidThread()); - token_service_->InvalidateAccessToken(account_id_, oauth2_scope_, token); -} - -std::unique_ptr<syncer::SyncAuthProvider> -ProfileSyncAuthProvider::CreateProviderForSyncThread() { - DCHECK(CalledOnValidThread()); - std::unique_ptr<syncer::SyncAuthProvider> auth_provider(new SyncThreadProxy( - weak_factory_.GetWeakPtr(), base::ThreadTaskRunnerHandle::Get())); - return auth_provider; -}
diff --git a/components/sync_driver/profile_sync_auth_provider.h b/components/sync_driver/profile_sync_auth_provider.h deleted file mode 100644 index 372c3ab..0000000 --- a/components/sync_driver/profile_sync_auth_provider.h +++ /dev/null
@@ -1,72 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_SYNC_DRIVER_PROFILE_SYNC_AUTH_PROVIDER_H_ -#define COMPONENTS_SYNC_DRIVER_PROFILE_SYNC_AUTH_PROVIDER_H_ - -#include <memory> -#include <string> - -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "components/sync/core/sync_auth_provider.h" -#include "google_apis/gaia/oauth2_token_service.h" - -class ProfileOAuth2TokenService; - -namespace base { -class SingleThreadTaskRunner; -} // namespace base - -// ProfileSyncAuthProvider implements function for SyncAuthProvider. It doesn't -// inherit from SyncAuthProvider because it lives on UI thread while requests -// originate from sync thread. SyncThreadProxy implements SyncAuthProvider and -// forwards all requests. -class ProfileSyncAuthProvider : public OAuth2TokenService::Consumer, - public base::NonThreadSafe { - public: - ProfileSyncAuthProvider(ProfileOAuth2TokenService* token_service, - const std::string& account_id, - const std::string& scope); - ~ProfileSyncAuthProvider() override; - - // OAuth2TokenService::Consumer implementation. - void OnGetTokenSuccess(const OAuth2TokenService::Request* request, - const std::string& access_token, - const base::Time& expiration_time) override; - void OnGetTokenFailure(const OAuth2TokenService::Request* request, - const GoogleServiceAuthError& error) override; - - // Request access token from OAuth2TokenService. Once access token is received - // result should be posted to callback on task_runner thread. - void RequestAccessToken( - const syncer::SyncAuthProvider::RequestTokenCallback& callback, - scoped_refptr<base::SingleThreadTaskRunner> task_runner); - - void InvalidateAccessToken(const std::string& token); - - std::unique_ptr<syncer::SyncAuthProvider> CreateProviderForSyncThread(); - - private: - class SyncThreadProxy; - - void RespondToTokenRequest(const GoogleServiceAuthError& error, - const std::string& token); - - ProfileOAuth2TokenService* token_service_; - std::string account_id_; - OAuth2TokenService::ScopeSet oauth2_scope_; - - // Only one outstanding request is allowed. Previous request is reported - // cancelled if new one arrives. - std::unique_ptr<OAuth2TokenService::Request> access_token_request_; - syncer::SyncAuthProvider::RequestTokenCallback request_token_callback_; - scoped_refptr<base::SingleThreadTaskRunner> callback_task_runner_; - - base::WeakPtrFactory<ProfileSyncAuthProvider> weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(ProfileSyncAuthProvider); -}; - -#endif // COMPONENTS_SYNC_DRIVER_PROFILE_SYNC_AUTH_PROVIDER_H_
diff --git a/components/sync_driver/profile_sync_auth_provider_unittest.cc b/components/sync_driver/profile_sync_auth_provider_unittest.cc deleted file mode 100644 index 582bb0a..0000000 --- a/components/sync_driver/profile_sync_auth_provider_unittest.cc +++ /dev/null
@@ -1,82 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/run_loop.h" -#include "components/signin/core/browser/fake_account_fetcher_service.h" -#include "components/signin/core/browser/fake_profile_oauth2_token_service.h" -#include "components/signin/core/browser/profile_oauth2_token_service.h" -#include "components/sync_driver/profile_sync_auth_provider.h" -#include "google_apis/gaia/gaia_constants.h" -#include "google_apis/gaia/google_service_auth_error.h" -#include "testing/gtest/include/gtest/gtest.h" - -const char kAccountId[] = "account.id"; - -class ProfileSyncAuthProviderTest : public ::testing::Test { - public: - ProfileSyncAuthProviderTest() {} - - ~ProfileSyncAuthProviderTest() override {} - - void SetUp() override { - token_service_.reset(new FakeProfileOAuth2TokenService()); - token_service_->set_auto_post_fetch_response_on_message_loop(true); - token_service_->UpdateCredentials(kAccountId, "fake_refresh_token"); - - auth_provider_frontend_.reset(new ProfileSyncAuthProvider( - token_service_.get(), kAccountId, - GaiaConstants::kChromeSyncOAuth2Scope)); - auth_provider_backend_ = - auth_provider_frontend_->CreateProviderForSyncThread(); - } - - void RequestTokenFinished(const GoogleServiceAuthError& error, - const std::string& token) { - issued_tokens_.push_back(token); - request_token_errors_.push_back(error); - } - - protected: - base::MessageLoop message_loop_; - - std::unique_ptr<FakeProfileOAuth2TokenService> token_service_; - std::unique_ptr<ProfileSyncAuthProvider> auth_provider_frontend_; - std::unique_ptr<syncer::SyncAuthProvider> auth_provider_backend_; - - std::vector<std::string> issued_tokens_; - std::vector<GoogleServiceAuthError> request_token_errors_; -}; - -TEST_F(ProfileSyncAuthProviderTest, RequestToken) { - // Request access token, make sure it gets valid response. - auth_provider_backend_->RequestAccessToken( - base::Bind(&ProfileSyncAuthProviderTest::RequestTokenFinished, - base::Unretained(this))); - base::RunLoop run_loop; - run_loop.RunUntilIdle(); - EXPECT_EQ(1U, request_token_errors_.size()); - EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(), request_token_errors_[0]); - EXPECT_NE("", issued_tokens_[0]); -} - -TEST_F(ProfileSyncAuthProviderTest, RequestTokenTwoConcurrentRequests) { - // Start two requests for access token. One should be reported as canceled, - // the other one should succeed. - auth_provider_backend_->RequestAccessToken( - base::Bind(&ProfileSyncAuthProviderTest::RequestTokenFinished, - base::Unretained(this))); - auth_provider_backend_->RequestAccessToken( - base::Bind(&ProfileSyncAuthProviderTest::RequestTokenFinished, - base::Unretained(this))); - base::RunLoop run_loop; - run_loop.RunUntilIdle(); - EXPECT_EQ(2U, request_token_errors_.size()); - - EXPECT_EQ("", issued_tokens_[0]); - EXPECT_EQ(GoogleServiceAuthError::REQUEST_CANCELED, - request_token_errors_[0].state()); - - EXPECT_NE("", issued_tokens_[1]); - EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(), request_token_errors_[1]); -}
diff --git a/components/test/run_all_unittests.cc b/components/test/run_all_unittests.cc index a82d4e2..07d04a1 100644 --- a/components/test/run_all_unittests.cc +++ b/components/test/run_all_unittests.cc
@@ -21,6 +21,7 @@ #if !defined(OS_IOS) #include "content/public/test/test_content_client_initializer.h" +#include "content/public/test/unittest_test_suite.h" #include "mojo/edk/embedder/embedder.h" #include "ui/gl/test/gl_surface_test_support.h" #endif @@ -136,7 +137,11 @@ } // namespace int main(int argc, char** argv) { +#if !defined(OS_IOS) + content::UnitTestTestSuite test_suite(new ComponentsTestSuite(argc, argv)); +#else ComponentsTestSuite test_suite(argc, argv); +#endif // The listener will set up common test environment for all components unit // tests. @@ -146,9 +151,12 @@ #if !defined(OS_IOS) mojo::edk::Init(); -#endif - + return base::LaunchUnitTests(argc, argv, + base::Bind(&content::UnitTestTestSuite::Run, + base::Unretained(&test_suite))); +#else return base::LaunchUnitTests( argc, argv, base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite))); +#endif }
diff --git a/components/test_runner/spell_check_client.cc b/components/test_runner/spell_check_client.cc index 68c663a..94ad604 100644 --- a/components/test_runner/spell_check_client.cc +++ b/components/test_runner/spell_check_client.cc
@@ -43,34 +43,6 @@ spell_check_.SpellCheckWord(text, &misspelled_offset, &misspelled_length); } -void SpellCheckClient::checkTextOfParagraph( - const blink::WebString& text, - blink::WebTextCheckingTypeMask mask, - blink::WebVector<blink::WebTextCheckingResult>* web_results) { - std::vector<blink::WebTextCheckingResult> results; - if (mask & blink::WebTextCheckingTypeSpelling) { - size_t offset = 0; - base::string16 data = text; - while (offset < data.length()) { - int misspelled_position = 0; - int misspelled_length = 0; - spell_check_.SpellCheckWord( - data.substr(offset), &misspelled_position, &misspelled_length); - if (!misspelled_length) - break; - blink::WebTextCheckingResult result; - result.decoration = blink::WebTextDecorationTypeSpelling; - result.location = offset + misspelled_position; - result.length = misspelled_length; - results.push_back(result); - offset += misspelled_position + misspelled_length; - } - } - if (mask & blink::WebTextCheckingTypeGrammar) - MockGrammarCheck::CheckGrammarOfString(text, &results); - web_results->assign(results); -} - void SpellCheckClient::requestCheckingOfText( const blink::WebString& text, const blink::WebVector<uint32_t>& markers, @@ -96,6 +68,13 @@ 0); } +void SpellCheckClient::cancelAllPendingRequests() { + if (!last_requested_text_checking_completion_) + return; + last_requested_text_checking_completion_->didCancelCheckingText(); + last_requested_text_checking_completion_ = nullptr; +} + void SpellCheckClient::FinishLastTextCheck() { if (!last_requested_text_checking_completion_) return;
diff --git a/components/test_runner/spell_check_client.h b/components/test_runner/spell_check_client.h index 978c5ba..f9f23cb1 100644 --- a/components/test_runner/spell_check_client.h +++ b/components/test_runner/spell_check_client.h
@@ -37,15 +37,12 @@ int& offset, int& length, blink::WebVector<blink::WebString>* optional_suggestions) override; - void checkTextOfParagraph( - const blink::WebString& text, - blink::WebTextCheckingTypeMask mask, - blink::WebVector<blink::WebTextCheckingResult>* web_results) override; void requestCheckingOfText( const blink::WebString& text, const blink::WebVector<uint32_t>& markers, const blink::WebVector<unsigned>& marker_offsets, blink::WebTextCheckingCompletion* completion) override; + void cancelAllPendingRequests() override; private: void FinishLastTextCheck();
diff --git a/components/test_runner/text_input_controller.cc b/components/test_runner/text_input_controller.cc index cd0aa73..788570b 100644 --- a/components/test_runner/text_input_controller.cc +++ b/components/test_runner/text_input_controller.cc
@@ -283,18 +283,14 @@ key_down.windowsKeyCode = 0xE5; // VKEY_PROCESSKEY view()->handleInputEvent(key_down); - // The value returned by std::string::length() may not correspond to the - // actual number of encoded characters in sequences of multi-byte or - // variable-length characters. - blink::WebString newText = blink::WebString::fromUTF8(text); - size_t textLength = newText.length(); - std::vector<blink::WebCompositionUnderline> underlines; - underlines.push_back(blink::WebCompositionUnderline( - 0, textLength, SK_ColorBLACK, false, SK_ColorTRANSPARENT)); + underlines.push_back(blink::WebCompositionUnderline(0, text.length(), + SK_ColorBLACK, false, + SK_ColorTRANSPARENT)); view()->setComposition( - newText, blink::WebVector<blink::WebCompositionUnderline>(underlines), - textLength, textLength); + blink::WebString::fromUTF8(text), + blink::WebVector<blink::WebCompositionUnderline>(underlines), + text.length(), text.length()); } blink::WebView* TextInputController::view() {
diff --git a/components/tracing/core/proto_utils.h b/components/tracing/core/proto_utils.h index 68599199..016975d 100644 --- a/components/tracing/core/proto_utils.h +++ b/components/tracing/core/proto_utils.h
@@ -10,13 +10,14 @@ #include <type_traits> #include "base/logging.h" -#include "base/macros.h" -#include "components/tracing/tracing_export.h" namespace tracing { namespace v2 { namespace proto { +// TODO(kraynov): Change namespace to tracing::proto::internal. +// This is required in headers and it's too low-level to be exposed. + // See https://developers.google.com/protocol-buffers/docs/encoding wire types. enum : uint32_t { @@ -30,69 +31,64 @@ constexpr size_t kMessageLengthFieldSize = 4; constexpr size_t kMaxMessageLength = (1u << (kMessageLengthFieldSize * 7)) - 1; -// Returns the number of bytes sufficient to encode the largest -// |int_size_in_bits|-bits integer using a non-redundant varint encoding. -template <typename T> -constexpr size_t GetMaxVarIntEncodedSize() { - return (sizeof(T) * 8 + 6) / 7; -} +// Field tag is encoded as 32-bit varint (5 bytes at most). +// Largest value of simple (not length-delimited) field is 64-bit varint +// (10 bytes at most). 15 bytes buffer is enough to store a simple field. +constexpr size_t kMaxTagEncodedSize = 5; +constexpr size_t kMaxSimpleFieldEncodedSize = 15; -// Variable-length field types: (s)int32, (s)int64, bool, enum. -inline uint32_t MakeTagVarInt(uint32_t field_id) { +// Proto types: (int|uint|sint)(32|64), bool, enum. +constexpr uint32_t MakeTagVarInt(uint32_t field_id) { return (field_id << 3) | kFieldTypeVarInt; } -// Length-limited field types: string, bytes, embedded messages. -inline uint32_t MakeTagLengthDelimited(uint32_t field_id) { +// Proto types: fixed64, sfixed64, fixed32, sfixed32, double, float. +template <typename T> +constexpr uint32_t MakeTagFixed(uint32_t field_id) { + static_assert(sizeof(T) == 8 || sizeof(T) == 4, "Value must be 4 or 8 bytes"); + return (field_id << 3) | + (sizeof(T) == 8 ? kFieldTypeFixed64 : kFieldTypeFixed32); +} + +// Proto types: string, bytes, embedded messages. +constexpr uint32_t MakeTagLengthDelimited(uint32_t field_id) { return (field_id << 3) | kFieldTypeLengthDelimited; } -// 32-bit fixed-length field types: fixed32, sfixed32, float. -inline uint32_t MakeTagFixed32(uint32_t field_id) { - return (field_id << 3) | kFieldTypeFixed32; -} - -// 64-bit fixed-length field types: fixed64, sfixed64, double. -inline uint32_t MakeTagFixed64(uint32_t field_id) { - return (field_id << 3) | kFieldTypeFixed64; +// Proto tipes: sint64, sint32. +template <typename T> +inline typename std::make_unsigned<T>::type ZigZagEncode(T value) { + return (value << 1) ^ (value >> (sizeof(T) * 8 - 1)); } template <typename T> -inline uint8_t* WriteVarIntInternal(T value, uint8_t* target) { - static_assert(std::is_unsigned<T>::value, "value must be unsigned"); - while (value >= 0x80) { - *target++ = static_cast<uint8_t>(value | 0x80); - value >>= 7; +inline uint8_t* WriteVarInt(T value, uint8_t* target) { + // Avoid arithmetic (sign expanding) shifts. + typedef typename std::make_unsigned<T>::type unsigned_T; + unsigned_T unsigned_value = static_cast<unsigned_T>(value); + + while (unsigned_value >= 0x80) { + *target++ = static_cast<uint8_t>(unsigned_value) | 0x80; + unsigned_value >>= 7; } - *target = static_cast<uint8_t>(value); + *target = static_cast<uint8_t>(unsigned_value); return target + 1; } -inline uint8_t* WriteVarIntU32(uint32_t value, uint8_t* target) { - return WriteVarIntInternal<uint32_t>(value, target); -} - -inline uint8_t* WriteVarIntU64(uint64_t value, uint8_t* target) { - return WriteVarIntInternal<uint64_t>(value, target); -} - -// TODO(kraynov): add support for signed integers and zig-zag encoding. - // Writes a fixed-size redundant encoding of the given |value|. This is -// used to backfill fixed-size reservations for the length field using a +// used to backfill fixed-size reservations for the length of field using a // non-canonical varint encoding (e.g. \x81\x80\x80\x00 instead of \x01). // See https://github.com/google/protobuf/issues/1530. // In particular, this is used for nested messages. The size of a nested message -// is not known until all its field have been written. A fixed amount of bytes -// is reserved to encode the size field and backfilled at the end. -template <size_t LENGTH> -void WriteRedundantVarIntU32(uint32_t value, uint8_t* buf) { - for (size_t i = 0; i < LENGTH; ++i) { - const uint8_t msb = (i < LENGTH - 1) ? 0x80 : 0; - buf[i] = static_cast<uint8_t>((value & 0x7F) | msb); +// is not known until all its field have been written. |kMessageLengthFieldSize| +// bytes are reserved to encode the size field and backfilled at the end. +inline void WriteRedundantLength(uint32_t value, uint8_t* buf) { + DCHECK_LE(value, kMaxMessageLength) << "Message is too long"; + for (size_t i = 0; i < kMessageLengthFieldSize; ++i) { + const uint8_t msb = (i < kMessageLengthFieldSize - 1) ? 0x80 : 0; + buf[i] = static_cast<uint8_t>(value) | msb; value >>= 7; } - DCHECK_EQ(0u, value) << "Buffer too short to encode the given value"; } } // namespace proto
diff --git a/components/tracing/core/proto_utils_unittest.cc b/components/tracing/core/proto_utils_unittest.cc index 796eb27..88505aa 100644 --- a/components/tracing/core/proto_utils_unittest.cc +++ b/components/tracing/core/proto_utils_unittest.cc
@@ -4,6 +4,8 @@ #include "components/tracing/core/proto_utils.h" +#include <limits> + #include "base/logging.h" #include "testing/gtest/include/gtest/gtest.h" @@ -12,57 +14,62 @@ namespace proto { namespace { -bool CheckWriteVarIntU32(const char* expected, size_t length, uint32_t value) { +template <typename T> +bool CheckWriteVarInt(const char* expected, size_t length, T value) { uint8_t buf[32]; - uint8_t* res = WriteVarIntU32(value, buf); + uint8_t* res = WriteVarInt<T>(value, buf); if (static_cast<size_t>(res - buf) != length) return false; - if (memcmp(expected, buf, length)) - return false; - return true; -} - -bool CheckWriteVarIntU64(const char* expected, size_t length, uint64_t value) { - uint8_t buf[32]; - uint8_t* res = WriteVarIntU64(value, buf); - if (static_cast<size_t>(res - buf) != length) - return false; - if (memcmp(expected, buf, length)) - return false; - return true; + return memcmp(expected, buf, length) == 0; } #define EXPECT_VARINT32_EQ(expected, expected_length, value) \ - EXPECT_PRED3(CheckWriteVarIntU32, expected, expected_length, value) + EXPECT_PRED3(CheckWriteVarInt<uint32_t>, expected, expected_length, value) #define EXPECT_VARINT64_EQ(expected, expected_length, value) \ - EXPECT_PRED3(CheckWriteVarIntU64, expected, expected_length, value) + EXPECT_PRED3(CheckWriteVarInt<uint64_t>, expected, expected_length, value) TEST(ProtoUtilsTest, Serialization) { + // According to C++ standard, right shift of negative value has + // implementation-defined resulting value. + if ((static_cast<int32_t>(0x80000000u) >> 31) != -1) + FAIL() << "Platform has unsupported negative number format or arithmetic"; + EXPECT_EQ(0x08u, MakeTagVarInt(1)); - EXPECT_EQ(0x09u, MakeTagFixed64(1)); + EXPECT_EQ(0x09u, MakeTagFixed<uint64_t>(1)); EXPECT_EQ(0x0Au, MakeTagLengthDelimited(1)); - EXPECT_EQ(0x0Du, MakeTagFixed32(1)); + EXPECT_EQ(0x0Du, MakeTagFixed<uint32_t>(1)); EXPECT_EQ(0x03F8u, MakeTagVarInt(0x7F)); - EXPECT_EQ(0x03F9u, MakeTagFixed64(0x7F)); + EXPECT_EQ(0x03F9u, MakeTagFixed<int64_t>(0x7F)); EXPECT_EQ(0x03FAu, MakeTagLengthDelimited(0x7F)); - EXPECT_EQ(0x03FDu, MakeTagFixed32(0x7F)); + EXPECT_EQ(0x03FDu, MakeTagFixed<int32_t>(0x7F)); EXPECT_EQ(0x0400u, MakeTagVarInt(0x80)); - EXPECT_EQ(0x0401u, MakeTagFixed64(0x80)); + EXPECT_EQ(0x0401u, MakeTagFixed<double>(0x80)); EXPECT_EQ(0x0402u, MakeTagLengthDelimited(0x80)); - EXPECT_EQ(0x0405u, MakeTagFixed32(0x80)); + EXPECT_EQ(0x0405u, MakeTagFixed<float>(0x80)); EXPECT_EQ(0x01FFF8u, MakeTagVarInt(0x3fff)); - EXPECT_EQ(0x01FFF9u, MakeTagFixed64(0x3fff)); + EXPECT_EQ(0x01FFF9u, MakeTagFixed<int64_t>(0x3fff)); EXPECT_EQ(0x01FFFAu, MakeTagLengthDelimited(0x3fff)); - EXPECT_EQ(0x01FFFDu, MakeTagFixed32(0x3fff)); + EXPECT_EQ(0x01FFFDu, MakeTagFixed<int32_t>(0x3fff)); EXPECT_EQ(0x020000u, MakeTagVarInt(0x4000)); - EXPECT_EQ(0x020001u, MakeTagFixed64(0x4000)); + EXPECT_EQ(0x020001u, MakeTagFixed<int64_t>(0x4000)); EXPECT_EQ(0x020002u, MakeTagLengthDelimited(0x4000)); - EXPECT_EQ(0x020005u, MakeTagFixed32(0x4000)); + EXPECT_EQ(0x020005u, MakeTagFixed<int32_t>(0x4000)); + + EXPECT_EQ(0u, ZigZagEncode(0)); + EXPECT_EQ(1u, ZigZagEncode(-1)); + EXPECT_EQ(2u, ZigZagEncode(1)); + EXPECT_EQ(3u, ZigZagEncode(-2)); + EXPECT_EQ(4294967293u, ZigZagEncode(-2147483647)); + EXPECT_EQ(4294967294u, ZigZagEncode(2147483647)); + EXPECT_EQ(std::numeric_limits<uint32_t>::max(), + ZigZagEncode(std::numeric_limits<int32_t>::min())); + EXPECT_EQ(std::numeric_limits<uint64_t>::max(), + ZigZagEncode(std::numeric_limits<int64_t>::min())); EXPECT_VARINT32_EQ("\x00", 1, 0); EXPECT_VARINT32_EQ("\x00", 1, 0); @@ -105,21 +112,22 @@ EXPECT_VARINT64_EQ("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01", 10, 0xFFFFFFFFFFFFFFFF); - uint8_t buf[4]; + uint8_t buf[kMessageLengthFieldSize]; - WriteRedundantVarIntU32<sizeof(buf)>(0, buf); + WriteRedundantLength(0, buf); EXPECT_EQ(0, memcmp("\x80\x80\x80\x00", buf, sizeof(buf))); - WriteRedundantVarIntU32<sizeof(buf)>(1, buf); + WriteRedundantLength(1, buf); EXPECT_EQ(0, memcmp("\x81\x80\x80\x00", buf, sizeof(buf))); - WriteRedundantVarIntU32<sizeof(buf)>(0x80, buf); + WriteRedundantLength(0x80, buf); EXPECT_EQ(0, memcmp("\x80\x81\x80\x00", buf, sizeof(buf))); - WriteRedundantVarIntU32<sizeof(buf)>(0x332211, buf); + WriteRedundantLength(0x332211, buf); EXPECT_EQ(0, memcmp("\x91\xC4\xCC\x01", buf, sizeof(buf))); - WriteRedundantVarIntU32<sizeof(buf)>(0x0FFFFFFF, buf); + // Largest allowed length. + WriteRedundantLength(0x0FFFFFFF, buf); EXPECT_EQ(0, memcmp("\xFF\xFF\xFF\x7F", buf, sizeof(buf))); }
diff --git a/components/tracing/core/proto_zero_message.cc b/components/tracing/core/proto_zero_message.cc index f4e63df5..a4e056e 100644 --- a/components/tracing/core/proto_zero_message.cc +++ b/components/tracing/core/proto_zero_message.cc
@@ -6,7 +6,6 @@ #include <string.h> -#include "components/tracing/core/proto_utils.h" #include "components/tracing/core/proto_zero_message_handle.h" #if !defined(ARCH_CPU_LITTLE_ENDIAN) @@ -49,47 +48,6 @@ #endif } -void ProtoZeroMessage::AppendVarIntU64(uint32_t field_id, uint64_t value) { - if (nested_message_) - EndNestedMessage(); - - uint8_t data[proto::GetMaxVarIntEncodedSize<uint32_t>() + - proto::GetMaxVarIntEncodedSize<uint64_t>()]; - uint8_t* data_end; - data_end = proto::WriteVarIntU32(proto::MakeTagVarInt(field_id), data); - data_end = proto::WriteVarIntU64(value, data_end); - WriteToStream(data, data_end); -} - -void ProtoZeroMessage::AppendVarIntU32(uint32_t field_id, uint32_t value) { - // TODO(kraynov): this could be perf-optimized. See http://crbug.com/624311 . - AppendVarIntU64(field_id, value); -} - -void ProtoZeroMessage::AppendFloat(uint32_t field_id, float value) { - if (nested_message_) - EndNestedMessage(); - - uint8_t data[proto::GetMaxVarIntEncodedSize<uint32_t>() + sizeof(value)]; - uint8_t* data_end; - data_end = proto::WriteVarIntU32(proto::MakeTagFixed32(field_id), data); - memcpy(data_end, &value, sizeof(value)); - data_end += sizeof(value); - WriteToStream(data, data_end); -} - -void ProtoZeroMessage::AppendDouble(uint32_t field_id, double value) { - if (nested_message_) - EndNestedMessage(); - - uint8_t data[proto::GetMaxVarIntEncodedSize<uint32_t>() + sizeof(value)]; - uint8_t* data_end; - data_end = proto::WriteVarIntU32(proto::MakeTagFixed64(field_id), data); - memcpy(data_end, &value, sizeof(value)); - data_end += sizeof(value); - WriteToStream(data, data_end); -} - void ProtoZeroMessage::AppendString(uint32_t field_id, const char* str) { AppendBytes(field_id, str, strlen(str)); } @@ -100,12 +58,14 @@ if (nested_message_) EndNestedMessage(); - // Write the proto preamble (field id, type and length of the buffer). - uint8_t data[2 * proto::GetMaxVarIntEncodedSize<uint32_t>()]; - uint8_t* data_end = - proto::WriteVarIntU32(proto::MakeTagLengthDelimited(field_id), data); - data_end = proto::WriteVarIntU32(static_cast<uint32_t>(size), data_end); - WriteToStream(data, data_end); + DCHECK_LT(size, proto::kMaxMessageLength); + // Write the proto preamble (field id, type and length of the field). + uint8_t buffer[proto::kMaxSimpleFieldEncodedSize]; + uint8_t* pos = buffer; + pos = proto::WriteVarInt(proto::MakeTagLengthDelimited(field_id), pos); + pos = proto::WriteVarInt(static_cast<uint32_t>(size), pos); + WriteToStream(buffer, pos); + const uint8_t* src_u8 = reinterpret_cast<const uint8_t*>(src); WriteToStream(src_u8, src_u8 + size); } @@ -122,7 +82,7 @@ #endif DCHECK_LT(size_, proto::kMaxMessageLength); DCHECK_EQ(proto::kMessageLengthFieldSize, size_field_.size()); - proto::WriteRedundantVarIntU32<proto::kMessageLengthFieldSize>( + proto::WriteRedundantLength( static_cast<uint32_t>(size_ - size_already_written_), size_field_.begin); size_field_.reset(); @@ -143,9 +103,9 @@ EndNestedMessage(); // Write the proto preamble for the nested message. - uint8_t data[proto::GetMaxVarIntEncodedSize<uint32_t>()]; + uint8_t data[proto::kMaxTagEncodedSize]; uint8_t* data_end = - proto::WriteVarIntU32(proto::MakeTagLengthDelimited(field_id), data); + proto::WriteVarInt(proto::MakeTagLengthDelimited(field_id), data); WriteToStream(data, data_end); message->Reset(stream_writer_);
diff --git a/components/tracing/core/proto_zero_message.h b/components/tracing/core/proto_zero_message.h index d7fe1d4..b5b0a37c 100644 --- a/components/tracing/core/proto_zero_message.h +++ b/components/tracing/core/proto_zero_message.h
@@ -15,6 +15,7 @@ #include "base/macros.h" #include "base/template_util.h" #include "build/build_config.h" +#include "components/tracing/core/proto_utils.h" #include "components/tracing/core/scattered_stream_writer.h" #include "components/tracing/tracing_export.h" @@ -61,13 +62,46 @@ protected: ProtoZeroMessage(); - void AppendVarIntU64(uint32_t field_id, uint64_t value); - void AppendVarIntU32(uint32_t field_id, uint32_t value); - void AppendFloat(uint32_t field_id, float value); - void AppendDouble(uint32_t field_id, double value); + // Proto types: uint64, uint32, int64, int32, bool, enum. + template <typename T> + void AppendVarInt(uint32_t field_id, T value) { + if (nested_message_) + EndNestedMessage(); + + uint8_t buffer[proto::kMaxSimpleFieldEncodedSize]; + uint8_t* pos = buffer; + + pos = proto::WriteVarInt(proto::MakeTagVarInt(field_id), pos); + // WriteVarInt encodes signed values in two's complement form. + pos = proto::WriteVarInt(value, pos); + WriteToStream(buffer, pos); + } + + // Proto types: sint64, sint32. + template <typename T> + void AppendSignedVarInt(uint32_t field_id, T value) { + AppendVarInt(field_id, proto::ZigZagEncode(value)); + } + + // Proto types: fixed64, sfixed64, fixed32, sfixed32, double, float. + template <typename T> + void AppendFixed(uint32_t field_id, T value) { + if (nested_message_) + EndNestedMessage(); + + uint8_t buffer[proto::kMaxSimpleFieldEncodedSize]; + uint8_t* pos = buffer; + + pos = proto::WriteVarInt(proto::MakeTagFixed<T>(field_id), pos); + memcpy(pos, &value, sizeof(T)); + pos += sizeof(T); + // TODO(kraynov): Optimize memcpy performance, see http://crbug.com/624311 . + WriteToStream(buffer, pos); + } + + // TODO(kraynov): Add AppendTinyInt. void AppendString(uint32_t field_id, const char* str); void AppendBytes(uint32_t field_id, const void* value, size_t size); - // TODO(kraynov): implement AppendVarIntS32/64(...) w/ zig-zag encoding. // Begins a nested message, using the static storage provided by the parent // class (see comment in |nested_messages_arena_|). The nested message ends
diff --git a/components/tracing/core/proto_zero_message_unittest.cc b/components/tracing/core/proto_zero_message_unittest.cc index 93b5ca3..90fecd6b 100644 --- a/components/tracing/core/proto_zero_message_unittest.cc +++ b/components/tracing/core/proto_zero_message_unittest.cc
@@ -87,7 +87,7 @@ } for (uint32_t i = 129; i <= 256; ++i) - msg->AppendVarIntU32(i, 42); + msg->AppendVarInt(i, 42); if ((depth & 2) == 0) msg->Finalize(); @@ -102,19 +102,20 @@ TEST_F(ProtoZeroMessageTest, BasicTypesNoNesting) { ProtoZeroMessage* msg = NewMessage(); - msg->AppendVarIntU32(1 /* field_id */, 0); - msg->AppendVarIntU32(2 /* field_id */, std::numeric_limits<uint32_t>::max()); - msg->AppendVarIntU64(3 /* field_id */, 42); - msg->AppendVarIntU64(4 /* field_id */, std::numeric_limits<uint64_t>::max()); - msg->AppendFloat(5 /* field_id */, 3.1415f); - msg->AppendDouble(6 /* field_id */, 3.14159265358979323846); + msg->AppendVarInt(1 /* field_id */, 0); + msg->AppendVarInt(2 /* field_id */, std::numeric_limits<uint32_t>::max()); + msg->AppendVarInt(3 /* field_id */, 42); + msg->AppendVarInt(4 /* field_id */, std::numeric_limits<uint64_t>::max()); + msg->AppendFixed(5 /* field_id */, 3.1415f /* float */); + msg->AppendFixed(6 /* field_id */, 3.14159265358979323846 /* double */); msg->AppendBytes(7 /* field_id */, kTestBytes, sizeof(kTestBytes)); // Field ids > 16 are expected to be varint encoded (preamble > 1 byte) msg->AppendString(257 /* field_id */, "0123456789abcdefABCDEF"); + msg->AppendSignedVarInt(3 /* field_id */, -21); - EXPECT_EQ(72u, msg->Finalize()); - EXPECT_EQ(72u, GetNumSerializedBytes()); + EXPECT_EQ(74u, msg->Finalize()); + EXPECT_EQ(74u, GetNumSerializedBytes()); // These lines match the serialization of the Append* calls above. ASSERT_EQ("0800", GetNextSerializedBytes(2)); @@ -126,22 +127,23 @@ ASSERT_EQ("3A0A00000000420142FF4200", GetNextSerializedBytes(12)); ASSERT_EQ("8A101630313233343536373839616263646566414243444546", GetNextSerializedBytes(25)); + ASSERT_EQ("1829", GetNextSerializedBytes(2)); } TEST_F(ProtoZeroMessageTest, NestedMessagesSimple) { ProtoZeroMessage* root_msg = NewMessage(); - root_msg->AppendVarIntU32(1 /* field_id */, 1); + root_msg->AppendVarInt(1 /* field_id */, 1); FakeChildMessage* nested_msg = root_msg->BeginNestedMessage<FakeChildMessage>(128 /* field_id */); ASSERT_EQ(0u, reinterpret_cast<uintptr_t>(nested_msg) % sizeof(void*)); - nested_msg->AppendVarIntU32(2 /* field_id */, 2); + nested_msg->AppendVarInt(2 /* field_id */, 2); nested_msg = root_msg->BeginNestedMessage<FakeChildMessage>(129 /* field_id */); - nested_msg->AppendVarIntU32(4 /* field_id */, 2); + nested_msg->AppendVarInt(4 /* field_id */, 2); - root_msg->AppendVarIntU32(5 /* field_id */, 3); + root_msg->AppendVarInt(5 /* field_id */, 3); // The expected size of the root message is supposed to be 20 bytes: // 2 bytes for the varint field (id: 1) (1 for preamble and one for payload) @@ -175,11 +177,11 @@ uint8_t root_msg_size[proto::kMessageLengthFieldSize] = {}; root_msg->set_size_field( {&root_msg_size[0], &root_msg_size[proto::kMessageLengthFieldSize]}); - root_msg->AppendVarIntU32(1, 0x42); + root_msg->AppendVarInt(1, 0x42); FakeChildMessage* nested_msg_1 = root_msg->BeginNestedMessage<FakeChildMessage>(2); - nested_msg_1->AppendVarIntU32(3, 0x43); + nested_msg_1->AppendVarInt(3, 0x43); FakeChildMessage* nested_msg_2 = nested_msg_1->BeginNestedMessage<FakeChildMessage>(4); @@ -301,13 +303,13 @@ ProtoZeroMessageHandle<FakeChildMessage> child_handle_1(nested_msg_1); ContiguousMemoryRange size_msg_1 = nested_msg_1->size_field(); memset(size_msg_1.begin, 0, size_msg_1.size()); - child_handle_1->AppendVarIntU32(1, 0x11); + child_handle_1->AppendVarInt(1, 0x11); auto* nested_msg_2 = NewMessage()->BeginNestedMessage<FakeChildMessage>(2); size_msg_2 = nested_msg_2->size_field(); memset(size_msg_2.begin, 0, size_msg_2.size()); ProtoZeroMessageHandle<FakeChildMessage> child_handle_2(nested_msg_2); - child_handle_2->AppendVarIntU32(2, 0xFF); + child_handle_2->AppendVarInt(2, 0xFF); // |nested_msg_1| should not be finalized yet. ASSERT_EQ(0u, size_msg_1.begin[0]);
diff --git a/components/translate.gypi b/components/translate.gypi index d4babfa..9e390c72cc 100644 --- a/components/translate.gypi +++ b/components/translate.gypi
@@ -150,21 +150,30 @@ # GN version: //components/translate/content/common 'target_name': 'translate_content_common', 'type': 'static_library', + 'variables': { + 'mojom_typemaps': [ + 'translate/content/common/translate.typemap', + '<(DEPTH)/mojo/common/common_custom_types.typemap', + '<(DEPTH)/url/mojo/gurl.typemap', + ], + }, + 'sources': [ + 'translate/content/common/translate_struct_traits.cc', + 'translate/content/common/translate.mojom', + ], + 'export_dependent_settings': [ + '../mojo/mojo_base.gyp:mojo_common_custom_types_mojom', + '../url/url.gyp:url_mojom', + ], 'dependencies': [ 'translate_core_common', 'translate_core_language_detection', '../base/base.gyp:base', - '../ipc/ipc.gyp:ipc', - '../url/ipc/url_ipc.gyp:url_ipc', + '../mojo/mojo_base.gyp:mojo_common_custom_types_mojom', + '../mojo/mojo_public.gyp:mojo_cpp_bindings', + '../url/url.gyp:url_mojom', ], - 'include_dirs': [ - '..', - ], - 'sources': [ - # Note: sources list duplicated in GN build. - 'translate/content/common/translate_messages.cc', - 'translate/content/common/translate_messages.h', - ], + 'includes': [ '../mojo/mojom_bindings_generator.gypi' ], }, { # GN version: //components/translate/content/renderer @@ -177,7 +186,6 @@ '../base/base.gyp:base', '../content/content.gyp:content_common', '../content/content.gyp:content_renderer', - '../ipc/ipc.gyp:ipc', '../third_party/WebKit/public/blink.gyp:blink', '../third_party/cld_2/cld_2.gyp:cld_2', '../url/url.gyp:url_lib',
diff --git a/components/translate/content/DEPS b/components/translate/content/DEPS index c3505fa..c57486b 100644 --- a/components/translate/content/DEPS +++ b/components/translate/content/DEPS
@@ -1,4 +1,4 @@ include_rules = [ "+content/public/common", - "+ipc", + "+mojo/public", ]
diff --git a/components/translate/content/browser/BUILD.gn b/components/translate/content/browser/BUILD.gn index 59bbcc8..0cfde4a8 100644 --- a/components/translate/content/browser/BUILD.gn +++ b/components/translate/content/browser/BUILD.gn
@@ -17,7 +17,6 @@ "//components/translate/core/common", "//content/public/browser", "//content/public/common", - "//ipc", "//net", ] }
diff --git a/components/translate/content/browser/content_translate_driver.cc b/components/translate/content/browser/content_translate_driver.cc index 24376c1..e9a6fe9 100644 --- a/components/translate/content/browser/content_translate_driver.cc +++ b/components/translate/content/browser/content_translate_driver.cc
@@ -9,7 +9,6 @@ #include "base/logging.h" #include "base/single_thread_task_runner.h" #include "base/threading/thread_task_runner_handle.h" -#include "components/translate/content/common/translate_messages.h" #include "components/translate/core/browser/translate_download_manager.h" #include "components/translate/core/browser/translate_manager.h" #include "content/public/browser/browser_context.h" @@ -39,12 +38,18 @@ navigation_controller_(nav_controller), translate_manager_(NULL), max_reload_check_attempts_(kMaxTranslateLoadCheckAttempts), + next_page_seq_no_(0), weak_pointer_factory_(this) { DCHECK(navigation_controller_); } ContentTranslateDriver::~ContentTranslateDriver() {} +void ContentTranslateDriver::BindRequest( + mojom::ContentTranslateDriverRequest request) { + bindings_.AddBinding(this, std::move(request)); +} + void ContentTranslateDriver::AddObserver(Observer* observer) { observer_list_.AddObserver(observer); } @@ -94,26 +99,30 @@ } void ContentTranslateDriver::OnIsPageTranslatedChanged() { - content::WebContents* web_contents = - navigation_controller_->GetWebContents(); - FOR_EACH_OBSERVER( - Observer, observer_list_, OnIsPageTranslatedChanged(web_contents)); + content::WebContents* web_contents = navigation_controller_->GetWebContents(); + FOR_EACH_OBSERVER(Observer, observer_list_, + OnIsPageTranslatedChanged(web_contents)); } void ContentTranslateDriver::TranslatePage(int page_seq_no, const std::string& translate_script, const std::string& source_lang, const std::string& target_lang) { - content::WebContents* web_contents = navigation_controller_->GetWebContents(); - web_contents->GetMainFrame()->Send(new ChromeFrameMsg_TranslatePage( - web_contents->GetMainFrame()->GetRoutingID(), page_seq_no, - translate_script, source_lang, target_lang)); + auto it = pages_.find(page_seq_no); + if (it == pages_.end()) + return; // This page has navigated away. + + it->second->Translate(translate_script, source_lang, target_lang, + base::Bind(&ContentTranslateDriver::OnPageTranslated, + base::Unretained(this))); } void ContentTranslateDriver::RevertTranslation(int page_seq_no) { - content::WebContents* web_contents = navigation_controller_->GetWebContents(); - web_contents->GetMainFrame()->Send(new ChromeFrameMsg_RevertTranslation( - web_contents->GetMainFrame()->GetRoutingID(), page_seq_no)); + auto it = pages_.find(page_seq_no); + if (it == pages_.end()) + return; // This page has navigated away. + + it->second->RevertTranslation(); } bool ContentTranslateDriver::IsOffTheRecord() { @@ -210,29 +219,21 @@ details.is_in_page, details.is_main_frame, reload); } -bool ContentTranslateDriver::OnMessageReceived( - const IPC::Message& message, - content::RenderFrameHost* render_frame_host) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(ContentTranslateDriver, message) - IPC_MESSAGE_HANDLER(ChromeFrameHostMsg_TranslateAssignedSequenceNumber, - OnTranslateAssignedSequenceNumber) - IPC_MESSAGE_HANDLER(ChromeFrameHostMsg_TranslateLanguageDetermined, - OnLanguageDetermined) - IPC_MESSAGE_HANDLER(ChromeFrameHostMsg_PageTranslated, OnPageTranslated) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; +void ContentTranslateDriver::OnPageAway(int page_seq_no) { + pages_.erase(page_seq_no); } -void ContentTranslateDriver::OnTranslateAssignedSequenceNumber( - int page_seq_no) { - translate_manager_->set_current_seq_no(page_seq_no); -} - -void ContentTranslateDriver::OnLanguageDetermined( +// mojom::ContentTranslateDriver implementation. +void ContentTranslateDriver::RegisterPage( + mojom::PagePtr page, const LanguageDetectionDetails& details, bool page_needs_translation) { + pages_[++next_page_seq_no_] = std::move(page); + pages_[next_page_seq_no_].set_connection_error_handler( + base::Bind(&ContentTranslateDriver::OnPageAway, base::Unretained(this), + next_page_seq_no_)); + translate_manager_->set_current_seq_no(next_page_seq_no_); + translate_manager_->GetLanguageState().LanguageDetermined( details.adopted_language, page_needs_translation); @@ -243,9 +244,13 @@ } void ContentTranslateDriver::OnPageTranslated( + bool cancelled, const std::string& original_lang, const std::string& translated_lang, TranslateErrors::Type error_type) { + if (cancelled) + return; + translate_manager_->PageTranslated( original_lang, translated_lang, error_type); FOR_EACH_OBSERVER(
diff --git a/components/translate/content/browser/content_translate_driver.h b/components/translate/content/browser/content_translate_driver.h index 685f8e6..a6a9faa 100644 --- a/components/translate/content/browser/content_translate_driver.h +++ b/components/translate/content/browser/content_translate_driver.h
@@ -5,12 +5,16 @@ #ifndef COMPONENTS_TRANSLATE_CONTENT_BROWSER_CONTENT_TRANSLATE_DRIVER_H_ #define COMPONENTS_TRANSLATE_CONTENT_BROWSER_CONTENT_TRANSLATE_DRIVER_H_ +#include <map> + #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" +#include "components/translate/content/common/translate.mojom.h" #include "components/translate/core/browser/translate_driver.h" #include "components/translate/core/common/translate_errors.h" #include "content/public/browser/web_contents_observer.h" +#include "mojo/public/cpp/bindings/binding_set.h" namespace content { class NavigationController; @@ -22,12 +26,11 @@ struct LanguageDetectionDetails; class TranslateManager; - // Content implementation of TranslateDriver. class ContentTranslateDriver : public TranslateDriver, - public content::WebContentsObserver { + public content::WebContentsObserver, + public mojom::ContentTranslateDriver { public: - // The observer for the ContentTranslateDriver. class Observer { public: @@ -51,9 +54,12 @@ virtual ~Observer() {} }; - ContentTranslateDriver(content::NavigationController* nav_controller); + explicit ContentTranslateDriver( + content::NavigationController* nav_controller); ~ContentTranslateDriver() override; + void BindRequest(mojom::ContentTranslateDriverRequest request); + // Adds or Removes observers. void AddObserver(Observer* observer); void RemoveObserver(Observer* observer); @@ -93,18 +99,20 @@ void DidNavigateAnyFrame(content::RenderFrameHost* render_frame_host, const content::LoadCommittedDetails& details, const content::FrameNavigateParams& params) override; - bool OnMessageReceived(const IPC::Message& message, - content::RenderFrameHost* render_frame_host) override; - // IPC handlers. - void OnTranslateAssignedSequenceNumber(int page_seq_no); - void OnLanguageDetermined(const LanguageDetectionDetails& details, - bool page_needs_translation); - void OnPageTranslated(const std::string& original_lang, + void OnPageTranslated(bool cancelled, + const std::string& original_lang, const std::string& translated_lang, TranslateErrors::Type error_type); + // mojom::ContentTranslateDriver implementation. + void RegisterPage(mojom::PagePtr page, + const LanguageDetectionDetails& details, + bool page_needs_translation) override; + private: + void OnPageAway(int page_seq_no); + // The navigation controller of the tab we are associated with. content::NavigationController* navigation_controller_; @@ -115,6 +123,14 @@ // Max number of attempts before checking if a page has been reloaded. int max_reload_check_attempts_; + // Records mojo connections with all current alive pages. + int next_page_seq_no_; + std::map<int, mojom::PagePtr> pages_; + + // ContentTranslateDriver is singleton per web contents , + // serve for multiple render frames. + mojo::BindingSet<mojom::ContentTranslateDriver> bindings_; + base::WeakPtrFactory<ContentTranslateDriver> weak_pointer_factory_; DISALLOW_COPY_AND_ASSIGN(ContentTranslateDriver);
diff --git a/components/translate/content/common/BUILD.gn b/components/translate/content/common/BUILD.gn index 37e27153..7e782e1d 100644 --- a/components/translate/content/common/BUILD.gn +++ b/components/translate/content/common/BUILD.gn
@@ -1,20 +1,16 @@ -# Copyright 2014 The Chromium Authors. All rights reserved. +# Copyright 2016 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import("//build/config/features.gni") +import("//mojo/public/tools/bindings/mojom.gni") -static_library("common") { +mojom("common") { sources = [ - "translate_messages.cc", - "translate_messages.h", + "translate.mojom", ] - deps = [ - "//base", - "//components/translate/core/common", - "//components/translate/core/language_detection", - "//content/public/common", - "//ipc", + public_deps = [ + "//mojo/common:common_custom_types", + "//url/mojo:url_mojom_gurl", ] }
diff --git a/components/translate/content/common/DEPS b/components/translate/content/common/DEPS new file mode 100644 index 0000000..1c40d98 --- /dev/null +++ b/components/translate/content/common/DEPS
@@ -0,0 +1,3 @@ +include_rules = [ + "+ipc", +]
diff --git a/components/translate/content/common/OWNERS b/components/translate/content/common/OWNERS new file mode 100644 index 0000000..1544352 --- /dev/null +++ b/components/translate/content/common/OWNERS
@@ -0,0 +1,4 @@ +per-file *.mojom=set noparent +per-file *.mojom=file://ipc/SECURITY_OWNERS +per-file *_struct_traits*.*=set noparent +per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/components/translate/content/common/translate.mojom b/components/translate/content/common/translate.mojom new file mode 100644 index 0000000..e0916071 --- /dev/null +++ b/components/translate/content/common/translate.mojom
@@ -0,0 +1,65 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module translate.mojom; + +import "mojo/common/common_custom_types.mojom"; +import "url/mojo/url.mojom"; + +enum TranslateError { + NONE, + NETWORK, + INITIALIZATION_ERROR, + UNKNOWN_LANGUAGE, + UNSUPPORTED_LANGUAGE, + IDENTICAL_LANGUAGES, + TRANSLATION_ERROR, + TRANSLATION_TIMEOUT, + UNEXPECTED_SCRIPT_ERROR, + BAD_ORIGIN, + SCRIPT_LOAD_ERROR, + TRANSLATE_ERROR_MAX, +}; + +struct LanguageDetectionDetails { + mojo.common.mojom.Time time; + url.mojom.Url url; + string content_language; + string cld_language; + bool is_cld_reliable; + bool has_notranslate; + string html_root_language; + string adopted_language; + string contents; +}; + +interface Page { + // Requests that the page be translated from |source_lang| to + // |target_lang|. + // + // If a Translate request is already in progress with a matching + // |target_lang|, this request will respond with |cancelled| set + // to |true|. + // + // If a Translate request is already in progress with a different + // |target_lang|, that request will respond with |cancelled| set + // to |true| and this request will proceed normally. + // + // If |cancelled| is |true| all other response values should be + // ignored. + Translate(string translate_script, string source_lang, string target_lang) + => (bool cancelled, string original_lang, string translated_lang, + TranslateError error); + + // Requests that the page be reverted to its original language with + // no translation applied. + RevertTranslation(); +}; + +interface ContentTranslateDriver { + // Notification that a new page is ready to translate, + // and the language for it has been determined. + RegisterPage(Page page, LanguageDetectionDetails details, + bool page_needs_translation); +};
diff --git a/components/translate/content/common/translate.typemap b/components/translate/content/common/translate.typemap new file mode 100644 index 0000000..3aafd6a --- /dev/null +++ b/components/translate/content/common/translate.typemap
@@ -0,0 +1,23 @@ +# 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. + +mojom = "//components/translate/content/common/translate.mojom" +public_headers = [ + "//components/translate/core/common/language_detection_details.h", + "//components/translate/core/common/translate_errors.h", +] +traits_headers = + [ "//components/translate/content/common/translate_struct_traits.h" ] +sources = [ + "//components/translate/content/common/translate_struct_traits.cc", +] +deps = [ + "//base", + "//components/translate/core/common", +] + +type_mappings = [ + "translate.mojom.LanguageDetectionDetails=translate::LanguageDetectionDetails", + "translate.mojom.TranslateError=translate::TranslateErrors::Type", +]
diff --git a/components/translate/content/common/translate_messages.cc b/components/translate/content/common/translate_messages.cc deleted file mode 100644 index 73a8661e..0000000 --- a/components/translate/content/common/translate_messages.cc +++ /dev/null
@@ -1,39 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Get basic type definitions. -#define IPC_MESSAGE_IMPL -#include "components/translate/content/common/translate_messages.h" - -// Generate constructors. -#include "ipc/struct_constructor_macros.h" -#include "components/translate/content/common/translate_messages.h" - -// Generate destructors. -#include "ipc/struct_destructor_macros.h" -#include "components/translate/content/common/translate_messages.h" - -// Generate param traits size methods. -#include "ipc/param_traits_size_macros.h" -namespace IPC { -#include "components/translate/content/common/translate_messages.h" -} - -// Generate param traits write methods. -#include "ipc/param_traits_write_macros.h" -namespace IPC { -#include "components/translate/content/common/translate_messages.h" -} // namespace IPC - -// Generate param traits read methods. -#include "ipc/param_traits_read_macros.h" -namespace IPC { -#include "components/translate/content/common/translate_messages.h" -} // namespace IPC - -// Generate param traits log methods. -#include "ipc/param_traits_log_macros.h" -namespace IPC { -#include "components/translate/content/common/translate_messages.h" -} // namespace IPC
diff --git a/components/translate/content/common/translate_messages.h b/components/translate/content/common/translate_messages.h deleted file mode 100644 index ef394f5..0000000 --- a/components/translate/content/common/translate_messages.h +++ /dev/null
@@ -1,67 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Multiply-included message file, hence no include guard. - -#include "components/translate/core/common/language_detection_details.h" -#include "components/translate/core/common/translate_errors.h" -#include "ipc/ipc_message_macros.h" -#include "ipc/ipc_message_utils.h" -#include "url/ipc/url_param_traits.h" - -#define IPC_MESSAGE_START TranslateMsgStart - -IPC_ENUM_TRAITS_MAX_VALUE(translate::TranslateErrors::Type, - translate::TranslateErrors::TYPE_LAST) - -IPC_STRUCT_TRAITS_BEGIN(translate::LanguageDetectionDetails) - IPC_STRUCT_TRAITS_MEMBER(time) - IPC_STRUCT_TRAITS_MEMBER(url) - IPC_STRUCT_TRAITS_MEMBER(content_language) - IPC_STRUCT_TRAITS_MEMBER(cld_language) - IPC_STRUCT_TRAITS_MEMBER(is_cld_reliable) - IPC_STRUCT_TRAITS_MEMBER(has_notranslate) - IPC_STRUCT_TRAITS_MEMBER(html_root_language) - IPC_STRUCT_TRAITS_MEMBER(adopted_language) - IPC_STRUCT_TRAITS_MEMBER(contents) -IPC_STRUCT_TRAITS_END() - -//----------------------------------------------------------------------------- -// RenderFrame messages -// These are messages sent from the browser to the renderer process. - -// Tells the renderer to translate the page contents from one language to -// another. -IPC_MESSAGE_ROUTED4(ChromeFrameMsg_TranslatePage, - int /* page_seq_no */, - std::string, /* the script injected in the page */ - std::string, /* BCP 47/RFC 5646 language code the page - is in */ - std::string /* BCP 47/RFC 5646 language code to translate - to */) - -// Tells the renderer to revert the text of translated page to its original -// contents. -IPC_MESSAGE_ROUTED1(ChromeFrameMsg_RevertTranslation, int /* page id */) - -//----------------------------------------------------------------------------- -// Host messages -// These are messages sent from the renderer to the browser process. - -// Notification that the current page was assigned a sequence number. -IPC_MESSAGE_ROUTED1(ChromeFrameHostMsg_TranslateAssignedSequenceNumber, - int /* page_seq_no */) - -// Notification that the language for the tab has been determined. -IPC_MESSAGE_ROUTED2( - ChromeFrameHostMsg_TranslateLanguageDetermined, - translate::LanguageDetectionDetails /* details about lang detection */, - bool /* whether the page needs translation */) - -// Notifies the browser that a page has been translated. -IPC_MESSAGE_ROUTED3( - ChromeFrameHostMsg_PageTranslated, - std::string /* the original language */, - std::string /* the translated language */, - translate::TranslateErrors::Type /* the error type if available */)
diff --git a/components/translate/content/common/translate_struct_traits.cc b/components/translate/content/common/translate_struct_traits.cc new file mode 100644 index 0000000..e2670744 --- /dev/null +++ b/components/translate/content/common/translate_struct_traits.cc
@@ -0,0 +1,120 @@ +// 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 "components/translate/content/common/translate_struct_traits.h" + +#include "ipc/ipc_message_utils.h" +#include "url/mojo/url_gurl_struct_traits.h" + +using namespace translate; + +namespace mojo { + +mojom::TranslateError +EnumTraits<mojom::TranslateError, TranslateErrors::Type>::ToMojom( + TranslateErrors::Type input) { + switch (input) { + case TranslateErrors::Type::NONE: + return mojom::TranslateError::NONE; + case TranslateErrors::Type::NETWORK: + return mojom::TranslateError::NETWORK; + case TranslateErrors::Type::INITIALIZATION_ERROR: + return mojom::TranslateError::INITIALIZATION_ERROR; + case TranslateErrors::Type::UNKNOWN_LANGUAGE: + return mojom::TranslateError::UNKNOWN_LANGUAGE; + case TranslateErrors::Type::UNSUPPORTED_LANGUAGE: + return mojom::TranslateError::UNSUPPORTED_LANGUAGE; + case TranslateErrors::Type::IDENTICAL_LANGUAGES: + return mojom::TranslateError::IDENTICAL_LANGUAGES; + case TranslateErrors::Type::TRANSLATION_ERROR: + return mojom::TranslateError::TRANSLATION_ERROR; + case TranslateErrors::Type::TRANSLATION_TIMEOUT: + return mojom::TranslateError::TRANSLATION_TIMEOUT; + case TranslateErrors::Type::UNEXPECTED_SCRIPT_ERROR: + return mojom::TranslateError::UNEXPECTED_SCRIPT_ERROR; + case TranslateErrors::Type::BAD_ORIGIN: + return mojom::TranslateError::BAD_ORIGIN; + case TranslateErrors::Type::SCRIPT_LOAD_ERROR: + return mojom::TranslateError::SCRIPT_LOAD_ERROR; + case TranslateErrors::Type::TRANSLATE_ERROR_MAX: + return mojom::TranslateError::TRANSLATE_ERROR_MAX; + } + + NOTREACHED(); + return mojom::TranslateError::NONE; +} + +bool EnumTraits<mojom::TranslateError, TranslateErrors::Type>::FromMojom( + mojom::TranslateError input, + TranslateErrors::Type* output) { + switch (input) { + case mojom::TranslateError::NONE: + *output = TranslateErrors::Type::NONE; + return true; + case mojom::TranslateError::NETWORK: + *output = TranslateErrors::Type::NETWORK; + return true; + case mojom::TranslateError::INITIALIZATION_ERROR: + *output = TranslateErrors::Type::INITIALIZATION_ERROR; + return true; + case mojom::TranslateError::UNKNOWN_LANGUAGE: + *output = TranslateErrors::Type::UNKNOWN_LANGUAGE; + return true; + case mojom::TranslateError::UNSUPPORTED_LANGUAGE: + *output = TranslateErrors::Type::UNSUPPORTED_LANGUAGE; + return true; + case mojom::TranslateError::IDENTICAL_LANGUAGES: + *output = TranslateErrors::Type::IDENTICAL_LANGUAGES; + return true; + case mojom::TranslateError::TRANSLATION_ERROR: + *output = TranslateErrors::Type::TRANSLATION_ERROR; + return true; + case mojom::TranslateError::TRANSLATION_TIMEOUT: + *output = TranslateErrors::Type::TRANSLATION_TIMEOUT; + return true; + case mojom::TranslateError::UNEXPECTED_SCRIPT_ERROR: + *output = TranslateErrors::Type::UNEXPECTED_SCRIPT_ERROR; + return true; + case mojom::TranslateError::BAD_ORIGIN: + *output = TranslateErrors::Type::BAD_ORIGIN; + return true; + case mojom::TranslateError::SCRIPT_LOAD_ERROR: + *output = TranslateErrors::Type::SCRIPT_LOAD_ERROR; + return true; + case mojom::TranslateError::TRANSLATE_ERROR_MAX: + *output = TranslateErrors::Type::TRANSLATE_ERROR_MAX; + return true; + } + + NOTREACHED(); + return false; +} + +// static +bool StructTraits<mojom::LanguageDetectionDetails, LanguageDetectionDetails>:: + Read(mojom::LanguageDetectionDetailsDataView data, + LanguageDetectionDetails* out) { + if (!data.ReadTime(&out->time)) + return false; + if (!data.ReadUrl(&out->url)) + return false; + if (!data.ReadContentLanguage(&out->content_language)) + return false; + if (!data.ReadCldLanguage(&out->cld_language)) + return false; + + out->is_cld_reliable = data.is_cld_reliable(); + out->has_notranslate = data.has_notranslate(); + + if (!data.ReadHtmlRootLanguage(&out->html_root_language)) + return false; + if (!data.ReadAdoptedLanguage(&out->adopted_language)) + return false; + if (!data.ReadContents(&out->contents)) + return false; + + return true; +} + +} // namespace mojo
diff --git a/components/translate/content/common/translate_struct_traits.h b/components/translate/content/common/translate_struct_traits.h new file mode 100644 index 0000000..d802fc2 --- /dev/null +++ b/components/translate/content/common/translate_struct_traits.h
@@ -0,0 +1,76 @@ +// 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 COMPONENTS_TRANSLATE_CONTENT_COMMON_TRANSLATE_STRUCT_TRAITS_H_ +#define COMPONENTS_TRANSLATE_CONTENT_COMMON_TRANSLATE_STRUCT_TRAITS_H_ + +#include "base/strings/string16.h" +#include "base/time/time.h" +#include "components/translate/content/common/translate.mojom.h" +#include "components/translate/core/common/language_detection_details.h" +#include "components/translate/core/common/translate_errors.h" +#include "mojo/public/cpp/bindings/struct_traits.h" + +namespace mojo { + +template <> +struct EnumTraits<translate::mojom::TranslateError, + translate::TranslateErrors::Type> { + static translate::mojom::TranslateError ToMojom( + translate::TranslateErrors::Type input); + static bool FromMojom(translate::mojom::TranslateError input, + translate::TranslateErrors::Type* output); +}; + +template <> +struct StructTraits<translate::mojom::LanguageDetectionDetails, + translate::LanguageDetectionDetails> { + static const base::Time& time(const translate::LanguageDetectionDetails& r) { + return r.time; + } + + static const GURL& url(const translate::LanguageDetectionDetails& r) { + return r.url; + } + + static const std::string& content_language( + const translate::LanguageDetectionDetails& r) { + return r.content_language; + } + + static const std::string& cld_language( + const translate::LanguageDetectionDetails& r) { + return r.cld_language; + } + + static bool is_cld_reliable(const translate::LanguageDetectionDetails& r) { + return r.is_cld_reliable; + } + + static bool has_notranslate(const translate::LanguageDetectionDetails& r) { + return r.has_notranslate; + } + + static const std::string& html_root_language( + const translate::LanguageDetectionDetails& r) { + return r.html_root_language; + } + + static const std::string& adopted_language( + const translate::LanguageDetectionDetails& r) { + return r.adopted_language; + } + + static const base::string16& contents( + const translate::LanguageDetectionDetails& r) { + return r.contents; + } + + static bool Read(translate::mojom::LanguageDetectionDetailsDataView data, + translate::LanguageDetectionDetails* out); +}; + +} // namespace mojo + +#endif // COMPONENTS_TRANSLATE_CONTENT_COMMON_TRANSLATE_STRUCT_TRAITS_H_
diff --git a/components/translate/content/renderer/BUILD.gn b/components/translate/content/renderer/BUILD.gn index 03dba49..0a16d44 100644 --- a/components/translate/content/renderer/BUILD.gn +++ b/components/translate/content/renderer/BUILD.gn
@@ -17,9 +17,9 @@ "//components/translate/core/language_detection", "//content/public/common", "//content/public/renderer", - "//ipc", + "//services/shell/public/cpp", "//third_party/WebKit/public:blink", - "//third_party/cld_2", + "//third_party/cld", "//url", "//v8", ]
diff --git a/components/translate/content/renderer/DEPS b/components/translate/content/renderer/DEPS index a0023b47..b95e8bf 100644 --- a/components/translate/content/renderer/DEPS +++ b/components/translate/content/renderer/DEPS
@@ -1,5 +1,6 @@ include_rules = [ "+content/public/renderer", + "+services/shell/public", "+third_party/cld_2", "+third_party/WebKit/public/web", "+v8",
diff --git a/components/translate/content/renderer/translate_helper.cc b/components/translate/content/renderer/translate_helper.cc index 6eca2104..330ac9a 100644 --- a/components/translate/content/renderer/translate_helper.cc +++ b/components/translate/content/renderer/translate_helper.cc
@@ -14,7 +14,6 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/threading/thread_task_runner_handle.h" -#include "components/translate/content/common/translate_messages.h" #include "components/translate/core/common/translate_constants.h" #include "components/translate/core/common/translate_metrics.h" #include "components/translate/core/common/translate_util.h" @@ -23,7 +22,7 @@ #include "content/public/common/url_constants.h" #include "content/public/renderer/render_frame.h" #include "content/public/renderer/render_thread.h" -#include "ipc/ipc_platform_file.h" +#include "services/shell/public/cpp/interface_provider.h" #include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebElement.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" @@ -78,7 +77,7 @@ const WebString content(ASCIIToUTF16("content")); for (WebNode child = head.firstChild(); !child.isNull(); - child = child.nextSibling()) { + child = child.nextSibling()) { if (!child.isElementNode()) continue; WebElement element = child.to<WebElement>(); @@ -108,34 +107,27 @@ //////////////////////////////////////////////////////////////////////////////// // TranslateHelper, public: -// TranslateHelper::TranslateHelper(content::RenderFrame* render_frame, int world_id, int extension_group, const std::string& extension_scheme) : content::RenderFrameObserver(render_frame), - page_seq_no_(0), - translation_pending_(false), world_id_(world_id), extension_group_(extension_group), extension_scheme_(extension_scheme), + binding_(this), weak_method_factory_(this) {} TranslateHelper::~TranslateHelper() { } void TranslateHelper::PrepareForUrl(const GURL& url) { - ++page_seq_no_; - Send(new ChromeFrameHostMsg_TranslateAssignedSequenceNumber(routing_id(), - page_seq_no_)); + // Navigated to a new page, close the binding for previous page. + binding_.Close(); + translate_callback_pending_.Reset(); } void TranslateHelper::PageCaptured(const base::string16& contents) { - PageCapturedImpl(page_seq_no_, contents); -} - -void TranslateHelper::PageCapturedImpl(int page_seq_no, - const base::string16& contents) { // Get the document language as set by WebKit from the http-equiv // meta tag for "content-language". This may or may not also // have a value derived from the actual Content-Language HTTP @@ -146,7 +138,7 @@ // relevant for things like langauge textbooks). This distinction // shouldn't affect translation. WebLocalFrame* main_frame = render_frame()->GetWebFrame(); - if (!main_frame || page_seq_no_ != page_seq_no) + if (!main_frame) return; WebDocument document = main_frame->document(); @@ -182,20 +174,28 @@ // translate-internals tab exists. details.contents = contents; - Send(new ChromeFrameHostMsg_TranslateLanguageDetermined( - routing_id(), details, !details.has_notranslate && !language.empty())); + // For the same render frame with the same url, each time when its texts are + // captured, it should be treated as a new page to do translation. + binding_.Close(); + GetTranslateDriver()->RegisterPage( + binding_.CreateInterfacePtrAndBind(), details, + !details.has_notranslate && !language.empty()); } void TranslateHelper::CancelPendingTranslation() { weak_method_factory_.InvalidateWeakPtrs(); - translation_pending_ = false; + // Make sure to send the cancelled response back. + if (translate_callback_pending_) { + translate_callback_pending_.Run(true, source_lang_, target_lang_, + TranslateErrors::NONE); + translate_callback_pending_.Reset(); + } source_lang_.clear(); target_lang_.clear(); } //////////////////////////////////////////////////////////////////////////////// // TranslateHelper, protected: -// bool TranslateHelper::IsTranslateLibAvailable() { return ExecuteScriptAndGetBoolResult( "typeof cr != 'undefined' && typeof cr.googleTranslate != 'undefined' && " @@ -304,36 +304,30 @@ return results[0]->NumberValue(); } -//////////////////////////////////////////////////////////////////////////////// -// TranslateHelper, private: -// -bool TranslateHelper::OnMessageReceived(const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(TranslateHelper, message) - IPC_MESSAGE_HANDLER(ChromeFrameMsg_TranslatePage, OnTranslatePage) - IPC_MESSAGE_HANDLER(ChromeFrameMsg_RevertTranslation, OnRevertTranslation) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -void TranslateHelper::OnTranslatePage(int page_seq_no, - const std::string& translate_script, - const std::string& source_lang, - const std::string& target_lang) { +// mojom::Page implementations. +void TranslateHelper::Translate(const std::string& translate_script, + const std::string& source_lang, + const std::string& target_lang, + const TranslateCallback& callback) { WebLocalFrame* main_frame = render_frame()->GetWebFrame(); - if (!main_frame || page_seq_no_ != page_seq_no) + if (!main_frame) { + // Cancelled. + callback.Run(true, source_lang, target_lang, TranslateErrors::NONE); return; // We navigated away, nothing to do. + } // A similar translation is already under way, nothing to do. - if (translation_pending_ && target_lang_ == target_lang) + if (translate_callback_pending_ && target_lang_ == target_lang) { + // This request is ignored. + callback.Run(true, source_lang, target_lang, TranslateErrors::NONE); return; + } // Any pending translation is now irrelevant. CancelPendingTranslation(); // Set our states. - translation_pending_ = true; + translate_callback_pending_ = callback; // If the source language is undetermined, we'll let the translate element // detect it. @@ -362,13 +356,10 @@ DCHECK(IsTranslateLibAvailable()); } - TranslatePageImpl(page_seq_no, 0); + TranslatePageImpl(0); } -void TranslateHelper::OnRevertTranslation(int page_seq_no) { - if (page_seq_no_ != page_seq_no) - return; // We navigated away, nothing to do. - +void TranslateHelper::RevertTranslation() { if (!IsTranslateLibAvailable()) { NOTREACHED(); return; @@ -379,11 +370,9 @@ ExecuteScript("cr.googleTranslate.revert()"); } -void TranslateHelper::CheckTranslateStatus(int page_seq_no) { - // If this is not the same page, the translation has been canceled. - if (page_seq_no_ != page_seq_no) - return; - +//////////////////////////////////////////////////////////////////////////////// +// TranslateHelper, private: +void TranslateHelper::CheckTranslateStatus() { // First check if there was an error. if (HasTranslationFailed()) { // TODO(toyoshim): Check |errorCode| of translate.js and notify it here. @@ -408,36 +397,31 @@ actual_source_lang = source_lang_; } - if (!translation_pending_) { + if (!translate_callback_pending_) { NOTREACHED(); return; } - translation_pending_ = false; - // Check JavaScript performance counters for UMA reports. ReportTimeToTranslate( ExecuteScriptAndGetDoubleResult("cr.googleTranslate.translationTime")); // Notify the browser we are done. - render_frame()->Send(new ChromeFrameHostMsg_PageTranslated( - render_frame()->GetRoutingID(), actual_source_lang, target_lang_, - TranslateErrors::NONE)); + translate_callback_pending_.Run(false, actual_source_lang, target_lang_, + TranslateErrors::NONE); + translate_callback_pending_.Reset(); return; } // The translation is still pending, check again later. base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, base::Bind(&TranslateHelper::CheckTranslateStatus, - weak_method_factory_.GetWeakPtr(), page_seq_no), + weak_method_factory_.GetWeakPtr()), AdjustDelay(kTranslateStatusCheckDelayMs)); } -void TranslateHelper::TranslatePageImpl(int page_seq_no, int count) { +void TranslateHelper::TranslatePageImpl(int count) { DCHECK_LT(count, kMaxTranslateInitCheckAttempts); - if (page_seq_no_ != page_seq_no) - return; - if (!IsTranslateLibReady()) { // The library is not ready, try again later, unless we have tried several // times unsuccessfully already. @@ -446,9 +430,8 @@ return; } base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, - base::Bind(&TranslateHelper::TranslatePageImpl, - weak_method_factory_.GetWeakPtr(), page_seq_no, count), + FROM_HERE, base::Bind(&TranslateHelper::TranslatePageImpl, + weak_method_factory_.GetWeakPtr(), count), AdjustDelay(count * kTranslateInitCheckDelayMs)); return; } @@ -467,16 +450,25 @@ // Check the status of the translation. base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, base::Bind(&TranslateHelper::CheckTranslateStatus, - weak_method_factory_.GetWeakPtr(), page_seq_no), + weak_method_factory_.GetWeakPtr()), AdjustDelay(kTranslateStatusCheckDelayMs)); } void TranslateHelper::NotifyBrowserTranslationFailed( TranslateErrors::Type error) { - translation_pending_ = false; + DCHECK(translate_callback_pending_); // Notify the browser there was an error. - render_frame()->Send(new ChromeFrameHostMsg_PageTranslated( - render_frame()->GetRoutingID(), source_lang_, target_lang_, error)); + translate_callback_pending_.Run(false, source_lang_, target_lang_, error); + translate_callback_pending_.Reset(); +} + +const mojom::ContentTranslateDriverPtr& TranslateHelper::GetTranslateDriver() { + if (!translate_driver_) { + render_frame()->GetRemoteInterfaces()->GetInterface( + mojo::GetProxy(&translate_driver_)); + } + + return translate_driver_; } void TranslateHelper::OnDestruct() {
diff --git a/components/translate/content/renderer/translate_helper.h b/components/translate/content/renderer/translate_helper.h index e7277510..bff4756 100644 --- a/components/translate/content/renderer/translate_helper.h +++ b/components/translate/content/renderer/translate_helper.h
@@ -12,8 +12,10 @@ #include "base/memory/weak_ptr.h" #include "base/strings/string16.h" #include "base/time/time.h" +#include "components/translate/content/common/translate.mojom.h" #include "components/translate/core/common/translate_errors.h" #include "content/public/renderer/render_frame_observer.h" +#include "mojo/public/cpp/bindings/binding.h" #include "url/gurl.h" namespace blink { @@ -25,12 +27,13 @@ // This class deals with page translation. // There is one TranslateHelper per RenderView. -class TranslateHelper : public content::RenderFrameObserver { +class TranslateHelper : public content::RenderFrameObserver, + public mojom::Page { public: - explicit TranslateHelper(content::RenderFrame* render_frame, - int world_id, - int extension_group, - const std::string& extension_scheme); + TranslateHelper(content::RenderFrame* render_frame, + int world_id, + int extension_group, + const std::string& extension_scheme); ~TranslateHelper() override; // Informs us that the page's text has been extracted. @@ -41,15 +44,14 @@ // this URL loads, this is the time to prepare for it. void PrepareForUrl(const GURL& url); - protected: - // The following methods are protected so they can be overridden in - // unit-tests. - void OnTranslatePage(int page_seq_no, - const std::string& translate_script, - const std::string& source_lang, - const std::string& target_lang); - void OnRevertTranslation(int page_seq_no); + // mojom::Page implementation. + void Translate(const std::string& translate_script, + const std::string& source_lang, + const std::string& target_lang, + const TranslateCallback& callback) override; + void RevertTranslation() override; + protected: // Returns true if the translate library is available, meaning the JavaScript // has already been injected in that page. virtual bool IsTranslateLibAvailable(); @@ -102,12 +104,10 @@ // Converts language code to the one used in server supporting list. static void ConvertLanguageCodeSynonym(std::string* code); - // RenderFrameObserver implementation. - bool OnMessageReceived(const IPC::Message& message) override; - void OnDestruct() override; + const mojom::ContentTranslateDriverPtr& GetTranslateDriver(); - // Informs us that the page's text has been extracted. - void PageCapturedImpl(int page_seq_no, const base::string16& contents); + // RenderFrameObserver implementation. + void OnDestruct() override; // Cancels any translation that is currently being performed. This does not // revert existing translations. @@ -116,11 +116,11 @@ // Checks if the current running page translation is finished or errored and // notifies the browser accordingly. If the translation has not terminated, // posts a task to check again later. - void CheckTranslateStatus(int page_seq_no); + void CheckTranslateStatus(); // Called by TranslatePage to do the actual translation. |count| is used to // limit the number of retries. - void TranslatePageImpl(int page_seq_no, int count); + void TranslatePageImpl(int count); // Sends a message to the browser to notify it that the translation failed // with |error|. @@ -130,12 +130,8 @@ // if the page is being closed. blink::WebLocalFrame* GetMainFrame(); - // An ever-increasing sequence number of the current page, used to match up - // translation requests with responses. - int page_seq_no_; - // The states associated with the current translation. - bool translation_pending_; + TranslateCallback translate_callback_pending_; std::string source_lang_; std::string target_lang_; @@ -152,6 +148,10 @@ // The URL scheme for translate extensions. std::string extension_scheme_; + mojom::ContentTranslateDriverPtr translate_driver_; + + mojo::Binding<mojom::Page> binding_; + // Method factory used to make calls to TranslatePageImpl. base::WeakPtrFactory<TranslateHelper> weak_method_factory_;
diff --git a/components/translate/core/browser/translate_browser_metrics.h b/components/translate/core/browser/translate_browser_metrics.h index 7190c226..a0d6af2 100644 --- a/components/translate/core/browser/translate_browser_metrics.h +++ b/components/translate/core/browser/translate_browser_metrics.h
@@ -40,6 +40,7 @@ INITIATION_STATUS_SHOW_INFOBAR, INITIATION_STATUS_MIME_TYPE_IS_NOT_SUPPORTED, INITIATION_STATUS_DISABLED_BY_KEY, + INITIATION_STATUS_LANGUAGE_IN_ULP, // Insert new items here. INITIATION_STATUS_MAX, };
diff --git a/components/translate/core/browser/translate_manager.cc b/components/translate/core/browser/translate_manager.cc index 9de6910..2330a77 100644 --- a/components/translate/core/browser/translate_manager.cc +++ b/components/translate/core/browser/translate_manager.cc
@@ -4,10 +4,13 @@ #include "components/translate/core/browser/translate_manager.h" +#include <map> + #include "base/bind.h" #include "base/command_line.h" #include "base/metrics/field_trial.h" #include "base/metrics/histogram.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/strings/stringprintf.h" #include "base/time/time.h" @@ -30,6 +33,7 @@ #include "components/translate/core/common/translate_pref_names.h" #include "components/translate/core/common/translate_switches.h" #include "components/translate/core/common/translate_util.h" +#include "components/variations/variations_associated_data.h" #include "google_apis/google_api_keys.h" #include "net/base/network_change_notifier.h" #include "net/base/url_util.h" @@ -37,6 +41,8 @@ namespace translate { +const base::Feature kTranslateLanguageByULP{"TranslateLanguageByULP", + base::FEATURE_DISABLED_BY_DEFAULT}; namespace { // Callbacks for translate errors. @@ -52,6 +58,60 @@ // Used in kReportLanguageDetectionErrorURL to specify the page URL. const char kUrlQueryName[] = "u"; +// Name for params in config for considering ULP in GetTargetLanguage(). +const char kTargetLanguageULPConfidenceThresholdName[] = + "target_language_ulp_confidence_threshold"; +const char kTargetLanguageULPProbabilityThresholdName[] = + "target_language_ulp_probability_threshold"; + +// Name for params in config for considering ULP in InitiateTranslation(). +const char kInitiateTranslationULPConfidenceThresholdName[] = + "initiate_translation_ulp_confidence_threshold"; +const char kInitiateTranslationULPProbabilityThresholdName[] = + "initiate_translation_ulp_probability_threshold"; + +// Constants for considering ULP. These built-in constatants of default will be +// override by the value in config params if present. +// Default constants for the GetTargetLanguage() function: +// The confidence threshold that we will consider to use the ULP +// "reading list". +const double kDefaultTargetLanguageULPConfidenceThreshold = 0.7; +// The probability threshold that we will consider to use a language on +// ULP "reading list". +const double kDefaultTargetLanguageULPProbabilityThreshold = 0.55; + +// Default constants for the InitiateTranslation() function: +// The confidence threshold that we will consider to use the ULP +// "reading list". +const double kDefaultInitiateTranslationULPConfidenceThreshold = 0.75; +// The probability threshold that we will consider to use a language on +// ULP "reading list". +const double kDefaultInitiateTranslationULPProbabilityThreshold = 0.5; + +// Return the probability of the |language| in the |list|, or 0.0 if it is not +// in +// the |list|. +double GetLanguageProbability( + const TranslatePrefs::LanguageAndProbabilityList& list, + const std::string language) { + for (const auto& it : list) { + if (language == it.first) { + return it.second; + } + } + return 0.0; +} + +// Get a value from the |map| by |key| and return the converted double, if +// failed +// return the |default_value| instead. +double GetDoubleFromMap(std::map<std::string, std::string>& map, + const std::string& key, + double default_value) { + double value = default_value; + return base::StringToDouble(map[key], &value) ? value : default_value; +} + } // namespace TranslateManager::~TranslateManager() {} @@ -189,8 +249,6 @@ // feature; the user will get an infobar, so they can control whether the // page's text is sent to the translate server. if (!translate_driver_->IsOffTheRecord()) { - std::unique_ptr<TranslatePrefs> translate_prefs = - translate_client_->GetTranslatePrefs(); std::string auto_target_lang = GetAutoTargetLanguage(language_code, translate_prefs.get()); if (!auto_target_lang.empty()) { @@ -210,6 +268,12 @@ return; } + if (LanguageInULP(language_code)) { + TranslateBrowserMetrics::ReportInitiationStatus( + TranslateBrowserMetrics::INITIATION_STATUS_LANGUAGE_IN_ULP); + return; + } + TranslateBrowserMetrics::ReportInitiationStatus( TranslateBrowserMetrics::INITIATION_STATUS_SHOW_INFOBAR); @@ -221,6 +285,27 @@ false); } +bool TranslateManager::LanguageInULP(const std::string& language) const { + if (!base::FeatureList::IsEnabled(kTranslateLanguageByULP)) + return false; + std::map<std::string, std::string> params; + variations::GetVariationParamsByFeature(translate::kTranslateLanguageByULP, + ¶ms); + // Check the language & probability on the reading list. + TranslatePrefs::LanguageAndProbabilityList reading; + if (translate_client_->GetTranslatePrefs()->GetReadingFromUserLanguageProfile( + &reading) > + GetDoubleFromMap(params, + kInitiateTranslationULPConfidenceThresholdName, + kDefaultInitiateTranslationULPConfidenceThreshold) && + GetLanguageProbability(reading, language) > + GetDoubleFromMap(params, + kInitiateTranslationULPProbabilityThresholdName, + kDefaultInitiateTranslationULPProbabilityThreshold)) + return true; + return false; +} + void TranslateManager::TranslatePage(const std::string& original_source_lang, const std::string& target_lang, bool triggered_from_menu) { @@ -355,14 +440,24 @@ // static std::string TranslateManager::GetTargetLanguage(const TranslatePrefs* prefs) { - std::string ui_lang = TranslateDownloadManager::GetLanguageCode( - TranslateDownloadManager::GetInstance()->application_locale()); - translate::ToTranslateLanguageSynonym(&ui_lang); + std::string language; - TranslateExperiment::OverrideUiLanguage(prefs->GetCountry(), &ui_lang); + // Get the override UI language. + TranslateExperiment::OverrideUiLanguage(prefs->GetCountry(), &language); - if (TranslateDownloadManager::IsSupportedLanguage(ui_lang)) - return ui_lang; + // If there are no override. + if (language.empty()) { + // Get the language from ULP. + language = TranslateManager::GetTargetLanguageFromULP(prefs); + if (!language.empty()) + return language; + + // Get the browser's user interface language. + language = TranslateDownloadManager::GetLanguageCode( + TranslateDownloadManager::GetInstance()->application_locale()); + } + if (TranslateDownloadManager::IsSupportedLanguage(language)) + return language; // Will translate to the first supported language on the Accepted Language // list or not at all if no such candidate exists. @@ -377,6 +472,29 @@ } // static +std::string TranslateManager::GetTargetLanguageFromULP( + const TranslatePrefs* prefs) { + if (!base::FeatureList::IsEnabled(kTranslateLanguageByULP)) + return std::string(); + std::map<std::string, std::string> params; + variations::GetVariationParamsByFeature(translate::kTranslateLanguageByULP, + ¶ms); + TranslatePrefs::LanguageAndProbabilityList reading; + // We only consider ULP if the confidence is greater than the threshold. + if (prefs->GetReadingFromUserLanguageProfile(&reading) <= + GetDoubleFromMap(params, kTargetLanguageULPConfidenceThresholdName, + kDefaultTargetLanguageULPConfidenceThreshold)) + return std::string(); + + if (reading.size() > 0 && + reading[0].second > + GetDoubleFromMap(params, kTargetLanguageULPProbabilityThresholdName, + kDefaultTargetLanguageULPProbabilityThreshold)) + return reading[0].first; + return std::string(); +} + +// static std::string TranslateManager::GetAutoTargetLanguage( const std::string& original_language, TranslatePrefs* translate_prefs) {
diff --git a/components/translate/core/browser/translate_manager.h b/components/translate/core/browser/translate_manager.h index 7ba8770..502474f 100644 --- a/components/translate/core/browser/translate_manager.h +++ b/components/translate/core/browser/translate_manager.h
@@ -11,6 +11,8 @@ #include <vector> #include "base/callback_list.h" +#include "base/feature_list.h" +#include "base/gtest_prod_util.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "components/translate/core/browser/language_state.h" @@ -21,9 +23,16 @@ namespace translate { +extern const base::Feature kTranslateLanguageByULP; + class TranslateClient; class TranslateDriver; class TranslatePrefs; + +namespace testing { +class TranslateManagerTest; +} // namespace testing + struct TranslateErrorDetails; // The TranslateManager class is responsible for showing an info-bar when a page @@ -52,6 +61,7 @@ // Returns the language to translate to. The language returned is the // first language found in the following list that is supported by the // translation service: + // High confidence and high probability reading language in ULP // the UI language // the accept-language list // If no language is found then an empty string is returned. @@ -103,11 +113,21 @@ static void SetIgnoreMissingKeyForTesting(bool ignore); private: + friend class translate::testing::TranslateManagerTest; + // Sends a translation request to the TranslateDriver. void DoTranslatePage(const std::string& translate_script, const std::string& source_lang, const std::string& target_lang); + // Returns the language to translate to by looking at ULP. Return empty string + // If it cannot conclude from ULP. + static std::string GetTargetLanguageFromULP(const TranslatePrefs* prefs); + + // Return true if the language is in the ULP with high confidence and high + // probability. + bool LanguageInULP(const std::string& language) const; + // Notifies all registered callbacks of translate errors. void NotifyTranslateError(TranslateErrors::Type error_type);
diff --git a/components/translate/core/browser/translate_manager_unittest.cc b/components/translate/core/browser/translate_manager_unittest.cc index 7c0ba44..7148fb5 100644 --- a/components/translate/core/browser/translate_manager_unittest.cc +++ b/components/translate/core/browser/translate_manager_unittest.cc
@@ -4,8 +4,10 @@ #include "components/translate/core/browser/translate_manager.h" +#include "base/json/json_reader.h" #include "base/run_loop.h" #include "base/test/histogram_tester.h" +#include "base/test/scoped_feature_list.h" #include "build/build_config.h" #include "components/infobars/core/infobar.h" #include "components/pref_registry/pref_registry_syncable.h" @@ -16,14 +18,21 @@ #include "components/translate/core/browser/translate_download_manager.h" #include "components/translate/core/browser/translate_prefs.h" #include "components/translate/core/common/translate_pref_names.h" +#include "components/variations/variations_associated_data.h" #include "net/base/network_change_notifier.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +using testing::_; +using testing::Return; +using testing::SetArgPointee; + namespace translate { namespace { +const char kTrialName[] = "MyTrial"; + #if defined(OS_CHROMEOS) const char kLanguagePreferredLanguages[] = "settings.language.preferred_languages"; @@ -115,6 +124,10 @@ PrefService* prefs_; }; +} // namespace + +namespace testing { + class TranslateManagerTest : public ::testing::Test { protected: TranslateManagerTest() @@ -122,7 +135,8 @@ kAcceptLanguages, kLanguagePreferredLanguages), manager_(TranslateDownloadManager::GetInstance()), - mock_translate_client_(&driver_, &prefs_) {} + mock_translate_client_(&driver_, &prefs_), + field_trial_list_(new base::FieldTrialList(nullptr)) {} void SetUp() override { // Ensure we're not requesting a server-side translate language list. @@ -139,6 +153,74 @@ user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); manager_->ResetForTesting(); } + + void TearDown() override { + manager_->ResetForTesting(); + variations::testing::ClearAllVariationParams(); + } + + // Utility function to prepare translate_manager_ for testing. + void PrepareTranslateManager() { + TranslateManager::SetIgnoreMissingKeyForTesting(true); + translate_manager_.reset(new translate::TranslateManager( + &mock_translate_client_, kAcceptLanguages)); + } + + // Prepare the test for ULP related tests. + // Put the ulp json into profile. + void PrepareULPTest(const char* ulp_json, bool turn_on_feature) { + PrepareTranslateManager(); + std::unique_ptr<base::Value> profile(CreateProfileFromJSON(ulp_json)); + prefs_.SetUserPref(TranslatePrefs::kPrefLanguageProfile, profile.release()); + if (turn_on_feature) + TurnOnTranslateByULP(); + } + + std::unique_ptr<base::Value> CreateProfileFromJSON(const char* json) { + int error_code = 0; + std::string error_msg; + int error_line = 0; + int error_column = 0; + + std::unique_ptr<base::Value> profile(base::JSONReader::ReadAndReturnError( + json, 0, &error_code, &error_msg, &error_line, &error_column)); + + EXPECT_EQ(0, error_code) << error_msg << " at " << error_line << ":" + << error_column << std::endl + << json; + return profile; + } + + void TurnOnTranslateByULP() { + scoped_refptr<base::FieldTrial> trial( + CreateFieldTrial(kTrialName, 100, "Enabled", NULL)); + std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList); + feature_list->RegisterFieldTrialOverride( + translate::kTranslateLanguageByULP.name, + base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial.get()); + scoped_feature_list_.InitWithFeatureList(std::move(feature_list)); + } + + scoped_refptr<base::FieldTrial> CreateFieldTrial( + const std::string& trial_name, + int total_probability, + const std::string& default_group_name, + int* default_group_number) { + return base::FieldTrialList::FactoryGetFieldTrial( + trial_name, total_probability, default_group_name, + base::FieldTrialList::kNoExpirationYear, 1, 1, + base::FieldTrial::SESSION_RANDOMIZED, default_group_number); + } + + // Functions to help TEST_F in subclass to access private functions in + // TranslteManager so we can unit test them. + std::string CallGetTargetLanguageFromULP() { + return TranslateManager::GetTargetLanguageFromULP(&translate_prefs_); + } + bool CallLanguageInULP(const std::string& language) { + return translate_manager_->LanguageInULP(language); + } + user_prefs::TestingPrefServiceSyncable prefs_; // TODO(groby): request TranslatePrefs from |mock_translate_client_| instead. @@ -149,11 +231,10 @@ translate::testing::MockTranslateDriver driver_; ::testing::NiceMock<MockTranslateClient> mock_translate_client_; std::unique_ptr<TranslateManager> translate_manager_; - - void TearDown() override { manager_->ResetForTesting(); } + std::unique_ptr<base::FieldTrialList> field_trial_list_; + base::test::ScopedFeatureList scoped_feature_list_; }; -} // namespace // Target language comes from application locale if the locale's language // is supported. @@ -225,4 +306,148 @@ 1); } +// Utility function to set the threshold params +void ChangeThresholdInParams( + const char* initiate_translation_confidence_threshold, + const char* initiate_translation_probability_threshold, + const char* target_language_confidence_threshold, + const char* target_language_probability_threshold) { + ASSERT_TRUE(variations::AssociateVariationParams( + kTrialName, "Enabled", {{"initiate_translation_ulp_confidence_threshold", + initiate_translation_confidence_threshold}, + {"initiate_translation_ulp_probability_threshold", + initiate_translation_probability_threshold}, + {"target_language_ulp_confidence_threshold", + target_language_confidence_threshold}, + {"target_language_ulp_probability_threshold", + target_language_probability_threshold}})); +} + +// Normal ULP in Json +const char ulp_1[] = + "{\n" + " \"reading\": {\n" + " \"confidence\": 0.8,\n" + " \"preference\": [\n" + " {\n" + " \"language\": \"fr\",\n" + " \"probability\": 0.6\n" + " }, {\n" + " \"language\": \"pt-PT\",\n" + " \"probability\": 0.4\n" + " }\n" + " ]\n" + " }\n" + "}"; + +// ULP in Json with smaller probability of several es-* language codes +// sum up to 0.7. +const char ulp_2[] = + "{\n" + " \"reading\": {\n" + " \"confidence\": 0.9,\n" + " \"preference\": [\n" + " {\n" + " \"language\": \"fr\",\n" + " \"probability\": 0.3\n" + " }, {\n" + " \"language\": \"es-419\",\n" + " \"probability\": 0.2\n" + " }, {\n" + " \"language\": \"es-MX\",\n" + " \"probability\": 0.2\n" + " }, {\n" + " \"language\": \"es-US\",\n" + " \"probability\": 0.2\n" + " }, {\n" + " \"language\": \"es-CL\",\n" + " \"probability\": 0.1\n" + " }\n" + " ]\n" + " }\n" + "}"; + +TEST_F(TranslateManagerTest, TestGetTargetLanguageFromULPFeatureOff) { + PrepareULPTest(ulp_1, false); + + EXPECT_STREQ("", CallGetTargetLanguageFromULP().c_str()); +} + +TEST_F(TranslateManagerTest, TestGetTargetLanguageFromULPHighConfidence) { + PrepareULPTest(ulp_1, true); + + // The default hardcoded threshold are confidence: 0.7, probability: 0.55 + EXPECT_STREQ("fr", CallGetTargetLanguageFromULP().c_str()); +} + +TEST_F(TranslateManagerTest, + TestGetTargetLanguageFromULPHighConfidenceThresholdFromConfig) { + PrepareULPTest(ulp_1, true); + ChangeThresholdInParams("", "", "0.81", "0.5"); + + // Should get empty string as result since the confidence threshold is above + // the ULP (0.8 in the ulp_1). + EXPECT_STREQ("", CallGetTargetLanguageFromULP().c_str()); +} + +TEST_F(TranslateManagerTest, + TestGetTargetLanguageFromULPHighProbabilityThresholdFromConfig) { + PrepareULPTest(ulp_1, true); + ChangeThresholdInParams("", "", "0.4", "0.61"); + + // Should get empty string as result since the confidence threshold is above + // the ULP (0.6 for fr in the ulp_1). + EXPECT_STREQ("", CallGetTargetLanguageFromULP().c_str()); +} + +TEST_F(TranslateManagerTest, TestGetTargetLanguageFromULPProbabilitySumUp) { + PrepareULPTest(ulp_2, true); + ChangeThresholdInParams("", "", "0.4", "0.61"); + + // Should get "es" since the sum of the "es-*" probability is 0.7. + EXPECT_STREQ("es", CallGetTargetLanguageFromULP().c_str()); +} + +TEST_F(TranslateManagerTest, TestLanguageInULPFeatureOff) { + PrepareULPTest(ulp_1, false); + + EXPECT_FALSE(CallLanguageInULP("fr")); + EXPECT_FALSE(CallLanguageInULP("pt")); + EXPECT_FALSE(CallLanguageInULP("zh-TW")); +} + +TEST_F(TranslateManagerTest, TestLanguageInULPDefaultThreshold) { + PrepareULPTest(ulp_1, true); + + // The default hardcoded threshold are confidence: 0.75, probability: 0.5 + EXPECT_TRUE(CallLanguageInULP("fr")); + EXPECT_FALSE(CallLanguageInULP("pt")); + EXPECT_FALSE(CallLanguageInULP("zh-TW")); +} + +TEST_F(TranslateManagerTest, + TestLanguageInULPHighConfidenceThresholdFromConfig) { + PrepareULPTest(ulp_1, true); + ChangeThresholdInParams("0.9", "0.5", "", ""); + // "fr" and "pt" should return false because the confidence threshold is set + // to 0.9. + EXPECT_FALSE(CallLanguageInULP("fr")); + EXPECT_FALSE(CallLanguageInULP("pt")); + EXPECT_FALSE(CallLanguageInULP("zh-TW")); +} + +TEST_F(TranslateManagerTest, + TestLanguageInULPLowConfidenceThresholdFromConfig) { + PrepareULPTest(ulp_1, true); + ChangeThresholdInParams("0.79", "0.39", "", ""); + // Both "fr" and "pt" should reutrn true because the confidence threshold is + // 0.79 and lower than 0.8 and the probability threshold is lower than both + // the one with "fr" (0.6) and "pt-PT" (0.4). + EXPECT_TRUE(CallLanguageInULP("fr")); + EXPECT_TRUE(CallLanguageInULP("pt")); + EXPECT_FALSE(CallLanguageInULP("zh-TW")); +} + +} // namespace testing + } // namespace translate
diff --git a/components/translate/core/browser/translate_prefs.cc b/components/translate/core/browser/translate_prefs.cc index 98419c0c9..ed57e98 100644 --- a/components/translate/core/browser/translate_prefs.cc +++ b/components/translate/core/browser/translate_prefs.cc
@@ -20,6 +20,7 @@ namespace translate { +const char TranslatePrefs::kPrefLanguageProfile[] = "language_profile"; const char TranslatePrefs::kPrefTranslateSiteBlacklist[] = "translate_site_blacklist"; const char TranslatePrefs::kPrefTranslateWhitelists[] = "translate_whitelists"; @@ -35,10 +36,18 @@ "translate_last_denied_time_for_language"; const char TranslatePrefs::kPrefTranslateTooOftenDeniedForLanguage[] = "translate_too_often_denied_for_language"; + const char kTranslateUI2016Q2TrialName[] = "TranslateUI2016Q2"; const char kAlwaysTranslateOfferThreshold[] = "always_translate_offer_threshold"; +// For reading ULP prefs. +const char kConfidence[] = "confidence"; +const char kLanguage[] = "language"; +const char kPreference[] = "preference"; +const char kProbability[] = "probability"; +const char kReading[] = "reading"; + // The below properties used to be used but now are deprecated. Don't use them // since an old profile might have some values there. // @@ -474,6 +483,8 @@ registry->RegisterDictionaryPref( kPrefTranslateTooOftenDeniedForLanguage, user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); + registry->RegisterDictionaryPref( + kPrefLanguageProfile, user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); } // static @@ -569,4 +580,58 @@ return (dict == NULL || dict->empty()); } +double TranslatePrefs::GetReadingFromUserLanguageProfile( + LanguageAndProbabilityList* out_value) const { + const base::DictionaryValue* dict = + prefs_->GetDictionary(kPrefLanguageProfile); + const base::DictionaryValue* entries = nullptr; + + // Return 0.0 if no ULP prefs. + if (!dict) + return 0.0; + + // Return 0.0 if no such list. + if (!dict->GetDictionary(kReading, &entries)) + return 0.0; + + double confidence = 0.0; + // Return 0.0 if cannot find confidence. + if (!entries->GetDouble(kConfidence, &confidence)) + return 0.0; + + const base::ListValue* preference = nullptr; + // Return the confidence if there are no item on the 'preference' field. + if (!entries->GetList(kPreference, &preference)) + return confidence; + + // Use a map to fold the probability of all the same normalized language + // code together. + std::map<std::string, double> probability_map; + // Iterate through the preference. + for (const auto& entry : *preference) { + const base::DictionaryValue* item = nullptr; + std::string language; + double probability = 0.0; + if (entry->GetAsDictionary(&item) && + item->GetString(kLanguage, &language) && + item->GetDouble(kProbability, &probability)) { + // Normalize the the language code known and supported by + // Translate. + translate::ToTranslateLanguageSynonym(&language); + // Discard if the normalized version is unsupported. + if (TranslateDownloadManager::IsSupportedLanguage(language)) { + probability_map[language] += probability; + } + } + } + for (const auto& it : probability_map) + out_value->push_back(it); + std::sort(out_value->begin(), out_value->end(), + [](const LanguageAndProbability& left, + const LanguageAndProbability& right) { + return left.second > right.second; + }); + return confidence; +} + } // namespace translate
diff --git a/components/translate/core/browser/translate_prefs.h b/components/translate/core/browser/translate_prefs.h index d03e2590..8a34621b 100644 --- a/components/translate/core/browser/translate_prefs.h +++ b/components/translate/core/browser/translate_prefs.h
@@ -78,6 +78,7 @@ // It is assumed that |prefs_| is alive while this instance is alive. class TranslatePrefs { public: + static const char kPrefLanguageProfile[]; static const char kPrefTranslateSiteBlacklist[]; static const char kPrefTranslateWhitelists[]; static const char kPrefTranslateDeniedCount[]; @@ -165,6 +166,17 @@ bool ShouldAutoTranslate(const std::string& original_language, std::string* target_language); + // Language and probability pair. + typedef std::pair<std::string, double> LanguageAndProbability; + typedef std::vector<LanguageAndProbability> LanguageAndProbabilityList; + + // Output the User Profile Profile's (ULP) "reading list" into |list| as + // ordered list of <string, double> pair, sorted by the double in decreasing + // order. Return the confidence of the list or 0.0 if there no ULP "reading + // list". + double GetReadingFromUserLanguageProfile( + LanguageAndProbabilityList* list) const; + static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); static void MigrateUserPrefs(PrefService* user_prefs, const char* accept_languages_pref);
diff --git a/components/translate/core/browser/translate_prefs_unittest.cc b/components/translate/core/browser/translate_prefs_unittest.cc index 5d77a33..b0bc6722 100644 --- a/components/translate/core/browser/translate_prefs_unittest.cc +++ b/components/translate/core/browser/translate_prefs_unittest.cc
@@ -9,7 +9,9 @@ #include <utility> #include <vector> +#include "base/json/json_reader.h" #include "base/test/scoped_feature_list.h" +#include "base/values.h" #include "build/build_config.h" #include "components/pref_registry/testing_pref_service_syncable.h" #include "components/prefs/scoped_user_pref_update.h" @@ -51,11 +53,6 @@ return update.GetOldestDenialTime(); } - void TurnOnTranslate2016Q2UIFlag() { - scoped_feature_list_.InitAndEnableFeature(translate::kTranslateUI2016Q2); - } - - base::test::ScopedFeatureList scoped_feature_list_; std::unique_ptr<user_prefs::TestingPrefServiceSyncable> prefs_; std::unique_ptr<translate::TranslatePrefs> translate_prefs_; @@ -65,7 +62,8 @@ }; TEST_F(TranslatePrefTest, IsTooOftenDeniedIn2016Q2UI) { - TurnOnTranslate2016Q2UIFlag(); + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature(translate::kTranslateUI2016Q2); translate_prefs_->ResetDenialState(); EXPECT_FALSE(translate_prefs_->IsTooOftenDenied(kTestLanguage)); @@ -80,7 +78,8 @@ } TEST_F(TranslatePrefTest, IsTooOftenIgnoredIn2016Q2UI) { - TurnOnTranslate2016Q2UIFlag(); + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature(translate::kTranslateUI2016Q2); translate_prefs_->ResetDenialState(); EXPECT_FALSE(translate_prefs_->IsTooOftenDenied(kTestLanguage)); @@ -212,4 +211,129 @@ now_ - base::TimeDelta::FromMinutes(2)); } +TEST_F(TranslatePrefTest, ULPPrefs) { + // Mock the pref. + // Case 1: well formed ULP. + const char json1[] = + "{\n" + " \"reading\": {\n" + " \"confidence\": 0.8,\n" + " \"preference\": [\n" + " {\n" + " \"language\": \"en-AU\",\n" + " \"probability\": 0.4\n" + " }, {\n" + " \"language\": \"fr\",\n" + " \"probability\": 0.6\n" + " }\n" + " ]\n" + " }\n" + "}"; + int error_code = 0; + std::string error_msg; + int error_line = 0; + int error_column = 0; + std::unique_ptr<base::Value> profile(base::JSONReader::ReadAndReturnError( + json1, 0, &error_code, &error_msg, &error_line, &error_column)); + ASSERT_EQ(0, error_code) << error_msg << " at " << error_line << ":" + << error_column << std::endl + << json1; + + prefs_->SetUserPref(TranslatePrefs::kPrefLanguageProfile, profile.release()); + + TranslatePrefs::LanguageAndProbabilityList list; + EXPECT_EQ(0.8, translate_prefs_->GetReadingFromUserLanguageProfile(&list)); + EXPECT_EQ(2UL, list.size()); + // the order in the ULP is wrong, and our code will sort it and make the + // larger + // one first. + EXPECT_EQ("fr", list[0].first); + EXPECT_EQ(0.6, list[0].second); + EXPECT_EQ("en", list[1].first); // the "en-AU" should be normalize to "en" + EXPECT_EQ(0.4, list[1].second); + + // Case 2: ill-formed ULP. + // Test if the ULP lacking some fields the code will gracefully ignore those + // items without crash. + const char json2[] = + "{\n" + " \"reading\": {\n" + " \"confidence\": 0.3,\n" + " \"preference\": [\n" + " {\n" // The first one do not have probability. Won't be counted. + " \"language\": \"th\"\n" + " }, {\n" + " \"language\": \"zh-TW\",\n" + " \"probability\": 0.4\n" + " }, {\n" // The third one has no language nor probability. Won't be + // counted. + " }, {\n" // The forth one has 'pt-BR' which is not supported by + // Translate. + // Should be normalize to 'pt' + " \"language\": \"pt-BR\",\n" + " \"probability\": 0.1\n" + " }, {\n" // The fifth one has no language. Won't be counted. + " \"probability\": 0.1\n" + " }\n" + " ]\n" + " }\n" + "}"; + + profile.reset(base::JSONReader::ReadAndReturnError(json2, 0, &error_code, + &error_msg, &error_line, + &error_column) + .release()); + ASSERT_EQ(0, error_code) << error_msg << " at " << error_line << ":" + << error_column << std::endl + << json2; + + prefs_->SetUserPref(TranslatePrefs::kPrefLanguageProfile, profile.release()); + + list.clear(); + EXPECT_EQ(0.3, translate_prefs_->GetReadingFromUserLanguageProfile(&list)); + EXPECT_EQ(2UL, list.size()); + EXPECT_EQ("zh-TW", list[0].first); + EXPECT_EQ(0.4, list[0].second); + EXPECT_EQ("pt", list[1].first); // the "pt-BR" should be normalize to "pt" + EXPECT_EQ(0.1, list[1].second); + + // Case 3: Language Code normalization and reordering. + const char json3[] = + "{\n" + " \"reading\": {\n" + " \"confidence\": 0.8,\n" + " \"preference\": [\n" + " {\n" + " \"language\": \"fr\",\n" + " \"probability\": 0.4\n" + " }, {\n" + " \"language\": \"en-US\",\n" + " \"probability\": 0.31\n" + " }, {\n" + " \"language\": \"en-GB\",\n" + " \"probability\": 0.29\n" + " }\n" + " ]\n" + " }\n" + "}"; + profile.reset(base::JSONReader::ReadAndReturnError(json3, 0, &error_code, + &error_msg, &error_line, + &error_column) + .release()); + ASSERT_EQ(0, error_code) << error_msg << " at " << error_line << ":" + << error_column << std::endl + << json3; + + prefs_->SetUserPref(TranslatePrefs::kPrefLanguageProfile, profile.release()); + + list.clear(); + EXPECT_EQ(0.8, translate_prefs_->GetReadingFromUserLanguageProfile(&list)); + EXPECT_EQ(2UL, list.size()); + EXPECT_EQ("en", list[0].first); // en-US and en-GB will be normalize into en + EXPECT_EQ(0.6, + list[0].second); // and their probability will add to gether be 0.6 + EXPECT_EQ("fr", list[1].first); // fr will move down to the 2nd one + EXPECT_EQ(0.4, list[1].second); +} + } // namespace translate
diff --git a/components/translate/core/browser/translate_ui_delegate_unittest.cc b/components/translate/core/browser/translate_ui_delegate_unittest.cc index a24b88e..8f040f6 100644 --- a/components/translate/core/browser/translate_ui_delegate_unittest.cc +++ b/components/translate/core/browser/translate_ui_delegate_unittest.cc
@@ -9,7 +9,6 @@ #include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/strings/stringprintf.h" -#include "base/test/scoped_feature_list.h" #include "build/build_config.h" #include "components/infobars/core/infobar.h" #include "components/pref_registry/pref_registry_syncable.h" @@ -96,16 +95,11 @@ ASSERT_FALSE(client_->GetTranslatePrefs()->IsTooOftenDenied("ar")); } - void TurnOnTranslate2016Q2UIFlag() { - scoped_feature_list_.InitAndEnableFeature(translate::kTranslateUI2016Q2); - } - MockTranslateDriver driver_; std::unique_ptr<MockTranslateClient> client_; std::unique_ptr<user_prefs::TestingPrefServiceSyncable> pref_service_; std::unique_ptr<TranslateManager> manager_; std::unique_ptr<TranslateUIDelegate> delegate_; - base::test::ScopedFeatureList scoped_feature_list_; private: DISALLOW_COPY_AND_ASSIGN(TranslateUIDelegateTest);
diff --git a/components/translate/core/language_detection/BUILD.gn b/components/translate/core/language_detection/BUILD.gn index 68eae65..d40e3bb8 100644 --- a/components/translate/core/language_detection/BUILD.gn +++ b/components/translate/core/language_detection/BUILD.gn
@@ -13,7 +13,7 @@ deps = [ "//base", "//components/translate/core/common", - "//third_party/cld_2", + "//third_party/cld", "//url", ] }
diff --git a/components/translate/core/language_detection/DEPS b/components/translate/core/language_detection/DEPS index eccda7a..3cb41688 100644 --- a/components/translate/core/language_detection/DEPS +++ b/components/translate/core/language_detection/DEPS
@@ -1,4 +1,6 @@ include_rules = [ # CLD library. - "+third_party/cld_2/src", + "+third_party/cld", + "+third_party/cld_2", + "+third_party/cld_3", ]
diff --git a/components/translate/core/language_detection/language_detection_util.cc b/components/translate/core/language_detection/language_detection_util.cc index 033116ec..8318e97e 100644 --- a/components/translate/core/language_detection/language_detection_util.cc +++ b/components/translate/core/language_detection/language_detection_util.cc
@@ -8,7 +8,10 @@ #include "base/logging.h" #include "base/macros.h" +#include "base/metrics/histogram_base.h" #include "base/metrics/histogram_macros.h" +#include "base/metrics/metrics_hashes.h" +#include "base/metrics/sparse_histogram.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" @@ -16,8 +19,16 @@ #include "components/translate/core/common/translate_constants.h" #include "components/translate/core/common/translate_metrics.h" #include "components/translate/core/common/translate_util.h" +#include "third_party/cld/cld_version.h" + +#if BUILDFLAG(CLD_VERSION) == 2 #include "third_party/cld_2/src/public/compact_lang_det.h" #include "third_party/cld_2/src/public/encodings.h" +#elif BUILDFLAG(CLD_VERSION) == 3 +#include "third_party/cld_3/src/src/nnet_language_identifier.h" +#else +# error "CLD_VERSION must be 2 or 3" +#endif namespace { @@ -74,6 +85,9 @@ std::string& code, std::string& html_lang) { std::string language = translate::kUnknownLanguageCode; + const std::string utf8_text(base::UTF16ToUTF8(text)); + +#if BUILDFLAG(CLD_VERSION) == 2 int num_bytes_evaluated = 0; bool is_reliable = false; const bool is_plain_text = true; @@ -82,7 +96,6 @@ int cld_language = 0; bool is_valid_language = false; - const std::string utf8_text(base::UTF16ToUTF8(text)); const int num_utf8_bytes = static_cast<int>(utf8_text.size()); const char* raw_utf8_bytes = utf8_text.c_str(); @@ -160,8 +173,40 @@ else language = CLD2::LanguageCode(static_cast<CLD2::Language>(cld_language)); } - VLOG(9) << "Detected lang_id: " << language << ", from Text:\n" << text - << "\n*************************************\n"; + +#elif BUILDFLAG(CLD_VERSION) == 3 + // Make a prediction. + chrome_lang_id::NNetLanguageIdentifier lang_id; + const chrome_lang_id::NNetLanguageIdentifier::Result lang_id_result = + lang_id.FindTopNMostLikelyLangs(utf8_text, /*num_langs=*/1).at(0); + const bool prediction_reliable = lang_id_result.is_reliable; + const std::string& predicted_language = lang_id_result.language; + + // Update histograms. + const base::HistogramBase::Sample pred_lang_hash = + static_cast<base::HistogramBase::Sample>( + base::HashMetricName(predicted_language)); + UMA_HISTOGRAM_SPARSE_SLOWLY("Translate.CLD3.LanguageDetected", + pred_lang_hash); + if (predicted_language != chrome_lang_id::NNetLanguageIdentifier::kUnknown) { + UMA_HISTOGRAM_PERCENTAGE("Translate.CLD3.LanguagePercentage", + static_cast<int>(100 * lang_id_result.proportion)); + } + + if (is_cld_reliable != NULL) { + *is_cld_reliable = prediction_reliable; + } + + if (prediction_reliable && + predicted_language != + chrome_lang_id::NNetLanguageIdentifier::kUnknown) { + language = predicted_language; + } + +#else +# error "CLD_VERSION must be 2 or 3" +#endif + return language; }
diff --git a/components/translate/ios/browser/js_language_detection_manager.mm b/components/translate/ios/browser/js_language_detection_manager.mm index 0baf5047..3e223e5 100644 --- a/components/translate/ios/browser/js_language_detection_manager.mm +++ b/components/translate/ios/browser/js_language_detection_manager.mm
@@ -22,10 +22,6 @@ return @"language_detection"; } -- (NSString*)presenceBeacon { - return @"__gCrWeb.languageDetection"; -} - #pragma mark - Public methods - (void)startLanguageDetection {
diff --git a/components/translate/ios/browser/js_translate_manager.mm b/components/translate/ios/browser/js_translate_manager.mm index ae982260..faec724 100644 --- a/components/translate/ios/browser/js_translate_manager.mm +++ b/components/translate/ios/browser/js_translate_manager.mm
@@ -78,8 +78,4 @@ return _translationScript.autorelease(); } -- (NSString*)presenceBeacon { - return @"cr.googleTranslate"; -} - @end
diff --git a/components/typemaps.gni b/components/typemaps.gni index db315e7c..f173d9c 100644 --- a/components/typemaps.gni +++ b/components/typemaps.gni
@@ -6,4 +6,5 @@ "//components/autofill/content/public/cpp/autofill_types.typemap", "//components/password_manager/content/public/cpp/credential_manager.typemap", "//components/safe_json/public/interfaces/safe_json.typemap", + "//components/translate/content/common/translate.typemap", ]
diff --git a/components/webcrypto/BUILD.gn b/components/webcrypto/BUILD.gn index 9c3ca509..b9a5e63 100644 --- a/components/webcrypto/BUILD.gn +++ b/components/webcrypto/BUILD.gn
@@ -85,7 +85,6 @@ deps = [ ":webcrypto", "//base/test:test_support", - "//components/test_runner:test_runner", "//crypto", "//crypto:platform", "//testing/gtest",
diff --git a/components/webcrypto/algorithms/test_helpers.cc b/components/webcrypto/algorithms/test_helpers.cc index 0380c70..8751735 100644 --- a/components/webcrypto/algorithms/test_helpers.cc +++ b/components/webcrypto/algorithms/test_helpers.cc
@@ -18,7 +18,6 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/values.h" -#include "components/test_runner/test_common.h" #include "components/webcrypto/algorithm_dispatch.h" #include "components/webcrypto/crypto_data.h" #include "components/webcrypto/generate_key_result.h" @@ -42,9 +41,7 @@ } // namespace // static -void WebCryptoTestBase::SetUpTestCase() { - test_runner::EnsureBlinkInitialized(); -} +void WebCryptoTestBase::SetUpTestCase() {} void PrintTo(const Status& status, ::std::ostream* os) { *os << StatusToString(status);
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index 7aaafd9..43cc13b 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -42,7 +42,6 @@ "//components/link_header_util", "//components/memory_coordinator/browser", "//components/mime_util", - "//components/scheduler:common", "//components/tracing", "//components/tracing:startup_tracing", "//components/url_formatter", @@ -71,6 +70,8 @@ "//gpu", "//gpu/command_buffer/client:gles2_implementation", "//gpu/command_buffer/client:gles2_interface", + "//ipc", + "//ipc:mojom", "//media", "//media/capture", "//media/gpu/ipc/client", @@ -111,6 +112,7 @@ "//ui/base", "//ui/base/ime", "//ui/display", + "//ui/display/types", "//ui/events", "//ui/events:gesture_detection", "//ui/events/blink", @@ -379,7 +381,6 @@ "//ui/aura", "//ui/aura_extra", "//ui/strings", - "//ui/views/mus", "//ui/wm", ] sources += [
diff --git a/content/browser/android/browser_jni_registrar.cc b/content/browser/android/browser_jni_registrar.cc index 277185c..f1814cb3 100644 --- a/content/browser/android/browser_jni_registrar.cc +++ b/content/browser/android/browser_jni_registrar.cc
@@ -31,6 +31,7 @@ #include "content/browser/time_zone_monitor_android.h" #include "content/browser/web_contents/web_contents_android.h" #include "mojo/android/system/core_impl.h" +#include "mojo/android/system/watcher_impl.h" namespace { base::android::RegistrationMethod kContentRegisteredMethods[] = { @@ -64,6 +65,7 @@ content::SpeechRecognizerImplAndroid::RegisterSpeechRecognizer}, {"TimeZoneMonitorAndroid", content::TimeZoneMonitorAndroid::Register}, {"TracingControllerAndroid", content::RegisterTracingControllerAndroid}, + {"WatcherImpl", mojo::android::RegisterWatcherImpl}, {"WebContentsAndroid", content::WebContentsAndroid::Register}, {"WebContentsObserver", content::RegisterWebContentsObserverProxy}, {"WebViewStatics", content::RegisterWebViewStatics},
diff --git a/content/browser/bluetooth/bluetooth_device_chooser_controller.cc b/content/browser/bluetooth/bluetooth_device_chooser_controller.cc index 6d02f23..b2d8792f 100644 --- a/content/browser/bluetooth/bluetooth_device_chooser_controller.cc +++ b/content/browser/bluetooth/bluetooth_device_chooser_controller.cc
@@ -321,7 +321,7 @@ return; } - PopulateFoundDevices(); + PopulateConnectedDevices(); if (!chooser_.get()) { // If the dialog's closing, no need to do any of the rest of this. return; @@ -339,8 +339,14 @@ void BluetoothDeviceChooserController::AddFilteredDevice( const device::BluetoothDevice& device) { if (chooser_.get() && MatchesFilters(device, options_->filters)) { - VLOG(1) << "Adding device to chooser: " << device.GetAddress(); - chooser_->AddDevice(device.GetAddress(), device.GetNameForDisplay()); + chooser_->AddOrUpdateDevice( + device.GetAddress(), + // TODO(https://crbug.com/634366): Update device's name when necessary. + false /* should_update_name */, device.GetNameForDisplay(), + // TODO(http://crbug.com/543466): Show connection and paired status. + false /* is_gatt_connected */, false /* is_paired */, + // TODO(http://crbug.com/629689): Add signal strength indicator. + nullptr /* rssi */); } } @@ -368,11 +374,11 @@ BluetoothDeviceChooserController::use_test_scan_duration_ = true; } -void BluetoothDeviceChooserController::PopulateFoundDevices() { - VLOG(1) << "Populating " << adapter_->GetDevices().size() - << " devices in chooser."; +void BluetoothDeviceChooserController::PopulateConnectedDevices() { for (const device::BluetoothDevice* device : adapter_->GetDevices()) { - AddFilteredDevice(*device); + if (device->IsGattConnected()) { + AddFilteredDevice(*device); + } } } @@ -432,7 +438,7 @@ switch (event) { case BluetoothChooser::Event::RESCAN: - PopulateFoundDevices(); + PopulateConnectedDevices(); DCHECK(chooser_); StartDeviceDiscovery(); // No need to close the chooser so we return.
diff --git a/content/browser/bluetooth/bluetooth_device_chooser_controller.h b/content/browser/bluetooth/bluetooth_device_chooser_controller.h index 5d81fd25..0375900 100644 --- a/content/browser/bluetooth/bluetooth_device_chooser_controller.h +++ b/content/browser/bluetooth/bluetooth_device_chooser_controller.h
@@ -83,8 +83,8 @@ static void SetTestScanDurationForTesting(); private: - // Populates the chooser with the devices that are already in the adapter. - void PopulateFoundDevices(); + // Populates the chooser with the GATT connected devices. + void PopulateConnectedDevices(); // Notifies the chooser that discovery is starting and starts a discovery // session.
diff --git a/content/browser/bluetooth/bluetooth_metrics.h b/content/browser/bluetooth/bluetooth_metrics.h index 34aae8c..9fc0bd12 100644 --- a/content/browser/bluetooth/bluetooth_metrics.h +++ b/content/browser/bluetooth/bluetooth_metrics.h
@@ -73,6 +73,7 @@ NEED_LOCATION_HELP_LINK_PRESSED = 14, BLUETOOTH_CHOOSER_POLICY_DISABLED = 15, BLUETOOTH_GLOBALLY_DISABLED = 16, + BLUETOOTH_CHOOSER_EVENT_HANDLER_INVALID = 17, // NOTE: Add new requestDevice() outcomes immediately above this line. Make // sure to update the enum list in // tools/metrics/histograms/histograms.xml accordingly. @@ -82,7 +83,7 @@ // There should be a call to this function before every // Send(BluetoothMsg_RequestDeviceSuccess...) or // Send(BluetoothMsg_RequestDeviceError...). -void RecordRequestDeviceOutcome(UMARequestDeviceOutcome outcome); +CONTENT_EXPORT void RecordRequestDeviceOutcome(UMARequestDeviceOutcome outcome); // Records stats about the arguments used when calling requestDevice. // - The number of filters used.
diff --git a/content/browser/bluetooth/web_bluetooth_service_impl.cc b/content/browser/bluetooth/web_bluetooth_service_impl.cc index 974eb1db..d559d92 100644 --- a/content/browser/bluetooth/web_bluetooth_service_impl.cc +++ b/content/browser/bluetooth/web_bluetooth_service_impl.cc
@@ -228,8 +228,6 @@ device::BluetoothDevice* device) { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (device_chooser_controller_.get()) { - VLOG(1) << "Adding device to device chooser controller: " - << device->GetAddress(); device_chooser_controller_->AddFilteredDevice(*device); } } @@ -237,6 +235,11 @@ void WebBluetoothServiceImpl::DeviceChanged(device::BluetoothAdapter* adapter, device::BluetoothDevice* device) { DCHECK_CURRENTLY_ON(BrowserThread::UI); + + if (device_chooser_controller_.get()) { + device_chooser_controller_->AddFilteredDevice(*device); + } + if (!device->IsGattConnected()) { base::Optional<WebBluetoothDeviceId> device_id = connected_devices_->CloseConnectionToDeviceWithAddress( @@ -250,6 +253,10 @@ void WebBluetoothServiceImpl::GattServicesDiscovered( device::BluetoothAdapter* adapter, device::BluetoothDevice* device) { + if (device_chooser_controller_.get()) { + device_chooser_controller_->AddFilteredDevice(*device); + } + DCHECK_CURRENTLY_ON(BrowserThread::UI); const std::string& device_address = device->GetAddress(); VLOG(1) << "Services discovered for device: " << device_address;
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc index 71a74b0d..d6dcc1e 100644 --- a/content/browser/browser_main_loop.cc +++ b/content/browser/browser_main_loop.cc
@@ -155,11 +155,11 @@ #endif #if defined(OS_WIN) -#include "media/capture/system_message_window_win.h" +#include "media/device_monitors/system_message_window_win.h" #elif defined(OS_LINUX) && defined(USE_UDEV) -#include "media/capture/device_monitor_udev.h" +#include "media/device_monitors/device_monitor_udev.h" #elif defined(OS_MACOSX) -#include "media/capture/device_monitor_mac.h" +#include "media/device_monitors/device_monitor_mac.h" #endif #if defined(OS_POSIX) && !defined(OS_MACOSX) @@ -1096,6 +1096,12 @@ case BrowserThread::IO: { TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:IOThread"); ResetThread_IO(std::move(io_thread_)); + + // TODO(alokp): Remove after collecting crash data. + // Temporary checks to verify that all shared workers are terminated. + // It is suspected that shared workers prevent render process hosts + // from shutting down: crbug.com/608049 + RenderProcessHostImpl::CheckAllWorkersTerminated(); break; } case BrowserThread::UI:
diff --git a/content/browser/browser_process_sub_thread.cc b/content/browser/browser_process_sub_thread.cc index 5aadda5..72ffbe3 100644 --- a/content/browser/browser_process_sub_thread.cc +++ b/content/browser/browser_process_sub_thread.cc
@@ -11,6 +11,7 @@ #include "content/browser/browser_child_process_host_impl.h" #include "content/browser/gpu/browser_gpu_memory_buffer_manager.h" #include "content/browser/notification_service_impl.h" +#include "content/browser/shared_worker/shared_worker_service_impl.h" #include "net/url_request/url_fetcher.h" #include "net/url_request/url_request.h" @@ -60,6 +61,12 @@ } void BrowserProcessSubThread::IOThreadPreCleanUp() { + // TODO(alokp): Remove after collecting crash data. + // Temporary checks to verify that all shared workers are terminated. + // It is suspected that shared workers prevent render process hosts + // from shutting down: crbug.com/608049 + SharedWorkerServiceImpl::GetInstance()->CheckAllWorkersTerminated(); + // Kill all things that might be holding onto // net::URLRequest/net::URLRequestContexts.
diff --git a/content/browser/cache_storage/cache_storage_cache.cc b/content/browser/cache_storage/cache_storage_cache.cc index 6dc652e7..4cdae52 100644 --- a/content/browser/cache_storage/cache_storage_cache.cc +++ b/content/browser/cache_storage/cache_storage_cache.cc
@@ -451,7 +451,9 @@ callback->Run(CACHE_STORAGE_OK); } -void CacheStorageCache::Keys(const RequestsCallback& callback) { +void CacheStorageCache::Keys(std::unique_ptr<ServiceWorkerFetchRequest> request, + const CacheStorageCacheQueryParams& options, + const RequestsCallback& callback) { if (backend_state_ == BACKEND_CLOSED) { callback.Run(CACHE_STORAGE_ERROR_STORAGE, std::unique_ptr<Requests>()); return; @@ -459,6 +461,7 @@ scheduler_->ScheduleOperation( base::Bind(&CacheStorageCache::KeysImpl, weak_ptr_factory_.GetWeakPtr(), + base::Passed(std::move(request)), options, scheduler_->WrapCallbackToRunNext(callback))); } @@ -593,6 +596,13 @@ return; } + if (!options.ignore_method && request && !request->method.empty() && + request->method != "GET") { + callback.Run(CACHE_STORAGE_OK, base::MakeUnique<QueryCacheResults>( + std::move(request), options, callback)); + return; + } + std::unique_ptr<QueryCacheResults> query_cache_results( new QueryCacheResults(std::move(request), options, callback)); OpenAllEntries(base::Bind(&CacheStorageCache::QueryCacheDidOpenAllEntries, @@ -625,11 +635,18 @@ return; } - if (query_cache_results->options.ignore_search) { - DCHECK(query_cache_results->request); + if (query_cache_results->request && + !query_cache_results->request->url.is_empty()) { disk_cache::Entry* entry(*iter); - if (RemoveQueryParam(query_cache_results->request->url) != - RemoveQueryParam(GURL(entry->GetKey()))) { + GURL requestURL = query_cache_results->request->url; + GURL cachedURL = GURL(entry->GetKey()); + + if (query_cache_results->options.ignore_search) { + requestURL = RemoveQueryParam(requestURL); + cachedURL = RemoveQueryParam(cachedURL); + } + + if (cachedURL != requestURL) { QueryCacheProcessNextEntry(std::move(query_cache_results), iter + 1); return; } @@ -692,6 +709,13 @@ return; } + if (!request->method.empty() && request->method != "GET") { + callback.Run(CACHE_STORAGE_ERROR_NOT_FOUND, + std::unique_ptr<ServiceWorkerResponse>(), + std::unique_ptr<storage::BlobDataHandle>()); + return; + } + std::unique_ptr<disk_cache::Entry*> scoped_entry_ptr( new disk_cache::Entry*()); disk_cache::Entry** entry_ptr = scoped_entry_ptr.get(); @@ -1266,16 +1290,17 @@ callback.Run(CACHE_STORAGE_OK); } -void CacheStorageCache::KeysImpl(const RequestsCallback& callback) { +void CacheStorageCache::KeysImpl( + std::unique_ptr<ServiceWorkerFetchRequest> request, + const CacheStorageCacheQueryParams& options, + const RequestsCallback& callback) { DCHECK_NE(BACKEND_UNINITIALIZED, backend_state_); if (backend_state_ != BACKEND_OPEN) { callback.Run(CACHE_STORAGE_ERROR_STORAGE, std::unique_ptr<Requests>()); return; } - std::unique_ptr<ServiceWorkerFetchRequest> request( - new ServiceWorkerFetchRequest); - QueryCache(std::move(request), CacheStorageCacheQueryParams(), + QueryCache(std::move(request), options, base::Bind(&CacheStorageCache::KeysDidQueryCache, weak_ptr_factory_.GetWeakPtr(), callback)); }
diff --git a/content/browser/cache_storage/cache_storage_cache.h b/content/browser/cache_storage/cache_storage_cache.h index 97e7455..c5e44e2 100644 --- a/content/browser/cache_storage/cache_storage_cache.h +++ b/content/browser/cache_storage/cache_storage_cache.h
@@ -133,9 +133,10 @@ CacheStorageError error); void BatchDidAllOperations(std::unique_ptr<ErrorCallback> callback); - // TODO(jkarlin): Have keys take an optional ServiceWorkerFetchRequest. // Returns CACHE_STORAGE_OK and a vector of requests if there are no errors. - void Keys(const RequestsCallback& callback); + void Keys(std::unique_ptr<ServiceWorkerFetchRequest> request, + const CacheStorageCacheQueryParams& options, + const RequestsCallback& callback); // Closes the backend. Future operations that require the backend // will exit early. Close should only be called once per CacheStorageCache. @@ -319,7 +320,9 @@ int rv); // Keys callbacks. - void KeysImpl(const RequestsCallback& callback); + void KeysImpl(std::unique_ptr<ServiceWorkerFetchRequest> request, + const CacheStorageCacheQueryParams& options, + const RequestsCallback& callback); void KeysDidQueryCache( const RequestsCallback& callback, CacheStorageError error,
diff --git a/content/browser/cache_storage/cache_storage_cache_unittest.cc b/content/browser/cache_storage/cache_storage_cache_unittest.cc index f52e741..1de9c9e 100644 --- a/content/browser/cache_storage/cache_storage_cache_unittest.cc +++ b/content/browser/cache_storage/cache_storage_cache_unittest.cc
@@ -384,6 +384,9 @@ no_body_request_ = ServiceWorkerFetchRequest(GURL("http://example.com/no_body.html"), "GET", headers, Referrer(), false); + body_head_request_ = + ServiceWorkerFetchRequest(GURL("http://example.com/body.html"), "HEAD", + headers, Referrer(), false); std::string expected_response; for (int i = 0; i < 100; ++i) @@ -504,12 +507,16 @@ return error == CACHE_STORAGE_OK; } - bool Keys() { + bool Keys( + const ServiceWorkerFetchRequest& request = ServiceWorkerFetchRequest(), + const CacheStorageCacheQueryParams& match_params = + CacheStorageCacheQueryParams()) { std::unique_ptr<base::RunLoop> loop(new base::RunLoop()); - cache_->Keys(base::Bind(&CacheStorageCacheTest::RequestsCallback, - base::Unretained(this), - base::Unretained(loop.get()))); + cache_->Keys( + CopyFetchRequest(request), match_params, + base::Bind(&CacheStorageCacheTest::RequestsCallback, + base::Unretained(this), base::Unretained(loop.get()))); loop->Run(); return callback_error_ == CACHE_STORAGE_OK; @@ -688,6 +695,7 @@ ServiceWorkerResponse body_response_with_query_; ServiceWorkerFetchRequest no_body_request_; ServiceWorkerResponse no_body_response_; + ServiceWorkerFetchRequest body_head_request_; std::unique_ptr<storage::BlobDataHandle> blob_handle_; std::string expected_blob_data_; @@ -801,7 +809,7 @@ EXPECT_FALSE(callback_response_data_); } -TEST_P(CacheStorageCacheTestP, PutReplcaceInBatch) { +TEST_P(CacheStorageCacheTestP, PutReplaceInBatch) { CacheStorageBatchOperation operation1; operation1.operation_type = CACHE_STORAGE_CACHE_OPERATION_TYPE_PUT; operation1.request = body_request_; @@ -840,6 +848,11 @@ ResponseBodiesEqual(expected_blob_data_, *callback_response_data_)); } +TEST_P(CacheStorageCacheTestP, MatchBodyHead) { + EXPECT_TRUE(Put(body_request_, body_response_)); + EXPECT_FALSE(Match(body_head_request_)); +} + TEST_P(CacheStorageCacheTestP, MatchAll_Empty) { std::unique_ptr<CacheStorageCache::Responses> responses; std::unique_ptr<CacheStorageCache::BlobDataHandles> body_handles; @@ -944,6 +957,28 @@ EXPECT_EQ(2u, matched_set.size()); } +TEST_P(CacheStorageCacheTestP, MatchAll_Head) { + EXPECT_TRUE(Put(body_request_, body_response_)); + + std::unique_ptr<CacheStorageCache::Responses> responses; + std::unique_ptr<CacheStorageCache::BlobDataHandles> body_handles; + CacheStorageCacheQueryParams match_params; + match_params.ignore_search = true; + EXPECT_TRUE( + MatchAll(body_head_request_, match_params, &responses, &body_handles)); + EXPECT_TRUE(responses->empty()); + EXPECT_TRUE(body_handles->empty()); + + match_params.ignore_method = true; + EXPECT_TRUE( + MatchAll(body_head_request_, match_params, &responses, &body_handles)); + ASSERT_EQ(1u, responses->size()); + ASSERT_EQ(1u, body_handles->size()); + EXPECT_TRUE( + ResponseMetadataEqual(SetCacheName(body_response_), responses->at(0))); + EXPECT_TRUE(ResponseBodiesEqual(expected_blob_data_, body_handles->at(0))); +} + TEST_P(CacheStorageCacheTestP, Vary) { body_request_.headers["vary_foo"] = "foo"; body_response_.headers["vary"] = "vary_foo"; @@ -1038,6 +1073,39 @@ EXPECT_TRUE(VerifyKeys(expected_key)); } +TEST_P(CacheStorageCacheTestP, KeysWithIgnoreSearchTrue) { + EXPECT_TRUE(Put(no_body_request_, no_body_response_)); + EXPECT_TRUE(Put(body_request_, body_response_)); + EXPECT_TRUE(Put(body_request_with_query_, body_response_with_query_)); + + CacheStorageCacheQueryParams match_params; + match_params.ignore_search = true; + + EXPECT_TRUE(Keys(body_request_with_query_, match_params)); + EXPECT_EQ(2u, callback_strings_.size()); + std::vector<std::string> expected_keys = { + body_request_.url.spec(), body_request_with_query_.url.spec()}; + EXPECT_TRUE(VerifyKeys(expected_keys)); +} + +TEST_P(CacheStorageCacheTestP, KeysWithIgnoreSearchFalse) { + EXPECT_TRUE(Put(no_body_request_, no_body_response_)); + EXPECT_TRUE(Put(body_request_, body_response_)); + EXPECT_TRUE(Put(body_request_with_query_, body_response_with_query_)); + + // Default value of ignore_search is false. + CacheStorageCacheQueryParams match_params; + match_params.ignore_search = false; + EXPECT_EQ(match_params.ignore_search, + CacheStorageCacheQueryParams().ignore_search); + + EXPECT_TRUE(Keys(body_request_with_query_, match_params)); + EXPECT_EQ(1u, callback_strings_.size()); + std::vector<std::string> expected_keys = { + body_request_with_query_.url.spec()}; + EXPECT_TRUE(VerifyKeys(expected_keys)); +} + TEST_P(CacheStorageCacheTestP, DeleteNoBody) { EXPECT_TRUE(Put(no_body_request_, no_body_response_)); EXPECT_TRUE(Match(no_body_request_));
diff --git a/content/browser/cache_storage/cache_storage_dispatcher_host.cc b/content/browser/cache_storage/cache_storage_dispatcher_host.cc index c34259f..7d1d229 100644 --- a/content/browser/cache_storage/cache_storage_dispatcher_host.cc +++ b/content/browser/cache_storage/cache_storage_dispatcher_host.cc
@@ -293,9 +293,14 @@ } CacheStorageCache* cache = it->second->value(); - cache->Keys(base::Bind(&CacheStorageDispatcherHost::OnCacheKeysCallback, this, - thread_id, request_id, - base::Passed(it->second->Clone()))); + std::unique_ptr<ServiceWorkerFetchRequest> request_ptr( + new ServiceWorkerFetchRequest(request.url, request.method, + request.headers, request.referrer, + request.is_reload)); + cache->Keys( + std::move(request_ptr), match_params, + base::Bind(&CacheStorageDispatcherHost::OnCacheKeysCallback, this, + thread_id, request_id, base::Passed(it->second->Clone()))); } void CacheStorageDispatcherHost::OnCacheBatch(
diff --git a/content/browser/compositor/DEPS b/content/browser/compositor/DEPS index 094a80ae..562daa27 100644 --- a/content/browser/compositor/DEPS +++ b/content/browser/compositor/DEPS
@@ -3,5 +3,4 @@ "+services/ui/common", "+services/ui/public/cpp", "+ui/platform_window", - "+ui/views", ]
diff --git a/content/browser/compositor/browser_compositor_output_surface.cc b/content/browser/compositor/browser_compositor_output_surface.cc index bf6aef1..f6141ca 100644 --- a/content/browser/compositor/browser_compositor_output_surface.cc +++ b/content/browser/compositor/browser_compositor_output_surface.cc
@@ -134,11 +134,6 @@ void BrowserCompositorOutputSurface::OnReflectorChanged() { } -base::Closure -BrowserCompositorOutputSurface::CreateCompositionStartedCallback() { - return base::Closure(); -} - cc::OverlayCandidateValidator* BrowserCompositorOutputSurface::GetOverlayCandidateValidator() const { return overlay_candidate_validator_.get();
diff --git a/content/browser/compositor/browser_compositor_output_surface.h b/content/browser/compositor/browser_compositor_output_surface.h index f0e8fd3..89d0fd8 100644 --- a/content/browser/compositor/browser_compositor_output_surface.h +++ b/content/browser/compositor/browser_compositor_output_surface.h
@@ -56,10 +56,6 @@ // Called when |reflector_| was updated. virtual void OnReflectorChanged(); - // Returns a callback that will be called when all mirroring - // compositors have started composition. - virtual base::Closure CreateCompositionStartedCallback(); - // Called when a swap completion is sent from the GPU process. // The argument |params_mac| is used to communicate parameters needed on Mac // to display the CALayer for the swap in the browser process.
diff --git a/content/browser/compositor/gpu_output_surface_mac.mm b/content/browser/compositor/gpu_output_surface_mac.mm index e728906..74dfb41 100644 --- a/content/browser/compositor/gpu_output_surface_mac.mm +++ b/content/browser/compositor/gpu_output_surface_mac.mm
@@ -12,6 +12,7 @@ #include "gpu/ipc/client/gpu_process_hosted_ca_layer_tree_params.h" #include "ui/accelerated_widget_mac/accelerated_widget_mac.h" #include "ui/base/cocoa/remote_layer_api.h" +#include "ui/display/types/display_snapshot.h" #include "ui/gfx/mac/io_surface.h" namespace content { @@ -62,6 +63,7 @@ std::move(overlay_candidate_validator), GL_TEXTURE_RECTANGLE_ARB, GL_RGBA, + gfx::BufferFormat::RGBA_8888, gpu_memory_buffer_manager), remote_layers_(new RemoteLayers) {}
diff --git a/content/browser/compositor/gpu_process_transport_factory.cc b/content/browser/compositor/gpu_process_transport_factory.cc index 8511ff2d..c3d27592 100644 --- a/content/browser/compositor/gpu_process_transport_factory.cc +++ b/content/browser/compositor/gpu_process_transport_factory.cc
@@ -56,6 +56,7 @@ #include "ui/compositor/compositor_constants.h" #include "ui/compositor/compositor_switches.h" #include "ui/compositor/layer.h" +#include "ui/display/types/display_snapshot.h" #include "ui/gfx/geometry/size.h" #if defined(USE_AURA) @@ -492,7 +493,7 @@ context_provider, data->surface_handle, compositor->vsync_manager(), begin_frame_source.get(), CreateOverlayCandidateValidator(compositor->widget()), - GL_TEXTURE_2D, GL_RGB, + GL_TEXTURE_2D, GL_RGB, ui::DisplaySnapshot::PrimaryFormat(), BrowserGpuMemoryBufferManager::current())); #endif } else { @@ -513,7 +514,7 @@ #if defined(USE_AURA) display_output_surface = base::WrapUnique(new MusBrowserCompositorOutputSurface( - data->surface_handle, context_provider, + compositor->window(), context_provider, compositor->vsync_manager(), begin_frame_source.get(), std::move(validator))); #else
diff --git a/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc b/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc index 6d4aca5..a46fc17 100644 --- a/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc +++ b/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc
@@ -28,12 +28,12 @@ overlay_candidate_validator, unsigned int target, unsigned int internalformat, + gfx::BufferFormat format, gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager) : GpuBrowserCompositorOutputSurface(std::move(context), std::move(vsync_manager), begin_frame_source, std::move(overlay_candidate_validator)), - internalformat_(internalformat), gpu_memory_buffer_manager_(gpu_memory_buffer_manager) { capabilities_.uses_default_gl_framebuffer = false; capabilities_.flipped_output_surface = true; @@ -49,8 +49,8 @@ gl_helper_.reset(new display_compositor::GLHelper( context_provider_->ContextGL(), context_provider_->ContextSupport())); buffer_queue_.reset(new display_compositor::BufferQueue( - context_provider_->ContextGL(), target, internalformat_, gl_helper_.get(), - gpu_memory_buffer_manager_, surface_handle)); + context_provider_->ContextGL(), target, internalformat, format, + gl_helper_.get(), gpu_memory_buffer_manager_, surface_handle)); buffer_queue_->Initialize(); }
diff --git a/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h b/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h index d94b126..4405230 100644 --- a/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h +++ b/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h
@@ -33,6 +33,7 @@ overlay_candidate_validator, unsigned int target, unsigned int internalformat, + gfx::BufferFormat format, gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager); ~GpuSurfacelessBrowserCompositorOutputSurface() override; @@ -55,7 +56,6 @@ const gpu::GpuProcessHostedCALayerTreeParamsMac* params_mac) override; private: - const unsigned int internalformat_; std::unique_ptr<display_compositor::GLHelper> gl_helper_; std::unique_ptr<display_compositor::BufferQueue> buffer_queue_; gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager_;
diff --git a/content/browser/compositor/mus_browser_compositor_output_surface.cc b/content/browser/compositor/mus_browser_compositor_output_surface.cc index 6e7a758..82e93450 100644 --- a/content/browser/compositor/mus_browser_compositor_output_surface.cc +++ b/content/browser/compositor/mus_browser_compositor_output_surface.cc
@@ -15,13 +15,11 @@ #include "gpu/ipc/client/command_buffer_proxy_impl.h" #include "services/ui/public/cpp/window.h" #include "services/ui/public/cpp/window_surface.h" -#include "ui/views/mus/native_widget_mus.h" -#include "ui/views/mus/window_tree_host_mus.h" namespace content { MusBrowserCompositorOutputSurface::MusBrowserCompositorOutputSurface( - gpu::SurfaceHandle surface_handle, + ui::Window* window, scoped_refptr<ContextProviderCommandBuffer> context, scoped_refptr<ui::CompositorVSyncManager> vsync_manager, cc::SyntheticBeginFrameSource* begin_frame_source, @@ -31,11 +29,7 @@ std::move(vsync_manager), begin_frame_source, std::move(overlay_candidate_validator)), - ui_window_(nullptr) { - views::WindowTreeHostMus* window_tree_host = - static_cast<views::WindowTreeHostMus*>( - aura::WindowTreeHost::GetForAcceleratedWidget(surface_handle)); - ui_window_ = window_tree_host->native_widget()->window(); + ui_window_(window) { ui_window_surface_ = ui_window_->RequestSurface(ui::mojom::SurfaceType::DEFAULT); }
diff --git a/content/browser/compositor/mus_browser_compositor_output_surface.h b/content/browser/compositor/mus_browser_compositor_output_surface.h index c1f9d26..0d84c8fe 100644 --- a/content/browser/compositor/mus_browser_compositor_output_surface.h +++ b/content/browser/compositor/mus_browser_compositor_output_surface.h
@@ -29,7 +29,7 @@ public ui::WindowSurfaceClient { public: MusBrowserCompositorOutputSurface( - gpu::SurfaceHandle surface_handle, + ui::Window* window, scoped_refptr<ContextProviderCommandBuffer> context, scoped_refptr<ui::CompositorVSyncManager> vsync_manager, cc::SyntheticBeginFrameSource* begin_frame_source,
diff --git a/content/browser/compositor/offscreen_browser_compositor_output_surface.cc b/content/browser/compositor/offscreen_browser_compositor_output_surface.cc index 0ac6de7e..eea945b4 100644 --- a/content/browser/compositor/offscreen_browser_compositor_output_surface.cc +++ b/content/browser/compositor/offscreen_browser_compositor_output_surface.cc
@@ -164,9 +164,4 @@ EnsureBackbuffer(); } -base::Closure -OffscreenBrowserCompositorOutputSurface::CreateCompositionStartedCallback() { - return base::Closure(); -} - } // namespace content
diff --git a/content/browser/compositor/offscreen_browser_compositor_output_surface.h b/content/browser/compositor/offscreen_browser_compositor_output_surface.h index c511322..197a5d5 100644 --- a/content/browser/compositor/offscreen_browser_compositor_output_surface.h +++ b/content/browser/compositor/offscreen_browser_compositor_output_surface.h
@@ -49,7 +49,6 @@ // BrowserCompositorOutputSurface void OnReflectorChanged() override; - base::Closure CreateCompositionStartedCallback() override; void OnGpuSwapBuffersCompleted( const std::vector<ui::LatencyInfo>& latency_info, gfx::SwapResult result,
diff --git a/content/browser/compositor/reflector_impl.cc b/content/browser/compositor/reflector_impl.cc index c7259dc0..2e4ae74 100644 --- a/content/browser/compositor/reflector_impl.cc +++ b/content/browser/compositor/reflector_impl.cc
@@ -23,7 +23,6 @@ ui::Layer* mirroring_layer) : mirrored_compositor_(mirrored_compositor), flip_texture_(false), - composition_count_(0), output_surface_(nullptr) { if (mirroring_layer) AddMirroringLayer(mirroring_layer); @@ -60,9 +59,6 @@ output_surface_ = output_surface; - composition_started_callback_ = - output_surface_->CreateCompositionStartedCallback(); - flip_texture_ = !output_surface->capabilities().flipped_output_surface; output_surface_->SetReflector(this); @@ -82,8 +78,6 @@ layer_data->needs_set_mailbox = true; mirroring_layers_.push_back(layer_data); mirrored_compositor_->ScheduleFullRedraw(); - - layer->GetCompositor()->AddObserver(this); } void ReflectorImpl::RemoveMirroringLayer(ui::Layer* layer) { @@ -94,23 +88,10 @@ (*iter)->layer->SetShowSolidColorContent(); mirroring_layers_.erase(iter); - layer->GetCompositor()->RemoveObserver(this); - composition_count_--; - if (composition_count_ == 0 && !composition_started_callback_.is_null()) - composition_started_callback_.Run(); - if (mirroring_layers_.empty() && output_surface_) DetachFromOutputSurface(); } -void ReflectorImpl::OnCompositingStarted(ui::Compositor* compositor, - base::TimeTicks start_time) { - if (composition_count_ > 0 && --composition_count_ == 0 && - !composition_started_callback_.is_null()) { - composition_started_callback_.Run(); - } -} - void ReflectorImpl::OnSourceTextureMailboxUpdated( scoped_refptr<OwnedMailbox> mailbox) { mailbox_ = mailbox; @@ -127,11 +108,8 @@ } void ReflectorImpl::OnSourceSwapBuffers() { - if (mirroring_layers_.empty()) { - if (!composition_started_callback_.is_null()) - composition_started_callback_.Run(); + if (mirroring_layers_.empty()) return; - } // Should be attached to the source output surface already. DCHECK(mailbox_.get()); @@ -141,15 +119,11 @@ // Request full redraw on mirroring compositor. for (LayerData* layer_data : mirroring_layers_) UpdateTexture(layer_data, size, layer_data->layer->bounds()); - composition_count_ = mirroring_layers_.size(); } void ReflectorImpl::OnSourcePostSubBuffer(const gfx::Rect& rect) { - if (mirroring_layers_.empty()) { - if (!composition_started_callback_.is_null()) - composition_started_callback_.Run(); + if (mirroring_layers_.empty()) return; - } // Should be attached to the source output surface already. DCHECK(mailbox_.get()); @@ -165,7 +139,6 @@ // Request redraw of the dirty portion in mirroring compositor. for (LayerData* layer_data : mirroring_layers_) UpdateTexture(layer_data, size, mirroring_rect); - composition_count_ = mirroring_layers_.size(); } static void ReleaseMailbox(scoped_refptr<OwnedMailbox> mailbox,
diff --git a/content/browser/compositor/reflector_impl.h b/content/browser/compositor/reflector_impl.h index b1eb6cf4..9e5355b 100644 --- a/content/browser/compositor/reflector_impl.h +++ b/content/browser/compositor/reflector_impl.h
@@ -7,15 +7,10 @@ #include <memory> -#include "base/callback.h" -#include "base/id_map.h" #include "base/memory/scoped_vector.h" -#include "base/memory/weak_ptr.h" -#include "base/synchronization/lock.h" #include "content/browser/compositor/image_transport_factory.h" #include "content/common/content_export.h" #include "gpu/command_buffer/common/mailbox_holder.h" -#include "ui/compositor/compositor_observer.h" #include "ui/compositor/reflector.h" #include "ui/gfx/geometry/size.h" @@ -33,10 +28,7 @@ // A reflector implementation that copies the framebuffer content // to the texture, then draw it onto the mirroring compositor. -class CONTENT_EXPORT ReflectorImpl - : public base::SupportsWeakPtr<ReflectorImpl>, - public ui::Reflector, - public ui::CompositorObserver { +class CONTENT_EXPORT ReflectorImpl : public ui::Reflector { public: ReflectorImpl(ui::Compositor* mirrored_compositor, ui::Layer* mirroring_layer); @@ -53,15 +45,6 @@ void AddMirroringLayer(ui::Layer* layer) override; void RemoveMirroringLayer(ui::Layer* layer) override; - // ui::CompositorObserver: - void OnCompositingDidCommit(ui::Compositor* compositor) override {} - void OnCompositingStarted(ui::Compositor* compositor, - base::TimeTicks start_time) override; - void OnCompositingEnded(ui::Compositor* compositor) override {} - void OnCompositingAborted(ui::Compositor* compositor) override {} - void OnCompositingLockStateChanged(ui::Compositor* compositor) override {} - void OnCompositingShuttingDown(ui::Compositor* compositor) override {} - // Called in |BrowserCompositorOutputSurface::SwapBuffers| to copy // the full screen image to the |mailbox_| texture. void OnSourceSwapBuffers(); @@ -91,9 +74,7 @@ scoped_refptr<OwnedMailbox> mailbox_; bool flip_texture_; - int composition_count_; BrowserCompositorOutputSurface* output_surface_; - base::Closure composition_started_callback_; }; } // namespace content
diff --git a/content/browser/find_request_manager_browsertest.cc b/content/browser/find_request_manager_browsertest.cc index cefb4fe9..b30df8a 100644 --- a/content/browser/find_request_manager_browsertest.cc +++ b/content/browser/find_request_manager_browsertest.cc
@@ -34,39 +34,52 @@ class TestWebContentsDelegate : public WebContentsDelegate { public: TestWebContentsDelegate() - : last_finished_request_id_(kInvalidId), - waiting_request_id_(kInvalidId) {} + : last_request_id_(kInvalidId), + last_finished_request_id_(kInvalidId), + next_reply_received_(false), + waiting_for_(NOTHING) {} ~TestWebContentsDelegate() override {} - // Waits for the final reply to the find request with ID |request_id|. - void WaitForFinalReply(int request_id) { - if (last_finished_request_id_ >= request_id) - return; - - waiting_request_id_ = request_id; - find_message_loop_runner_ = new content::MessageLoopRunner; - find_message_loop_runner_->Run(); - } - // Returns the current find results. FindResults GetFindResults() { return current_results_; } -#if defined(OS_ANDROID) - // Waits for the next find reply. This is useful for waiting for a single - // match to be activated, which results in a single find reply (without a - // unique request ID). - void WaitForNextReply() { - waiting_request_id_ = 0; - find_message_loop_runner_ = new content::MessageLoopRunner; - find_message_loop_runner_->Run(); + // Waits for all pending replies to be received. + void WaitForFinalReply() { + if (last_finished_request_id_ >= last_request_id_) + return; + + WaitFor(FINAL_REPLY); } + // Waits for the next find reply. This is useful for waiting for a single + // match to be activated, or for a new frame to be searched. + void WaitForNextReply() { + if (next_reply_received_) + return; + + WaitFor(NEXT_REPLY); + } + + // Indicates that the next find reply from this point will be the one to wait + // for when WaitForNextReply() is called. It may be the case that the reply + // comes before the call to WaitForNextReply(), in which case it will return + // immediately. + void MarkNextReply() { + next_reply_received_ = false; + } + + // Called when a new find request is issued, so the delegate knows the last + // request ID. + void UpdateLastRequest(int request_id) { + last_request_id_ = request_id; + } + +#if defined(OS_ANDROID) // Waits for all of the find match rects to be received. void WaitForMatchRects() { - match_rects_message_loop_runner_ = new content::MessageLoopRunner; - match_rects_message_loop_runner_->Run(); + WaitFor(MATCH_RECTS); } const std::vector<gfx::RectF>& find_match_rects() const { @@ -79,6 +92,15 @@ #endif private: + enum WaitingFor { + NOTHING, + FINAL_REPLY, + NEXT_REPLY, +#if defined(OS_ANDROID) + MATCH_RECTS +#endif + }; + // WebContentsDelegate override. void FindReply(WebContents* web_contents, int request_id, @@ -94,17 +116,47 @@ if (active_match_ordinal != -1) current_results_.active_match_ordinal = active_match_ordinal; - if (final_update) - last_finished_request_id_ = request_id; + if (!final_update) + return; - // If we are waiting for a final reply and this is it, stop waiting. - if (find_message_loop_runner_.get() && - last_finished_request_id_ >= waiting_request_id_) { - find_message_loop_runner_->Quit(); + if (request_id > last_finished_request_id_) + last_finished_request_id_ = request_id; + next_reply_received_ = true; + + // If we are waiting for this find reply, stop waiting. + if (waiting_for_ == NEXT_REPLY || + (waiting_for_ == FINAL_REPLY && + last_finished_request_id_ >= last_request_id_)) { + StopWaiting(); } } + // Uses |message_loop_runner_| to wait for various things. + void WaitFor(WaitingFor wait_for) { + ASSERT_EQ(NOTHING, waiting_for_); + ASSERT_NE(NOTHING, wait_for); + + // Wait for |wait_for|. + waiting_for_ = wait_for; + message_loop_runner_ = new content::MessageLoopRunner; + message_loop_runner_->Run(); + + // Done waiting. + waiting_for_ = NOTHING; + message_loop_runner_ = nullptr; + } + + // Stop waiting for |waiting_for_|. + void StopWaiting() { + if (!message_loop_runner_.get()) + return; + + ASSERT_NE(NOTHING, waiting_for_); + message_loop_runner_->Quit(); + } + #if defined(OS_ANDROID) + // WebContentsDelegate override. void FindMatchRectsReply(WebContents* web_contents, int version, const std::vector<gfx::RectF>& rects, @@ -114,8 +166,8 @@ active_match_rect_ = active_rect; // If we are waiting for match rects, stop waiting. - if (match_rects_message_loop_runner_.get()) - match_rects_message_loop_runner_->Quit(); + if (waiting_for_ == MATCH_RECTS) + StopWaiting(); } std::vector<gfx::RectF> find_match_rects_; @@ -126,15 +178,19 @@ // The latest known results from the current find request. FindResults current_results_; + // The ID of the last find request issued. + int last_request_id_; + // The ID of the last find request to finish (all replies received). int last_finished_request_id_; - // If waiting using |find_message_loop_runner_|, this is the ID of the find - // request being waited for. - int waiting_request_id_; + // Indicates whether the next reply after MarkNextReply() has been received. + bool next_reply_received_; - scoped_refptr<content::MessageLoopRunner> find_message_loop_runner_; - scoped_refptr<content::MessageLoopRunner> match_rects_message_loop_runner_; + // Indicates what |message_loop_runner_| is waiting for, if anything. + WaitingFor waiting_for_; + + scoped_refptr<content::MessageLoopRunner> message_loop_runner_; DISALLOW_COPY_AND_ASSIGN(TestWebContentsDelegate); }; @@ -206,15 +262,12 @@ void Find(const std::string& search_text, const blink::WebFindOptions& options) { - contents()->Find(++last_request_id_, + delegate()->UpdateLastRequest(++last_request_id_); + contents()->Find(last_request_id_, base::UTF8ToUTF16(search_text), options); } - void WaitForFinalReply() const { - delegate()->WaitForFinalReply(last_request_id_); - } - WebContents* contents() const { return shell()->web_contents(); } @@ -292,7 +345,7 @@ blink::WebFindOptions options; Find("result", options); - WaitForFinalReply(); + delegate()->WaitForFinalReply(); FindResults results = delegate()->GetFindResults(); EXPECT_EQ(last_request_id(), results.request_id); @@ -302,7 +355,7 @@ options.findNext = true; for (int i = 2; i <= 10; ++i) { Find("result", options); - WaitForFinalReply(); + delegate()->WaitForFinalReply(); results = delegate()->GetFindResults(); EXPECT_EQ(last_request_id(), results.request_id); @@ -313,7 +366,7 @@ options.forward = false; for (int i = 9; i >= 5; --i) { Find("result", options); - WaitForFinalReply(); + delegate()->WaitForFinalReply(); results = delegate()->GetFindResults(); EXPECT_EQ(last_request_id(), results.request_id); @@ -336,7 +389,7 @@ Find("resu", default_options); Find("resul", default_options); Find("result", default_options); - WaitForFinalReply(); + delegate()->WaitForFinalReply(); FindResults results = delegate()->GetFindResults(); EXPECT_EQ(last_request_id(), results.request_id); @@ -356,7 +409,7 @@ options.findNext = true; for (int i = 2; i <= 1000; ++i) Find("result", options); - WaitForFinalReply(); + delegate()->WaitForFinalReply(); FindResults results = delegate()->GetFindResults(); EXPECT_EQ(last_request_id(), results.request_id); @@ -378,7 +431,7 @@ Find("result", options); Find("result", options); Find("result", options); - WaitForFinalReply(); + delegate()->WaitForFinalReply(); FindResults results = delegate()->GetFindResults(); EXPECT_EQ(last_request_id(), results.request_id); @@ -394,7 +447,6 @@ // The number of matches and active match ordinal should update automatically // to exclude the matches from the removed frame. results = delegate()->GetFindResults(); - EXPECT_EQ(last_request_id(), results.request_id); EXPECT_EQ(12, results.number_of_matches); EXPECT_EQ(8, results.active_match_ordinal); @@ -408,7 +460,7 @@ blink::WebFindOptions default_options; Find("hello", default_options); - WaitForFinalReply(); + delegate()->WaitForFinalReply(); FindResults results = delegate()->GetFindResults(); EXPECT_EQ(last_request_id(), results.request_id); @@ -423,7 +475,7 @@ blink::WebFindOptions default_options; Find("result", default_options); - WaitForFinalReply(); + delegate()->WaitForFinalReply(); EXPECT_EQ(19, delegate()->GetFindResults().number_of_matches); // Request the find match rects. @@ -505,7 +557,7 @@ blink::WebFindOptions default_options; Find("result", default_options); - WaitForFinalReply(); + delegate()->WaitForFinalReply(); EXPECT_EQ(19, delegate()->GetFindResults().number_of_matches); // Get the find match rects. @@ -519,6 +571,7 @@ int order[19] = {11, 13, 2, 0, 16, 5, 7, 10, 6, 1, 15, 14, 9, 17, 18, 3, 8, 12, 4}; for (int i = 0; i < 19; ++i) { + delegate()->MarkNextReply(); contents()->ActivateNearestFindResult( rects[order[i]].CenterPoint().x(), rects[order[i]].CenterPoint().y()); delegate()->WaitForNextReply();
diff --git a/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/content/browser/frame_host/navigation_controller_impl_browsertest.cc index 9dfab1a..9007168 100644 --- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc +++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
@@ -3020,6 +3020,92 @@ EXPECT_EQ(data_url, entry2->root_node()->children[1]->frame_entry->url()); } +// Verify that we don't clobber any content injected into the initial blank page +// if we go back to an about:blank subframe. See https://crbug.com/626416. +IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, + FrameNavigationEntry_RecreatedBlankSubframe) { + // 1. Start on a page that injects content into an about:blank iframe. + GURL main_url(embedded_test_server()->GetURL( + "/navigation_controller/inject_into_blank_iframe.html")); + GURL blank_url(url::kAboutBlankURL); + EXPECT_TRUE(NavigateToURL(shell(), main_url)); + NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>( + shell()->web_contents()->GetController()); + FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) + ->GetFrameTree() + ->root(); + ASSERT_EQ(1U, root->child_count()); + ASSERT_EQ(0U, root->child_at(0)->child_count()); + EXPECT_EQ(main_url, root->current_url()); + EXPECT_EQ(blank_url, root->child_at(0)->current_url()); + + // Verify that the parent was able to script the iframe. + std::string expected_text("Injected text"); + { + std::string value; + EXPECT_TRUE(ExecuteScriptAndExtractString( + root->child_at(0), + "domAutomationController.send(document.body.innerHTML)", &value)); + EXPECT_EQ(expected_text, value); + } + + EXPECT_EQ(1, controller.GetEntryCount()); + EXPECT_EQ(0, controller.GetLastCommittedEntryIndex()); + NavigationEntryImpl* entry = controller.GetLastCommittedEntry(); + + // The entry should have a FrameNavigationEntry for the blank subframe. + if (SiteIsolationPolicy::UseSubframeNavigationEntries()) { + ASSERT_EQ(1U, entry->root_node()->children.size()); + EXPECT_EQ(blank_url, entry->root_node()->children[0]->frame_entry->url()); + } + + // 3. Navigate the main frame, destroying the frames. + GURL main_url_2(embedded_test_server()->GetURL( + "/navigation_controller/simple_page_1.html")); + EXPECT_TRUE(NavigateToURL(shell(), main_url_2)); + ASSERT_EQ(0U, root->child_count()); + EXPECT_EQ(main_url_2, root->current_url()); + + EXPECT_EQ(2, controller.GetEntryCount()); + EXPECT_EQ(1, controller.GetLastCommittedEntryIndex()); + + // 4. Go back, recreating the iframe. + { + TestNavigationObserver back_load_observer(shell()->web_contents()); + controller.GoBack(); + back_load_observer.Wait(); + } + ASSERT_EQ(1U, root->child_count()); + EXPECT_EQ(main_url, root->current_url()); + + // TODO(creis): The child's current_url should be about:blank, but we're not + // currently getting a commit in this case. For now, we'll lack a commit for + // this frame, similar to the slow URL case. See https://crbug.com/626416. + if (SiteIsolationPolicy::UseSubframeNavigationEntries()) + EXPECT_TRUE(root->child_at(0)->current_url().is_empty()); + else + EXPECT_EQ(blank_url, root->child_at(0)->current_url()); + + // Verify that the parent was able to script the iframe. + { + std::string value; + EXPECT_TRUE(ExecuteScriptAndExtractString( + root->child_at(0), + "domAutomationController.send(document.body.innerHTML)", &value)); + EXPECT_EQ(expected_text, value); + } + + EXPECT_EQ(2, controller.GetEntryCount()); + EXPECT_EQ(0, controller.GetLastCommittedEntryIndex()); + EXPECT_EQ(entry, controller.GetLastCommittedEntry()); + + // The entry should have a FrameNavigationEntry for the blank subframe. + if (SiteIsolationPolicy::UseSubframeNavigationEntries()) { + ASSERT_EQ(1U, entry->root_node()->children.size()); + EXPECT_EQ(blank_url, entry->root_node()->children[0]->frame_entry->url()); + } +} + // Verifies that we clear the children FrameNavigationEntries if a history // navigation redirects, so that we don't try to load previous history items in // frames of the new page. This should only clear the children of the frame @@ -5012,7 +5098,14 @@ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); EXPECT_EQ(2, controller.GetLastCommittedEntryIndex()); EXPECT_EQ(url_b, root->current_url()); - EXPECT_EQ(frame_url_b1, root->child_at(0)->current_url()); + + // TODO(creis): The child's current_url should be about:blank, but we're not + // currently getting a commit in this case. For now, we'll lack a commit for + // this frame, similar to the slow URL case. See https://crbug.com/626416. + if (SiteIsolationPolicy::UseSubframeNavigationEntries()) + EXPECT_TRUE(root->child_at(0)->current_url().is_empty()); + else + EXPECT_EQ(frame_url_b1, root->child_at(0)->current_url()); // Check the PageState of the previous entry to ensure it isn't corrupted. NavigationEntry* entry = controller.GetEntryAtIndex(1);
diff --git a/content/browser/frame_host/navigation_entry_impl.cc b/content/browser/frame_host/navigation_entry_impl.cc index c3e45e6..41033a81 100644 --- a/content/browser/frame_host/navigation_entry_impl.cc +++ b/content/browser/frame_host/navigation_entry_impl.cc
@@ -636,6 +636,9 @@ // ResetForCommit: should_clear_history_list_ // ResetForCommit: frame_tree_node_id_ // ResetForCommit: intent_received_timestamp_ +#if defined(OS_ANDROID) + copy->has_user_gesture_ = has_user_gesture_; +#endif copy->extra_data_ = extra_data_; return copy;
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index 68ec2156..7783a26 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -980,7 +980,8 @@ // TODO(creis, clamy): Cancel any cross-process navigation in PlzNavigate. if (GetParent() && !frame_tree_node_->has_committed_real_load() && frame_tree_node_->render_manager()->pending_frame_host()) { - frame_tree_node_->render_manager()->CancelPending(); + frame_tree_node_->render_manager()->CancelPendingIfNecessary( + frame_tree_node_->render_manager()->pending_frame_host()); } } @@ -1478,11 +1479,16 @@ iter.second.Run(ui::AXTreeUpdate()); ax_tree_snapshot_callbacks_.clear(); - // If the process has died, we don't need to wait for the swap out ack from - // this RenderFrame if it is pending deletion. Complete the swap out to - // destroy it. - if (!is_active()) + if (!is_active()) { + // If the process has died, we don't need to wait for the swap out ack from + // this RenderFrame if it is pending deletion. Complete the swap out to + // destroy it. OnSwappedOut(); + } else { + // If this was the current pending or speculative RFH dying, cancel and + // destroy it. + frame_tree_node_->render_manager()->CancelPendingIfNecessary(this); + } // Note: don't add any more code at this point in the function because // |this| may be deleted. Any additional cleanup should happen before @@ -2140,13 +2146,6 @@ void RenderFrameHostImpl::ResetWaitingState() { DCHECK(is_active()); - // The active state of the RVH is determined by its main frame, since - // subframes should have their own widgets. - if (frame_tree_node_->IsMainFrame()) { - render_view_host_->set_is_active(true); - render_view_host_->set_is_swapped_out(false); - } - // Whenever we reset the RFH state, we should not be waiting for beforeunload // or close acks. We clear them here to be safe, since they can cause // navigations to be ignored in OnDidCommitProvisionalLoad.
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc index 6e33a629..651c3590 100644 --- a/content/browser/frame_host/render_frame_host_manager.cc +++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -1029,6 +1029,17 @@ GetRenderFrameProxyHost(instance)->set_render_frame_proxy_created(false); } +void RenderFrameHostManager::CancelPendingIfNecessary( + RenderFrameHostImpl* render_frame_host) { + if (render_frame_host == pending_render_frame_host_.get()) + CancelPending(); + else if (render_frame_host == speculative_render_frame_host_.get()) { + // TODO(nasko, clamy): This should just clean up the speculative RFH + // without canceling the request. See https://crbug.com/636119. + frame_tree_node_->ResetNavigationRequest(false); + } +} + void RenderFrameHostManager::ActiveFrameCountIsZero( SiteInstanceImpl* site_instance) { // |site_instance| no longer contains any active RenderFrameHosts, so we don't @@ -2136,6 +2147,8 @@ if (is_main_frame) { render_frame_host_->render_view_host()->set_main_frame_routing_id( render_frame_host_->routing_id()); + render_frame_host_->render_view_host()->set_is_active(true); + render_frame_host_->render_view_host()->set_is_swapped_out(false); old_render_frame_host->render_view_host()->set_main_frame_routing_id( MSG_ROUTING_NONE); } @@ -2193,9 +2206,15 @@ // different SiteInstance, we want to get back to normal and then navigate as // usual. We will reuse the pending RFH below if it matches the destination // SiteInstance. - if (pending_render_frame_host_ && - pending_render_frame_host_->GetSiteInstance() != new_instance) - CancelPending(); + if (pending_render_frame_host_) { + if (pending_render_frame_host_->GetSiteInstance() != new_instance) { + CancelPending(); + } else { + // When a pending RFH is reused, it should always be live, since it is + // cleared whenever a process dies. + CHECK(pending_render_frame_host_->IsRenderFrameLive()); + } + } if (new_instance.get() != current_instance) { TRACE_EVENT_INSTANT2(
diff --git a/content/browser/frame_host/render_frame_host_manager.h b/content/browser/frame_host/render_frame_host_manager.h index dd08ac2..30b96e0 100644 --- a/content/browser/frame_host/render_frame_host_manager.h +++ b/content/browser/frame_host/render_frame_host_manager.h
@@ -508,6 +508,10 @@ void ActiveFrameCountIsZero(SiteInstanceImpl* site_instance) override; void RenderProcessGone(SiteInstanceImpl* site_instance) override; + // Cancels and destroys the pending or speculative RenderFrameHost if they + // match the provided |render_frame_host|. + void CancelPendingIfNecessary(RenderFrameHostImpl* render_frame_host); + // Sets up the necessary state for a new RenderViewHost. If |proxy| is not // null, it creates a RenderFrameProxy in the target renderer process which is // used to route IPC messages when in swapped out state. Returns early if the @@ -515,9 +519,6 @@ bool InitRenderView(RenderViewHostImpl* render_view_host, RenderFrameProxyHost* proxy); - // Terminates and deletes the pending RenderFrameHost. - void CancelPending(); - private: friend class NavigatorTestWithBrowserSideNavigation; friend class RenderFrameHostManagerTest; @@ -713,6 +714,9 @@ void DiscardUnusedFrame( std::unique_ptr<RenderFrameHostImpl> render_frame_host); + // Terminates and deletes the pending RenderFrameHost. + void CancelPending(); + // Clears pending_render_frame_host_, returning it to the caller for disposal. std::unique_ptr<RenderFrameHostImpl> UnsetPendingRenderFrameHost();
diff --git a/content/browser/frame_host/render_frame_message_filter.cc b/content/browser/frame_host/render_frame_message_filter.cc index 5db2491..97769836 100644 --- a/content/browser/frame_host/render_frame_message_filter.cc +++ b/content/browser/frame_host/render_frame_message_filter.cc
@@ -15,7 +15,6 @@ #include "content/browser/download/download_stats.h" #include "content/browser/frame_host/render_frame_host_impl.h" #include "content/browser/gpu/gpu_data_manager_impl.h" -#include "content/browser/host_zoom_map_impl.h" #include "content/browser/renderer_host/render_widget_helper.h" #include "content/browser/resource_context_impl.h" #include "content/common/content_constants_internal.h" @@ -26,7 +25,6 @@ #include "content/public/browser/browser_thread.h" #include "content/public/browser/download_manager.h" #include "content/public/browser/download_url_parameters.h" -#include "content/public/browser/storage_partition.h" #include "content/public/common/content_constants.h" #include "content/public/common/content_switches.h" #include "gpu/GLES2/gl2extchromium.h" @@ -223,13 +221,7 @@ resource_context_(browser_context->GetResourceContext()), render_widget_helper_(render_widget_helper), incognito_(browser_context->IsOffTheRecord()), - render_process_id_(render_process_id), - host_zoom_map_impl_(render_process_id - ? static_cast<const HostZoomMapImpl*>( - RenderProcessHost::FromID(render_process_id) - ->GetStoragePartition() - ->GetHostZoomMap()) - : nullptr) { + render_process_id_(render_process_id) { } RenderFrameMessageFilter::~RenderFrameMessageFilter() { @@ -456,19 +448,6 @@ render_frame_id, url, first_party_for_cookies, callback)); } -void RenderFrameMessageFilter::GetHostZoomLevel( - int32_t render_frame_id, - const GURL& url, - const GetHostZoomLevelCallback& callback) { - // We need to make sure this is serviced directly on the IO thread so that it - // does not get out of order with the resource request in AsyncResourceHandler - // which lives on the IO thread. - DCHECK_CURRENTLY_ON(BrowserThread::IO); - double zoom_level = host_zoom_map_impl_->GetZoomLevelForView( - url, render_process_id_, render_frame_id); - callback.Run(zoom_level); -} - #if defined(ENABLE_PLUGINS) void RenderFrameMessageFilter::OnGetPlugins(
diff --git a/content/browser/frame_host/render_frame_message_filter.h b/content/browser/frame_host/render_frame_message_filter.h index e351629..d576df03 100644 --- a/content/browser/frame_host/render_frame_message_filter.h +++ b/content/browser/frame_host/render_frame_message_filter.h
@@ -31,7 +31,6 @@ namespace content { class BrowserContext; -class HostZoomMapImpl; class PluginServiceImpl; struct Referrer; class RenderWidgetHelper; @@ -118,9 +117,7 @@ const GURL& url, const GURL& first_party_for_cookies, const GetCookiesCallback& callback) override; - void GetHostZoomLevel(int32_t render_frame_id, - const GURL& url, - const GetHostZoomLevelCallback& callback) override; + #if defined(ENABLE_PLUGINS) void OnGetPlugins(bool refresh, IPC::Message* reply_msg); @@ -176,8 +173,6 @@ bool incognito_; const int render_process_id_; - - const HostZoomMapImpl* host_zoom_map_impl_; }; } // namespace content
diff --git a/content/browser/host_zoom_map_impl.h b/content/browser/host_zoom_map_impl.h index ad4c07e..ea323f3 100644 --- a/content/browser/host_zoom_map_impl.h +++ b/content/browser/host_zoom_map_impl.h
@@ -149,6 +149,8 @@ // Page scale factor data for each renderer. ViewPageScaleFactorsAreOne view_page_scale_factors_are_one_; + // Don't expect more than a couple of tabs that are using a temporary zoom + // level, so vector is fine for now. TemporaryZoomLevels temporary_zoom_levels_; // Used around accesses to |host_zoom_levels_|, |default_zoom_level_|,
diff --git a/content/browser/loader/DEPS b/content/browser/loader/DEPS index 7921ba10..672240b 100644 --- a/content/browser/loader/DEPS +++ b/content/browser/loader/DEPS
@@ -23,6 +23,7 @@ "+content/public/common/resource_response.h", # TODO: these all have to be removed. + "+content/browser/host_zoom_map_impl.h", "+content/public/common/content_features.h", # TODO: To be replaced by mojo.
diff --git a/content/browser/loader/async_resource_handler.cc b/content/browser/loader/async_resource_handler.cc index 6be0add..19e0868 100644 --- a/content/browser/loader/async_resource_handler.cc +++ b/content/browser/loader/async_resource_handler.cc
@@ -17,6 +17,7 @@ #include "base/metrics/histogram_macros.h" #include "base/strings/string_number_conversions.h" #include "base/time/time.h" +#include "content/browser/host_zoom_map_impl.h" #include "content/browser/loader/netlog_observer.h" #include "content/browser/loader/resource_buffer.h" #include "content/browser/loader/resource_dispatcher_host_impl.h" @@ -356,6 +357,21 @@ NetLogObserver::PopulateResponseInfo(request(), response); + const HostZoomMapImpl* host_zoom_map = + static_cast<const HostZoomMapImpl*>(info->filter()->GetHostZoomMap()); + + if (info->GetResourceType() == RESOURCE_TYPE_MAIN_FRAME && host_zoom_map) { + const GURL& request_url = request()->url(); + int render_process_id = info->GetChildID(); + int render_view_id = info->GetRouteID(); + + double zoom_level = host_zoom_map->GetZoomLevelForView( + request_url, render_process_id, render_view_id); + + info->filter()->Send(new ViewMsg_SetZoomLevelForLoadingURL( + render_view_id, request_url, zoom_level)); + } + // If the parent handler downloaded the resource to a file, grant the child // read permissions on it. if (!response->head.download_file_path.empty()) {
diff --git a/content/browser/loader/async_resource_handler_unittest.cc b/content/browser/loader/async_resource_handler_unittest.cc index 90b253f..7117631f 100644 --- a/content/browser/loader/async_resource_handler_unittest.cc +++ b/content/browser/loader/async_resource_handler_unittest.cc
@@ -97,6 +97,7 @@ nullptr, nullptr, nullptr, + nullptr, base::Bind(&RecordingResourceMessageFilter::GetContexts, base::Unretained(this))), resource_context_(resource_context),
diff --git a/content/browser/loader/async_revalidation_manager_unittest.cc b/content/browser/loader/async_revalidation_manager_unittest.cc index bed7412..392760d 100644 --- a/content/browser/loader/async_revalidation_manager_unittest.cc +++ b/content/browser/loader/async_revalidation_manager_unittest.cc
@@ -212,6 +212,7 @@ nullptr, nullptr, nullptr, + nullptr, base::Bind(&BlackholeFilter::GetContexts, base::Unretained(this))), resource_context_(resource_context) { ChildProcessSecurityPolicyImpl::GetInstance()->Add(child_id());
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc index d0bc8a6..b7adcbf 100644 --- a/content/browser/loader/resource_dispatcher_host_impl.cc +++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -286,69 +286,6 @@ request->set_referrer_policy(net_referrer_policy); } -// Consults the RendererSecurity policy to determine whether the -// ResourceDispatcherHostImpl should service this request. A request might be -// disallowed if the renderer is not authorized to retrieve the request URL or -// if the renderer is attempting to upload an unauthorized file. -bool ShouldServiceRequest(int process_type, - int child_id, - const ResourceRequest& request_data, - const net::HttpRequestHeaders& headers, - ResourceMessageFilter* filter, - ResourceContext* resource_context) { - ChildProcessSecurityPolicyImpl* policy = - ChildProcessSecurityPolicyImpl::GetInstance(); - - // Check if the renderer is permitted to request the requested URL. - if (!policy->CanRequestURL(child_id, request_data.url)) { - VLOG(1) << "Denied unauthorized request for " - << request_data.url.possibly_invalid_spec(); - return false; - } - - // Check if the renderer is using an illegal Origin header. If so, kill it. - std::string origin_string; - bool has_origin = headers.GetHeader("Origin", &origin_string) && - origin_string != "null"; - if (has_origin) { - GURL origin(origin_string); - if (!policy->CanCommitURL(child_id, origin) || - GetContentClient()->browser()->IsIllegalOrigin(resource_context, - child_id, origin)) { - VLOG(1) << "Killed renderer for illegal origin: " << origin_string; - bad_message::ReceivedBadMessage(filter, bad_message::RDH_ILLEGAL_ORIGIN); - return false; - } - } - - // Check if the renderer is permitted to upload the requested files. - if (request_data.request_body.get()) { - const std::vector<ResourceRequestBodyImpl::Element>* uploads = - request_data.request_body->elements(); - std::vector<ResourceRequestBodyImpl::Element>::const_iterator iter; - for (iter = uploads->begin(); iter != uploads->end(); ++iter) { - if (iter->type() == ResourceRequestBodyImpl::Element::TYPE_FILE && - !policy->CanReadFile(child_id, iter->path())) { - NOTREACHED() << "Denied unauthorized upload of " - << iter->path().value(); - return false; - } - if (iter->type() == - ResourceRequestBodyImpl::Element::TYPE_FILE_FILESYSTEM) { - storage::FileSystemURL url = - filter->file_system_context()->CrackURL(iter->filesystem_url()); - if (!policy->CanReadFileSystemFile(child_id, url)) { - NOTREACHED() << "Denied unauthorized upload of " - << iter->filesystem_url().spec(); - return false; - } - } - } - } - - return true; -} - void RemoveDownloadFileFromChildSecurityPolicy(int child_id, const base::FilePath& path) { ChildProcessSecurityPolicyImpl::GetInstance()->RevokeAllPermissionsForFile( @@ -493,6 +430,13 @@ } // namespace +ResourceDispatcherHostImpl::HeaderInterceptorInfo::HeaderInterceptorInfo() {} + +ResourceDispatcherHostImpl::HeaderInterceptorInfo::~HeaderInterceptorInfo() {} + +ResourceDispatcherHostImpl::HeaderInterceptorInfo::HeaderInterceptorInfo( + const HeaderInterceptorInfo& other) {} + // static ResourceDispatcherHost* ResourceDispatcherHost::Get() { return g_resource_dispatcher_host; @@ -749,6 +693,23 @@ } } +void ResourceDispatcherHostImpl::RegisterInterceptor( + const std::string& http_header, + const std::string& starts_with, + const InterceptorCallback& interceptor) { + DCHECK(!http_header.empty()); + DCHECK(interceptor); + // Only one interceptor per header is supported. + DCHECK(http_header_interceptor_map_.find(http_header) == + http_header_interceptor_map_.end()); + + HeaderInterceptorInfo interceptor_info; + interceptor_info.starts_with = starts_with; + interceptor_info.interceptor = interceptor; + + http_header_interceptor_map_[http_header] = interceptor_info; +} + void ResourceDispatcherHostImpl::Shutdown() { DCHECK_CURRENTLY_ON(BrowserThread::UI); BrowserThread::PostTask(BrowserThread::IO, @@ -1357,13 +1318,55 @@ net::HttpRequestHeaders headers; headers.AddHeadersFromString(request_data.headers); - if (is_shutdown_ || - !ShouldServiceRequest(process_type, child_id, request_data, headers, - filter_, resource_context)) { + BeginRequestStatus begin_request_status = CONTINUE; + OnHeaderProcessedCallback callback; + if (!is_shutdown_) { + callback = + base::Bind(&ResourceDispatcherHostImpl::ContinuePendingBeginRequest, + base::Unretained(this), request_id, request_data, + sync_result, route_id, headers); + begin_request_status = + ShouldServiceRequest(process_type, child_id, request_data, headers, + filter_, resource_context, callback); + } else { + begin_request_status = ABORT; + } + if (begin_request_status == ABORT) { + AbortRequestBeforeItStarts(filter_, sync_result, request_id); + return; + } else if (begin_request_status == CONTINUE) { + callback.Run(true, 0); + } +} + +void ResourceDispatcherHostImpl::ContinuePendingBeginRequest( + int request_id, + const ResourceRequest& request_data, + IPC::Message* sync_result, // only valid for sync + int route_id, + const net::HttpRequestHeaders& headers, + bool continue_request, + int error_code) { + if (!continue_request) { + // TODO(ananta): Find a way to specify the right error code here. Passing + // in a non-content error code is not safe. + bad_message::ReceivedBadMessage(filter_, bad_message::RDH_ILLEGAL_ORIGIN); AbortRequestBeforeItStarts(filter_, sync_result, request_id); return; } + int process_type = filter_->process_type(); + int child_id = filter_->child_id(); + + bool is_navigation_stream_request = + IsBrowserSideNavigationEnabled() && + IsResourceTypeFrame(request_data.resource_type); + + ResourceContext* resource_context = NULL; + net::URLRequestContext* request_context = NULL; + filter_->GetContexts(request_data.resource_type, &resource_context, + &request_context); + // Allow the observer to block/handle the request. if (delegate_ && !delegate_->ShouldBeginRequest(request_data.method, request_data.url, @@ -2605,4 +2608,87 @@ : CertStore::GetInstance(); } +ResourceDispatcherHostImpl::BeginRequestStatus +ResourceDispatcherHostImpl::ShouldServiceRequest( + int process_type, + int child_id, + const ResourceRequest& request_data, + const net::HttpRequestHeaders& headers, + ResourceMessageFilter* filter, + ResourceContext* resource_context, + OnHeaderProcessedCallback callback) { + ChildProcessSecurityPolicyImpl* policy = + ChildProcessSecurityPolicyImpl::GetInstance(); + + // Check if the renderer is permitted to request the requested URL. + if (!policy->CanRequestURL(child_id, request_data.url)) { + VLOG(1) << "Denied unauthorized request for " + << request_data.url.possibly_invalid_spec(); + return ABORT; + } + + // Check if the renderer is using an illegal Origin header. If so, kill it. + std::string origin_string; + bool has_origin = + headers.GetHeader("Origin", &origin_string) && origin_string != "null"; + if (has_origin) { + GURL origin(origin_string); + if (!policy->CanCommitURL(child_id, origin)) { + VLOG(1) << "Killed renderer for illegal origin: " << origin_string; + bad_message::ReceivedBadMessage(filter, bad_message::RDH_ILLEGAL_ORIGIN); + return ABORT; + } + } + + // Check if the renderer is permitted to upload the requested files. + if (request_data.request_body.get()) { + const std::vector<ResourceRequestBodyImpl::Element>* uploads = + request_data.request_body->elements(); + std::vector<ResourceRequestBodyImpl::Element>::const_iterator iter; + for (iter = uploads->begin(); iter != uploads->end(); ++iter) { + if (iter->type() == ResourceRequestBodyImpl::Element::TYPE_FILE && + !policy->CanReadFile(child_id, iter->path())) { + NOTREACHED() << "Denied unauthorized upload of " + << iter->path().value(); + return ABORT; + } + if (iter->type() == + ResourceRequestBodyImpl::Element::TYPE_FILE_FILESYSTEM) { + storage::FileSystemURL url = + filter->file_system_context()->CrackURL(iter->filesystem_url()); + if (!policy->CanReadFileSystemFile(child_id, url)) { + NOTREACHED() << "Denied unauthorized upload of " + << iter->filesystem_url().spec(); + return ABORT; + } + } + } + } + + // Check if we have a registered interceptor for the headers passed in. If + // yes then we need to mark the current request as pending and wait for the + // interceptor to invoke the |callback| with a status code indicating whether + // the request needs to be aborted or continued. + for (net::HttpRequestHeaders::Iterator it(headers); it.GetNext();) { + HeaderInterceptorMap::iterator index = + http_header_interceptor_map_.find(it.name()); + if (index != http_header_interceptor_map_.end()) { + HeaderInterceptorInfo& interceptor_info = index->second; + + bool call_interceptor = true; + if (!interceptor_info.starts_with.empty()) { + call_interceptor = + base::StartsWith(it.value(), interceptor_info.starts_with, + base::CompareCase::INSENSITIVE_ASCII); + } + if (call_interceptor) { + interceptor_info.interceptor.Run(it.name(), it.value(), child_id, + resource_context, callback); + return PENDING; + } + } + } + return CONTINUE; +} + } // namespace content
diff --git a/content/browser/loader/resource_dispatcher_host_impl.h b/content/browser/loader/resource_dispatcher_host_impl.h index 339daec..3e6c504 100644 --- a/content/browser/loader/resource_dispatcher_host_impl.h +++ b/content/browser/loader/resource_dispatcher_host_impl.h
@@ -107,6 +107,9 @@ void SetDelegate(ResourceDispatcherHostDelegate* delegate) override; void SetAllowCrossOriginAuthPrompt(bool value) override; void ClearLoginDelegateForRequest(net::URLRequest* request) override; + void RegisterInterceptor(const std::string& http_header, + const std::string& starts_with, + const InterceptorCallback& interceptor) override; // Puts the resource dispatcher host in an inactive state (unable to begin // new requests). Cancels all pending requests. @@ -325,6 +328,23 @@ // Map from ProcessID+RouteID pair to the "most interesting" LoadState. typedef std::map<GlobalRoutingID, LoadInfo> LoadInfoMap; + // Information about a HTTP header interceptor. + struct HeaderInterceptorInfo { + // Structure is sufficiently complicated to require the constructor + // destructor definitions in the cc file. + HeaderInterceptorInfo(); + ~HeaderInterceptorInfo(); + HeaderInterceptorInfo(const HeaderInterceptorInfo& other); + + // Used to prefix match the value of the http header. + std::string starts_with; + // The interceptor. + InterceptorCallback interceptor; + }; + + // Map from HTTP header to its information HeaderInterceptorInfo. + typedef std::map<std::string, HeaderInterceptorInfo> HeaderInterceptorMap; + // ResourceLoaderDelegate implementation: ResourceDispatcherHostLoginDelegate* CreateLoginDelegate( ResourceLoader* loader, @@ -454,6 +474,24 @@ IPC::Message* sync_result, // only valid for sync int route_id); // only valid for async + // There are requests which need decisions to be made like the following: + // Whether the presence of certain HTTP headers like the Origin header are + // valid, etc. These requests may need to be aborted based on these + // decisions which could be time consuming. We allow for these decisions + // to be made asynchronously. The request proceeds when we hear back from + // the interceptors about whether to continue or not. + // The |continue_request| parameter in the function indicates whether the + // request should be continued or aborted. The |error_code| parameter is set + // if |continue_request| is false. + void ContinuePendingBeginRequest( + int request_id, + const ResourceRequest& request_data, + IPC::Message* sync_result, // only valid for sync + int route_id, + const net::HttpRequestHeaders& headers, + bool continue_request, + int error_code); + // Creates a ResourceHandler to be used by BeginRequest() for normal resource // loading. std::unique_ptr<ResourceHandler> CreateResourceHandler( @@ -537,6 +575,28 @@ CertStore* GetCertStore(); + // This enum holds values which indicate how we want to proceed with a + // request that is about to be started. + enum BeginRequestStatus { + CONTINUE = 0, // Continue with the request. + ABORT = 1, // Abort. + PENDING = 2, // Wait for the decision to come back. + LAST_SERVICE_REQUEST_STATUS = PENDING, + }; + + // Consults the RendererSecurity policy to determine whether the + // ResourceDispatcherHostImpl should service this request. A request might + // be disallowed if the renderer is not authorized to retrieve the request + // URL or if the renderer is attempting to upload an unauthorized file. + BeginRequestStatus ShouldServiceRequest( + int process_type, + int child_id, + const ResourceRequest& request_data, + const net::HttpRequestHeaders& headers, + ResourceMessageFilter* filter, + ResourceContext* resource_context, + OnHeaderProcessedCallback callback); + LoaderMap pending_loaders_; // Collection of temp files downloaded for child processes via @@ -631,6 +691,9 @@ // outlive this ResourceDispatcherHostImpl. CertStore* cert_store_for_testing_; + // Used to invoke an interceptor for the HTTP header. + HeaderInterceptorMap http_header_interceptor_map_; + DISALLOW_COPY_AND_ASSIGN(ResourceDispatcherHostImpl); };
diff --git a/content/browser/loader/resource_dispatcher_host_unittest.cc b/content/browser/loader/resource_dispatcher_host_unittest.cc index 74df61c..a1b1f7b 100644 --- a/content/browser/loader/resource_dispatcher_host_unittest.cc +++ b/content/browser/loader/resource_dispatcher_host_unittest.cc
@@ -242,6 +242,7 @@ NULL, NULL, NULL, + NULL, base::Bind(&TestFilterSpecifyingChild::GetContexts, base::Unretained(this))), resource_context_(resource_context),
diff --git a/content/browser/loader/resource_message_filter.cc b/content/browser/loader/resource_message_filter.cc index 958b7d0..eb1993b59 100644 --- a/content/browser/loader/resource_message_filter.cc +++ b/content/browser/loader/resource_message_filter.cc
@@ -6,6 +6,7 @@ #include "content/browser/appcache/chrome_appcache_service.h" #include "content/browser/blob_storage/chrome_blob_storage_context.h" +#include "content/browser/host_zoom_level_context.h" #include "content/browser/loader/resource_dispatcher_host_impl.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" #include "content/common/resource_messages.h" @@ -21,6 +22,7 @@ ChromeBlobStorageContext* blob_storage_context, storage::FileSystemContext* file_system_context, ServiceWorkerContextWrapper* service_worker_context, + HostZoomLevelContext* host_zoom_level_context, const GetContextsCallback& get_contexts_callback) : BrowserMessageFilter(ResourceMsgStart), child_id_(child_id), @@ -29,6 +31,7 @@ blob_storage_context_(blob_storage_context), file_system_context_(file_system_context), service_worker_context_(service_worker_context), + host_zoom_level_context_(host_zoom_level_context), get_contexts_callback_(get_contexts_callback), weak_ptr_factory_(this) { } @@ -54,6 +57,12 @@ request_context); } +const HostZoomMap* ResourceMessageFilter::GetHostZoomMap() const { + if (host_zoom_level_context_.get()) + return host_zoom_level_context_->GetHostZoomMap(); + return NULL; +} + base::WeakPtr<ResourceMessageFilter> ResourceMessageFilter::GetWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); }
diff --git a/content/browser/loader/resource_message_filter.h b/content/browser/loader/resource_message_filter.h index a6f25c0..44937a0b 100644 --- a/content/browser/loader/resource_message_filter.h +++ b/content/browser/loader/resource_message_filter.h
@@ -10,6 +10,7 @@ #include "base/callback_forward.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" +#include "content/browser/host_zoom_level_context.h" #include "content/common/content_export.h" #include "content/public/browser/browser_message_filter.h" #include "content/public/common/resource_type.h" @@ -51,6 +52,7 @@ ChromeBlobStorageContext* blob_storage_context, storage::FileSystemContext* file_system_context, ServiceWorkerContextWrapper* service_worker_context, + HostZoomLevelContext* host_zoom_level_context, const GetContextsCallback& get_contexts_callback); // BrowserMessageFilter implementation. @@ -80,6 +82,10 @@ return service_worker_context_.get(); } + // Returns a raw pointer to the HostZoomLevelContext's associated HostZoomMap, + // or NULL if no context is present. + const HostZoomMap* GetHostZoomMap() const; + int child_id() const { return child_id_; } int process_type() const { return process_type_; } @@ -99,6 +105,7 @@ scoped_refptr<ChromeBlobStorageContext> blob_storage_context_; scoped_refptr<storage::FileSystemContext> file_system_context_; scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_; + scoped_refptr<HostZoomLevelContext> host_zoom_level_context_; GetContextsCallback get_contexts_callback_;
diff --git a/content/browser/media/media_internals.cc b/content/browser/media/media_internals.cc index 3ef8673..ba7e6906 100644 --- a/content/browser/media/media_internals.cc +++ b/content/browser/media/media_internals.cc
@@ -485,7 +485,7 @@ RenderProcessHost* process = Source<RenderProcessHost>(source).ptr(); uma_handler_->OnProcessTerminated(process->GetID()); - pending_events_map_.erase(process->GetID()); + saved_events_by_process_.erase(process->GetID()); } // Converts the |event| to a |update|. Returns whether the conversion succeeded. @@ -568,10 +568,10 @@ void MediaInternals::SendHistoricalMediaEvents() { DCHECK_CURRENTLY_ON(BrowserThread::UI); - for (const auto& pending_events : pending_events_map_) { - for (const auto& event : pending_events.second) { + for (const auto& saved_events : saved_events_by_process_) { + for (const auto& event : saved_events.second) { base::string16 update; - if (ConvertEventToUpdate(pending_events.first, event, &update)) + if (ConvertEventToUpdate(saved_events.first, event, &update)) SendUpdate(update); } } @@ -666,9 +666,6 @@ const media::MediaLogEvent& event) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - // Max number of saved updates allowed for one process. - const size_t kMaxNumEvents = 128; - // Do not save instantaneous events that happen frequently and have little // value in the future. if (event.type == media::MediaLogEvent::NETWORK_ACTIVITY_SET || @@ -676,12 +673,22 @@ return; } - auto& pending_events = pending_events_map_[process_id]; - // TODO(xhwang): Notify user that some old logs could have been truncated. - // See http://crbug.com/498520 - if (pending_events.size() >= kMaxNumEvents) - pending_events.pop_front(); - pending_events.push_back(event); + // Save the event and limit the total number per renderer. At the time of + // writing, 512 events of the kind: { "property": value } together consume + // ~88kb of memory on linux. + std::list<media::MediaLogEvent>& saved_events = + saved_events_by_process_[process_id]; + saved_events.push_back(event); + if (saved_events.size() > 512) { + // Remove all events for a given player as soon as we have to remove a + // single event for that player to avoid showing incomplete players. + int id_to_remove = saved_events.front().id; + auto new_end = std::remove_if(saved_events.begin(), saved_events.end(), + [&](const media::MediaLogEvent& event) { + return event.id == id_to_remove; + }); + saved_events.erase(new_end, saved_events.end()); + } } void MediaInternals::UpdateAudioLog(AudioLogUpdateType type,
diff --git a/content/browser/media/media_internals.h b/content/browser/media/media_internals.h index 77f4fb1bf..9a78553 100644 --- a/content/browser/media/media_internals.h +++ b/content/browser/media/media_internals.h
@@ -99,12 +99,6 @@ friend class MediaInternalsTest; friend struct base::DefaultLazyInstanceTraits<MediaInternals>; - // Pending events for a particular process. - using PendingEvents = std::list<media::MediaLogEvent>; - - // The maps between process ID and PendingEvents. - using PendingEventsMap = std::map<int, PendingEvents>; - MediaInternals(); // Sends |update| to each registered UpdateCallback. Safe to call from any @@ -130,7 +124,9 @@ // Must only be accessed on the UI thread. std::vector<UpdateCallback> update_callbacks_; - PendingEventsMap pending_events_map_; + + // Saved events by process ID for showing recent players in the UI. + std::map<int, std::list<media::MediaLogEvent>> saved_events_by_process_; // Must only be accessed on the IO thread. base::ListValue video_capture_capabilities_cached_data_;
diff --git a/content/browser/mojo/mojo_shell_context.cc b/content/browser/mojo/mojo_shell_context.cc index 2836bf4..cb0f5bd2 100644 --- a/content/browser/mojo/mojo_shell_context.cc +++ b/content/browser/mojo/mojo_shell_context.cc
@@ -4,44 +4,37 @@ #include "content/browser/mojo/mojo_shell_context.h" -#include <unordered_map> +#include <memory> +#include <string> #include <utility> #include "base/bind.h" -#include "base/command_line.h" #include "base/lazy_instance.h" #include "base/macros.h" #include "base/memory/ptr_util.h" -#include "base/path_service.h" #include "base/single_thread_task_runner.h" -#include "base/threading/thread_task_runner_handle.h" #include "content/browser/gpu/gpu_process_host.h" #include "content/common/mojo/constants.h" #include "content/common/mojo/mojo_shell_connection_impl.h" -#include "content/common/process_control.mojom.h" #include "content/grit/content_resources.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/utility_process_host.h" #include "content/public/browser/utility_process_host_client.h" #include "content/public/common/content_client.h" -#include "content/public/common/content_switches.h" +#include "content/public/common/mojo_shell_connection.h" #include "mojo/edk/embedder/embedder.h" -#include "mojo/public/cpp/bindings/interface_request.h" -#include "mojo/public/cpp/bindings/string.h" #include "services/catalog/catalog.h" #include "services/catalog/manifest_provider.h" #include "services/catalog/store.h" #include "services/shell/connect_params.h" #include "services/shell/native_runner.h" #include "services/shell/public/cpp/connector.h" -#include "services/shell/public/cpp/identity.h" #include "services/shell/public/cpp/service.h" -#include "services/shell/public/interfaces/connector.mojom.h" #include "services/shell/public/interfaces/service.mojom.h" -#include "services/shell/public/interfaces/service_factory.mojom.h" #include "services/shell/runner/common/client_util.h" #include "services/shell/runner/host/in_process_native_runner.h" +#include "services/shell/service_manager.h" #include "services/user/public/cpp/constants.h" namespace content { @@ -53,46 +46,35 @@ void DestroyConnectorOnIOThread() { g_io_thread_connector.Get().reset(); } -void StartUtilityProcessOnIOThread( - mojo::InterfaceRequest<mojom::ProcessControl> request, - const base::string16& process_name, - bool use_sandbox) { +void StartUtilityProcessOnIOThread(shell::mojom::ServiceFactoryRequest request, + const base::string16& process_name, + bool use_sandbox) { UtilityProcessHost* process_host = UtilityProcessHost::Create(nullptr, nullptr); process_host->SetName(process_name); if (!use_sandbox) process_host->DisableSandbox(); process_host->Start(); - process_host->GetRemoteInterfaces()->GetInterface(std::move(request)); } -void OnApplicationLoaded(const std::string& name, bool success) { - if (!success) - LOG(ERROR) << "Failed to launch Mojo application for " << name; -} - -void LaunchAppInUtilityProcess(const std::string& app_name, - const base::string16& process_name, - bool use_sandbox, - shell::mojom::ServiceRequest request) { - mojom::ProcessControlPtr process_control; - mojom::ProcessControlRequest process_request = - mojo::GetProxy(&process_control); +void StartServiceInUtilityProcess(const std::string& service_name, + const base::string16& process_name, + bool use_sandbox, + shell::mojom::ServiceRequest request) { + shell::mojom::ServiceFactoryPtr service_factory; BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(&StartUtilityProcessOnIOThread, - base::Passed(&process_request), + base::Passed(GetProxy(&service_factory)), process_name, use_sandbox)); - process_control->LoadApplication(app_name, std::move(request), - base::Bind(&OnApplicationLoaded, app_name)); + service_factory->CreateService(std::move(request), service_name); } #if (ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) -// Request mojom::ProcessControl from GPU process host. Must be called on IO -// thread. -void RequestGpuProcessControl( - mojo::InterfaceRequest<mojom::ProcessControl> request) { +// Request shell::mojom::ServiceFactory from GPU process host. Must be called on +// IO thread. +void RequestGpuServiceFactory(shell::mojom::ServiceFactoryRequest request) { BrowserChildProcessHostDelegate* process_host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED); if (!process_host) { @@ -102,60 +84,50 @@ // TODO(xhwang): It's possible that |process_host| is non-null, but the actual // process is dead. In that case, |request| will be dropped and application - // load requests through mojom::ProcessControl will also fail. Make sure we - // handle + // load requests through ServiceFactory will also fail. Make sure we handle // these cases correctly. process_host->GetRemoteInterfaces()->GetInterface(std::move(request)); } -void LaunchAppInGpuProcess(const std::string& app_name, - shell::mojom::ServiceRequest request) { - mojom::ProcessControlPtr process_control; - mojom::ProcessControlRequest process_request = - mojo::GetProxy(&process_control); +void StartServiceInGpuProcess(const std::string& service_name, + shell::mojom::ServiceRequest request) { + shell::mojom::ServiceFactoryPtr service_factory; BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, - base::Bind(&RequestGpuProcessControl, base::Passed(&process_request))); - process_control->LoadApplication(app_name, std::move(request), - base::Bind(&OnApplicationLoaded, app_name)); + base::Bind(&RequestGpuServiceFactory, + base::Passed(GetProxy(&service_factory)))); + service_factory->CreateService(std::move(request), service_name); } #endif // ENABLE_MOJO_MEDIA_IN_GPU_PROCESS -} // namespace - // A ManifestProvider which resolves application names to builtin manifest // resources for the catalog service to consume. -class MojoShellContext::BuiltinManifestProvider - : public catalog::ManifestProvider { +class BuiltinManifestProvider : public catalog::ManifestProvider { public: BuiltinManifestProvider() {} ~BuiltinManifestProvider() override {} - void AddManifestResource(const std::string& name, int resource_id) { - auto result = manifest_resources_.insert( - std::make_pair(name, resource_id)); - DCHECK(result.second); - } - void AddManifests(std::unique_ptr< ContentBrowserClient::MojoApplicationManifestMap> manifests) { + DCHECK(!manifests_); manifests_ = std::move(manifests); } + void AddManifestResource(const std::string& name, int resource_id) { + std::string contents = GetContentClient()->GetDataResource( + resource_id, ui::ScaleFactor::SCALE_FACTOR_NONE).as_string(); + DCHECK(!contents.empty()); + + DCHECK(manifests_); + auto result = manifests_->insert(std::make_pair(name, contents)); + DCHECK(result.second) << "Duplicate manifest entry: " << name; + } + private: // catalog::ManifestProvider: bool GetApplicationManifest(const base::StringPiece& name, std::string* manifest_contents) override { - auto it = manifest_resources_.find(name.as_string()); - if (it != manifest_resources_.end()) { - *manifest_contents = - GetContentClient() - ->GetDataResource(it->second, ui::ScaleFactor::SCALE_FACTOR_NONE) - .as_string(); - DCHECK(!manifest_contents->empty()); - return true; - } auto manifest_it = manifests_->find(name.as_string()); if (manifest_it != manifests_->end()) { *manifest_contents = manifest_it->second; @@ -165,53 +137,110 @@ return false; } - std::unordered_map<std::string, int> manifest_resources_; std::unique_ptr<ContentBrowserClient::MojoApplicationManifestMap> manifests_; DISALLOW_COPY_AND_ASSIGN(BuiltinManifestProvider); }; +} // namespace + +// State which lives on the IO thread and drives the ServiceManager. +class MojoShellContext::InProcessServiceManagerContext + : public base::RefCountedThreadSafe<InProcessServiceManagerContext> { + public: + InProcessServiceManagerContext() {} + + shell::mojom::ServiceRequest Start( + std::unique_ptr<BuiltinManifestProvider> manifest_provider) { + shell::mojom::ServicePtr embedder_service_proxy; + shell::mojom::ServiceRequest embedder_service_request = + mojo::GetProxy(&embedder_service_proxy); + shell::mojom::ServicePtrInfo embedder_service_proxy_info = + embedder_service_proxy.PassInterface(); + BrowserThread::GetTaskRunnerForThread(BrowserThread::IO)->PostTask( + FROM_HERE, + base::Bind(&InProcessServiceManagerContext::StartOnIOThread, this, + base::Passed(&manifest_provider), + base::Passed(&embedder_service_proxy_info))); + return embedder_service_request; + } + + void ShutDown() { + BrowserThread::GetTaskRunnerForThread(BrowserThread::IO)->PostTask( + FROM_HERE, + base::Bind(&InProcessServiceManagerContext::ShutDownOnIOThread, this)); + } + + private: + friend class base::RefCountedThreadSafe<InProcessServiceManagerContext>; + + ~InProcessServiceManagerContext() {} + + void StartOnIOThread( + std::unique_ptr<BuiltinManifestProvider> manifest_provider, + shell::mojom::ServicePtrInfo embedder_service_proxy_info) { + manifest_provider_ = std::move(manifest_provider); + + scoped_refptr<base::SingleThreadTaskRunner> file_task_runner = + BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE); + std::unique_ptr<shell::NativeRunnerFactory> native_runner_factory( + new shell::InProcessNativeRunnerFactory( + BrowserThread::GetBlockingPool())); + catalog_.reset(new catalog::Catalog( + file_task_runner.get(), nullptr, manifest_provider_.get())); + service_manager_.reset(new shell::ServiceManager( + std::move(native_runner_factory), catalog_->TakeService())); + + shell::mojom::ServiceRequest request = + service_manager_->StartEmbedderService(kBrowserMojoApplicationName); + mojo::FuseInterface( + std::move(request), std::move(embedder_service_proxy_info)); + } + + void ShutDownOnIOThread() { + service_manager_.reset(); + catalog_.reset(); + manifest_provider_.reset(); + } + + std::unique_ptr<BuiltinManifestProvider> manifest_provider_; + std::unique_ptr<catalog::Catalog> catalog_; + std::unique_ptr<shell::ServiceManager> service_manager_; + + DISALLOW_COPY_AND_ASSIGN(InProcessServiceManagerContext); +}; + + MojoShellContext::MojoShellContext() { - scoped_refptr<base::SingleThreadTaskRunner> file_task_runner = - BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE); - std::unique_ptr<shell::NativeRunnerFactory> native_runner_factory( - new shell::InProcessNativeRunnerFactory( - BrowserThread::GetBlockingPool())); - - // Allow the embedder to register additional Mojo application manifests - // beyond the default ones below. - std::unique_ptr<ContentBrowserClient::MojoApplicationManifestMap> manifests( - new ContentBrowserClient::MojoApplicationManifestMap); - GetContentClient()->browser()->RegisterMojoApplicationManifests( - manifests.get()); - - manifest_provider_.reset(new BuiltinManifestProvider); - manifest_provider_->AddManifests(std::move(manifests)); - manifest_provider_->AddManifestResource(kBrowserMojoApplicationName, - IDR_MOJO_CONTENT_BROWSER_MANIFEST); - manifest_provider_->AddManifestResource(kGpuMojoApplicationName, - IDR_MOJO_CONTENT_GPU_MANIFEST); - manifest_provider_->AddManifestResource(kRendererMojoApplicationName, - IDR_MOJO_CONTENT_RENDERER_MANIFEST); - manifest_provider_->AddManifestResource(kUtilityMojoApplicationName, - IDR_MOJO_CONTENT_UTILITY_MANIFEST); - manifest_provider_->AddManifestResource("mojo:catalog", - IDR_MOJO_CATALOG_MANIFEST); - manifest_provider_->AddManifestResource(user_service::kUserServiceName, - IDR_MOJO_PROFILE_MANIFEST); - - catalog_.reset(new catalog::Catalog(file_task_runner.get(), nullptr, - manifest_provider_.get())); - shell::mojom::ServiceRequest request; if (shell::ShellIsRemote()) { mojo::edk::SetParentPipeHandleFromCommandLine(); request = shell::GetServiceRequestFromCommandLine(); } else { - service_manager_.reset(new shell::ServiceManager( - std::move(native_runner_factory), catalog_->TakeService())); - request = - service_manager_->StartEmbedderService(kBrowserMojoApplicationName); + // Allow the embedder to register additional Mojo application manifests + // beyond the default ones below. + std::unique_ptr<ContentBrowserClient::MojoApplicationManifestMap> manifests( + new ContentBrowserClient::MojoApplicationManifestMap); + GetContentClient()->browser()->RegisterMojoApplicationManifests( + manifests.get()); + std::unique_ptr<BuiltinManifestProvider> manifest_provider = + base::MakeUnique<BuiltinManifestProvider>(); + manifest_provider->AddManifests(std::move(manifests)); + manifest_provider->AddManifestResource(kBrowserMojoApplicationName, + IDR_MOJO_CONTENT_BROWSER_MANIFEST); + manifest_provider->AddManifestResource(kGpuMojoApplicationName, + IDR_MOJO_CONTENT_GPU_MANIFEST); + manifest_provider->AddManifestResource(kRendererMojoApplicationName, + IDR_MOJO_CONTENT_RENDERER_MANIFEST); + manifest_provider->AddManifestResource(kUtilityMojoApplicationName, + IDR_MOJO_CONTENT_UTILITY_MANIFEST); + manifest_provider->AddManifestResource("mojo:catalog", + IDR_MOJO_CATALOG_MANIFEST); + manifest_provider->AddManifestResource(user_service::kUserServiceName, + IDR_MOJO_PROFILE_MANIFEST); + + in_process_context_ = new InProcessServiceManagerContext; + request = in_process_context_->Start(std::move(manifest_provider)); } MojoShellConnection::SetForProcess(MojoShellConnection::Create( std::move(request), @@ -238,7 +267,7 @@ for (const auto& app : sandboxed_apps) { MojoShellConnection::GetForProcess()->AddServiceRequestHandler( app.first, - base::Bind(&LaunchAppInUtilityProcess, app.first, app.second, + base::Bind(&StartServiceInUtilityProcess, app.first, app.second, true /* use_sandbox */)); } @@ -249,13 +278,13 @@ for (const auto& app : unsandboxed_apps) { MojoShellConnection::GetForProcess()->AddServiceRequestHandler( app.first, - base::Bind(&LaunchAppInUtilityProcess, app.first, app.second, + base::Bind(&StartServiceInUtilityProcess, app.first, app.second, false /* use_sandbox */)); } #if (ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) MojoShellConnection::GetForProcess()->AddServiceRequestHandler( - "mojo:media", base::Bind(&LaunchAppInGpuProcess, "mojo:media")); + "mojo:media", base::Bind(&StartServiceInGpuProcess, "mojo:media")); #endif } @@ -264,7 +293,8 @@ MojoShellConnection::DestroyForProcess(); BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(&DestroyConnectorOnIOThread)); - catalog_.reset(); + if (in_process_context_) + in_process_context_->ShutDown(); } // static
diff --git a/content/browser/mojo/mojo_shell_context.h b/content/browser/mojo/mojo_shell_context.h index 8602773..8885270 100644 --- a/content/browser/mojo/mojo_shell_context.h +++ b/content/browser/mojo/mojo_shell_context.h
@@ -5,23 +5,19 @@ #ifndef CONTENT_BROWSER_MOJO_MOJO_SHELL_CONTEXT_H_ #define CONTENT_BROWSER_MOJO_MOJO_SHELL_CONTEXT_H_ -#include <map> -#include <memory> - -#include "base/callback_forward.h" -#include "base/compiler_specific.h" #include "base/macros.h" +#include "base/memory/ref_counted.h" #include "content/common/content_export.h" -#include "services/shell/service_manager.h" -namespace catalog { -class Catalog; +namespace shell { +class Connector; } namespace content { -// MojoShellContext hosts the browser's ApplicationManager, coordinating -// app registration and interconnection. +// MojoShellContext manages the browser's connection to the ServiceManager, +// hosting a new in-process ServiceManager if the browser was not launched from +// an external one. class CONTENT_EXPORT MojoShellContext { public: MojoShellContext(); @@ -31,11 +27,9 @@ static shell::Connector* GetConnectorForIOThread(); private: - class BuiltinManifestProvider; + class InProcessServiceManagerContext; - std::unique_ptr<BuiltinManifestProvider> manifest_provider_; - std::unique_ptr<catalog::Catalog> catalog_; - std::unique_ptr<shell::ServiceManager> service_manager_; + scoped_refptr<InProcessServiceManagerContext> in_process_context_; DISALLOW_COPY_AND_ASSIGN(MojoShellContext); };
diff --git a/content/browser/notifications/notification_database.cc b/content/browser/notifications/notification_database.cc index 1dc687a..e7ac09b 100644 --- a/content/browser/notifications/notification_database.cc +++ b/content/browser/notifications/notification_database.cc
@@ -236,9 +236,11 @@ NotificationDatabase::Status NotificationDatabase::DeleteAllNotificationDataForOrigin( const GURL& origin, + const std::string& tag, std::set<int64_t>* deleted_notification_set) { - return DeleteAllNotificationDataInternal( - origin, kInvalidServiceWorkerRegistrationId, deleted_notification_set); + return DeleteAllNotificationDataInternal(origin, tag, + kInvalidServiceWorkerRegistrationId, + deleted_notification_set); } NotificationDatabase::Status @@ -246,8 +248,9 @@ const GURL& origin, int64_t service_worker_registration_id, std::set<int64_t>* deleted_notification_set) { - return DeleteAllNotificationDataInternal( - origin, service_worker_registration_id, deleted_notification_set); + return DeleteAllNotificationDataInternal(origin, "" /* tag */, + service_worker_registration_id, + deleted_notification_set); } NotificationDatabase::Status NotificationDatabase::Destroy() { @@ -328,6 +331,7 @@ NotificationDatabase::Status NotificationDatabase::DeleteAllNotificationDataInternal( const GURL& origin, + const std::string& tag, int64_t service_worker_registration_id, std::set<int64_t>* deleted_notification_set) { DCHECK(sequence_checker_.CalledOnValidSequence()); @@ -335,6 +339,9 @@ DCHECK(origin.is_valid()); const std::string prefix = CreateDataPrefix(origin); + const bool should_deserialize = + service_worker_registration_id != kInvalidServiceWorkerRegistrationId || + !tag.empty(); leveldb::Slice prefix_slice(prefix); leveldb::WriteBatch batch; @@ -346,14 +353,21 @@ if (!iter->key().starts_with(prefix_slice)) break; - if (service_worker_registration_id != kInvalidServiceWorkerRegistrationId) { + if (should_deserialize) { Status status = DeserializedNotificationData(iter->value().ToString(), ¬ification_database_data); if (status != STATUS_OK) return status; - if (notification_database_data.service_worker_registration_id != - service_worker_registration_id) { + if (!tag.empty() && + notification_database_data.notification_data.tag != tag) { + continue; + } + + if (service_worker_registration_id != + kInvalidServiceWorkerRegistrationId && + notification_database_data.service_worker_registration_id != + service_worker_registration_id) { continue; } }
diff --git a/content/browser/notifications/notification_database.h b/content/browser/notifications/notification_database.h index 5cc9ea93..c08dbfe 100644 --- a/content/browser/notifications/notification_database.h +++ b/content/browser/notifications/notification_database.h
@@ -119,11 +119,13 @@ // failure if the to-be-deleted notification does not exist. Status DeleteNotificationData(int64_t notification_id, const GURL& origin); - // Deletes all data associated with |origin| from the database, and appends - // the deleted notification ids to |deleted_notification_set|. Returns the - // status code of the deletion operation. + // Deletes all data associated with |origin| from the database, optionally + // filtered by the |tag|, and appends the deleted notification ids to + // |deleted_notification_set|. Returns the status code of the deletion + // operation. Status DeleteAllNotificationDataForOrigin( const GURL& origin, + const std::string& tag, std::set<int64_t>* deleted_notification_set); // Deletes all data associated with the |service_worker_registration_id| @@ -167,10 +169,11 @@ // Deletes all notification data with the given constraints. |origin| must // always be set - use Destroy() when the goal is to empty the database. If // |service_worker_registration_id| is invalid, all notification data for the - // |origin| will be deleted. + // |origin| will be deleted, optionally filtered by the |tag| when non-empty. // All deleted notification ids will be written to |deleted_notification_set|. Status DeleteAllNotificationDataInternal( const GURL& origin, + const std::string& tag, int64_t service_worker_registration_id, std::set<int64_t>* deleted_notification_set);
diff --git a/content/browser/notifications/notification_database_unittest.cc b/content/browser/notifications/notification_database_unittest.cc index c08114c..f02e0679 100644 --- a/content/browser/notifications/notification_database_unittest.cc +++ b/content/browser/notifications/notification_database_unittest.cc
@@ -24,15 +24,18 @@ const struct { const char* origin; + const char* tag; int64_t service_worker_registration_id; } kExampleNotificationData[] = { - {"https://example.com", 0}, - {"https://example.com", kExampleServiceWorkerRegistrationId}, - {"https://example.com", kExampleServiceWorkerRegistrationId}, - {"https://example.com", kExampleServiceWorkerRegistrationId + 1}, - {"https://chrome.com", 0}, - {"https://chrome.com", 0}, - {"https://chrome.com", kExampleServiceWorkerRegistrationId}}; + {"https://example.com", "" /* tag */, 0}, + {"https://example.com", "" /* tag */, kExampleServiceWorkerRegistrationId}, + {"https://example.com", "" /* tag */, kExampleServiceWorkerRegistrationId}, + {"https://example.com", "" /* tag */, + kExampleServiceWorkerRegistrationId + 1}, + {"https://chrome.com", "" /* tag */, 0}, + {"https://chrome.com", "" /* tag */, 0}, + {"https://chrome.com", "" /* tag */, kExampleServiceWorkerRegistrationId}, + {"https://chrome.com", "foo" /* tag */, 0}}; class NotificationDatabaseTest : public ::testing::Test { protected: @@ -51,12 +54,14 @@ // will be stored in |notification_id|. void CreateAndWriteNotification(NotificationDatabase* database, const GURL& origin, + const std::string& tag, int64_t service_worker_registration_id, int64_t* notification_id) { NotificationDatabaseData database_data; database_data.origin = origin; database_data.service_worker_registration_id = service_worker_registration_id; + database_data.notification_data.tag = tag; ASSERT_EQ(NotificationDatabase::STATUS_OK, database->WriteNotificationData(origin, database_data, @@ -70,6 +75,7 @@ for (size_t i = 0; i < arraysize(kExampleNotificationData); ++i) { ASSERT_NO_FATAL_FAILURE(CreateAndWriteNotification( database, GURL(kExampleNotificationData[i].origin), + kExampleNotificationData[i].tag, kExampleNotificationData[i].service_worker_registration_id, ¬ification_id)); } @@ -180,12 +186,14 @@ // Verify that getting two ids on the same database instance results in // incrementing values. Notification ids will start at 1. - ASSERT_NO_FATAL_FAILURE(CreateAndWriteNotification( - database.get(), origin, 0 /* sw_registration_id */, ¬ification_id)); + ASSERT_NO_FATAL_FAILURE( + CreateAndWriteNotification(database.get(), origin, "" /* tag */, + 0 /* sw_registration_id */, ¬ification_id)); EXPECT_EQ(notification_id, 1); - ASSERT_NO_FATAL_FAILURE(CreateAndWriteNotification( - database.get(), origin, 0 /* sw_registration_id */, ¬ification_id)); + ASSERT_NO_FATAL_FAILURE( + CreateAndWriteNotification(database.get(), origin, "" /* tag */, + 0 /* sw_registration_id */, ¬ification_id)); EXPECT_EQ(notification_id, 2); database.reset(CreateDatabaseOnFileSystem(database_dir.path())); @@ -194,8 +202,9 @@ // Verify that the next notification id was stored in the database, and // continues where we expect it to be, even after closing and opening it. - ASSERT_NO_FATAL_FAILURE(CreateAndWriteNotification( - database.get(), origin, 0 /* sw_registration_id */, ¬ification_id)); + ASSERT_NO_FATAL_FAILURE( + CreateAndWriteNotification(database.get(), origin, "" /* tag */, + 0 /* sw_registration_id */, ¬ification_id)); EXPECT_EQ(notification_id, 3); } @@ -367,7 +376,8 @@ // notification id (it is the responsibility of the user to increment this). for (int i = 1; i <= 10; ++i) { ASSERT_NO_FATAL_FAILURE(CreateAndWriteNotification( - database.get(), origin, i /* sw_registration_id */, ¬ification_id)); + database.get(), origin, "" /* tag */, i /* sw_registration_id */, + ¬ification_id)); EXPECT_EQ(notification_id, i); } @@ -521,7 +531,7 @@ std::set<int64_t> deleted_notification_set; ASSERT_EQ(NotificationDatabase::STATUS_OK, database->DeleteAllNotificationDataForOrigin( - origin, &deleted_notification_set)); + origin, "" /* tag */, &deleted_notification_set)); EXPECT_EQ(4u, deleted_notification_set.size()); @@ -532,6 +542,62 @@ EXPECT_EQ(0u, notifications.size()); } +TEST_F(NotificationDatabaseTest, DeleteAllNotificationDataForOriginWithTag) { + std::unique_ptr<NotificationDatabase> database(CreateDatabaseInMemory()); + ASSERT_EQ(NotificationDatabase::STATUS_OK, + database->Open(true /* create_if_missing */)); + + ASSERT_NO_FATAL_FAILURE(PopulateDatabaseWithExampleData(database.get())); + + GURL origin("https://chrome.com"); + + std::vector<NotificationDatabaseData> notifications; + ASSERT_EQ(NotificationDatabase::STATUS_OK, + database->ReadAllNotificationDataForOrigin(origin, ¬ifications)); + + const std::string& tag = "foo"; + + size_t notifications_with_tag = 0; + size_t notifications_without_tag = 0; + + for (const auto& database_data : notifications) { + if (database_data.notification_data.tag == tag) + ++notifications_with_tag; + else + ++notifications_without_tag; + } + + ASSERT_GT(notifications_with_tag, 0u); + ASSERT_GT(notifications_without_tag, 0u); + + std::set<int64_t> deleted_notification_set; + ASSERT_EQ(NotificationDatabase::STATUS_OK, + database->DeleteAllNotificationDataForOrigin( + origin, "foo" /* tag */, &deleted_notification_set)); + + EXPECT_EQ(notifications_with_tag, deleted_notification_set.size()); + + std::vector<NotificationDatabaseData> updated_notifications; + ASSERT_EQ(NotificationDatabase::STATUS_OK, + database->ReadAllNotificationDataForOrigin(origin, + &updated_notifications)); + + EXPECT_EQ(notifications_without_tag, updated_notifications.size()); + + size_t updated_notifications_with_tag = 0; + size_t updated_notifications_without_tag = 0; + + for (const auto& database_data : updated_notifications) { + if (database_data.notification_data.tag == tag) + ++updated_notifications_with_tag; + else + ++updated_notifications_without_tag; + } + + EXPECT_EQ(0u, updated_notifications_with_tag); + EXPECT_EQ(notifications_without_tag, updated_notifications_without_tag); +} + TEST_F(NotificationDatabaseTest, DeleteAllNotificationDataForOriginEmpty) { std::unique_ptr<NotificationDatabase> database(CreateDatabaseInMemory()); ASSERT_EQ(NotificationDatabase::STATUS_OK, @@ -542,7 +608,7 @@ std::set<int64_t> deleted_notification_set; ASSERT_EQ(NotificationDatabase::STATUS_OK, database->DeleteAllNotificationDataForOrigin( - origin, &deleted_notification_set)); + origin, "" /* tag */, &deleted_notification_set)); EXPECT_EQ(0u, deleted_notification_set.size()); }
diff --git a/content/browser/notifications/platform_notification_context_impl.cc b/content/browser/notifications/platform_notification_context_impl.cc index 8ee48789..f986fa8 100644 --- a/content/browser/notifications/platform_notification_context_impl.cc +++ b/content/browser/notifications/platform_notification_context_impl.cc
@@ -239,6 +239,31 @@ const WriteResultCallback& callback) { DCHECK(task_runner_->RunsTasksOnCurrentThread()); + // Eagerly delete data for replaced notifications from the database. + if (!database_data.notification_data.tag.empty()) { + std::set<int64_t> deleted_notification_set; + NotificationDatabase::Status delete_status = + database_->DeleteAllNotificationDataForOrigin( + origin, database_data.notification_data.tag, + &deleted_notification_set); + + UMA_HISTOGRAM_ENUMERATION("Notifications.Database.DeleteBeforeWriteResult", + delete_status, + NotificationDatabase::STATUS_COUNT); + + // Unless the database was corrupted following this change, there is no + // reason to bail out here in event of failure because the notification + // display logic will handle notification replacement for the user. + if (delete_status == NotificationDatabase::STATUS_ERROR_CORRUPTED) { + DestroyDatabase(); + + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::Bind(callback, false /* success */, 0 /* notification_id */)); + return; + } + } + int64_t notification_id = 0; NotificationDatabase::Status status = database_->WriteNotificationData(origin, database_data, ¬ification_id);
diff --git a/content/browser/notifications/platform_notification_context_unittest.cc b/content/browser/notifications/platform_notification_context_unittest.cc index 3616794..a72fd38 100644 --- a/content/browser/notifications/platform_notification_context_unittest.cc +++ b/content/browser/notifications/platform_notification_context_unittest.cc
@@ -8,6 +8,7 @@ #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/run_loop.h" +#include "base/strings/utf_string_conversions.h" #include "base/threading/thread_task_runner_handle.h" #include "content/browser/notifications/platform_notification_context_impl.h" #include "content/browser/service_worker/embedded_worker_test_helper.h" @@ -169,6 +170,69 @@ EXPECT_EQ(notification_database_data.origin, read_database_data.origin); } +TEST_F(PlatformNotificationContextTest, WriteReadReplacedNotification) { + scoped_refptr<PlatformNotificationContextImpl> context = + CreatePlatformNotificationContext(); + + const GURL origin("https://example.com"); + const std::string tag = "foo"; + + NotificationDatabaseData notification_database_data; + notification_database_data.service_worker_registration_id = + kFakeServiceWorkerRegistrationId; + notification_database_data.origin = origin; + notification_database_data.notification_data.title = + base::ASCIIToUTF16("First"); + notification_database_data.notification_data.tag = tag; + + // Write the first notification with the given |tag|. + context->WriteNotificationData( + origin, notification_database_data, + base::Bind(&PlatformNotificationContextTest::DidWriteNotificationData, + base::Unretained(this))); + + base::RunLoop().RunUntilIdle(); + + int64_t read_notification_id = notification_id(); + + // The write operation should have succeeded with a notification id. + ASSERT_TRUE(success()); + EXPECT_GT(read_notification_id, 0); + + notification_database_data.notification_data.title = + base::ASCIIToUTF16("Second"); + + // Write the second notification with the given |tag|. + context->WriteNotificationData( + origin, notification_database_data, + base::Bind(&PlatformNotificationContextTest::DidWriteNotificationData, + base::Unretained(this))); + + base::RunLoop().RunUntilIdle(); + + ASSERT_TRUE(success()); + ASSERT_NE(notification_id(), read_notification_id); + ASSERT_GT(notification_id(), 0); + + // Reading the notifications should only yield the second, replaced one. + std::vector<NotificationDatabaseData> notification_database_datas; + context->ReadAllNotificationDataForServiceWorkerRegistration( + origin, kFakeServiceWorkerRegistrationId, + base::Bind(&PlatformNotificationContextTest::DidReadAllNotificationDatas, + base::Unretained(this), ¬ification_database_datas)); + + base::RunLoop().RunUntilIdle(); + + // The read operation should have succeeded, with the right notification. + ASSERT_TRUE(success()); + + ASSERT_EQ(1u, notification_database_datas.size()); + + EXPECT_EQ(tag, notification_database_datas[0].notification_data.tag); + EXPECT_EQ(base::ASCIIToUTF16("Second"), + notification_database_datas[0].notification_data.title); +} + TEST_F(PlatformNotificationContextTest, DeleteInvalidNotification) { scoped_refptr<PlatformNotificationContextImpl> context = CreatePlatformNotificationContext();
diff --git a/content/browser/renderer_host/dwrite_font_proxy_message_filter_win.cc b/content/browser/renderer_host/dwrite_font_proxy_message_filter_win.cc index d3c2568c..0e9907a0 100644 --- a/content/browser/renderer_host/dwrite_font_proxy_message_filter_win.cc +++ b/content/browser/renderer_host/dwrite_font_proxy_message_filter_win.cc
@@ -54,6 +54,14 @@ LAST_RESORT_FONT_GET_FAMILY_FAILED = 2, ERROR_NO_COLLECTION = 3, MAP_CHARACTERS_NO_FAMILY = 4, + ADD_FILES_FOR_FONT_CREATE_FACE_FAILED = 5, + ADD_FILES_FOR_FONT_GET_FILE_COUNT_FAILED = 6, + ADD_FILES_FOR_FONT_GET_FILES_FAILED = 7, + ADD_FILES_FOR_FONT_GET_LOADER_FAILED = 8, + ADD_FILES_FOR_FONT_QI_FAILED = 9, + ADD_LOCAL_FILE_GET_REFERENCE_KEY_FAILED = 10, + ADD_LOCAL_FILE_GET_PATH_LENGTH_FAILED = 11, + ADD_LOCAL_FILE_GET_PATH_FAILED = 12, MESSAGE_FILTER_ERROR_MAX_VALUE }; @@ -454,12 +462,14 @@ HRESULT hr; hr = font->CreateFontFace(&font_face); if (FAILED(hr)) { + LogMessageFilterError(ADD_FILES_FOR_FONT_CREATE_FACE_FAILED); return false; } UINT32 file_count; hr = font_face->GetFiles(&file_count, nullptr); if (FAILED(hr)) { + LogMessageFilterError(ADD_FILES_FOR_FONT_GET_FILE_COUNT_FAILED); return false; } @@ -468,6 +478,7 @@ hr = font_face->GetFiles( &file_count, reinterpret_cast<IDWriteFontFile**>(font_files.data())); if (FAILED(hr)) { + LogMessageFilterError(ADD_FILES_FOR_FONT_GET_FILES_FAILED); return false; } @@ -475,6 +486,7 @@ mswr::ComPtr<IDWriteFontFileLoader> loader; hr = font_files[file_index]->GetLoader(&loader); if (FAILED(hr)) { + LogMessageFilterError(ADD_FILES_FOR_FONT_GET_LOADER_FAILED); return false; } @@ -496,6 +508,7 @@ return false; } else if (FAILED(hr)) { + LogMessageFilterError(ADD_FILES_FOR_FONT_QI_FAILED); return false; } @@ -517,12 +530,14 @@ UINT32 key_size; hr = font_file->GetReferenceKey(&key, &key_size); if (FAILED(hr)) { + LogMessageFilterError(ADD_LOCAL_FILE_GET_REFERENCE_KEY_FAILED); return false; } UINT32 path_length = 0; hr = local_loader->GetFilePathLengthFromKey(key, key_size, &path_length); if (FAILED(hr)) { + LogMessageFilterError(ADD_LOCAL_FILE_GET_PATH_LENGTH_FAILED); return false; } ++path_length; // Reserve space for the null terminator. @@ -531,6 +546,7 @@ hr = local_loader->GetFilePathFromKey(key, key_size, file_path_chars.data(), path_length); if (FAILED(hr)) { + LogMessageFilterError(ADD_LOCAL_FILE_GET_PATH_FAILED); return false; }
diff --git a/content/browser/renderer_host/ime_adapter_android.cc b/content/browser/renderer_host/ime_adapter_android.cc index 47a060f..a712e54 100644 --- a/content/browser/renderer_host/ime_adapter_android.cc +++ b/content/browser/renderer_host/ime_adapter_android.cc
@@ -329,6 +329,18 @@ return true; } +void ImeAdapterAndroid::RequestCursorUpdate( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj, + bool immediate_request, + bool monitor_request) { + RenderWidgetHostImpl* rwhi = GetRenderWidgetHostImpl(); + if (!rwhi) + return; + rwhi->Send(new InputMsg_RequestCompositionUpdate( + rwhi->GetRoutingID(), immediate_request, monitor_request)); +} + bool ImeAdapterAndroid::IsImeThreadEnabled( JNIEnv* env, const base::android::JavaParamRef<jobject>&) {
diff --git a/content/browser/renderer_host/ime_adapter_android.h b/content/browser/renderer_host/ime_adapter_android.h index 1f559c6..ea88d543 100644 --- a/content/browser/renderer_host/ime_adapter_android.h +++ b/content/browser/renderer_host/ime_adapter_android.h
@@ -78,6 +78,8 @@ int before, int after); void ResetImeAdapter(JNIEnv*, const base::android::JavaParamRef<jobject>&); + void RequestCursorUpdate(JNIEnv*, const base::android::JavaParamRef<jobject>&, + bool immediateRequest, bool monitorRequest); bool RequestTextInputStateUpdate(JNIEnv*, const base::android::JavaParamRef<jobject>&); bool IsImeThreadEnabled(JNIEnv*, const base::android::JavaParamRef<jobject>&);
diff --git a/content/browser/renderer_host/input/web_input_event_builders_mac.h b/content/browser/renderer_host/input/web_input_event_builders_mac.h index 649cde5..dbab1d8 100644 --- a/content/browser/renderer_host/input/web_input_event_builders_mac.h +++ b/content/browser/renderer_host/input/web_input_event_builders_mac.h
@@ -26,9 +26,7 @@ class CONTENT_EXPORT WebMouseWheelEventBuilder { public: static blink::WebMouseWheelEvent Build(NSEvent* event, - NSView* view, - bool can_rubberband_left, - bool can_rubberband_right); + NSView* view); }; class CONTENT_EXPORT WebGestureEventBuilder {
diff --git a/content/browser/renderer_host/input/web_input_event_builders_mac.mm b/content/browser/renderer_host/input/web_input_event_builders_mac.mm index 4b11acbe..b0bfa20 100644 --- a/content/browser/renderer_host/input/web_input_event_builders_mac.mm +++ b/content/browser/renderer_host/input/web_input_event_builders_mac.mm
@@ -419,9 +419,7 @@ blink::WebMouseWheelEvent WebMouseWheelEventBuilder::Build( NSEvent* event, - NSView* view, - bool can_rubberband_left, - bool can_rubberband_right) { + NSView* view) { blink::WebMouseWheelEvent result; result.type = blink::WebInputEvent::MouseWheel; @@ -431,9 +429,6 @@ SetWebEventLocationFromEventInView(&result, event, view); - result.canRubberbandLeft = can_rubberband_left; - result.canRubberbandRight = can_rubberband_right; - // Of Mice and Men // --------------- //
diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc index 2433951..0d549c7 100644 --- a/content/browser/renderer_host/media/media_stream_manager.cc +++ b/content/browser/renderer_host/media/media_stream_manager.cc
@@ -67,7 +67,7 @@ #endif #if defined(OS_MACOSX) -#include "media/capture/device_monitor_mac.h" +#include "media/device_monitors/device_monitor_mac.h" #endif namespace content {
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index 9919ef6..0ce8b224 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -47,7 +47,6 @@ #include "cc/output/buffer_to_texture_target_map.h" #include "components/memory_coordinator/browser/memory_coordinator.h" #include "components/memory_coordinator/common/memory_coordinator_features.h" -#include "components/scheduler/common/scheduler_switches.h" #include "components/tracing/common/tracing_switches.h" #include "content/browser/appcache/appcache_dispatcher_host.h" #include "content/browser/appcache/chrome_appcache_service.h" @@ -165,6 +164,7 @@ #include "gpu/command_buffer/service/gpu_switches.h" #include "ipc/attachment_broker.h" #include "ipc/attachment_broker_privileged.h" +#include "ipc/ipc.mojom.h" #include "ipc/ipc_channel.h" #include "ipc/ipc_channel_mojo.h" #include "ipc/ipc_logging.h" @@ -711,6 +711,20 @@ g_renderer_main_thread_factory = create; } +// static +// TODO(alokp): Remove after collecting crash data. +// Temporary checks to verify that all shared workers are terminated. +// It is suspected that shared workers prevent render process hosts +// from shutting down: crbug.com/608049 +void RenderProcessHostImpl::CheckAllWorkersTerminated() { + iterator iter(AllHostsIterator()); + while (!iter.IsAtEnd()) { + RenderProcessHostImpl* host = + static_cast<RenderProcessHostImpl*>(iter.GetCurrentValue()); + CHECK_EQ(0, host->worker_ref_count_); + } +} + RenderProcessHostImpl::~RenderProcessHostImpl() { #ifndef NDEBUG DCHECK(is_self_deleted_) @@ -820,8 +834,7 @@ g_renderer_main_thread_factory(InProcessChildThreadParams( channel_id, BrowserThread::GetTaskRunnerForThread(BrowserThread::IO), - mojo_channel_token_, - mojo_child_connection_->service_token()))); + std::string(), mojo_child_connection_->service_token()))); base::Thread::Options options; #if defined(OS_WIN) && !defined(OS_MACOSX) @@ -881,12 +894,11 @@ const std::string& channel_id) { scoped_refptr<base::SingleThreadTaskRunner> runner = BrowserThread::GetTaskRunnerForThread(BrowserThread::IO); - mojo_channel_token_ = mojo::edk::GenerateRandomToken(); - mojo::ScopedMessagePipeHandle handle = - mojo::edk::CreateParentMessagePipe(mojo_channel_token_, child_token_); - + IPC::mojom::ChannelBootstrapPtr bootstrap; + GetRemoteInterfaces()->GetInterface(&bootstrap); std::unique_ptr<IPC::ChannelFactory> channel_factory = - IPC::ChannelMojo::CreateServerFactory(std::move(handle), runner); + IPC::ChannelMojo::CreateServerFactory( + bootstrap.PassInterface().PassHandle(), runner); // Do NOT expand ifdef or run time condition checks here! Synchronous // IPCs from browser process are banned. It is only narrowly allowed @@ -963,6 +975,7 @@ blob_storage_context.get(), storage_partition_impl_->GetFileSystemContext(), storage_partition_impl_->GetServiceWorkerContext(), + storage_partition_impl_->GetHostZoomLevelContext(), get_contexts_callback); AddFilter(resource_message_filter); @@ -1421,10 +1434,6 @@ AppendCompositorCommandLineFlags(command_line); - if (!mojo_channel_token_.empty()) { - command_line->AppendSwitchASCII(switches::kMojoChannelToken, - mojo_channel_token_); - } command_line->AppendSwitchASCII(switches::kMojoApplicationChannelToken, mojo_child_connection_->service_token()); } @@ -1600,8 +1609,6 @@ cc::switches::kTopControlsHideThreshold, cc::switches::kTopControlsShowThreshold, - scheduler::switches::kDisableBackgroundTimerThrottling, - #if defined(ENABLE_PLUGINS) switches::kEnablePepperTesting, #endif @@ -2429,7 +2436,8 @@ // TODO(bcwhite): Update this with the correct memory size. std::unique_ptr<base::SharedMemory> shm(new base::SharedMemory()); - shm->CreateAndMapAnonymous(2 << 20); // 2 MiB + if (!shm->CreateAndMapAnonymous(2 << 20)) // 2 MiB + return; metrics_allocator_.reset(new base::SharedPersistentMemoryAllocator( std::move(shm), GetID(), "RendererMetrics", /*readonly=*/false));
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h index bccbbcc..a4a331a 100644 --- a/content/browser/renderer_host/render_process_host_impl.h +++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -244,6 +244,12 @@ static void RegisterRendererMainThreadFactory( RendererMainThreadFactoryFunction create); + // TODO(alokp): Remove after collecting crash data. + // Temporary checks to verify that all shared workers are terminated. + // It is suspected that shared workers prevent render process hosts + // from shutting down: crbug.com/608049 + static void CheckAllWorkersTerminated(); + #if defined(OS_ANDROID) const scoped_refptr<BrowserDemuxerAndroid>& browser_demuxer_android() { return browser_demuxer_android_; @@ -523,9 +529,6 @@ base::WaitableEvent never_signaled_; #endif - std::string mojo_channel_token_; - mojo::ScopedMessagePipeHandle in_process_renderer_handle_; - base::WeakPtrFactory<RenderProcessHostImpl> weak_factory_; DISALLOW_COPY_AND_ASSIGN(RenderProcessHostImpl);
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc index f993e0a5..a3a1a6a 100644 --- a/content/browser/renderer_host/render_view_host_impl.cc +++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -325,7 +325,7 @@ // We should not set both main_frame_routing_id_ and proxy_route_id. Log // cases that this happens (without crashing) to track down - // https://crbug.com/574245. + // https://crbug.com/575245. // TODO(creis): Remove this once we've found the cause. if (main_frame_routing_id_ != MSG_ROUTING_NONE && proxy_route_id != MSG_ROUTING_NONE)
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 7286cec3..35364cb2 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -45,6 +45,7 @@ #include "content/browser/renderer_host/ui_events_helper.h" #include "content/browser/renderer_host/web_input_event_aura.h" #include "content/common/content_switches_internal.h" +#include "content/common/input_messages.h" #include "content/common/site_isolation_policy.h" #include "content/common/text_input_state.h" #include "content/common/view_messages.h" @@ -107,7 +108,6 @@ #endif #if defined(OS_LINUX) && !defined(OS_CHROMEOS) -#include "content/common/input_messages.h" #include "ui/base/ime/linux/text_edit_command_auralinux.h" #include "ui/base/ime/linux/text_edit_key_bindings_delegate_auralinux.h" #endif @@ -2996,8 +2996,23 @@ const TextInputState* state = text_input_manager_->GetTextInputState(); if (state && state->show_ime_if_needed && - state->type != ui::TEXT_INPUT_TYPE_NONE) + state->type != ui::TEXT_INPUT_TYPE_NONE) { GetInputMethod()->ShowImeIfNeeded(); + + // Start monitoring the composition information if the focused node is + // editable. + host_->Send(new InputMsg_RequestCompositionUpdate( + host_->GetRoutingID(), + false /* immediate request */, + true /* monitor request */)); + } else { + // Stop monitoring the composition information if the focused node is not + // editable. + host_->Send(new InputMsg_RequestCompositionUpdate( + host_->GetRoutingID(), + false /* immediate request */, + false /* monitor request */)); + } } void RenderWidgetHostViewAura::OnImeCancelComposition( @@ -3023,11 +3038,28 @@ TextInputManager* text_input_manager, RenderWidgetHostViewBase* updated_view) { #if defined(USE_X11) && !defined(OS_CHROMEOS) - if (!GetTextInputManager() || !GetTextInputManager()->GetActiveWidget()) + if (!GetTextInputManager()) return; - const TextInputManager::TextSelection* text_selection = - GetTextInputManager()->GetTextSelection(); + const TextInputManager::TextSelection* text_selection = nullptr; + if (is_guest_view_hack_) { + // We obtain the TextSelection from focused RWH which is obtained from the + // frame tree. BrowserPlugin-based guests' RWH is not part of the frame tree + // and the focused RWH will be that of the embedder which is incorrect. In + // this case we should use TextSelection for |this| since RWHV for guest + // forwards text selection information to its platform view. + text_selection = GetTextInputManager()->GetTextSelection(this); + } else { + RenderWidgetHostImpl* focused_widget = + host_->delegate()->GetFocusedRenderWidgetHost(host_); + if (!!focused_widget && !!focused_widget->GetView()) { + text_selection = GetTextInputManager()->GetTextSelection( + focused_widget->GetView()); + } + } + + if (!text_selection) + return; if (text_selection->text.empty() || text_selection->range.is_empty()) return;
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc index 56469f0..f82453c 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -76,6 +76,7 @@ #include "ui/aura/window.h" #include "ui/aura/window_event_dispatcher.h" #include "ui/aura/window_observer.h" +#include "ui/base/clipboard/clipboard.h" #include "ui/base/ui_base_types.h" #include "ui/compositor/compositor.h" #include "ui/compositor/layer_tree_owner.h" @@ -163,7 +164,8 @@ class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate { public: - MockRenderWidgetHostDelegate() : rwh_(nullptr), is_fullscreen_(false) {} + MockRenderWidgetHostDelegate() + : rwh_(nullptr), is_fullscreen_(false), focused_widget_(nullptr) {} ~MockRenderWidgetHostDelegate() override {} const NativeWebKeyboardEvent* last_event() const { return last_event_.get(); } void set_widget_host(RenderWidgetHostImpl* rwh) { rwh_ = rwh; } @@ -171,6 +173,13 @@ TextInputManager* GetTextInputManager() override { return &text_input_manager_; } + RenderWidgetHostImpl* GetFocusedRenderWidgetHost( + RenderWidgetHostImpl* widget_host) override { + return !!focused_widget_ ? focused_widget_ : widget_host; + } + void set_focused_widget(RenderWidgetHostImpl* focused_widget) { + focused_widget_ = focused_widget; + } protected: // RenderWidgetHostDelegate: @@ -194,6 +203,7 @@ RenderWidgetHostImpl* rwh_; bool is_fullscreen_; TextInputManager text_input_manager_; + RenderWidgetHostImpl* focused_widget_; DISALLOW_COPY_AND_ASSIGN(MockRenderWidgetHostDelegate); }; @@ -568,11 +578,23 @@ protected: BrowserContext* browser_context() { return browser_context_.get(); } + MockRenderWidgetHostDelegate* render_widget_host_delegate() const { + return delegates_.back().get(); + } + // Sets the |view| active in TextInputManager with the given |type|. |type| // cannot be ui::TEXT_INPUT_TYPE_NONE. + // Must not be called in the destruction path of |view|. void ActivateViewForTextInputManager(RenderWidgetHostViewBase* view, ui::TextInputType type) { DCHECK_NE(ui::TEXT_INPUT_TYPE_NONE, type); + // First mock-focus the widget if not already. + if (render_widget_host_delegate()->GetFocusedRenderWidgetHost( + widget_host_) != view->GetRenderWidgetHost()) { + render_widget_host_delegate()->set_focused_widget( + RenderWidgetHostImpl::From(view->GetRenderWidgetHost())); + } + TextInputManager* manager = static_cast<RenderWidgetHostImpl*>(view->GetRenderWidgetHost()) ->delegate() @@ -4233,10 +4255,6 @@ } protected: - MockRenderWidgetHostDelegate* render_widget_host_delegate() const { - return delegates_.back().get(); - } - ui::TextInputClient* text_input_client() const { return view_; } bool has_composition_text() const { @@ -4539,4 +4557,31 @@ } } +#if defined(USE_X11) && !defined(OS_CHROMEOS) +// This test will verify that after selection, the selected text is written to +// the clipboard from the focused widget. +TEST_F(InputMethodStateAuraTest, SelectedTextCopiedToClipboard) { + ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); + EXPECT_TRUE(!!clipboard); + std::vector<std::string> texts = {"text0", "text1", "text2", "text3"}; + for (auto index : active_view_sequence_) { + clipboard->Clear(ui::CLIPBOARD_TYPE_SELECTION); + + // Focus the corresponding widget. + render_widget_host_delegate()->set_focused_widget( + RenderWidgetHostImpl::From(views_[index]->GetRenderWidgetHost())); + + // Change the selection of the currently focused widget. It suffices to just + // call the method on the view. + base::string16 expected_text = base::ASCIIToUTF16(texts[index]); + views_[index]->SelectionChanged(expected_text, 0U, gfx::Range(0, 5)); + + // Retrieve the selected text from clipboard and verify it is as expected. + base::string16 result_text; + clipboard->ReadText(ui::CLIPBOARD_TYPE_SELECTION, &result_text); + EXPECT_EQ(expected_text, result_text); + } +} +#endif + } // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_view_base.cc b/content/browser/renderer_host/render_widget_host_view_base.cc index 7db1dcd6..3a295ca 100644 --- a/content/browser/renderer_host/render_widget_host_view_base.cc +++ b/content/browser/renderer_host/render_widget_host_view_base.cc
@@ -445,7 +445,7 @@ void RenderWidgetHostViewBase::ImeCancelComposition() { // TODO(ekaramad): Use TextInputManager code paths for IME on other platforms. -#if defined(USE_AURA) +#if !defined(OS_ANDROID) if (GetTextInputManager()) GetTextInputManager()->ImeCancelComposition(this); #endif
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.h b/content/browser/renderer_host/render_widget_host_view_mac.h index fbcb774..1021356 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.h +++ b/content/browser/renderer_host/render_widget_host_view_mac.h
@@ -284,7 +284,6 @@ void Focus() override; void UpdateCursor(const WebCursor& cursor) override; void SetIsLoading(bool is_loading) override; - void ImeCancelComposition() override; void ImeCompositionRangeChanged( const gfx::Range& range, const std::vector<gfx::Rect>& character_bounds) override; @@ -356,6 +355,9 @@ void OnUpdateTextInputStateCalled(TextInputManager* text_input_manager, RenderWidgetHostViewBase* updated_view, bool did_update_state) override; + void OnImeCancelComposition(TextInputManager* text_input_manager, + RenderWidgetHostViewBase* updated_view) override; + // IPC::Sender implementation. bool Send(IPC::Message* message) override;
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm index adc93fa6..9ed2ca7a 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.mm +++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -914,7 +914,9 @@ } } -void RenderWidgetHostViewMac::ImeCancelComposition() { +void RenderWidgetHostViewMac::OnImeCancelComposition( + TextInputManager* text_input_manager, + RenderWidgetHostViewBase* updated_view) { [cocoa_view_ cancelComposition]; } @@ -2175,11 +2177,8 @@ if (renderWidgetHostView_->render_widget_host_) { // History-swiping is not possible if the logic reaches this point. - // Allow rubber-banding in both directions. - bool canRubberbandLeft = true; - bool canRubberbandRight = true; WebMouseWheelEvent webEvent = WebMouseWheelEventBuilder::Build( - event, self, canRubberbandLeft, canRubberbandRight); + event, self); webEvent.railsMode = mouseWheelFilter_.UpdateRailsMode(webEvent); ui::LatencyInfo latency_info; latency_info.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0); @@ -2350,10 +2349,7 @@ // This is responsible for content scrolling! if (renderWidgetHostView_->render_widget_host_) { - BOOL canRubberbandLeft = [responderDelegate_ canRubberbandLeft:self]; - BOOL canRubberbandRight = [responderDelegate_ canRubberbandRight:self]; - WebMouseWheelEvent webEvent = WebMouseWheelEventBuilder::Build( - event, self, canRubberbandLeft, canRubberbandRight); + WebMouseWheelEvent webEvent = WebMouseWheelEventBuilder::Build(event, self); webEvent.railsMode = mouseWheelFilter_.UpdateRailsMode(webEvent); if (renderWidgetHostView_->ShouldRouteEvent(webEvent)) { renderWidgetHostView_->render_widget_host_->delegate()
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 a177cc0b..06960dc 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
@@ -96,12 +96,6 @@ - (void)touchesEndedWithEvent:(NSEvent*)event {} - (void)beginGestureWithEvent:(NSEvent*)event {} - (void)endGestureWithEvent:(NSEvent*)event {} -- (BOOL)canRubberbandLeft:(NSView*)view { - return true; -} -- (BOOL)canRubberbandRight:(NSView*)view { - return true; -} @end @@ -1253,4 +1247,31 @@ host->ShutdownAndDestroyWidget(true); } +// This test creates a test view to mimic a child frame's view and verifies that +// calling ImeCancelComposition on either the child view or the tab's view will +// always lead to a call to cancelComposition on the cocoa view. +TEST_F(RenderWidgetHostViewMacTest, ImeCancelCompositionForAllViews) { + TestRenderWidgetHostView* child_view = + new TestRenderWidgetHostView(rvh()->GetWidget()); + // Set the marked test on cocoa view. + NSString* text = [[NSString alloc] initWithString:@"sample text"]; + NSRange selectedRange = NSMakeRange(0, 1); + NSRange replacementRange = NSMakeRange(0, 1); + // Make Cocoa view assume there is marked text. + [rwhv_cocoa_ setMarkedText:text + selectedRange:selectedRange + replacementRange:replacementRange]; + EXPECT_TRUE([rwhv_cocoa_ hasMarkedText]); + child_view->ImeCancelComposition(); + EXPECT_FALSE([rwhv_cocoa_ hasMarkedText]); + + // Repeat for the tab's view. + [rwhv_cocoa_ setMarkedText:text + selectedRange:selectedRange + replacementRange:replacementRange]; + EXPECT_TRUE([rwhv_cocoa_ hasMarkedText]); + rwhv_mac_->ImeCancelComposition(); + EXPECT_FALSE([rwhv_cocoa_ hasMarkedText]); +} + } // namespace content
diff --git a/content/browser/resources/media/media_internals.html b/content/browser/resources/media/media_internals.html index 2d3d657..be0d684 100644 --- a/content/browser/resources/media/media_internals.html +++ b/content/browser/resources/media/media_internals.html
@@ -29,7 +29,7 @@ <tabpanel id="players"> <div id="list-wrapper"> <div id="player-list-wrapper"> - <h2>Players</h2> + <h2>Recent Players</h2> <ul id="player-list" class="show-none-if-empty"></ul> </div> </div>
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc index f9d6d7f..a4a6da90 100644 --- a/content/browser/security_exploit_browsertest.cc +++ b/content/browser/security_exploit_browsertest.cc
@@ -9,6 +9,7 @@ #include "base/macros.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" +#include "content/browser/bad_message.h" #include "content/browser/dom_storage/dom_storage_context_wrapper.h" #include "content/browser/dom_storage/session_storage_namespace_impl.h" #include "content/browser/frame_host/navigator.h" @@ -24,6 +25,7 @@ #include "content/public/browser/content_browser_client.h" #include "content/public/browser/interstitial_page.h" #include "content/public/browser/interstitial_page_delegate.h" +#include "content/public/browser/resource_context.h" #include "content/public/browser/resource_dispatcher_host.h" #include "content/public/browser/storage_partition.h" #include "content/public/common/appcache_info.h" @@ -401,15 +403,15 @@ ASSERT_EQ("\"okay2\"", interstitial->last_command()); } -class IsolatedAppContentBrowserClient : public TestContentBrowserClient { - public: - bool IsIllegalOrigin(content::ResourceContext* resource_context, - int child_process_id, - const GURL& origin) override { - // Simulate a case where an app origin is not in an app process. - return true; - } -}; +// Intercepts the HTTP origin header and on being invoked once it is found +// aborts the requeest. +void OnHttpHeaderReceived(const std::string& header, + const std::string& value, + int child_process_id, + content::ResourceContext* resource_context, + OnHeaderProcessedCallback callback) { + callback.Run(false, content::bad_message::RDH_ILLEGAL_ORIGIN); +} // Renderer processes should not be able to spoof Origin HTTP headers. IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, InvalidOriginHeaders) { @@ -445,10 +447,9 @@ // ResourceRequest IPC can't be created in a test outside content/. NavigateToURL(shell(), web_url); { - // Set up a ContentBrowserClient that simulates an app URL in a non-app - // process. - IsolatedAppContentBrowserClient app_client; - ContentBrowserClient* old_client = SetBrowserClientForTesting(&app_client); + content::ResourceDispatcherHost::Get()->RegisterInterceptor( + "Origin", "", base::Bind(&OnHttpHeaderReceived)); + RenderProcessHostWatcher web_process_killed( web_rfh->GetProcess(), RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); @@ -458,7 +459,6 @@ kRequestIdNotPreviouslyUsed, embedder_isolated_origin_msg)); web_process_killed.Wait(); - SetBrowserClientForTesting(old_client); } // Web processes cannot make XHRs with invalid Origin headers.
diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc index c914a550..fe9cd8b4 100644 --- a/content/browser/service_worker/service_worker_provider_host.cc +++ b/content/browser/service_worker/service_worker_provider_host.cc
@@ -282,8 +282,10 @@ void ServiceWorkerProviderHost::AddMatchingRegistration( ServiceWorkerRegistration* registration) { - DCHECK(ServiceWorkerUtils::ScopeMatches( - registration->pattern(), document_url_)); + // TODO(shimazu): Change CHECK to DCHECK after https://crbug.com/634222 is + // fixed. + CHECK( + ServiceWorkerUtils::ScopeMatches(registration->pattern(), document_url_)); if (!IsContextSecureForServiceWorker()) return; size_t key = registration->pattern().spec().size();
diff --git a/content/browser/shared_worker/shared_worker_service_impl.cc b/content/browser/shared_worker/shared_worker_service_impl.cc index 64bbe0b..cdb4ca49 100644 --- a/content/browser/shared_worker/shared_worker_service_impl.cc +++ b/content/browser/shared_worker/shared_worker_service_impl.cc
@@ -446,6 +446,15 @@ WorkerDestroyed(worker_process_id, worker_route_id)); } +// TODO(alokp): Remove after collecting crash data. +// Temporary checks to verify that all shared workers are terminated. +// It is suspected that shared workers prevent render process hosts +// from shutting down: crbug.com/608049 +void SharedWorkerServiceImpl::CheckAllWorkersTerminated() { + std::set<int> dependent_renderers = GetRenderersWithWorkerDependency(); + CHECK_EQ(0u, dependent_renderers.size()); +} + blink::WebWorkerCreationError SharedWorkerServiceImpl::ReserveRenderProcessToCreateWorker( std::unique_ptr<SharedWorkerPendingInstance> pending_instance) {
diff --git a/content/browser/shared_worker/shared_worker_service_impl.h b/content/browser/shared_worker/shared_worker_service_impl.h index 3c36f638..3228174 100644 --- a/content/browser/shared_worker/shared_worker_service_impl.h +++ b/content/browser/shared_worker/shared_worker_service_impl.h
@@ -93,6 +93,12 @@ void NotifyWorkerDestroyed(int worker_process_id, int worker_route_id); + // TODO(alokp): Remove after collecting crash data. + // Temporary checks to verify that all shared workers are terminated. + // It is suspected that shared workers prevent render process hosts + // from shutting down: crbug.com/608049 + void CheckAllWorkersTerminated(); + private: class SharedWorkerPendingInstance; class SharedWorkerReserver;
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc index 5ec546b..31d3eb2b 100644 --- a/content/browser/site_per_process_browsertest.cc +++ b/content/browser/site_per_process_browsertest.cc
@@ -7648,4 +7648,118 @@ } #endif +// Test that the pending RenderFrameHost is canceled and destroyed when its +// process dies. Previously, reusing a top-level pending RFH which +// is not live was hitting a CHECK in CreateRenderView due to having neither a +// main frame routing ID nor a proxy routing ID. See https://crbug.com/627400 +// for more details. +IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, + PendingRFHIsCanceledWhenItsProcessDies) { + GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html")); + EXPECT_TRUE(NavigateToURL(shell(), main_url)); + FrameTreeNode* root = web_contents()->GetFrameTree()->root(); + + // Open a popup at b.com. + GURL popup_url(embedded_test_server()->GetURL("b.com", "/title1.html")); + Shell* popup_shell = OpenPopup(root, popup_url, "foo"); + EXPECT_TRUE(popup_shell); + + // The RenderViewHost for b.com in the main tab should not be active. + SiteInstance* b_instance = popup_shell->web_contents()->GetSiteInstance(); + RenderViewHostImpl* rvh = + web_contents()->GetFrameTree()->GetRenderViewHost(b_instance); + EXPECT_FALSE(rvh->is_active()); + + // Navigate main tab to a b.com URL that will not commit. + GURL stall_url(embedded_test_server()->GetURL("b.com", "/title2.html")); + TestNavigationManager delayer(shell()->web_contents(), stall_url); + shell()->LoadURL(stall_url); + EXPECT_TRUE(delayer.WaitForWillStartRequest()); + + // The pending RFH should be in the same process as the popup. + RenderFrameHostImpl* pending_rfh = + IsBrowserSideNavigationEnabled() + ? root->render_manager()->speculative_frame_host() + : root->render_manager()->pending_frame_host(); + RenderProcessHost* pending_process = pending_rfh->GetProcess(); + EXPECT_EQ(pending_process, + popup_shell->web_contents()->GetMainFrame()->GetProcess()); + + // Kill the b.com process, currently in use by the pending RenderFrameHost + // and the popup. + RenderProcessHostWatcher crash_observer( + pending_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); + EXPECT_TRUE(pending_process->Shutdown(0, false)); + crash_observer.Wait(); + + // The pending RFH should have been canceled and destroyed, so that it won't + // be reused while it's not live in the next navigation. + { + RenderFrameHostImpl* pending_rfh = + IsBrowserSideNavigationEnabled() + ? root->render_manager()->speculative_frame_host() + : root->render_manager()->pending_frame_host(); + EXPECT_FALSE(pending_rfh); + } + + // Navigate main tab to b.com again. This should not crash. + GURL b_url(embedded_test_server()->GetURL("b.com", "/title3.html")); + EXPECT_TRUE(NavigateToURL(shell(), b_url)); + + // The b.com RVH in the main tab should become active. + EXPECT_TRUE(rvh->is_active()); +} + +// Test that killing a pending RenderFrameHost's process doesn't leave its +// RenderViewHost confused whether it's active or not for future navigations +// that try to reuse it. See https://crbug.com/627893 for more details. +// Similar to the test above for https://crbug.com/627400, except the popup is +// navigated after pending RFH's process is killed, rather than the main tab. +IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, + RenderViewHostKeepsSwappedOutStateIfPendingRFHDies) { + GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html")); + EXPECT_TRUE(NavigateToURL(shell(), main_url)); + FrameTreeNode* root = web_contents()->GetFrameTree()->root(); + + // Open a popup at b.com. + GURL popup_url(embedded_test_server()->GetURL("b.com", "/title1.html")); + Shell* popup_shell = OpenPopup(root, popup_url, "foo"); + EXPECT_TRUE(popup_shell); + + // The RenderViewHost for b.com in the main tab should not be active. + SiteInstance* b_instance = popup_shell->web_contents()->GetSiteInstance(); + RenderViewHostImpl* rvh = + web_contents()->GetFrameTree()->GetRenderViewHost(b_instance); + EXPECT_FALSE(rvh->is_active()); + + // Navigate main tab to a b.com URL that will not commit. + GURL stall_url(embedded_test_server()->GetURL("b.com", "/title2.html")); + TestNavigationManager delayer(shell()->web_contents(), stall_url); + shell()->LoadURL(stall_url); + EXPECT_TRUE(delayer.WaitForWillStartRequest()); + + // Kill the b.com process, currently in use by the pending RenderFrameHost + // and the popup. + RenderProcessHost* pending_process = + popup_shell->web_contents()->GetMainFrame()->GetProcess(); + RenderProcessHostWatcher crash_observer( + pending_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); + EXPECT_TRUE(pending_process->Shutdown(0, false)); + crash_observer.Wait(); + + // Since the navigation above didn't commit, the b.com RenderViewHost in the + // main tab should still not be active. + EXPECT_FALSE(rvh->is_active()); + + // Navigate popup to b.com to recreate the b.com process. When creating + // opener proxies, |rvh| should be reused as a swapped out RVH. In + // https://crbug.com/627893, recreating the opener RenderView was hitting a + // CHECK(params.swapped_out) in the renderer process, since its + // RenderViewHost was brought into an active state by the navigation to + // |stall_url| above, even though it never committed. + GURL b_url(embedded_test_server()->GetURL("b.com", "/title3.html")); + EXPECT_TRUE(NavigateToURL(popup_shell, b_url)); + EXPECT_FALSE(rvh->is_active()); +} + } // namespace content
diff --git a/content/browser/ssl/ssl_error_handler.cc b/content/browser/ssl/ssl_error_handler.cc index 11e68910..1bf03a2 100644 --- a/content/browser/ssl/ssl_error_handler.cc +++ b/content/browser/ssl/ssl_error_handler.cc
@@ -7,8 +7,6 @@ #include "base/bind.h" #include "content/browser/frame_host/navigation_controller_impl.h" #include "content/browser/frame_host/render_frame_host_impl.h" -#include "content/browser/ssl/ssl_manager.h" -#include "content/browser/ssl/ssl_policy.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/resource_request_info.h" @@ -20,161 +18,63 @@ namespace content { -SSLErrorHandler::SSLErrorHandler(const base::WeakPtr<Delegate>& delegate, +namespace { + +void CompleteCancelRequest( + const base::WeakPtr<SSLErrorHandler::Delegate>& delegate, + const net::SSLInfo& ssl_info, + int error) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + if (delegate.get()) + delegate->CancelSSLRequest(error, &ssl_info); +} + +void CompleteContinueRequest( + const base::WeakPtr<SSLErrorHandler::Delegate>& delegate) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + if (delegate.get()) { + delegate->ContinueSSLRequest(); + } +} + +} // namespace + +SSLErrorHandler::SSLErrorHandler(WebContents* web_contents, + const base::WeakPtr<Delegate>& delegate, ResourceType resource_type, const GURL& url, const net::SSLInfo& ssl_info, bool fatal) - : manager_(NULL), - delegate_(delegate), - request_has_been_notified_(false), + : delegate_(delegate), request_url_(url), resource_type_(resource_type), ssl_info_(ssl_info), cert_error_(net::MapCertStatusToNetError(ssl_info.cert_status)), - fatal_(fatal) { - DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); - DCHECK(delegate.get()); - - // This makes sure we don't disappear on the IO thread until we've given an - // answer to the net::URLRequest. - // - // Release in CompleteCancelRequest, CompleteContinueRequest, or - // CompleteTakeNoAction. - AddRef(); + fatal_(fatal), + web_contents_(web_contents) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); } SSLErrorHandler::~SSLErrorHandler() {} -void SSLErrorHandler::OnDispatchFailed() { - // Requests can fail to dispatch because they don't have a WebContents. See - // <http://crbug.com/86537>. In this case we have to make a decision in this - // function, so we ignore revocation check failures. - if (net::IsCertStatusMinorError(ssl_info().cert_status)) { - ContinueRequest(); - } else { - CancelRequest(); - } -} - -void SSLErrorHandler::OnDispatched() { - manager_->policy()->OnCertError(this); -} - -void SSLErrorHandler::Dispatch( - const base::Callback<WebContents*(void)>& web_contents_getter) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - WebContents* web_contents = web_contents_getter.Run(); - - if (!web_contents) { - // We arrived on the UI thread, but the tab we're looking for is no longer - // here. - OnDispatchFailed(); - return; - } - - // Hand ourselves off to the SSLManager. - manager_ = - static_cast<NavigationControllerImpl*>(&web_contents->GetController())-> - ssl_manager(); - OnDispatched(); -} - void SSLErrorHandler::CancelRequest() { DCHECK_CURRENTLY_ON(BrowserThread::UI); - - // We need to complete this task on the IO thread. - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind( - &SSLErrorHandler::CompleteCancelRequest, this, net::ERR_ABORTED)); + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, + base::Bind(&CompleteCancelRequest, delegate_, + ssl_info(), net::ERR_ABORTED)); } void SSLErrorHandler::DenyRequest() { DCHECK_CURRENTLY_ON(BrowserThread::UI); - - // We need to complete this task on the IO thread. - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind( - &SSLErrorHandler::CompleteCancelRequest, this, - net::ERR_INSECURE_RESPONSE)); + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, + base::Bind(&CompleteCancelRequest, delegate_, + ssl_info(), net::ERR_INSECURE_RESPONSE)); } void SSLErrorHandler::ContinueRequest() { DCHECK_CURRENTLY_ON(BrowserThread::UI); - - // We need to complete this task on the IO thread. - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&SSLErrorHandler::CompleteContinueRequest, this)); -} - -void SSLErrorHandler::TakeNoAction() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - // We need to complete this task on the IO thread. - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&SSLErrorHandler::CompleteTakeNoAction, this)); -} - -SSLManager* SSLErrorHandler::GetManager() const { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - return manager_; -} - -void SSLErrorHandler::CompleteCancelRequest(int error) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - - // It is important that we notify the net::URLRequest only once. If we try - // to notify the request twice, it may no longer exist and |this| might have - // already have been deleted. - DCHECK(!request_has_been_notified_); - if (request_has_been_notified_) - return; - - if (delegate_.get()) - delegate_->CancelSSLRequest(error, &ssl_info_); - request_has_been_notified_ = true; - - // We're done with this object on the IO thread. - Release(); -} - -void SSLErrorHandler::CompleteContinueRequest() { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - - // It is important that we notify the net::URLRequest only once. If we try to - // notify the request twice, it may no longer exist and |this| might have - // already have been deleted. - DCHECK(!request_has_been_notified_); - if (request_has_been_notified_) - return; - - if (delegate_.get()) - delegate_->ContinueSSLRequest(); - request_has_been_notified_ = true; - - // We're done with this object on the IO thread. - Release(); -} - -void SSLErrorHandler::CompleteTakeNoAction() { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - - // It is important that we notify the net::URLRequest only once. If we try to - // notify the request twice, it may no longer exist and |this| might have - // already have been deleted. - DCHECK(!request_has_been_notified_); - if (request_has_been_notified_) - return; - - request_has_been_notified_ = true; - - // We're done with this object on the IO thread. - Release(); + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, + base::Bind(&CompleteContinueRequest, delegate_)); } } // namespace content
diff --git a/content/browser/ssl/ssl_error_handler.h b/content/browser/ssl/ssl_error_handler.h index b981e7e..d00a43b 100644 --- a/content/browser/ssl/ssl_error_handler.h +++ b/content/browser/ssl/ssl_error_handler.h
@@ -26,25 +26,15 @@ class SSLManager; class WebContents; -// An SSLErrorHandler carries information from the IO thread to the UI thread -// and is dispatched to the appropriate SSLManager when it arrives on the -// UI thread. Subclasses should override the OnDispatched/OnDispatchFailed -// methods to implement the actions that should be taken on the UI thread. -// These methods can call the different convenience methods ContinueRequest/ -// CancelRequest to perform any required action on the net::URLRequest the -// ErrorHandler was created with. -// -// IMPORTANT NOTE: -// -// If you are not doing anything in OnDispatched/OnDispatchFailed, make sure -// you call TakeNoAction(). This is necessary for ensuring the instance is -// not leaked. -// -class SSLErrorHandler : public base::RefCountedThreadSafe<SSLErrorHandler> { +// SSLErrorHandler is the UI-thread class for handling SSL certificate +// errors. Users of this class can call CancelRequest(), +// ContinueRequest(), or DenyRequest() when a decision about how to +// handle the error has been made. Users of this class must +// call exactly one of those methods exactly once. +class SSLErrorHandler { public: - // Delegate functions must be called from IO thread. Finally, - // CancelSSLRequest() or ContinueSSLRequest() will be called after - // SSLErrorHandler makes a decision on the SSL error. + // SSLErrorHandler's delegate lives on the IO thread, and thus these + // delegate methods must be called on the IO thread only. class CONTENT_EXPORT Delegate { public: // Called when SSLErrorHandler decides to cancel the request because of @@ -59,26 +49,27 @@ virtual ~Delegate() {} }; - // Construct on the IO thread. - SSLErrorHandler(const base::WeakPtr<Delegate>& delegate, + SSLErrorHandler(WebContents* web_contents, + const base::WeakPtr<Delegate>& delegate, ResourceType resource_type, const GURL& url, const net::SSLInfo& ssl_info, bool fatal); - // Find the appropriate SSLManager for the net::URLRequest and begin handling - // this error. - // - // Call on UI thread. - void Dispatch(const base::Callback<WebContents*(void)>& web_contents_getter); + virtual ~SSLErrorHandler(); - // These accessors are available on either thread const net::SSLInfo& ssl_info() const { return ssl_info_; } - int cert_error() const { return cert_error_; } - bool fatal() const { return fatal_; } + const GURL& request_url() const { return request_url_; } + ResourceType resource_type() const { return resource_type_; } + WebContents* web_contents() const { return web_contents_; } + + int cert_error() const { return cert_error_; } + + bool fatal() const { return fatal_; } + // Cancels the associated net::URLRequest. CONTENT_EXPORT void CancelRequest(); @@ -93,65 +84,31 @@ // warning message). void DenyRequest(); - // Does nothing on the net::URLRequest but ensures the current instance ref - // count is decremented appropriately. - void TakeNoAction(); - - // Returns the manager associated with this SSLErrorHandler. - // Should only be accessed on the UI thread. - SSLManager* GetManager() const; - private: - friend class base::RefCountedThreadSafe<SSLErrorHandler>; - - virtual ~SSLErrorHandler(); - - virtual void OnDispatchFailed(); - - // Can use the manager_ member. - virtual void OnDispatched(); - - // Should only be accessed on the UI thread. - SSLManager* manager_; // Our manager. - - // The delegate we are associated with. + // This must not be dereferenced on the UI thread. SSLErrorHandler + // simply holds on to the reference to be passed back to the IO thread + // to enact a decision about the error once one has been made. base::WeakPtr<Delegate> delegate_; - // Completes the CancelRequest operation on the IO thread. - // Call on the IO thread. - void CompleteCancelRequest(int error); - - // Completes the ContinueRequest operation on the IO thread. - // - // Call on the IO thread. - void CompleteContinueRequest(); - - // Derefs this instance. - // Call on the IO thread. - void CompleteTakeNoAction(); - - // A flag to make sure we notify the net::URLRequest exactly once. - // Should only be accessed on the IO thread - bool request_has_been_notified_; - - // The below read-only members may be accessed on any thread. - - // The URL that we requested. + // The URL for the request that generated the error. const GURL request_url_; // What kind of resource is associated with the request that generated // the error. const ResourceType resource_type_; - // The SSLInfo associated with the request that generated the error. + // The net::SSLInfo associated with the request that generated the error. const net::SSLInfo ssl_info_; - // The net error code that occurred on the request. + // A net error code describing the error that occurred. const int cert_error_; // True if the error is from a host requiring certificate errors to be fatal. const bool fatal_; + // The WebContents associated with the request that generated the error. + WebContents* web_contents_; + DISALLOW_COPY_AND_ASSIGN(SSLErrorHandler); };
diff --git a/content/browser/ssl/ssl_manager.cc b/content/browser/ssl/ssl_manager.cc index bcec1167..f50efb2 100644 --- a/content/browser/ssl/ssl_manager.cc +++ b/content/browser/ssl/ssl_manager.cc
@@ -19,7 +19,6 @@ #include "content/common/ssl_status_serialization.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" -#include "content/public/browser/load_from_memory_cache_details.h" #include "content/public/browser/navigation_details.h" #include "content/public/browser/resource_request_details.h" #include "content/public/common/ssl_status.h" @@ -44,6 +43,35 @@ DISALLOW_COPY_AND_ASSIGN(SSLManagerSet); }; +void HandleSSLErrorOnUI( + const base::Callback<WebContents*(void)>& web_contents_getter, + const base::WeakPtr<SSLErrorHandler::Delegate>& delegate, + const ResourceType resource_type, + const GURL& url, + const net::SSLInfo& ssl_info, + bool fatal) { + content::WebContents* web_contents = web_contents_getter.Run(); + std::unique_ptr<SSLErrorHandler> handler(new SSLErrorHandler( + web_contents, delegate, resource_type, url, ssl_info, fatal)); + + if (!web_contents) { + // Requests can fail to dispatch because they don't have a WebContents. See + // https://crbug.com/86537. In this case we have to make a decision in this + // function, so we ignore revocation check failures. + if (net::IsCertStatusMinorError(ssl_info.cert_status)) { + handler->ContinueRequest(); + } else { + handler->CancelRequest(); + } + return; + } + + SSLManager* manager = + static_cast<NavigationControllerImpl*>(&web_contents->GetController()) + ->ssl_manager(); + manager->policy()->OnCertError(std::move(handler)); +} + } // namespace // static @@ -61,14 +89,12 @@ << " url: " << url.spec() << " cert_status: " << std::hex << ssl_info.cert_status; - // A certificate error occurred. Construct a SSLErrorHandler object and - // hand it over to the UI thread for processing. + // A certificate error occurred. Construct a SSLErrorHandler object + // on the UI thread for processing. BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, - base::Bind( - &SSLErrorHandler::Dispatch, - new SSLErrorHandler(delegate, resource_type, url, ssl_info, fatal), - web_contents_getter)); + base::Bind(&HandleSSLErrorOnUI, web_contents_getter, delegate, + resource_type, url, ssl_info, fatal)); } // static @@ -140,12 +166,6 @@ UpdateEntry(navigation_entry); } -void SSLManager::DidLoadFromMemoryCache( - const LoadFromMemoryCacheDetails& details) { - // Simulate loading this resource through the usual path. - policy()->OnRequestStarted(details.url, details.cert_id, details.cert_status); -} - void SSLManager::DidStartResourceResponse( const ResourceRequestDetails& details) { // Notify our policy that we started a resource request. Ideally, the
diff --git a/content/browser/ssl/ssl_manager.h b/content/browser/ssl/ssl_manager.h index 82e724b..b6dbd62 100644 --- a/content/browser/ssl/ssl_manager.h +++ b/content/browser/ssl/ssl_manager.h
@@ -28,7 +28,6 @@ class NavigationControllerImpl; class SSLPolicy; struct LoadCommittedDetails; -struct LoadFromMemoryCacheDetails; struct ResourceRedirectDetails; struct ResourceRequestDetails; @@ -83,7 +82,6 @@ NavigationControllerImpl* controller() { return controller_; } void DidCommitProvisionalLoad(const LoadCommittedDetails& details); - void DidLoadFromMemoryCache(const LoadFromMemoryCacheDetails& details); void DidStartResourceResponse(const ResourceRequestDetails& details); void DidReceiveResourceRedirect(const ResourceRedirectDetails& details);
diff --git a/content/browser/ssl/ssl_policy.cc b/content/browser/ssl/ssl_policy.cc index 4c44226..9d60c36 100644 --- a/content/browser/ssl/ssl_policy.cc +++ b/content/browser/ssl/ssl_policy.cc
@@ -35,14 +35,45 @@ HAD_PREVIOUS_EXCEPTION = 1, SSL_GOOD_CERT_SEEN_EVENT_MAX = 2 }; + +void OnAllowCertificate(SSLErrorHandler* handler, + const SSLPolicy* const policy, + CertificateRequestResultType decision) { + DCHECK(handler->ssl_info().is_valid()); + switch (decision) { + case CERTIFICATE_REQUEST_RESULT_TYPE_CONTINUE: + // Note that we should not call SetMaxSecurityStyle here, because + // the active NavigationEntry has just been deleted (in + // HideInterstitialPage) and the new NavigationEntry will not be + // set until DidNavigate. This is ok, because the new + // NavigationEntry will have its max security style set within + // DidNavigate. + // + // While AllowCertForHost() executes synchronously on this thread, + // ContinueRequest() gets posted to a different thread. Calling + // AllowCertForHost() first ensures deterministic ordering. + policy->backend()->AllowCertForHost(*handler->ssl_info().cert.get(), + handler->request_url().host(), + handler->cert_error()); + handler->ContinueRequest(); + return; + case CERTIFICATE_REQUEST_RESULT_TYPE_DENY: + handler->DenyRequest(); + return; + case CERTIFICATE_REQUEST_RESULT_TYPE_CANCEL: + handler->CancelRequest(); + return; + } } +} // namespace + SSLPolicy::SSLPolicy(SSLPolicyBackend* backend) : backend_(backend) { DCHECK(backend_); } -void SSLPolicy::OnCertError(SSLErrorHandler* handler) { +void SSLPolicy::OnCertError(std::unique_ptr<SSLErrorHandler> handler) { bool expired_previous_decision = false; // First we check if we know the policy for this error. DCHECK(handler->ssl_info().is_valid()); @@ -75,7 +106,7 @@ options_mask |= STRICT_ENFORCEMENT; if (expired_previous_decision) options_mask |= EXPIRED_PREVIOUS_DECISION; - OnCertErrorInternal(handler, options_mask); + OnCertErrorInternal(std::move(handler), options_mask); break; case net::ERR_CERT_NO_REVOCATION_MECHANISM: // Ignore this error. @@ -95,7 +126,7 @@ options_mask |= STRICT_ENFORCEMENT; if (expired_previous_decision) options_mask |= EXPIRED_PREVIOUS_DECISION; - OnCertErrorInternal(handler, options_mask); + OnCertErrorInternal(std::move(handler), options_mask); break; default: NOTREACHED(); @@ -132,7 +163,8 @@ if (backend_->HasAllowException(url.host())) { // If there's no certificate error, a good certificate has been seen, so // clear out any exceptions that were made by the user for bad - // certificates. + // certificates. This intentionally does not apply to cached resources + // (see https://crbug.com/634553 for an explanation). backend_->RevokeUserAllowExceptions(url.host()); event = HAD_PREVIOUS_EXCEPTION; } @@ -190,51 +222,25 @@ return SECURITY_STYLE_AUTHENTICATED; } -void SSLPolicy::OnAllowCertificate(scoped_refptr<SSLErrorHandler> handler, - CertificateRequestResultType decision) { - DCHECK(handler->ssl_info().is_valid()); - switch (decision) { - case CERTIFICATE_REQUEST_RESULT_TYPE_CONTINUE: - // Note that we should not call SetMaxSecurityStyle here, because the - // active - // NavigationEntry has just been deleted (in HideInterstitialPage) and the - // new NavigationEntry will not be set until DidNavigate. This is ok, - // because the new NavigationEntry will have its max security style set - // within DidNavigate. - // - // While AllowCertForHost() executes synchronously on this thread, - // ContinueRequest() gets posted to a different thread. Calling - // AllowCertForHost() first ensures deterministic ordering. - backend_->AllowCertForHost(*handler->ssl_info().cert.get(), - handler->request_url().host(), - handler->cert_error()); - handler->ContinueRequest(); - return; - case CERTIFICATE_REQUEST_RESULT_TYPE_DENY: - handler->DenyRequest(); - return; - case CERTIFICATE_REQUEST_RESULT_TYPE_CANCEL: - handler->CancelRequest(); - return; - } -} - //////////////////////////////////////////////////////////////////////////////// // Certificate Error Routines -void SSLPolicy::OnCertErrorInternal(SSLErrorHandler* handler, +void SSLPolicy::OnCertErrorInternal(std::unique_ptr<SSLErrorHandler> handler, int options_mask) { bool overridable = (options_mask & OVERRIDABLE) != 0; bool strict_enforcement = (options_mask & STRICT_ENFORCEMENT) != 0; bool expired_previous_decision = (options_mask & EXPIRED_PREVIOUS_DECISION) != 0; + + WebContents* web_contents = handler->web_contents(); + int cert_error = handler->cert_error(); + const net::SSLInfo& ssl_info = handler->ssl_info(); + const GURL& request_url = handler->request_url(); + ResourceType resource_type = handler->resource_type(); GetContentClient()->browser()->AllowCertificateError( - handler->GetManager()->controller()->GetWebContents(), - handler->cert_error(), handler->ssl_info(), handler->request_url(), - handler->resource_type(), overridable, strict_enforcement, - expired_previous_decision, - base::Bind(&SSLPolicy::OnAllowCertificate, base::Unretained(this), - make_scoped_refptr(handler))); + web_contents, cert_error, ssl_info, request_url, resource_type, + overridable, strict_enforcement, expired_previous_decision, + base::Bind(&OnAllowCertificate, base::Owned(handler.release()), this)); } void SSLPolicy::InitializeEntryIfNeeded(NavigationEntryImpl* entry) {
diff --git a/content/browser/ssl/ssl_policy.h b/content/browser/ssl/ssl_policy.h index cdcbebe..0ba7869 100644 --- a/content/browser/ssl/ssl_policy.h +++ b/content/browser/ssl/ssl_policy.h
@@ -33,7 +33,7 @@ explicit SSLPolicy(SSLPolicyBackend* backend); // An error occurred with the certificate in an SSL connection. - void OnCertError(SSLErrorHandler* handler); + void OnCertError(std::unique_ptr<SSLErrorHandler> handler); void DidRunInsecureContent(NavigationEntryImpl* entry, const GURL& security_origin); @@ -64,10 +64,6 @@ EXPIRED_PREVIOUS_DECISION = 1 << 2 }; - // Callback that the user chose to accept or deny the certificate. - void OnAllowCertificate(scoped_refptr<SSLErrorHandler> handler, - CertificateRequestResultType decision); - // Helper method for derived classes handling certificate errors. // // Options should be a bitmask combination of OnCertErrorInternalOptionsMask. @@ -78,7 +74,8 @@ // certificate validation (e.g. with HTTP Strict-Transport-Security). // EXPIRED_PREVIOUS_DECISION indicates whether a user decision had been // previously made but the decision has expired. - void OnCertErrorInternal(SSLErrorHandler* handler, int options_mask); + void OnCertErrorInternal(std::unique_ptr<SSLErrorHandler> handler, + int options_mask); // If the security style of |entry| has not been initialized, then initialize // it with the default style for its URL.
diff --git a/content/browser/top_document_isolation_browsertest.cc b/content/browser/top_document_isolation_browsertest.cc index bca52ee1..b0409db8 100644 --- a/content/browser/top_document_isolation_browsertest.cc +++ b/content/browser/top_document_isolation_browsertest.cc
@@ -278,16 +278,9 @@ DepictFrameTree(root())); } -// Flaky on Mac and Windows. See http://crbug.com/611300. -#if defined(OS_MACOSX) || defined(OS_WIN) -#define MAYBE_NavigateToSubframeSiteWithPopup2 \ - DISABLED_NavigateToSubframeSiteWithPopup2 -#else -#define MAYBE_NavigateToSubframeSiteWithPopup2 NavigateToSubframeSiteWithPopup2 -#endif - +// Flaky. See http://crbug.com/611300. IN_PROC_BROWSER_TEST_F(TopDocumentIsolationTest, - MAYBE_NavigateToSubframeSiteWithPopup2) { + DISABLED_NavigateToSubframeSiteWithPopup2) { if (content::AreAllSitesIsolatedForTesting()) return; // Top Document Isolation is disabled in this mode.
diff --git a/content/browser/tracing/tracing_controller_impl.cc b/content/browser/tracing/tracing_controller_impl.cc index 3666955..2ca4738 100644 --- a/content/browser/tracing/tracing_controller_impl.cc +++ b/content/browser/tracing/tracing_controller_impl.cc
@@ -340,7 +340,8 @@ } void TracingControllerImpl::AddMetadata(const base::DictionaryValue& data) { - metadata_->MergeDictionary(&data); + if (metadata_) + metadata_->MergeDictionary(&data); } bool TracingControllerImpl::StopTracing(
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index 26e6d0a..a25b0a0 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -3460,9 +3460,6 @@ LoadFromMemoryCacheDetails details( url, status.cert_id, status.cert_status, http_method, mime_type, resource_type); - - controller_.ssl_manager()->DidLoadFromMemoryCache(details); - FOR_EACH_OBSERVER(WebContentsObserver, observers_, DidLoadResourceFromMemoryCache(details));
diff --git a/content/child/BUILD.gn b/content/child/BUILD.gn index f39db3a8..519e75d7 100644 --- a/content/child/BUILD.gn +++ b/content/child/BUILD.gn
@@ -43,7 +43,6 @@ deps = [ "//base", "//components/mime_util", - "//components/scheduler:scheduler", "//components/tracing", "//components/tracing:startup_tracing", "//components/webcrypto", @@ -53,6 +52,8 @@ "//content/public/common:common_sources", "//crypto:platform", "//gpu/command_buffer/client", + "//ipc", + "//ipc:mojom", "//media", "//mojo/common", "//mojo/edk/system", @@ -65,7 +66,7 @@ "//third_party/WebKit/public:blink_headers", "//third_party/WebKit/public:image_resources", "//third_party/WebKit/public:resources", - "//third_party/icu", + "//third_party/ced", "//ui/base", "//ui/events/gestures/blink", "//ui/gfx",
diff --git a/content/child/blink_platform_impl.cc b/content/child/blink_platform_impl.cc index ba47d22d..2123110 100644 --- a/content/child/blink_platform_impl.cc +++ b/content/child/blink_platform_impl.cc
@@ -35,8 +35,6 @@ #include "blink/public/resources/grit/blink_resources.h" #include "build/build_config.h" #include "components/mime_util/mime_util.h" -#include "components/scheduler/child/web_task_runner_impl.h" -#include "components/scheduler/child/webthread_impl_for_worker_scheduler.h" #include "content/app/resources/grit/content_resources.h" #include "content/app/strings/grit/content_strings.h" #include "content/child/background_sync/background_sync_provider.h" @@ -59,6 +57,7 @@ #include "third_party/WebKit/public/platform/WebSecurityOrigin.h" #include "third_party/WebKit/public/platform/WebString.h" #include "third_party/WebKit/public/platform/WebURL.h" +#include "third_party/WebKit/public/platform/scheduler/child/webthread_impl_for_worker_scheduler.h" #include "ui/base/layout.h" #include "ui/events/gestures/blink/web_gesture_curve_impl.h" #include "ui/events/keycodes/dom/keycode_converter.h" @@ -71,7 +70,7 @@ using blink::WebURL; using blink::WebURLError; using blink::WebURLLoader; -using scheduler::WebThreadImplForWorkerScheduler; +using blink::scheduler::WebThreadImplForWorkerScheduler; namespace content { @@ -390,7 +389,7 @@ } void BlinkPlatformImpl::WaitUntilWebThreadTLSUpdate( - scheduler::WebThreadBase* thread) { + blink::scheduler::WebThreadBase* thread) { base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC, base::WaitableEvent::InitialState::NOT_SIGNALED); thread->GetTaskRunner()->PostTask( @@ -454,7 +453,7 @@ } void BlinkPlatformImpl::SetCompositorThread( - scheduler::WebThreadBase* compositor_thread) { + blink::scheduler::WebThreadBase* compositor_thread) { compositor_thread_ = compositor_thread; if (compositor_thread_) WaitUntilWebThreadTLSUpdate(compositor_thread_);
diff --git a/content/child/blink_platform_impl.h b/content/child/blink_platform_impl.h index 1ee9106..ed2839e9 100644 --- a/content/child/blink_platform_impl.h +++ b/content/child/blink_platform_impl.h
@@ -37,9 +37,11 @@ class WaitableEvent; } +namespace blink { namespace scheduler { class WebThreadBase; } +} namespace content { class BackgroundSyncProvider; @@ -136,11 +138,11 @@ // This class does *not* own the compositor thread. It is the responsibility // of the caller to ensure that the compositor thread is cleared before it is // destructed. - void SetCompositorThread(scheduler::WebThreadBase* compositor_thread); + void SetCompositorThread(blink::scheduler::WebThreadBase* compositor_thread); private: void InternalInit(); - void WaitUntilWebThreadTLSUpdate(scheduler::WebThreadBase* thread); + void WaitUntilWebThreadTLSUpdate(blink::scheduler::WebThreadBase* thread); void UpdateWebThreadTLS(blink::WebThread* thread, base::WaitableEvent* event); bool IsMainThread() const; @@ -159,7 +161,7 @@ scoped_refptr<PushDispatcher> push_dispatcher_; std::unique_ptr<BackgroundSyncProvider> main_thread_sync_provider_; - scheduler::WebThreadBase* compositor_thread_; + blink::scheduler::WebThreadBase* compositor_thread_; }; } // namespace content
diff --git a/content/child/child_thread_impl.cc b/content/child/child_thread_impl.cc index f0b739c..562ebf8 100644 --- a/content/child/child_thread_impl.cc +++ b/content/child/child_thread_impl.cc
@@ -54,6 +54,7 @@ #include "content/common/child_process_messages.h" #include "content/common/in_process_child_thread_params.h" #include "content/common/mojo/constants.h" +#include "content/public/common/connection_filter.h" #include "content/public/common/content_switches.h" #include "content/public/common/mojo_channel_switches.h" #include "content/public/common/mojo_shell_connection.h" @@ -70,6 +71,7 @@ #include "mojo/edk/embedder/platform_channel_pair.h" #include "mojo/edk/embedder/scoped_ipc_support.h" #include "services/shell/public/cpp/connector.h" +#include "services/shell/public/cpp/interface_factory.h" #include "services/shell/public/cpp/interface_provider.h" #include "services/shell/public/cpp/interface_registry.h" #include "services/shell/runner/common/client_util.h" @@ -257,6 +259,37 @@ mojo::edk::SetParentPipeHandle(std::move(platform_channel)); } +class ChannelBootstrapFilter + : public ConnectionFilter, + public shell::InterfaceFactory<IPC::mojom::ChannelBootstrap> { + public: + explicit ChannelBootstrapFilter(IPC::mojom::ChannelBootstrapPtrInfo bootstrap) + : bootstrap_(std::move(bootstrap)) {} + + private: + // ConnectionFilter: + bool OnConnect(const shell::Identity& remote_identity, + shell::InterfaceRegistry* registry, + shell::Connector* connector) override { + if (remote_identity.name() != kBrowserMojoApplicationName) + return false; + + registry->AddInterface<IPC::mojom::ChannelBootstrap>(this); + return true; + } + + // shell::InterfaceFactory<IPC::mojom::ChannelBootstrap>: + void Create(const shell::Identity& remote_identity, + IPC::mojom::ChannelBootstrapRequest request) override { + DCHECK(bootstrap_.is_valid()); + mojo::FuseInterface(std::move(request), std::move(bootstrap_)); + } + + IPC::mojom::ChannelBootstrapPtrInfo bootstrap_; + + DISALLOW_COPY_AND_ASSIGN(ChannelBootstrapFilter); +}; + } // namespace ChildThread* ChildThread::Get() { @@ -377,15 +410,29 @@ bool create_pipe_now = true; if (use_mojo_channel) { VLOG(1) << "Mojo is enabled on child"; + std::string channel_token; mojo::ScopedMessagePipeHandle handle; if (!IsInBrowserProcess()) { - DCHECK(!handle.is_valid()); - handle = mojo::edk::CreateChildMessagePipe( + channel_token = base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( - switches::kMojoChannelToken)); + switches::kMojoChannelToken); } else { - handle = mojo::edk::CreateChildMessagePipe(ipc_token); + channel_token = ipc_token; } + + if (!channel_token.empty()) { + // TODO(rockot): Remove all paths which lead to this branch. The Channel + // connection should always be established by a shell connection from the + // browser. http://crbug.com/623396. + handle = mojo::edk::CreateChildMessagePipe(channel_token); + } else { + DCHECK(mojo_shell_connection_); + IPC::mojom::ChannelBootstrapPtr bootstrap; + handle = mojo::GetProxy(&bootstrap).PassMessagePipe(); + mojo_shell_connection_->AddConnectionFilter( + base::MakeUnique<ChannelBootstrapFilter>(bootstrap.PassInterface())); + } + DCHECK(handle.is_valid()); channel_->Init( IPC::ChannelMojo::CreateClientFactory( @@ -459,9 +506,6 @@ // ConnectionFilter. mojo_shell_connection_->SetupInterfaceRequestProxies( GetInterfaceRegistry(), remote_interfaces); - - if (options.auto_start_mojo_shell_connection) - StartMojoShellConnection(); } sync_message_filter_ = channel_->CreateSyncMessageFilter(); @@ -532,8 +576,14 @@ IPC::AttachmentBroker* broker = IPC::AttachmentBroker::GetGlobal(); if (broker && !broker->IsPrivilegedBroker()) broker->RegisterBrokerCommunicationChannel(channel_.get()); + ConnectChannel(options.use_mojo_channel, options.in_process_ipc_token); + // This must always be done after ConnectChannel, because ConnectChannel() may + // add a ConnectionFilter to the connection. + if (options.auto_start_mojo_shell_connection && mojo_shell_connection_) + StartMojoShellConnection(); + int connection_timeout = kConnectionTimeoutS; std::string connection_override = base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
diff --git a/content/child/child_thread_impl.h b/content/child/child_thread_impl.h index ae2fa20..783d12b 100644 --- a/content/child/child_thread_impl.h +++ b/content/child/child_thread_impl.h
@@ -20,6 +20,7 @@ #include "build/build_config.h" #include "content/common/content_export.h" #include "content/public/child/child_thread.h" +#include "ipc/ipc.mojom.h" #include "ipc/ipc_message.h" // For IPC_MESSAGE_LOG_ENABLED. #include "ipc/ipc_platform_file.h" #include "ipc/message_router.h"
diff --git a/content/child/ftp_directory_listing_response_delegate.cc b/content/child/ftp_directory_listing_response_delegate.cc index 73f3914b..dfcfa56 100644 --- a/content/child/ftp_directory_listing_response_delegate.cc +++ b/content/child/ftp_directory_listing_response_delegate.cc
@@ -9,7 +9,7 @@ #include <vector> -#include "base/i18n/icu_encoding_detection.h" +#include "base/i18n/encoding_detection.h" #include "base/i18n/icu_string_conversions.h" #include "base/logging.h" #include "base/strings/string_util.h" @@ -40,7 +40,7 @@ // Try detecting the encoding. The sample is rather small though, so it may // fail. std::string encoding; - if (base::DetectEncoding(path, &encoding) && !encoding.empty()) { + if (base::DetectEncoding(path, &encoding) && encoding != "US-ASCII") { base::string16 path_utf16; if (base::CodepageToUTF16(path, encoding.c_str(), base::OnStringConversionError::SUBSTITUTE,
diff --git a/content/child/process_control_impl.cc b/content/child/process_control_impl.cc deleted file mode 100644 index 2dece52..0000000 --- a/content/child/process_control_impl.cc +++ /dev/null
@@ -1,52 +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 "content/child/process_control_impl.h" - -#include <utility> - -#include "base/bind.h" -#include "base/memory/ptr_util.h" -#include "content/common/mojo/embedded_application_runner.h" -#include "content/public/common/content_client.h" - -namespace content { - -ProcessControlImpl::ProcessControlImpl() { -} - -ProcessControlImpl::~ProcessControlImpl() { -} - -void ProcessControlImpl::LoadApplication( - const mojo::String& name, - shell::mojom::ServiceRequest request, - const LoadApplicationCallback& callback) { - // Only register apps on first run. - if (!has_registered_apps_) { - DCHECK(apps_.empty()); - ApplicationMap apps; - RegisterApplications(&apps); - for (const auto& app : apps) { - std::unique_ptr<EmbeddedApplicationRunner> runner( - new EmbeddedApplicationRunner(app.first, app.second)); - runner->SetQuitClosure(base::Bind(&ProcessControlImpl::OnApplicationQuit, - base::Unretained(this))); - apps_.insert(std::make_pair(app.first, std::move(runner))); - } - has_registered_apps_ = true; - } - - auto it = apps_.find(name); - if (it == apps_.end()) { - callback.Run(false); - OnLoadFailed(); - return; - } - - callback.Run(true); - it->second->BindServiceRequest(std::move(request)); -} - -} // namespace content
diff --git a/content/child/process_control_impl.h b/content/child/process_control_impl.h deleted file mode 100644 index 77320f83..0000000 --- a/content/child/process_control_impl.h +++ /dev/null
@@ -1,49 +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 CONTENT_CHILD_PROCESS_CONTROL_IMPL_H_ -#define CONTENT_CHILD_PROCESS_CONTROL_IMPL_H_ - -#include <map> -#include <memory> - -#include "base/macros.h" -#include "content/common/process_control.mojom.h" -#include "content/public/common/mojo_application_info.h" -#include "services/shell/public/interfaces/service.mojom.h" - -namespace content { - -class EmbeddedApplicationRunner; - -// Default implementation of the mojom::ProcessControl interface. -class ProcessControlImpl : public mojom::ProcessControl { - public: - using ApplicationMap = std::map<std::string, MojoApplicationInfo>; - - ProcessControlImpl(); - ~ProcessControlImpl() override; - - virtual void RegisterApplications(ApplicationMap* apps) = 0; - virtual void OnApplicationQuit() {} - - // ProcessControl: - void LoadApplication(const mojo::String& name, - shell::mojom::ServiceRequest request, - const LoadApplicationCallback& callback) override; - - private: - // Called if a LoadApplication request fails. - virtual void OnLoadFailed() {} - - bool has_registered_apps_ = false; - std::unordered_map<std::string, std::unique_ptr<EmbeddedApplicationRunner>> - apps_; - - DISALLOW_COPY_AND_ASSIGN(ProcessControlImpl); -}; - -} // namespace content - -#endif // CONTENT_CHILD_PROCESS_CONTROL_IMPL_H_
diff --git a/content/child/request_info.cc b/content/child/request_info.cc index 2d69b51d5..b88cf00 100644 --- a/content/child/request_info.cc +++ b/content/child/request_info.cc
@@ -4,6 +4,8 @@ #include "content/child/request_info.h" +#include "base/single_thread_task_runner.h" + namespace content { RequestInfo::RequestInfo() @@ -28,7 +30,6 @@ do_not_prompt_for_login(false), report_raw_headers(false), extra_data(NULL), - loading_web_task_runner(nullptr), lofi_state(LOFI_UNSPECIFIED) {} RequestInfo::~RequestInfo() {}
diff --git a/content/child/request_info.h b/content/child/request_info.h index f7d7339..4f45380 100644 --- a/content/child/request_info.h +++ b/content/child/request_info.h
@@ -11,6 +11,7 @@ #include <string> #include "base/macros.h" +#include "base/memory/ref_counted.h" #include "content/common/content_export.h" #include "content/common/navigation_params.h" #include "content/common/service_worker/service_worker_types.h" @@ -20,14 +21,13 @@ #include "content/public/common/resource_type.h" #include "net/base/request_priority.h" #include "third_party/WebKit/public/platform/WebReferrerPolicy.h" -#include "third_party/WebKit/public/platform/WebTaskRunner.h" #include "third_party/WebKit/public/platform/WebURLRequest.h" #include "url/gurl.h" #include "url/origin.h" -namespace blink { -class WebTaskRunner; -} // namespace blink +namespace base { +class SingleThreadTaskRunner; +} namespace content { @@ -123,7 +123,7 @@ blink::WebURLRequest::ExtraData* extra_data; // Optional, the specific task queue to execute loading tasks on. - std::unique_ptr<blink::WebTaskRunner> loading_web_task_runner; + scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner; // PlzNavigate: the stream URL to request during navigations to get access to // the ResourceBody that has already been fetched by the browser process.
diff --git a/content/child/resource_dispatcher.cc b/content/child/resource_dispatcher.cc index 9c5a47a0..1662cd9 100644 --- a/content/child/resource_dispatcher.cc +++ b/content/child/resource_dispatcher.cc
@@ -591,11 +591,9 @@ std::move(peer), request->resource_type, request->origin_pid, frame_origin, request->url, request_info.download_to_file)); - if (resource_scheduling_filter_.get() && - request_info.loading_web_task_runner) { + if (resource_scheduling_filter_.get() && request_info.loading_task_runner) { resource_scheduling_filter_->SetRequestIdTaskRunner( - request_id, - request_info.loading_web_task_runner->clone()); + request_id, request_info.loading_task_runner); } message_sender_->Send(new ResourceHostMsg_RequestResource(
diff --git a/content/child/resource_scheduling_filter.cc b/content/child/resource_scheduling_filter.cc index 2d53cd0..9621fe4 100644 --- a/content/child/resource_scheduling_filter.cc +++ b/content/child/resource_scheduling_filter.cc
@@ -11,32 +11,9 @@ #include "content/child/resource_dispatcher.h" #include "ipc/ipc_message.h" #include "ipc/ipc_message_start.h" -#include "third_party/WebKit/public/platform/WebTaskRunner.h" -#include "third_party/WebKit/public/platform/WebTraceLocation.h" namespace content { -namespace { -class DispatchMessageTask : public blink::WebTaskRunner::Task { - public: - DispatchMessageTask( - base::WeakPtr<ResourceSchedulingFilter> resource_scheduling_filter, - const IPC::Message& message) - : resource_scheduling_filter_(resource_scheduling_filter), - message_(message) {} - - void run() override { - if (!resource_scheduling_filter_.get()) - return; - resource_scheduling_filter_->DispatchMessage(message_); - } - - private: - base::WeakPtr<ResourceSchedulingFilter> resource_scheduling_filter_; - const IPC::Message message_; -}; -} // namespace - ResourceSchedulingFilter::ResourceSchedulingFilter( const scoped_refptr<base::SingleThreadTaskRunner>& main_thread_task_runner, ResourceDispatcher* resource_dispatcher) @@ -63,25 +40,23 @@ // one, or on the general main_thread_task_runner if there isn't. RequestIdToTaskRunnerMap::const_iterator iter = request_id_to_task_runner_map_.find(request_id); + scoped_refptr<base::SingleThreadTaskRunner> task_runner; if (iter != request_id_to_task_runner_map_.end()) { - // TODO(alexclarke): Find a way to let blink and chromium FROM_HERE coexist. - iter->second->postTask( - BLINK_FROM_HERE, - new DispatchMessageTask(weak_ptr_factory_.GetWeakPtr(), message)); + task_runner = iter->second; } else { - main_thread_task_runner_->PostTask( - FROM_HERE, base::Bind(&ResourceSchedulingFilter::DispatchMessage, - weak_ptr_factory_.GetWeakPtr(), message)); + task_runner = main_thread_task_runner_; } + task_runner->PostTask(FROM_HERE, + base::Bind(&ResourceSchedulingFilter::DispatchMessage, + weak_ptr_factory_.GetWeakPtr(), message)); return true; } void ResourceSchedulingFilter::SetRequestIdTaskRunner( int id, - std::unique_ptr<blink::WebTaskRunner> web_task_runner) { + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) { base::AutoLock lock(request_id_to_task_runner_map_lock_); - request_id_to_task_runner_map_.insert( - std::make_pair(id, std::move(web_task_runner))); + request_id_to_task_runner_map_.insert(std::make_pair(id, task_runner)); } void ResourceSchedulingFilter::ClearRequestIdTaskRunner(int id) {
diff --git a/content/child/resource_scheduling_filter.h b/content/child/resource_scheduling_filter.h index 93d243c9..ddd7ec3 100644 --- a/content/child/resource_scheduling_filter.h +++ b/content/child/resource_scheduling_filter.h
@@ -17,10 +17,6 @@ #include "content/common/content_export.h" #include "ipc/message_filter.h" -namespace blink { -class WebTaskRunner; -} - namespace content { class ResourceDispatcher; @@ -41,7 +37,7 @@ // Sets the task runner associated with request messages with |id|. void SetRequestIdTaskRunner( int id, - std::unique_ptr<blink::WebTaskRunner> web_task_runner); + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner); // Removes the task runner associated with |id|. void ClearRequestIdTaskRunner(int id); @@ -52,7 +48,7 @@ ~ResourceSchedulingFilter() override; using RequestIdToTaskRunnerMap = - std::map<int, std::unique_ptr<blink::WebTaskRunner>>; + std::map<int, scoped_refptr<base::SingleThreadTaskRunner>>; // This lock guards |request_id_to_task_runner_map_| base::Lock request_id_to_task_runner_map_lock_;
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc index 873f2c9d..f9e44a9 100644 --- a/content/child/runtime_features.cc +++ b/content/child/runtime_features.cc
@@ -249,6 +249,9 @@ if (base::FeatureList::IsEnabled(features::kParseHTMLOnMainThread)) WebRuntimeFeatures::enableFeatureFromString("ParseHTMLOnMainThread", true); + if (command_line.HasSwitch(switches::kDisableBackgroundTimerThrottling)) + WebRuntimeFeatures::enableTimerThrottlingForBackgroundTabs(false); + WebRuntimeFeatures::enableRenderingPipelineThrottling( base::FeatureList::IsEnabled(features::kRenderingPipelineThrottling));
diff --git a/content/child/service_factory.cc b/content/child/service_factory.cc new file mode 100644 index 0000000..936d4b7 --- /dev/null +++ b/content/child/service_factory.cc
@@ -0,0 +1,45 @@ +// 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 "content/child/service_factory.h" + +#include <utility> + +#include "base/bind.h" +#include "base/memory/ptr_util.h" +#include "content/common/mojo/embedded_application_runner.h" +#include "content/public/common/content_client.h" + +namespace content { + +ServiceFactory::ServiceFactory() {} +ServiceFactory::~ServiceFactory() {} + +void ServiceFactory::CreateService(shell::mojom::ServiceRequest request, + const mojo::String& name) { + // Only register services on first run. + if (!has_registered_services_) { + DCHECK(services_.empty()); + ServiceMap services; + RegisterServices(&services); + for (const auto& service : services) { + std::unique_ptr<EmbeddedApplicationRunner> runner( + new EmbeddedApplicationRunner(service.first, service.second)); + runner->SetQuitClosure(base::Bind(&ServiceFactory::OnServiceQuit, + base::Unretained(this))); + services_.insert(std::make_pair(service.first, std::move(runner))); + } + has_registered_services_ = true; + } + + auto it = services_.find(name); + if (it == services_.end()) { + OnLoadFailed(); + return; + } + + it->second->BindServiceRequest(std::move(request)); +} + +} // namespace content
diff --git a/content/child/service_factory.h b/content/child/service_factory.h new file mode 100644 index 0000000..1502da22 --- /dev/null +++ b/content/child/service_factory.h
@@ -0,0 +1,49 @@ +// 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 CONTENT_CHILD_SERVICE_FACTORY_H_ +#define CONTENT_CHILD_SERVICE_FACTORY_H_ + +#include <map> +#include <memory> + +#include "base/macros.h" +#include "content/public/common/mojo_application_info.h" +#include "services/shell/public/interfaces/service.mojom.h" +#include "services/shell/public/interfaces/service_factory.mojom.h" + +namespace content { + +class EmbeddedApplicationRunner; + +// Base class for child-process specific implementations of +// shell::mojom::ServiceFactory. +class ServiceFactory : public shell::mojom::ServiceFactory { + public: + using ServiceMap = std::map<std::string, MojoApplicationInfo>; + + ServiceFactory(); + ~ServiceFactory() override; + + virtual void RegisterServices(ServiceMap* services) = 0; + virtual void OnServiceQuit() {} + + // shell::mojom::ServiceFactory: + void CreateService(shell::mojom::ServiceRequest request, + const mojo::String& name) override; + + private: + // Called if CreateService fails to find a registered service. + virtual void OnLoadFailed() {} + + bool has_registered_services_ = false; + std::unordered_map<std::string, std::unique_ptr<EmbeddedApplicationRunner>> + services_; + + DISALLOW_COPY_AND_ASSIGN(ServiceFactory); +}; + +} // namespace content + +#endif // CONTENT_CHILD_SERVICE_FACTORY_H_
diff --git a/content/child/web_url_loader_impl.cc b/content/child/web_url_loader_impl.cc index 24e9015..518feec4 100644 --- a/content/child/web_url_loader_impl.cc +++ b/content/child/web_url_loader_impl.cc
@@ -22,7 +22,6 @@ #include "base/time/time.h" #include "build/build_config.h" #include "components/mime_util/mime_util.h" -#include "components/scheduler/child/web_task_runner_impl.h" #include "content/child/child_thread_impl.h" #include "content/child/ftp_directory_listing_response_delegate.h" #include "content/child/request_extra_data.h" @@ -52,7 +51,7 @@ #include "net/url_request/url_request_data_job.h" #include "third_party/WebKit/public/platform/WebHTTPLoadInfo.h" #include "third_party/WebKit/public/platform/WebSecurityOrigin.h" -#include "third_party/WebKit/public/platform/WebTraceLocation.h" +#include "third_party/WebKit/public/platform/WebTaskRunner.h" #include "third_party/WebKit/public/platform/WebURL.h" #include "third_party/WebKit/public/platform/WebURLError.h" #include "third_party/WebKit/public/platform/WebURLLoadTiming.h" @@ -301,9 +300,7 @@ public: using ReceivedData = RequestPeer::ReceivedData; - Context(WebURLLoaderImpl* loader, - ResourceDispatcher* resource_dispatcher, - std::unique_ptr<blink::WebTaskRunner> task_runner); + Context(WebURLLoaderImpl* loader, ResourceDispatcher* resource_dispatcher); WebURLLoaderClient* client() const { return client_; } void set_client(WebURLLoaderClient* client) { client_ = client; } @@ -314,7 +311,8 @@ int intra_priority_value); void Start(const WebURLRequest& request, SyncLoadResponse* sync_load_response); - void SetWebTaskRunner(std::unique_ptr<blink::WebTaskRunner> task_runner); + void SetTaskRunner( + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner); void OnUploadProgress(uint64_t position, uint64_t size); bool OnReceivedRedirect(const net::RedirectInfo& redirect_info, @@ -334,19 +332,6 @@ friend class base::RefCounted<Context>; ~Context(); - class HandleDataURLTask : public blink::WebTaskRunner::Task { - public: - explicit HandleDataURLTask(scoped_refptr<Context> context) - : context_(context) {} - - void run() override { - context_->HandleDataURL(); - } - - private: - scoped_refptr<Context> context_; - }; - // Called when the body data stream is detached from the reader side. void CancelBodyStreaming(); // We can optimize the handling of data URLs in most cases. @@ -357,7 +342,7 @@ WebURLRequest request_; WebURLLoaderClient* client_; ResourceDispatcher* resource_dispatcher_; - std::unique_ptr<blink::WebTaskRunner> web_task_runner_; + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; WebReferrerPolicy referrer_policy_; std::unique_ptr<FtpDirectoryListingResponseDelegate> ftp_listing_delegate_; std::unique_ptr<StreamOverrideParameters> stream_override_; @@ -396,14 +381,12 @@ // WebURLLoaderImpl::Context -------------------------------------------------- -WebURLLoaderImpl::Context::Context( - WebURLLoaderImpl* loader, - ResourceDispatcher* resource_dispatcher, - std::unique_ptr<blink::WebTaskRunner> web_task_runner) +WebURLLoaderImpl::Context::Context(WebURLLoaderImpl* loader, + ResourceDispatcher* resource_dispatcher) : loader_(loader), client_(NULL), resource_dispatcher_(resource_dispatcher), - web_task_runner_(std::move(web_task_runner)), + task_runner_(base::ThreadTaskRunnerHandle::Get()), referrer_policy_(blink::WebReferrerPolicyDefault), defers_loading_(NOT_DEFERRING), request_id_(-1) {} @@ -437,11 +420,8 @@ defers_loading_ = SHOULD_DEFER; } else if (!value && defers_loading_ != NOT_DEFERRING) { if (defers_loading_ == DEFERRED_DATA) { - // TODO(alexclarke): Find a way to let blink and chromium FROM_HERE - // coexist. - web_task_runner_->postTask( - BLINK_FROM_HERE, - new HandleDataURLTask(this)); + task_runner_->PostTask(FROM_HERE, + base::Bind(&Context::HandleDataURL, this)); } defers_loading_ = NOT_DEFERRING; } @@ -471,11 +451,8 @@ GetInfoFromDataURL(sync_load_response->url, sync_load_response, &sync_load_response->data); } else { - // TODO(alexclarke): Find a way to let blink and chromium FROM_HERE - // coexist. - web_task_runner_->postTask( - BLINK_FROM_HERE, - new HandleDataURLTask(this)); + task_runner_->PostTask(FROM_HERE, + base::Bind(&Context::HandleDataURL, this)); } return; } @@ -546,7 +523,7 @@ GetRequestContextFrameTypeForWebURLRequest(request); request_info.extra_data = request.getExtraData(); request_info.report_raw_headers = request.reportRawHeaders(); - request_info.loading_web_task_runner = web_task_runner_->clone(); + request_info.loading_task_runner = task_runner_; request_info.lofi_state = static_cast<LoFiState>(request.getLoFiState()); scoped_refptr<ResourceRequestBodyImpl> request_body = @@ -579,9 +556,9 @@ resource_dispatcher_->SetDefersLoading(request_id_, true); } -void WebURLLoaderImpl::Context::SetWebTaskRunner( - std::unique_ptr<blink::WebTaskRunner> web_task_runner) { - web_task_runner_ = std::move(web_task_runner); +void WebURLLoaderImpl::Context::SetTaskRunner( + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) { + task_runner_ = task_runner; } void WebURLLoaderImpl::Context::OnUploadProgress(uint64_t position, @@ -944,11 +921,8 @@ // WebURLLoaderImpl ----------------------------------------------------------- -WebURLLoaderImpl::WebURLLoaderImpl( - ResourceDispatcher* resource_dispatcher, - std::unique_ptr<blink::WebTaskRunner> web_task_runner) - : context_( - new Context(this, resource_dispatcher, std::move(web_task_runner))) {} +WebURLLoaderImpl::WebURLLoaderImpl(ResourceDispatcher* resource_dispatcher) + : context_(new Context(this, resource_dispatcher)) {} WebURLLoaderImpl::~WebURLLoaderImpl() { cancel(); @@ -1183,9 +1157,7 @@ void WebURLLoaderImpl::setLoadingTaskRunner( blink::WebTaskRunner* loading_task_runner) { - // There's no guarantee on the lifetime of |loading_task_runner| so we take a - // copy. - context_->SetWebTaskRunner(loading_task_runner->clone()); + context_->SetTaskRunner(loading_task_runner->taskRunner()); } // This function is implemented here because it uses net functions. it is
diff --git a/content/child/web_url_loader_impl.h b/content/child/web_url_loader_impl.h index 97f3d630..79c81ad 100644 --- a/content/child/web_url_loader_impl.h +++ b/content/child/web_url_loader_impl.h
@@ -38,8 +38,7 @@ public: // Takes ownership of |web_task_runner|. - WebURLLoaderImpl(ResourceDispatcher* resource_dispatcher, - std::unique_ptr<blink::WebTaskRunner> web_task_runner); + WebURLLoaderImpl(ResourceDispatcher* resource_dispatcher); ~WebURLLoaderImpl() override; static void PopulateURLResponse(const GURL& url,
diff --git a/content/child/web_url_loader_impl_unittest.cc b/content/child/web_url_loader_impl_unittest.cc index dc4baeb..57ca624 100644 --- a/content/child/web_url_loader_impl_unittest.cc +++ b/content/child/web_url_loader_impl_unittest.cc
@@ -19,9 +19,6 @@ #include "base/single_thread_task_runner.h" #include "base/time/default_tick_clock.h" #include "base/time/time.h" -#include "components/scheduler/child/scheduler_tqm_delegate_impl.h" -#include "components/scheduler/child/web_task_runner_impl.h" -#include "components/scheduler/child/worker_scheduler.h" #include "content/child/request_extra_data.h" #include "content/child/request_info.h" #include "content/child/resource_dispatcher.h" @@ -119,11 +116,8 @@ class TestWebURLLoaderClient : public blink::WebURLLoaderClient { public: - TestWebURLLoaderClient(ResourceDispatcher* dispatcher, - scoped_refptr<scheduler::TaskQueue> task_runner) - : loader_(new WebURLLoaderImpl( - dispatcher, - base::WrapUnique(new scheduler::WebTaskRunnerImpl(task_runner)))), + TestWebURLLoaderClient(ResourceDispatcher* dispatcher) + : loader_(new WebURLLoaderImpl(dispatcher)), delete_on_receive_redirect_(false), delete_on_receive_response_(false), delete_on_receive_data_(false), @@ -276,14 +270,8 @@ class WebURLLoaderImplTest : public testing::Test { public: - explicit WebURLLoaderImplTest() - : worker_scheduler_(scheduler::WorkerScheduler::Create( - scheduler::SchedulerTqmDelegateImpl::Create( - &message_loop_, - base::WrapUnique(new base::DefaultTickClock())))) { - worker_scheduler_->Init(); - client_.reset(new TestWebURLLoaderClient( - &dispatcher_, worker_scheduler_->DefaultTaskRunner())); + WebURLLoaderImplTest() { + client_.reset(new TestWebURLLoaderClient(&dispatcher_)); } ~WebURLLoaderImplTest() override {} @@ -373,9 +361,6 @@ private: base::MessageLoop message_loop_; - // WorkerScheduler is needed because WebURLLoaderImpl needs a - // scheduler::TaskQueue. - std::unique_ptr<scheduler::WorkerScheduler> worker_scheduler_; TestResourceDispatcher dispatcher_; std::unique_ptr<TestWebURLLoaderClient> client_; };
diff --git a/content/child/webmessageportchannel_impl.cc b/content/child/webmessageportchannel_impl.cc index b2ef7e4..2b4d265a 100644 --- a/content/child/webmessageportchannel_impl.cc +++ b/content/child/webmessageportchannel_impl.cc
@@ -168,9 +168,13 @@ WebMessagePortChannelArray* channels_ptr) { std::unique_ptr<WebMessagePortChannelArray> channels(channels_ptr); if (!main_thread_task_runner_->BelongsToCurrentThread()) { + // Note: we must construct the base::string16 here and pass that. Otherwise, + // the WebString will be passed, leading to references to the StringImpl + // from two threads, which is a data race. main_thread_task_runner_->PostTask( FROM_HERE, base::Bind(&WebMessagePortChannelImpl::SendPostMessage, this, - message, base::Passed(std::move(channels)))); + base::Passed(base::string16(message)), + base::Passed(std::move(channels)))); } else { SendPostMessage(message, std::move(channels)); }
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn index 528dac7c..3078d4d9 100644 --- a/content/common/BUILD.gn +++ b/content/common/BUILD.gn
@@ -241,7 +241,6 @@ "frame.mojom", "image_downloader/image_downloader.mojom", "leveldb_wrapper.mojom", - "process_control.mojom", "render_frame_message_filter.mojom", "render_widget_window_tree_client_factory.mojom", "service_worker/embedded_worker_setup.mojom",
diff --git a/content/common/input/web_input_event_traits.cc b/content/common/input/web_input_event_traits.cc index fd0e1b5..d88d85c 100644 --- a/content/common/input/web_input_event_traits.cc +++ b/content/common/input/web_input_event_traits.cc
@@ -52,11 +52,10 @@ result, "{\n Delta: (%f, %f)\n WheelTicks: (%f, %f)\n Accel: (%f, %f)\n" " ScrollByPage: %d\n HasPreciseScrollingDeltas: %d\n" - " Phase: (%d, %d)\n CanRubberband: (%d, %d)\n}", + " Phase: (%d, %d)", event.deltaX, event.deltaY, event.wheelTicksX, event.wheelTicksY, event.accelerationRatioX, event.accelerationRatioY, event.scrollByPage, - event.hasPreciseScrollingDeltas, event.phase, event.momentumPhase, - event.canRubberbandLeft, event.canRubberbandRight); + event.hasPreciseScrollingDeltas, event.phase, event.momentumPhase); } void ApppendEventDetails(const WebGestureEvent& event, std::string* result) {
diff --git a/content/common/input_messages.h b/content/common/input_messages.h index 4d3c0ce..5ca7f71 100644 --- a/content/common/input_messages.h +++ b/content/common/input_messages.h
@@ -262,6 +262,11 @@ IPC_MESSAGE_ROUTED0(InputMsg_RequestTextInputStateUpdate) #endif +// Request from browser to update the cursor and composition information. +IPC_MESSAGE_ROUTED2(InputMsg_RequestCompositionUpdate, + bool /* immediate request */, + bool /* monitor request */) + IPC_MESSAGE_ROUTED0(InputMsg_SyntheticGestureCompleted) // -----------------------------------------------------------------------------
diff --git a/content/common/manifest_util_unittest.cc b/content/common/manifest_util_unittest.cc new file mode 100644 index 0000000..b4f1a0c --- /dev/null +++ b/content/common/manifest_util_unittest.cc
@@ -0,0 +1,77 @@ +// 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 "content/public/common/manifest_util.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +namespace content { + +TEST(ManifestUtilTest, WebDisplayModeConversions) { + struct ReversibleConversion { + blink::WebDisplayMode display_mode; + std::string lowercase_display_mode_string; + } reversible_conversions[] = { + {blink::WebDisplayModeUndefined, ""}, + {blink::WebDisplayModeBrowser, "browser"}, + {blink::WebDisplayModeMinimalUi, "minimal-ui"}, + {blink::WebDisplayModeStandalone, "standalone"}, + {blink::WebDisplayModeFullscreen, "fullscreen"}, + }; + + for (const ReversibleConversion& conversion : reversible_conversions) { + EXPECT_EQ( + conversion.display_mode, + WebDisplayModeFromString(conversion.lowercase_display_mode_string)); + EXPECT_EQ(conversion.lowercase_display_mode_string, + WebDisplayModeToString(conversion.display_mode)); + } + + // WebDisplayModeFromString() should work with non-lowercase strings. + EXPECT_EQ(blink::WebDisplayModeFullscreen, + WebDisplayModeFromString("Fullscreen")); + + // WebDisplayModeFromString() should return + // blink::WebDisplayModeUndefined if the string isn't known. + EXPECT_EQ(blink::WebDisplayModeUndefined, + WebDisplayModeFromString("random")); +} + +TEST(ManifestUtilTest, WebScreenOrientationLockTypeConversions) { + struct ReversibleConversion { + blink::WebScreenOrientationLockType orientation; + std::string lowercase_orientation_string; + } reversible_conversions[] = { + {blink::WebScreenOrientationLockDefault, ""}, + {blink::WebScreenOrientationLockPortraitPrimary, "portrait-primary"}, + {blink::WebScreenOrientationLockPortraitSecondary, "portrait-secondary"}, + {blink::WebScreenOrientationLockLandscapePrimary, "landscape-primary"}, + {blink::WebScreenOrientationLockLandscapeSecondary, + "landscape-secondary"}, + {blink::WebScreenOrientationLockAny, "any"}, + {blink::WebScreenOrientationLockLandscape, "landscape"}, + {blink::WebScreenOrientationLockPortrait, "portrait"}, + {blink::WebScreenOrientationLockNatural, "natural"}, + }; + + for (const ReversibleConversion& conversion : reversible_conversions) { + EXPECT_EQ(conversion.orientation, + WebScreenOrientationLockTypeFromString( + conversion.lowercase_orientation_string)); + EXPECT_EQ(conversion.lowercase_orientation_string, + WebScreenOrientationLockTypeToString(conversion.orientation)); + } + + // WebScreenOrientationLockTypeFromString() should work with non-lowercase + // strings. + EXPECT_EQ(blink::WebScreenOrientationLockNatural, + WebScreenOrientationLockTypeFromString("Natural")); + + // WebScreenOrientationLockTypeFromString() should return + // blink::WebScreenOrientationLockDefault if the string isn't known. + EXPECT_EQ(blink::WebScreenOrientationLockDefault, + WebScreenOrientationLockTypeFromString("random")); +} + +} // namespace content
diff --git a/content/common/net/url_fetcher.cc b/content/common/net/url_fetcher.cc index 90a664c..f4bf457 100644 --- a/content/common/net/url_fetcher.cc +++ b/content/common/net/url_fetcher.cc
@@ -12,10 +12,9 @@ namespace { -base::SupportsUserData::Data* CreateURLRequestUserData( - int render_process_id, - int render_view_id) { - return new URLRequestUserData(render_process_id, render_view_id); +base::SupportsUserData::Data* CreateURLRequestUserData(int render_process_id, + int render_frame_id) { + return new URLRequestUserData(render_process_id, render_frame_id); } } // namespace
diff --git a/content/common/origin_trials/trial_token_unittest.cc b/content/common/origin_trials/trial_token_unittest.cc index 784cd938..3c88134d 100644 --- a/content/common/origin_trials/trial_token_unittest.cc +++ b/content/common/origin_trials/trial_token_unittest.cc
@@ -28,6 +28,13 @@ // 0x10, 0xac, 0xf9, 0x3a, 0x1c, 0xb8, 0xa9, 0x28, 0x70, 0xd2, 0x9a, // 0xd0, 0x0b, 0x59, 0xe1, 0xac, 0x2b, 0xb7, 0xd5, 0xca, 0x1f, 0x64, // 0x90, 0x08, 0x8e, 0xa8, 0xe0, 0x56, 0x3a, 0x04, 0xd0 +// +// This private key can also be found in tools/origin_trials/eftest.key in +// binary form. Please update that if changing the key. +// +// To use this with a real browser, use --origin-trial-public-key with the +// public key, base-64-encoded: +// --origin-trial-public-key=dRCs+TocuKkocNKa0AtZ4awrt9XKH2SQCI6o4FY6BNA= const uint8_t kTestPublicKey[] = { 0x75, 0x10, 0xac, 0xf9, 0x3a, 0x1c, 0xb8, 0xa9, 0x28, 0x70, 0xd2, 0x9a, 0xd0, 0x0b, 0x59, 0xe1, 0xac, 0x2b, 0xb7, 0xd5, 0xca, 0x1f,
diff --git a/content/common/process_control.mojom b/content/common/process_control.mojom deleted file mode 100644 index d7b883282..0000000 --- a/content/common/process_control.mojom +++ /dev/null
@@ -1,13 +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. - -module content.mojom; - -import "services/shell/public/interfaces/service.mojom"; - -interface ProcessControl { - LoadApplication(string url, - shell.mojom.Service& request) => (bool success); -}; -
diff --git a/content/common/render_frame_message_filter.mojom b/content/common/render_frame_message_filter.mojom index 279a12d..5bbf05e 100644 --- a/content/common/render_frame_message_filter.mojom +++ b/content/common/render_frame_message_filter.mojom
@@ -17,8 +17,4 @@ [Sync] GetCookies(int32 render_frame_id, url.mojom.Url url, url.mojom.Url first_party_for_cookies) => (string cookies); - - // Retrieves the zoom level for the given URL. - GetHostZoomLevel(int32 render_frame_id, url.mojom.Url url) - => (double zoom_level); };
diff --git a/content/common/view_messages.h b/content/common/view_messages.h index 02896b3..562ec44 100644 --- a/content/common/view_messages.h +++ b/content/common/view_messages.h
@@ -623,6 +623,13 @@ IPC_MESSAGE_ROUTED1(ViewMsg_Zoom, content::PageZoom /* function */) +// Set the zoom level for a particular url that the renderer is in the +// process of loading. This will be stored, to be used if the load commits +// and ignored otherwise. +IPC_MESSAGE_ROUTED2(ViewMsg_SetZoomLevelForLoadingURL, + GURL /* url */, + double /* zoom_level */) + // Change encoding of page in the renderer. IPC_MESSAGE_ROUTED1(ViewMsg_SetPageEncoding, std::string /*new encoding name*/)
diff --git a/content/content_browser.gypi b/content/content_browser.gypi index 2e09e241..aa88064 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi
@@ -12,7 +12,6 @@ '../components/leveldb/leveldb.gyp:leveldb_lib', '../components/link_header_util/link_header_util.gyp:link_header_util', '../components/mime_util/mime_util.gyp:mime_util', - '../components/scheduler/scheduler.gyp:scheduler_common', '../components/url_formatter/url_formatter.gyp:url_formatter', '../crypto/crypto.gyp:crypto', '../device/battery/battery.gyp:device_battery',
diff --git a/content/content_child.gypi b/content/content_child.gypi index 0b6b6c4..742c8cb 100644 --- a/content/content_child.gypi +++ b/content/content_child.gypi
@@ -5,7 +5,6 @@ 'dependencies': [ '../base/base.gyp:base', '../components/mime_util/mime_util.gyp:mime_util', - '../components/scheduler/scheduler.gyp:scheduler', '../components/tracing.gyp:tracing', '../components/webcrypto/webcrypto.gyp:webcrypto', '../ipc/ipc.gyp:ipc', @@ -138,8 +137,6 @@ 'child/notifications/notification_manager.h', 'child/power_monitor_broadcast_source.cc', 'child/power_monitor_broadcast_source.h', - 'child/process_control_impl.cc', - 'child/process_control_impl.h', 'child/push_messaging/push_dispatcher.cc', 'child/push_messaging/push_dispatcher.h', 'child/push_messaging/push_provider.cc', @@ -161,6 +158,8 @@ 'child/scoped_child_process_reference.cc', 'child/scoped_child_process_reference.h', 'child/scoped_web_callbacks.h', + 'child/service_factory.cc', + 'child/service_factory.h', 'child/service_worker/service_worker_dispatcher.cc', 'child/service_worker/service_worker_dispatcher.h', 'child/service_worker/service_worker_handle_reference.cc',
diff --git a/content/content_common.gypi b/content/content_common.gypi index c16e64a..61bc47a 100644 --- a/content/content_common.gypi +++ b/content/content_common.gypi
@@ -146,6 +146,8 @@ 'public/common/main_function_params.h', 'public/common/manifest.cc', 'public/common/manifest.h', + 'public/common/manifest_util.cc', + 'public/common/manifest_util.h', 'public/common/media_metadata.cc', 'public/common/media_metadata.h', 'public/common/media_stream_request.cc',
diff --git a/content/content_gpu.gypi b/content/content_gpu.gypi index 512bbe60..c88c1447 100644 --- a/content/content_gpu.gypi +++ b/content/content_gpu.gypi
@@ -21,8 +21,8 @@ 'gpu/gpu_main.cc', 'gpu/gpu_process.cc', 'gpu/gpu_process.h', - 'gpu/gpu_process_control_impl.cc', - 'gpu/gpu_process_control_impl.h', + 'gpu/gpu_service_factory.cc', + 'gpu/gpu_service_factory.h', 'gpu/gpu_watchdog_thread.cc', 'gpu/gpu_watchdog_thread.h', 'gpu/in_process_gpu_thread.cc',
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi index a210e3e..7b0a7d7 100644 --- a/content/content_renderer.gypi +++ b/content/content_renderer.gypi
@@ -10,7 +10,6 @@ '../cc/cc.gyp:cc_proto', '../cc/blink/cc_blink.gyp:cc_blink', '../components/components.gyp:memory_coordinator_child', - '../components/scheduler/scheduler.gyp:scheduler', '../components/url_formatter/url_formatter.gyp:url_formatter', '../device/battery/battery.gyp:device_battery', '../device/battery/battery.gyp:device_battery_mojo_bindings',
diff --git a/content/content_tests.gypi b/content/content_tests.gypi index 7351061..13c9e9f 100644 --- a/content/content_tests.gypi +++ b/content/content_tests.gypi
@@ -113,8 +113,6 @@ 'test/fake_compositor_dependencies.h', 'test/fake_plugin_service.cc', 'test/fake_plugin_service.h', - 'test/fake_renderer_scheduler.cc', - 'test/fake_renderer_scheduler.h', 'test/mock_background_sync_controller.cc', 'test/mock_background_sync_controller.h', 'test/mock_google_streaming_server.cc', @@ -690,6 +688,7 @@ 'common/inter_process_time_ticks_converter_unittest.cc', 'common/mac/attributed_string_coder_unittest.mm', 'common/mac/font_descriptor_unittest.mm', + 'common/manifest_util_unittest.cc', 'common/navigation_params_unittest.cc', 'common/one_writer_seqlock_unittest.cc', 'common/origin_trials/trial_token_unittest.cc', @@ -846,8 +845,6 @@ '../cc/ipc/cc_ipc.gyp:cc_ipc', '../cc/cc_tests.gyp:cc_test_support', '../components/components.gyp:display_compositor', - '../components/scheduler/scheduler.gyp:scheduler', - '../components/scheduler/scheduler.gyp:scheduler_test_support', '../device/gamepad/gamepad.gyp:device_gamepad', '../gpu/gpu.gyp:gpu_ipc_common', '../gpu/gpu.gyp:gpu_ipc_service_test_support', @@ -1013,7 +1010,6 @@ 'content.gyp:content_renderer', '../device/nfc/nfc.gyp:device_nfc_mojo_bindings', 'test_support_content', - '../components/scheduler/scheduler.gyp:scheduler_test_support', '../components/test_runner/test_runner.gyp:test_runner', '../skia/skia.gyp:skia', '../ui/accessibility/accessibility.gyp:ax_gen',
diff --git a/content/content_utility.gypi b/content/content_utility.gypi index 13f77149..abd8b75 100644 --- a/content/content_utility.gypi +++ b/content/content_utility.gypi
@@ -19,12 +19,10 @@ 'utility/utility_blink_platform_impl.cc', 'utility/utility_blink_platform_impl.h', 'utility/utility_main.cc', - 'utility/utility_process_control_impl.cc', - 'utility/utility_process_control_impl.h', + 'utility/utility_service_factory.cc', + 'utility/utility_service_factory.h', 'utility/utility_thread_impl.cc', 'utility/utility_thread_impl.h', - 'utility/webthread_impl_for_utility_thread.cc', - 'utility/webthread_impl_for_utility_thread.h', ], 'public_utility_sources': [ 'public/utility/content_utility_client.cc',
diff --git a/content/gpu/BUILD.gn b/content/gpu/BUILD.gn index 597b4cd5..b07607cb 100644 --- a/content/gpu/BUILD.gn +++ b/content/gpu/BUILD.gn
@@ -36,8 +36,8 @@ "gpu_main.cc", "gpu_process.cc", "gpu_process.h", - "gpu_process_control_impl.cc", - "gpu_process_control_impl.h", + "gpu_service_factory.cc", + "gpu_service_factory.h", "gpu_watchdog_thread.cc", "gpu_watchdog_thread.h", "in_process_gpu_thread.cc",
diff --git a/content/gpu/gpu_child_thread.cc b/content/gpu/gpu_child_thread.cc index b3d9ba03..2b7adb3 100644 --- a/content/gpu/gpu_child_thread.cc +++ b/content/gpu/gpu_child_thread.cc
@@ -18,7 +18,7 @@ #include "content/child/thread_safe_sender.h" #include "content/common/establish_channel_params.h" #include "content/common/gpu_host_messages.h" -#include "content/gpu/gpu_process_control_impl.h" +#include "content/gpu/gpu_service_factory.h" #include "content/gpu/gpu_watchdog_thread.h" #include "content/public/common/content_client.h" #include "content/public/common/content_switches.h" @@ -385,10 +385,10 @@ #endif // Only set once per process instance. - process_control_.reset(new GpuProcessControlImpl()); + service_factory_.reset(new GpuServiceFactory); GetInterfaceRegistry()->AddInterface(base::Bind( - &GpuChildThread::BindProcessControlRequest, base::Unretained(this))); + &GpuChildThread::BindServiceFactoryRequest, base::Unretained(this))); if (GetContentClient()->gpu()) { // NULL in tests. GetContentClient()->gpu()->ExposeInterfacesToBrowser( @@ -554,11 +554,11 @@ } } -void GpuChildThread::BindProcessControlRequest( - mojom::ProcessControlRequest request) { - DVLOG(1) << "GPU: Binding ProcessControl request"; - DCHECK(process_control_); - process_control_bindings_.AddBinding(process_control_.get(), +void GpuChildThread::BindServiceFactoryRequest( + shell::mojom::ServiceFactoryRequest request) { + DVLOG(1) << "GPU: Binding shell::mojom::ServiceFactoryRequest"; + DCHECK(service_factory_); + service_factory_bindings_.AddBinding(service_factory_.get(), std::move(request)); }
diff --git a/content/gpu/gpu_child_thread.h b/content/gpu/gpu_child_thread.h index 8d10a63..853972b 100644 --- a/content/gpu/gpu_child_thread.h +++ b/content/gpu/gpu_child_thread.h
@@ -19,7 +19,6 @@ #include "base/time/time.h" #include "build/build_config.h" #include "content/child/child_thread_impl.h" -#include "content/common/process_control.mojom.h" #include "gpu/command_buffer/service/gpu_preferences.h" #include "gpu/config/gpu_info.h" #include "gpu/ipc/service/gpu_channel.h" @@ -28,6 +27,7 @@ #include "gpu/ipc/service/gpu_config.h" #include "gpu/ipc/service/x_util.h" #include "mojo/public/cpp/bindings/binding_set.h" +#include "services/shell/public/interfaces/service_factory.mojom.h" #include "ui/gfx/native_widget_types.h" namespace gpu { @@ -44,7 +44,7 @@ } namespace content { -class GpuProcessControlImpl; +class GpuServiceFactory; class GpuWatchdogThread; struct EstablishChannelParams; @@ -130,7 +130,7 @@ #endif void OnLoseAllContexts(); - void BindProcessControlRequest(mojom::ProcessControlRequest request); + void BindServiceFactoryRequest(shell::mojom::ServiceFactoryRequest request); gpu::GpuPreferences gpu_preferences_; @@ -164,11 +164,11 @@ // The gpu::GpuMemoryBufferFactory instance used to allocate GpuMemoryBuffers. gpu::GpuMemoryBufferFactory* const gpu_memory_buffer_factory_; - // Process control for Mojo application hosting. - std::unique_ptr<GpuProcessControlImpl> process_control_; + // ServiceFactory for shell::Service hosting. + std::unique_ptr<GpuServiceFactory> service_factory_; - // Bindings to the mojom::ProcessControl impl. - mojo::BindingSet<mojom::ProcessControl> process_control_bindings_; + // Bindings to the shell::mojom::ServiceFactory impl. + mojo::BindingSet<shell::mojom::ServiceFactory> service_factory_bindings_; DISALLOW_COPY_AND_ASSIGN(GpuChildThread); };
diff --git a/content/gpu/gpu_process_control_impl.cc b/content/gpu/gpu_process_control_impl.cc deleted file mode 100644 index 9ec00e1..0000000 --- a/content/gpu/gpu_process_control_impl.cc +++ /dev/null
@@ -1,28 +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 "content/gpu/gpu_process_control_impl.h" - -#if defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "media/mojo/services/mojo_media_application_factory.h" // nogncheck -#endif - -namespace content { - -GpuProcessControlImpl::GpuProcessControlImpl() {} - -GpuProcessControlImpl::~GpuProcessControlImpl() {} - -void GpuProcessControlImpl::RegisterApplications(ApplicationMap* apps) { -#if defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) - MojoApplicationInfo app_info; - app_info.application_factory = base::Bind(&media::CreateMojoMediaApplication); - app_info.use_own_thread = true; - apps->insert(std::make_pair("mojo:media", app_info)); -#endif -} - -} // namespace content
diff --git a/content/gpu/gpu_process_control_impl.h b/content/gpu/gpu_process_control_impl.h deleted file mode 100644 index 1f85b31..0000000 --- a/content/gpu/gpu_process_control_impl.h +++ /dev/null
@@ -1,28 +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 CONTENT_GPU_GPU_PROCESS_CONTROL_IMPL_H_ -#define CONTENT_GPU_GPU_PROCESS_CONTROL_IMPL_H_ - -#include "base/macros.h" -#include "content/child/process_control_impl.h" - -namespace content { - -// Customization of ProcessControlImpl for the GPU process. -class GpuProcessControlImpl : public ProcessControlImpl { - public: - GpuProcessControlImpl(); - ~GpuProcessControlImpl() override; - - // ProcessControlImpl: - void RegisterApplications(ApplicationMap* apps) override; - - private: - DISALLOW_COPY_AND_ASSIGN(GpuProcessControlImpl); -}; - -} // namespace content - -#endif // CONTENT_GPU_GPU_PROCESS_CONTROL_IMPL_H_
diff --git a/content/gpu/gpu_service_factory.cc b/content/gpu/gpu_service_factory.cc new file mode 100644 index 0000000..64dd47b1 --- /dev/null +++ b/content/gpu/gpu_service_factory.cc
@@ -0,0 +1,29 @@ +// 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 "content/gpu/gpu_service_factory.h" + +#if defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "media/mojo/services/mojo_media_application_factory.h" // nogncheck +#endif + +namespace content { + +GpuServiceFactory::GpuServiceFactory() {} + +GpuServiceFactory::~GpuServiceFactory() {} + +void GpuServiceFactory::RegisterServices(ServiceMap* services) { +#if defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) + MojoApplicationInfo service_info; + service_info.application_factory = + base::Bind(&media::CreateMojoMediaApplication); + service_info.use_own_thread = true; + services->insert(std::make_pair("mojo:media", service_info)); +#endif +} + +} // namespace content
diff --git a/content/gpu/gpu_service_factory.h b/content/gpu/gpu_service_factory.h new file mode 100644 index 0000000..5d5d797f --- /dev/null +++ b/content/gpu/gpu_service_factory.h
@@ -0,0 +1,28 @@ +// 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 CONTENT_GPU_GPU_SERVICE_FACTORY_H_ +#define CONTENT_GPU_GPU_SERVICE_FACTORY_H_ + +#include "base/macros.h" +#include "content/child/service_factory.h" + +namespace content { + +// Customization of ServiceFactory for the GPU process. +class GpuServiceFactory : public ServiceFactory { + public: + GpuServiceFactory(); + ~GpuServiceFactory() override; + + // ServiceFactory overrides: + void RegisterServices(ServiceMap* services) override; + + private: + DISALLOW_COPY_AND_ASSIGN(GpuServiceFactory); +}; + +} // namespace content + +#endif // CONTENT_GPU_GPU_SERVICE_FACTORY_H_
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/CursorAnchorInfoController.java b/content/public/android/java/src/org/chromium/content/browser/input/CursorAnchorInfoController.java index 443e7d2..718db16 100644 --- a/content/public/android/java/src/org/chromium/content/browser/input/CursorAnchorInfoController.java +++ b/content/public/android/java/src/org/chromium/content/browser/input/CursorAnchorInfoController.java
@@ -9,7 +9,6 @@ import android.os.Build; import android.view.View; import android.view.inputmethod.CursorAnchorInfo; -import android.view.inputmethod.InputConnection; import org.chromium.base.VisibleForTesting; import org.chromium.base.annotations.SuppressFBWarnings; @@ -129,13 +128,17 @@ /** * Sets positional information of composing text as an array of character bounds. * @param compositionCharacterBounds Array of character bounds in local coordinates. + * @param view The attached view. */ - public void setCompositionCharacterBounds(float[] compositionCharacterBounds) { + public void setCompositionCharacterBounds(float[] compositionCharacterBounds, View view) { if (!mIsEditable) return; if (!Arrays.equals(compositionCharacterBounds, mCompositionCharacterBounds)) { mLastCursorAnchorInfo = null; mCompositionCharacterBounds = compositionCharacterBounds; + if (mHasCoordinateInfo) { + updateCursorAnchorInfo(view); + } } } @@ -198,14 +201,6 @@ } } - /** - * Resets the current state on update monitoring mode to the default (= do nothing.) - */ - public void resetMonitoringState() { - mMonitorModeEnabled = false; - mHasPendingImmediateRequest = false; - } - public void focusedNodeChanged(boolean isEditable) { mIsEditable = isEditable; mCompositionCharacterBounds = null; @@ -213,11 +208,18 @@ mLastCursorAnchorInfo = null; } - public boolean onRequestCursorUpdates(int cursorUpdateMode, View view) { + public boolean onRequestCursorUpdates(boolean immediateRequest, boolean monitorRequest, + View view) { if (!mIsEditable) return false; - mMonitorModeEnabled = (cursorUpdateMode & InputConnection.CURSOR_UPDATE_MONITOR) != 0; - if ((cursorUpdateMode & InputConnection.CURSOR_UPDATE_IMMEDIATE) != 0) { + if (mMonitorModeEnabled && !monitorRequest) { + // Invalidate saved cursor anchor info if monitor request is cancelled since no longer + // new values will be arrived from renderer and immediate request may return too old + // position. + invalidateLastCursorAnchorInfo(); + } + mMonitorModeEnabled = monitorRequest; + if (immediateRequest) { mHasPendingImmediateRequest = true; updateCursorAnchorInfo(view); }
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java index 8c1ae7a..ade6398b 100644 --- a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java +++ b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java
@@ -18,6 +18,7 @@ import android.view.View; import android.view.inputmethod.BaseInputConnection; import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputConnection; import org.chromium.base.Log; import org.chromium.base.VisibleForTesting; @@ -192,8 +193,15 @@ mViewEmbedder.getAttachedView(), this, mTextInputType, mTextInputFlags, mLastSelectionStart, mLastSelectionEnd, outAttrs)); if (DEBUG_LOGS) Log.w(TAG, "onCreateInputConnection: " + mInputConnection); + if (mCursorAnchorInfoController != null) { - mCursorAnchorInfoController.resetMonitoringState(); + mCursorAnchorInfoController.onRequestCursorUpdates( + false /* not an immediate request */, false /* disable monitoring */, + mViewEmbedder.getAttachedView()); + } + if (mNativeImeAdapterAndroid != 0) { + nativeRequestCursorUpdate(mNativeImeAdapterAndroid, + false /* not an immediate request */, false /* disable monitoring */); } return mInputConnection; } @@ -674,8 +682,16 @@ * Notified when IME requested Chrome to change the cursor update mode. */ public boolean onRequestCursorUpdates(int cursorUpdateMode) { + final boolean immediateRequest = + (cursorUpdateMode & InputConnection.CURSOR_UPDATE_IMMEDIATE) != 0; + final boolean monitorRequest = + (cursorUpdateMode & InputConnection.CURSOR_UPDATE_MONITOR) != 0; + + if (mNativeImeAdapterAndroid != 0) { + nativeRequestCursorUpdate(mNativeImeAdapterAndroid, immediateRequest, monitorRequest); + } if (mCursorAnchorInfoController == null) return false; - return mCursorAnchorInfoController.onRequestCursorUpdates(cursorUpdateMode, + return mCursorAnchorInfoController.onRequestCursorUpdates(immediateRequest, monitorRequest, mViewEmbedder.getAttachedView()); } @@ -731,7 +747,8 @@ @CalledByNative private void setCharacterBounds(float[] characterBounds) { if (mCursorAnchorInfoController == null) return; - mCursorAnchorInfoController.setCompositionCharacterBounds(characterBounds); + mCursorAnchorInfoController.setCompositionCharacterBounds(characterBounds, + mViewEmbedder.getAttachedView()); } @CalledByNative @@ -763,5 +780,7 @@ int before, int after); private native void nativeResetImeAdapter(long nativeImeAdapterAndroid); private native boolean nativeRequestTextInputStateUpdate(long nativeImeAdapterAndroid); + private native void nativeRequestCursorUpdate(long nativeImeAdapterAndroid, + boolean immediateRequest, boolean monitorRequest); private native boolean nativeIsImeThreadEnabled(long nativeImeAdapterAndroid); }
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/ThreadedInputConnectionFactory.java b/content/public/android/java/src/org/chromium/content/browser/input/ThreadedInputConnectionFactory.java index 70269049..ebd95756 100644 --- a/content/public/android/java/src/org/chromium/content/browser/input/ThreadedInputConnectionFactory.java +++ b/content/public/android/java/src/org/chromium/content/browser/input/ThreadedInputConnectionFactory.java
@@ -204,8 +204,8 @@ @VisibleForTesting protected void onRegisterProxyViewFailed() { + Log.w(TAG, "onRegisterProxyViewFailed"); mInputMethodUma.recordProxyViewFailure(); - throw new AssertionError("Failed to register proxy view"); } @Override
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/AddressDetectionTest.java b/content/public/android/javatests/src/org/chromium/content/browser/AddressDetectionTest.java index efc8f18..cdb2c539 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/AddressDetectionTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/AddressDetectionTest.java
@@ -26,6 +26,7 @@ public void testMultipleAddressesInText() throws Throwable { startActivityWithTestUrl( "content/test/data/android/content_detection/geo_address_multiple.html"); + assertWaitForPageScaleFactorMatch(1.0f); assertTrue(isExpectedGeoIntent(scrollAndTapExpectingIntent("test1"), "1600 Amphitheatre Parkway Mountain View, CA 94043")); @@ -39,6 +40,7 @@ public void testSplitAddresses() throws Throwable { startActivityWithTestUrl( "content/test/data/android/content_detection/geo_address_split.html"); + assertWaitForPageScaleFactorMatch(1.0f); assertTrue(isExpectedGeoIntent(scrollAndTapExpectingIntent("test1"), "9606 North MoPac Expressway Suite 400 Austin, TX 78759")); @@ -58,6 +60,7 @@ public void testAddressLimits() throws Throwable { startActivityWithTestUrl( "content/test/data/android/content_detection/geo_address_limits.html"); + assertWaitForPageScaleFactorMatch(1.0f); assertTrue(isExpectedGeoIntent(scrollAndTapExpectingIntent("test1"), "2590 Pearl Street Suite 100 Boulder, CO 80302")); @@ -77,6 +80,7 @@ public void testRealAddresses() throws Throwable { startActivityWithTestUrl( "content/test/data/android/content_detection/geo_address_real.html"); + assertWaitForPageScaleFactorMatch(1.0f); assertTrue(isExpectedGeoIntent(scrollAndTapExpectingIntent("test1"), "57th Street and Lake Shore Drive Chicago, IL 60637")); @@ -96,6 +100,7 @@ public void testSpecialChars() throws Throwable { startActivityWithTestUrl( "content/test/data/android/content_detection/geo_address_special_chars.html"); + assertWaitForPageScaleFactorMatch(1.0f); assertTrue(isExpectedGeoIntent(scrollAndTapExpectingIntent("test1"), "100 34th Avenue , San Francisco, CA 94121"));
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ClickListenerTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ClickListenerTest.java index 6d9e8079..2c57e814 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/ClickListenerTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/ClickListenerTest.java
@@ -18,6 +18,7 @@ public void testClickContentOnLink() throws Throwable { startActivityWithTestUrl( "content/test/data/android/content_detection/click_listeners.html"); + assertWaitForPageScaleFactorMatch(1.0f); // Clicks on addresses in links should change the url. scrollAndTapNavigatingOut("linktest"); @@ -29,6 +30,7 @@ public void testClickContentOnJSListener1() throws Throwable { startActivityWithTestUrl( "content/test/data/android/content_detection/click_listeners.html"); + assertWaitForPageScaleFactorMatch(1.0f); // Clicks on addresses in elements listening to click events should be // processed normally without address detection. @@ -41,6 +43,7 @@ public void testClickContentOnJSListener2() throws Throwable { startActivityWithTestUrl( "content/test/data/android/content_detection/click_listeners.html"); + assertWaitForPageScaleFactorMatch(1.0f); // Same as previous test, but using addEventListener instead of onclick. scrollAndTapNavigatingOut("clicktest2");
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java index 715c30a..5499a4f 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java
@@ -50,6 +50,7 @@ waitForActiveShellToBeDoneLoading(); mContentViewCore = getContentViewCore(); + assertWaitForPageScaleFactorMatch(1.1f); waitForSelectActionBarVisible(false); waitForPastePopupStatus(false); }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewScrollingTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewScrollingTest.java index d5fbd4d..d20e507 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewScrollingTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewScrollingTest.java
@@ -155,6 +155,7 @@ launchContentShellWithUrl(LARGE_PAGE); waitForActiveShellToBeDoneLoading(); + assertWaitForPageScaleFactorMatch(2.0f); assertEquals(0, getContentViewCore().getNativeScrollXForTest()); assertEquals(0, getContentViewCore().getNativeScrollYForTest());
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewZoomingTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewZoomingTest.java index 26dff8fb..a8708e32 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewZoomingTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewZoomingTest.java
@@ -82,6 +82,7 @@ super.setUp(); launchContentShellWithUrl(LARGE_PAGE); waitForActiveShellToBeDoneLoading(); + assertWaitForPageScaleFactorMatch(2.0f); } @SmallTest
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/EmailAddressDetectionTest.java b/content/public/android/javatests/src/org/chromium/content/browser/EmailAddressDetectionTest.java index 11d12d6..95aa5d9 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/EmailAddressDetectionTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/EmailAddressDetectionTest.java
@@ -25,6 +25,7 @@ @Feature({"ContentDetection", "TabContents"}) public void testValidEmailAddresses() throws Throwable { startActivityWithTestUrl("content/test/data/android/content_detection/email.html"); + assertWaitForPageScaleFactorMatch(1.0f); // valid_1: i.want.a.pony@chromium.org. String intentUrl = scrollAndTapExpectingIntent("valid_1");
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/PhoneNumberDetectionTest.java b/content/public/android/javatests/src/org/chromium/content/browser/PhoneNumberDetectionTest.java index af150264..899dda3c 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/PhoneNumberDetectionTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/PhoneNumberDetectionTest.java
@@ -30,6 +30,7 @@ public void testInternationalNumberIntents() throws Throwable { startActivityWithTestUrl( "content/test/data/android/content_detection/phone_international.html"); + assertWaitForPageScaleFactorMatch(1.0f); // US: +1 650-253-0000. String intentUrl = scrollAndTapExpectingIntent("US"); @@ -146,6 +147,7 @@ public void testLocalUSNumbers() throws Throwable { startActivityWithTestUrl( "content/test/data/android/content_detection/phone_local.html"); + assertWaitForPageScaleFactorMatch(1.0f); // US_1: 1-888-433-5788. String intentUrl = scrollAndTapExpectingIntent("US_1"); @@ -170,6 +172,7 @@ public void testLocalUKNumbers() throws Throwable { startActivityWithTestUrl( "content/test/data/android/content_detection/phone_local.html"); + assertWaitForPageScaleFactorMatch(1.0f); // GB_1: (0) 20 7323 8299. String intentUrl = scrollAndTapExpectingIntent("GB_1"); @@ -194,6 +197,7 @@ public void testLocalFRNumbers() throws Throwable { startActivityWithTestUrl( "content/test/data/android/content_detection/phone_local.html"); + assertWaitForPageScaleFactorMatch(1.0f); // FR_1: 01 40 20 50 50. String intentUrl = scrollAndTapExpectingIntent("FR_1");
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/VibrationManagerImplTest.java b/content/public/android/javatests/src/org/chromium/content/browser/VibrationManagerImplTest.java index 72761be..44d71c9 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/VibrationManagerImplTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/VibrationManagerImplTest.java
@@ -7,6 +7,7 @@ import android.os.Vibrator; import android.test.suitebuilder.annotation.MediumTest; +import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.UrlUtils; import org.chromium.content.browser.test.util.Criteria; @@ -74,8 +75,9 @@ * the fake wrapper vibrate() should be called and 3000 milliseconds should be recorded * correctly. */ - @MediumTest - @Feature({"Vibration"}) + // @MediumTest + // @Feature({"Vibration"}) + @DisabledTest public void testVibrate() throws Throwable { loadNewShell(URL_VIBRATOR_VIBRATE);
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/CursorAnchorInfoControllerTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/CursorAnchorInfoControllerTest.java index 768b6bbf..180336a24 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/input/CursorAnchorInfoControllerTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/input/CursorAnchorInfoControllerTest.java
@@ -13,7 +13,6 @@ import android.text.TextUtils; import android.view.View; import android.view.inputmethod.CursorAnchorInfo; -import android.view.inputmethod.InputConnection; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.MinAndroidSdkLevel; @@ -141,10 +140,11 @@ assertFalse( "IC#onRequestCursorUpdates() must be rejected if the focused node is not editable.", - controller.onRequestCursorUpdates(InputConnection.CURSOR_UPDATE_MONITOR, view)); + controller.onRequestCursorUpdates( + false /* immediate request */, true /* monitor request */, view)); // Make sure that the focused node is considered to be non-editable by default. - controller.setCompositionCharacterBounds(new float[] {0.0f, 1.0f, 2.0f, 3.0f}); + controller.setCompositionCharacterBounds(new float[] {0.0f, 1.0f, 2.0f, 3.0f}, view); composingTextDelegate.updateTextAndSelection(controller, "0", 0, 1, 0, 1); controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 0.0f), true, true, 2.0f, 0.0f, 3.0f, view); @@ -155,7 +155,7 @@ // Make sure that the controller does not crash even if it is called while the focused node // is not editable. - controller.setCompositionCharacterBounds(new float[] {30.0f, 1.0f, 32.0f, 3.0f}); + controller.setCompositionCharacterBounds(new float[] {30.0f, 1.0f, 32.0f, 3.0f}, view); composingTextDelegate.updateTextAndSelection(controller, "1", 0, 1, 0, 1); controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 100.0f), true, true, 2.0f, 0.0f, 3.0f, view); @@ -179,9 +179,9 @@ // Make sure that #updateCursorAnchorInfo() is not be called until the matrix info becomes // available with #onUpdateFrameInfo(). - assertTrue(controller.onRequestCursorUpdates(InputConnection.CURSOR_UPDATE_IMMEDIATE, - view)); - controller.setCompositionCharacterBounds(new float[] {0.0f, 1.0f, 2.0f, 3.0f}); + assertTrue(controller.onRequestCursorUpdates( + true /* immediate request */, false /* monitor request */, view)); + controller.setCompositionCharacterBounds(new float[] {0.0f, 1.0f, 2.0f, 3.0f}, view); composingTextDelegate.updateTextAndSelection(controller, "0", 0, 1, 0, 1); assertEquals(0, immw.getUpdateCursorAnchorInfoCounter()); controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 0.0f), @@ -205,8 +205,8 @@ // Make sure that #onUpdateFrameInfo() is immediately called because the matrix info is // already available. - assertTrue(controller.onRequestCursorUpdates(InputConnection.CURSOR_UPDATE_IMMEDIATE, - view)); + assertTrue(controller.onRequestCursorUpdates( + true /* immediate request */, false /* monitor request */, view)); assertEquals(2, immw.getUpdateCursorAnchorInfoCounter()); assertScaleAndTranslate(2.0f, 0.0f, 0.0f, immw.getLastCursorAnchorInfo()); assertHasInsertionMarker(CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION, 2.0f, 0.0f, 3.0f, @@ -222,8 +222,7 @@ // Make sure that CURSOR_UPDATE_IMMEDIATE and CURSOR_UPDATE_MONITOR can be specified at // the same time. assertTrue(controller.onRequestCursorUpdates( - InputConnection.CURSOR_UPDATE_IMMEDIATE | InputConnection.CURSOR_UPDATE_MONITOR, - view)); + true /* immediate request*/, true /* monitor request */, view)); assertEquals(3, immw.getUpdateCursorAnchorInfoCounter()); assertScaleAndTranslate(2.0f, 0.0f, 0.0f, immw.getLastCursorAnchorInfo()); immw.clearLastCursorAnchorInfo(); @@ -246,8 +245,8 @@ controller.focusedNodeChanged(false); controller.focusedNodeChanged(true); composingTextDelegate.clearTextAndSelection(controller); - assertTrue(controller.onRequestCursorUpdates(InputConnection.CURSOR_UPDATE_IMMEDIATE, - view)); + assertTrue(controller.onRequestCursorUpdates( + true /* immediate request */, false /* monitor request */, view)); controller.focusedNodeChanged(false); composingTextDelegate.clearTextAndSelection(controller); controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 100.0f), @@ -257,8 +256,8 @@ // Make sure that CURSOR_UPDATE_IMMEDIATE can be enabled again. controller.focusedNodeChanged(true); composingTextDelegate.clearTextAndSelection(controller); - assertTrue(controller.onRequestCursorUpdates(InputConnection.CURSOR_UPDATE_IMMEDIATE, - view)); + assertTrue(controller.onRequestCursorUpdates( + true /* immediate request */, false /* monitor request */, view)); controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 0.0f), true, true, 2.0f, 0.0f, 3.0f, view); assertEquals(5, immw.getUpdateCursorAnchorInfoCounter()); @@ -289,8 +288,9 @@ // Make sure that #updateCursorAnchorInfo() is not be called until the matrix info becomes // available with #onUpdateFrameInfo(). - assertTrue(controller.onRequestCursorUpdates(InputConnection.CURSOR_UPDATE_MONITOR, view)); - controller.setCompositionCharacterBounds(new float[] {0.0f, 1.0f, 2.0f, 3.0f}); + assertTrue(controller.onRequestCursorUpdates( + false /* immediate request */, true /* monitor request */, view)); + controller.setCompositionCharacterBounds(new float[] {0.0f, 1.0f, 2.0f, 3.0f}, view); composingTextDelegate.updateTextAndSelection(controller, "0", 0, 1, 0, 1); assertEquals(0, immw.getUpdateCursorAnchorInfoCounter()); controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 0.0f), @@ -309,15 +309,15 @@ // Make sure that #updateCursorAnchorInfo() is not be called if any coordinate parameter is // changed for better performance. - controller.setCompositionCharacterBounds(new float[] {0.0f, 1.0f, 2.0f, 3.0f}); + controller.setCompositionCharacterBounds(new float[] {0.0f, 1.0f, 2.0f, 3.0f}, view); controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 0.0f), true, true, 2.0f, 0.0f, 3.0f, view); assertEquals(1, immw.getUpdateCursorAnchorInfoCounter()); // Make sure that #updateCursorAnchorInfo() is called if #setCompositionCharacterBounds() // is called with a different parameter. - controller.setCompositionCharacterBounds(new float[] {30.0f, 1.0f, 32.0f, 3.0f}); - assertEquals(1, immw.getUpdateCursorAnchorInfoCounter()); + controller.setCompositionCharacterBounds(new float[] {30.0f, 1.0f, 32.0f, 3.0f}, view); + assertEquals(2, immw.getUpdateCursorAnchorInfoCounter()); controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 0.0f), true, true, 2.0f, 0.0f, 3.0f, view); assertEquals(2, immw.getUpdateCursorAnchorInfoCounter()); @@ -388,10 +388,11 @@ controller.focusedNodeChanged(false); controller.focusedNodeChanged(true); composingTextDelegate.clearTextAndSelection(controller); - assertTrue(controller.onRequestCursorUpdates(InputConnection.CURSOR_UPDATE_MONITOR, view)); + assertTrue(controller.onRequestCursorUpdates( + false /* immediate request */, true /* monitor request */, view)); controller.focusedNodeChanged(false); composingTextDelegate.clearTextAndSelection(controller); - controller.setCompositionCharacterBounds(new float[] {0.0f, 1.0f, 2.0f, 3.0f}); + controller.setCompositionCharacterBounds(new float[] {0.0f, 1.0f, 2.0f, 3.0f}, view); composingTextDelegate.updateTextAndSelection(controller, "0", 0, 1, 0, 1); controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 0.0f), true, true, 2.0f, 0.0f, 3.0f, view); @@ -400,8 +401,9 @@ // Make sure that CURSOR_UPDATE_MONITOR can be enabled again. controller.focusedNodeChanged(true); composingTextDelegate.clearTextAndSelection(controller); - assertTrue(controller.onRequestCursorUpdates(InputConnection.CURSOR_UPDATE_MONITOR, view)); - controller.setCompositionCharacterBounds(new float[] {0.0f, 1.0f, 2.0f, 3.0f}); + assertTrue(controller.onRequestCursorUpdates( + false /* immediate request */, true /* monitor request */, view)); + controller.setCompositionCharacterBounds(new float[] {0.0f, 1.0f, 2.0f, 3.0f}, view); composingTextDelegate.updateTextAndSelection(controller, "0", 0, 1, 0, 1); assertEquals(5, immw.getUpdateCursorAnchorInfoCounter()); viewDelegate.locationX = 0; @@ -436,11 +438,12 @@ controller.focusedNodeChanged(true); composingTextDelegate.clearTextAndSelection(controller); - assertTrue(controller.onRequestCursorUpdates(InputConnection.CURSOR_UPDATE_MONITOR, view)); + assertTrue(controller.onRequestCursorUpdates( + false /* immediate request */, true /* monitor request */, view)); composingTextDelegate.updateTextAndSelection(controller, "01234", 1, 3, 1, 1); controller.setCompositionCharacterBounds(new float[] {0.0f, 1.0f, 2.0f, 3.0f, - 4.0f, 1.1f, 6.0f, 2.9f}); + 4.0f, 1.1f, 6.0f, 2.9f}, view); controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 0.0f), false, false, Float.NaN, Float.NaN, Float.NaN, view); assertEquals(1, immw.getUpdateCursorAnchorInfoCounter()); @@ -475,7 +478,8 @@ controller.focusedNodeChanged(true); composingTextDelegate.clearTextAndSelection(controller); - assertTrue(controller.onRequestCursorUpdates(InputConnection.CURSOR_UPDATE_MONITOR, view)); + assertTrue(controller.onRequestCursorUpdates( + false /* immediate request */, true /* monitor request */, view)); composingTextDelegate.updateTextAndSelection(controller, "01234", 3, 3, 1, 1); controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 0.0f), @@ -507,7 +511,8 @@ controller.focusedNodeChanged(true); composingTextDelegate.clearTextAndSelection(controller); - assertTrue(controller.onRequestCursorUpdates(InputConnection.CURSOR_UPDATE_MONITOR, view)); + assertTrue(controller.onRequestCursorUpdates( + false /* immediate request */, true /* monitor request */, view)); // Test no insertion marker. controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 0.0f), @@ -545,7 +550,8 @@ controller.focusedNodeChanged(true); composingTextDelegate.clearTextAndSelection(controller); - assertTrue(controller.onRequestCursorUpdates(InputConnection.CURSOR_UPDATE_MONITOR, view)); + assertTrue(controller.onRequestCursorUpdates( + false /* immediate request */, true /* monitor request */, view)); // Test no transformation viewDelegate.locationX = 0;
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeLollipopTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeLollipopTest.java index 159d73a5..b087295 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeLollipopTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeLollipopTest.java
@@ -16,6 +16,8 @@ import org.chromium.content.browser.test.util.Criteria; import org.chromium.content.browser.test.util.CriteriaHelper; +import java.util.concurrent.Callable; + /** * Integration tests for text input for Android L (or above) features. */ @@ -58,14 +60,19 @@ }); requestCursorUpdates(InputConnection.CURSOR_UPDATE_IMMEDIATE); waitForUpdateCursorAnchorInfoComposingText("abcd"); + + setComposingText("abcde", 2); + requestCursorUpdates(InputConnection.CURSOR_UPDATE_IMMEDIATE); + waitForUpdateCursorAnchorInfoComposingText("abcde"); } - private void requestCursorUpdates(final int cursorUpdateMode) { + private void requestCursorUpdates(final int cursorUpdateMode) throws Exception { final InputConnection connection = mConnection; - ThreadUtils.runOnUiThreadBlocking(new Runnable() { + runBlockingOnImeThread(new Callable<Void>() { @Override - public void run() { + public Void call() { connection.requestCursorUpdates(cursorUpdateMode); + return null; } }); }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java index 9bec9495..532d265 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
@@ -139,6 +139,9 @@ assertTextsAroundCursor("he", "", "llo"); } + // When newCursorPosition != 1, setComposingText doesn't work for ReplicaInputConnection + // because there is a bug in BaseInputConnection. + @CommandLineFlags.Add("enable-features=ImeThread") @SmallTest @Feature({"TextInput", "Main"}) public void testSetComposingTextForDifferentnewCursorPositions() throws Throwable { @@ -187,24 +190,6 @@ @SmallTest @Feature({"TextInput", "Main"}) - public void testSetComposingTextWithEmptyText() throws Throwable { - commitText("hello", 1); - waitAndVerifyUpdateSelection(0, 5, 5, -1, -1); - - setComposingText("AB", 1); - waitAndVerifyUpdateSelection(1, 7, 7, 5, 7); - - // With previous composition. - setComposingText("", -3); - waitAndVerifyUpdateSelection(2, 2, 2, -1, -1); - - // Without previous composition. - setComposingText("", 3); - waitAndVerifyUpdateSelection(3, 4, 4, -1, -1); - } - - @SmallTest - @Feature({"TextInput", "Main"}) public void testCommitWhileComposingText() throws Throwable { setComposingText("h", 1); waitAndVerifyUpdateSelection(0, 1, 1, 0, 1); @@ -1505,7 +1490,12 @@ }); } - private <T> T runBlockingOnImeThread(Callable<T> c) throws Exception { + /** + * Run the {@Callable} on IME thread (or UI thread if not applicable). + * @param c The callable + * @return The result from running the callable. + */ + protected <T> T runBlockingOnImeThread(Callable<T> c) throws Exception { return ImeTestUtils.runBlockingOnHandler(mConnectionFactory.getHandler(), c); }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/SelectPopupTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/SelectPopupTest.java index 39f630a9..d0788356 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/input/SelectPopupTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/input/SelectPopupTest.java
@@ -67,6 +67,8 @@ super.setUp(); launchContentShellWithUrl(SELECT_URL); waitForActiveShellToBeDoneLoading(); + // TODO(aurimas) remove this wait once crbug.com/179511 is fixed. + assertWaitForPageScaleFactorMatch(1); } /**
diff --git a/content/public/browser/bluetooth_chooser.h b/content/public/browser/bluetooth_chooser.h index aec3c2f..ea2b4f55 100644 --- a/content/public/browser/bluetooth_chooser.h +++ b/content/public/browser/bluetooth_chooser.h
@@ -68,9 +68,15 @@ enum class DiscoveryState { FAILED_TO_START, DISCOVERING, IDLE }; virtual void ShowDiscoveryState(DiscoveryState state) {} - // Shows a new device in the chooser. - virtual void AddDevice(const std::string& device_id, - const base::string16& device_name) {} + // Adds a new device to the chooser or updates the information of an existing + // device. Passing nullptr for |rssi| means that the device doesn't not have + // RSSI which happens when the device is already connected. + virtual void AddOrUpdateDevice(const std::string& device_id, + bool should_update_name, + const base::string16& device_name, + bool is_gatt_connected, + bool is_paired, + const int8_t* rssi) {} // Tells the chooser that a device is no longer available. The chooser should // not call DeviceSelected() for a device that's been removed.
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc index 0b3e019..f742cfa42 100644 --- a/content/public/browser/content_browser_client.cc +++ b/content/public/browser/content_browser_client.cc
@@ -72,12 +72,6 @@ return true; } -bool ContentBrowserClient::IsIllegalOrigin(ResourceContext* resource_context, - int child_process_id, - const GURL& origin) { - return false; -} - bool ContentBrowserClient::ShouldAllowOpenURL(SiteInstance* site_instance, const GURL& url) { return true;
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h index 9bbe5f4..966e17d 100644 --- a/content/public/browser/content_browser_client.h +++ b/content/public/browser/content_browser_client.h
@@ -235,14 +235,6 @@ // This is called on the UI thread. virtual bool CanCommitURL(RenderProcessHost* process_host, const GURL& url); - // Returns true if no URL within |origin| is allowed to commit in the given - // process. Must return false if there exists at least one URL in |origin| - // that is allowed to commit. - // This is called on the IO thread. - virtual bool IsIllegalOrigin(ResourceContext* resource_context, - int child_process_id, - const GURL& origin); - // Returns whether a URL should be allowed to open from a specific context. // This also applies in cases where the new URL will open in another process. virtual bool ShouldAllowOpenURL(SiteInstance* site_instance, const GURL& url);
diff --git a/content/public/browser/render_widget_host_view_mac_delegate.h b/content/public/browser/render_widget_host_view_mac_delegate.h index 427f466f..8e05950 100644 --- a/content/public/browser/render_widget_host_view_mac_delegate.h +++ b/content/public/browser/render_widget_host_view_mac_delegate.h
@@ -51,12 +51,6 @@ - (void)touchesCancelledWithEvent:(NSEvent*)event; - (void)touchesEndedWithEvent:(NSEvent*)event; -// These methods control whether a given view is allowed to rubberband in the -// given direction. This is inversely related to whether the view is allowed to -// 2-finger history swipe in the given direction. -- (BOOL)canRubberbandLeft:(NSView*)view; -- (BOOL)canRubberbandRight:(NSView*)view; - // The browser process received an ACK from the renderer after it processed // |event|. - (void)rendererHandledWheelEvent:(const blink::WebMouseWheelEvent&)event
diff --git a/content/public/browser/resource_dispatcher_host.h b/content/public/browser/resource_dispatcher_host.h index 3bdd0ca..b5159ce0 100644 --- a/content/public/browser/resource_dispatcher_host.h +++ b/content/public/browser/resource_dispatcher_host.h
@@ -8,6 +8,7 @@ #include <stdint.h> #include <memory> +#include <string> #include "base/callback_forward.h" #include "content/common/content_export.h" @@ -25,6 +26,27 @@ struct Referrer; class RenderFrameHost; +// This callback is invoked when the interceptor finishes processing the +// header. +// Parameter 1 is a bool indicating success or failure. +// Parameter 2 contains the error code in case of failure, else 0. +typedef base::Callback<void(bool, int)> OnHeaderProcessedCallback; + +// This callback is registered by interceptors who are interested in being +// notified of certain HTTP headers in outgoing requests. For e.g. Origin. +// Parameter 1 contains the HTTP header. +// Parameter 2 contains its value. +// Parameter 3 contains the child process id. +// Parameter 4 contains the current ResourceContext. +// Parameter 5 contains the callback which needs to be invoked once the +// interceptor finishes its processing. +typedef base::Callback<void(const std::string&, + const std::string&, + int, + ResourceContext*, + OnHeaderProcessedCallback)> + InterceptorCallback; + class CONTENT_EXPORT ResourceDispatcherHost { public: // Returns the singleton instance of the ResourceDispatcherHost. @@ -51,6 +73,17 @@ // Clears the ResourceDispatcherHostLoginDelegate associated with the request. virtual void ClearLoginDelegateForRequest(net::URLRequest* request) = 0; + // Registers the |interceptor| for the |http_header| passed in. + // The |starts_with| parameter is used to match the prefix of the + // |http_header| in the response and the interceptor will be invoked if there + // is a match. If the |starts_with| parameter is empty, the interceptor will + // be invoked for every occurrence of the |http_header|. + // Currently only HTTP header based interceptors are supported. + // At the moment we only support one interceptor per |http_header|. + virtual void RegisterInterceptor(const std::string& http_header, + const std::string& starts_with, + const InterceptorCallback& interceptor) = 0; + protected: virtual ~ResourceDispatcherHost() {} };
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index d2a1f789..272453f4 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -158,7 +158,7 @@ // Use IME's own thread instead of using main UI thread. It also means that // we will not use replica editor and do a round trip to renderer to synchronize // with Blink data. -const base::Feature kImeThread{"ImeThread", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kImeThread{"ImeThread", base::FEATURE_ENABLED_BY_DEFAULT}; // FeatureList definition for the Seccomp field trial. const base::Feature kSeccompSandboxAndroid{"SeccompSandboxAndroid",
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc index f2d8e9a..d94380d 100644 --- a/content/public/common/content_switches.cc +++ b/content/public/common/content_switches.cc
@@ -108,6 +108,10 @@ extern const char kDisableBackgroundingOccludedWindowsForTesting[] = "disable-backgrounding-occluded-windows"; +// Disable task throttling of timer tasks from background pages. +const char kDisableBackgroundTimerThrottling[] = + "disable-background-timer-throttling"; + // Disable one or more Blink runtime-enabled features. // Use names from RuntimeEnabledFeatures.in, separated by commas. // Applied after kEnableBlinkFeatures, and after other flags that change these
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h index 8fa1c47..c94d56a 100644 --- a/content/public/common/content_switches.h +++ b/content/public/common/content_switches.h
@@ -40,6 +40,7 @@ extern const char kDisableBackingStoreLimit[]; CONTENT_EXPORT extern const char kDisableBackgroundingOccludedWindowsForTesting[]; +CONTENT_EXPORT extern const char kDisableBackgroundTimerThrottling[]; CONTENT_EXPORT extern const char kDisableBlinkFeatures[]; CONTENT_EXPORT extern const char kDisableDatabases[]; CONTENT_EXPORT extern const char kDisableDistanceFieldText[];
diff --git a/content/public/common/manifest_util.cc b/content/public/common/manifest_util.cc new file mode 100644 index 0000000..1b4d0a8 --- /dev/null +++ b/content/public/common/manifest_util.cc
@@ -0,0 +1,85 @@ +// 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 "content/public/common/manifest_util.h" + +#include "base/strings/string_util.h" + +namespace content { + +std::string WebDisplayModeToString(blink::WebDisplayMode display) { + switch (display) { + case blink::WebDisplayModeUndefined: + return ""; + case blink::WebDisplayModeBrowser: + return "browser"; + case blink::WebDisplayModeMinimalUi: + return "minimal-ui"; + case blink::WebDisplayModeStandalone: + return "standalone"; + case blink::WebDisplayModeFullscreen: + return "fullscreen"; + } + return ""; +} + +blink::WebDisplayMode WebDisplayModeFromString(const std::string& display) { + if (base::LowerCaseEqualsASCII(display, "browser")) + return blink::WebDisplayModeBrowser; + else if (base::LowerCaseEqualsASCII(display, "minimal-ui")) + return blink::WebDisplayModeMinimalUi; + else if (base::LowerCaseEqualsASCII(display, "standalone")) + return blink::WebDisplayModeStandalone; + else if (base::LowerCaseEqualsASCII(display, "fullscreen")) + return blink::WebDisplayModeFullscreen; + return blink::WebDisplayModeUndefined; +} + +std::string WebScreenOrientationLockTypeToString( + blink::WebScreenOrientationLockType orientation) { + switch (orientation) { + case blink::WebScreenOrientationLockDefault: + return ""; + case blink::WebScreenOrientationLockPortraitPrimary: + return "portrait-primary"; + case blink::WebScreenOrientationLockPortraitSecondary: + return "portrait-secondary"; + case blink::WebScreenOrientationLockLandscapePrimary: + return "landscape-primary"; + case blink::WebScreenOrientationLockLandscapeSecondary: + return "landscape-secondary"; + case blink::WebScreenOrientationLockAny: + return "any"; + case blink::WebScreenOrientationLockLandscape: + return "landscape"; + case blink::WebScreenOrientationLockPortrait: + return "portrait"; + case blink::WebScreenOrientationLockNatural: + return "natural"; + } + return ""; +} + +blink::WebScreenOrientationLockType +WebScreenOrientationLockTypeFromString(const std::string& orientation) { + if (base::LowerCaseEqualsASCII(orientation, "portrait-primary")) + return blink::WebScreenOrientationLockPortraitPrimary; + else if (base::LowerCaseEqualsASCII(orientation, "portrait-secondary")) + return blink::WebScreenOrientationLockPortraitSecondary; + else if (base::LowerCaseEqualsASCII(orientation, "landscape-primary")) + return blink::WebScreenOrientationLockLandscapePrimary; + else if (base::LowerCaseEqualsASCII(orientation, "landscape-secondary")) + return blink::WebScreenOrientationLockLandscapeSecondary; + else if (base::LowerCaseEqualsASCII(orientation, "any")) + return blink::WebScreenOrientationLockAny; + else if (base::LowerCaseEqualsASCII(orientation, "landscape")) + return blink::WebScreenOrientationLockLandscape; + else if (base::LowerCaseEqualsASCII(orientation, "portrait")) + return blink::WebScreenOrientationLockPortrait; + else if (base::LowerCaseEqualsASCII(orientation, "natural")) + return blink::WebScreenOrientationLockNatural; + return blink::WebScreenOrientationLockDefault; +} + +} // namespace content
diff --git a/content/public/common/manifest_util.h b/content/public/common/manifest_util.h new file mode 100644 index 0000000..c40b76d3 --- /dev/null +++ b/content/public/common/manifest_util.h
@@ -0,0 +1,47 @@ +// 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 CONTENT_PUBLIC_COMMON_MANIFEST_UTIL_H_ +#define CONTENT_PUBLIC_COMMON_MANIFEST_UTIL_H_ + +#include <string> + +#include "content/common/content_export.h" +#include "third_party/WebKit/public/platform/WebDisplayMode.h" +#include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h" + +namespace content { + +// Converts a blink::WebDisplayMode to a string. Returns one of +// https://www.w3.org/TR/appmanifest/#dfn-display-modes-values. Return values +// are lowercase. Returns an empty string for blink::WebDisplayModeUndefined. +CONTENT_EXPORT std::string WebDisplayModeToString( + blink::WebDisplayMode display); + +// Returns the blink::WebDisplayMode which matches |display|. +// |display| should be one of +// https://www.w3.org/TR/appmanifest/#dfn-display-modes-values. |display| is +// case insensitive. Returns blink::WebDisplayModeUndefined if there is no +// match. +CONTENT_EXPORT blink::WebDisplayMode WebDisplayModeFromString( + const std::string& display); + +// Converts a blink::WebScreenOrientationLockType to a string. Returns one of +// https://www.w3.org/TR/screen-orientation/#orientationlocktype-enum. Return +// values are lowercase. Returns an empty string for +// blink::WebScreenOrientationLockDefault. +CONTENT_EXPORT std::string WebScreenOrientationLockTypeToString( + blink::WebScreenOrientationLockType); + +// Returns the blink::WebScreenOrientationLockType which matches +// |orientation|. |orientation| should be one of +// https://www.w3.org/TR/screen-orientation/#orientationlocktype-enum. +// |orientation| is case insensitive. Returns +// blink::WebScreenOrientationLockDefault if there is no match. +CONTENT_EXPORT blink::WebScreenOrientationLockType +WebScreenOrientationLockTypeFromString(const std::string& orientation); + +} // namespace content + +#endif // CONTENT_PUBLIC_COMMON_MANIFEST_UTIL_H_
diff --git a/content/public/renderer/content_renderer_client.cc b/content/public/renderer/content_renderer_client.cc index 4ad49c8..b7bafaf 100644 --- a/content/public/renderer/content_renderer_client.cc +++ b/content/public/renderer/content_renderer_client.cc
@@ -7,6 +7,7 @@ #include "content/public/renderer/media_stream_renderer_factory.h" #include "media/base/renderer_factory.h" #include "third_party/WebKit/public/platform/modules/app_banner/WebAppBannerClient.h" +#include "url/gurl.h" namespace content { @@ -228,4 +229,8 @@ return true; } +GURL ContentRendererClient::OverrideFlashEmbedWithHTML(const GURL& url) { + return GURL(); +} + } // namespace content
diff --git a/content/public/renderer/content_renderer_client.h b/content/public/renderer/content_renderer_client.h index 9ad5aef7..b7b042f 100644 --- a/content/public/renderer/content_renderer_client.h +++ b/content/public/renderer/content_renderer_client.h
@@ -359,6 +359,10 @@ // browser process via |registry|. virtual void ExposeInterfacesToBrowser( shell::InterfaceRegistry* interface_registry) {} + + // Overwrites the given URL to use an HTML5 embed if possible. + // An empty URL is returned if the URL is not overriden. + virtual GURL OverrideFlashEmbedWithHTML(const GURL& url); }; } // namespace content
diff --git a/content/public/renderer/plugin_instance_throttler.h b/content/public/renderer/plugin_instance_throttler.h index ca981c6..404def0 100644 --- a/content/public/renderer/plugin_instance_throttler.h +++ b/content/public/renderer/plugin_instance_throttler.h
@@ -9,6 +9,7 @@ #include "base/macros.h" #include "content/common/content_export.h" +#include "content/public/renderer/render_frame.h" namespace blink { class WebPlugin; @@ -73,7 +74,8 @@ virtual void OnThrottlerDestroyed() {} }; - static std::unique_ptr<PluginInstanceThrottler> Create(); + static std::unique_ptr<PluginInstanceThrottler> Create( + RenderFrame::RecordPeripheralDecision record_decision); static void RecordUnthrottleMethodMetric(PowerSaverUnthrottleMethod method);
diff --git a/content/public/renderer/render_frame.h b/content/public/renderer/render_frame.h index 47b958d..59bec7d2 100644 --- a/content/public/renderer/render_frame.h +++ b/content/public/renderer/render_frame.h
@@ -82,6 +82,11 @@ CONTENT_STATUS_NUM_ITEMS }; + enum RecordPeripheralDecision { + DONT_RECORD_DECISION = 0, + RECORD_DECISION = 1 + }; + // Returns the RenderFrame given a WebFrame. static RenderFrame* FromWebFrame(blink::WebFrame* web_frame); @@ -177,7 +182,8 @@ virtual PeripheralContentStatus GetPeripheralContentStatus( const url::Origin& main_frame_origin, const url::Origin& content_origin, - const gfx::Size& unobscured_size) const = 0; + const gfx::Size& unobscured_size, + RecordPeripheralDecision record_decision) const = 0; // Whitelists a |content_origin| so its content will never be throttled in // this RenderFrame. Whitelist is cleared by top level navigation.
diff --git a/content/public/test/render_view_test.cc b/content/public/test/render_view_test.cc index 72c1e356..bb5cf713 100644 --- a/content/public/test/render_view_test.cc +++ b/content/public/test/render_view_test.cc
@@ -13,7 +13,6 @@ #include "base/run_loop.h" #include "base/single_thread_task_runner.h" #include "build/build_config.h" -#include "components/scheduler/renderer/renderer_scheduler.h" #include "content/app/mojo/mojo_init.h" #include "content/common/dom_storage/dom_storage_types.h" #include "content/common/frame_messages.h" @@ -40,6 +39,7 @@ #include "third_party/WebKit/public/platform/WebScreenInfo.h" #include "third_party/WebKit/public/platform/WebSecurityOrigin.h" #include "third_party/WebKit/public/platform/WebURLRequest.h" +#include "third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h" #include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebHistoryItem.h" #include "third_party/WebKit/public/web/WebInputElement.h" @@ -115,9 +115,8 @@ : public RendererBlinkPlatformImpl { public: RendererBlinkPlatformImplTestOverrideImpl( - scheduler::RendererScheduler* scheduler) - : RendererBlinkPlatformImpl(scheduler, nullptr) { - } + blink::scheduler::RendererScheduler* scheduler) + : RendererBlinkPlatformImpl(scheduler, nullptr) {} // Get rid of the dependency to the sandbox, which is not available in // RenderViewTest. @@ -126,7 +125,7 @@ RenderViewTest::RendererBlinkPlatformImplTestOverride:: RendererBlinkPlatformImplTestOverride() { - renderer_scheduler_ = scheduler::RendererScheduler::Create(); + renderer_scheduler_ = blink::scheduler::RendererScheduler::Create(); blink_platform_impl_.reset( new RendererBlinkPlatformImplTestOverrideImpl(renderer_scheduler_.get())); }
diff --git a/content/public/test/render_view_test.h b/content/public/test/render_view_test.h index 17ca0579..3c07ef18 100644 --- a/content/public/test/render_view_test.h +++ b/content/public/test/render_view_test.h
@@ -26,6 +26,9 @@ #include "third_party/WebKit/public/web/WebLeakDetector.h" namespace blink { +namespace scheduler { +class RendererScheduler; +} class WebInputElement; class WebWidget; } @@ -34,10 +37,6 @@ class Rect; } -namespace scheduler { -class RendererScheduler; -} - namespace content { class ContentBrowserClient; class ContentClient; @@ -62,7 +61,7 @@ void Shutdown(); private: - std::unique_ptr<scheduler::RendererScheduler> renderer_scheduler_; + std::unique_ptr<blink::scheduler::RendererScheduler> renderer_scheduler_; std::unique_ptr<RendererBlinkPlatformImplTestOverrideImpl> blink_platform_impl_; };
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn index a25ec7c..b27095f 100644 --- a/content/renderer/BUILD.gn +++ b/content/renderer/BUILD.gn
@@ -42,7 +42,6 @@ "//cc/surfaces", "//cc/surfaces:surface_id", "//components/memory_coordinator/child", - "//components/scheduler:scheduler", "//components/url_formatter", "//content:resources", "//content/child",
diff --git a/content/renderer/cache_storage/cache_storage_dispatcher.cc b/content/renderer/cache_storage/cache_storage_dispatcher.cc index a490e4c6..1fefe44 100644 --- a/content/renderer/cache_storage/cache_storage_dispatcher.cc +++ b/content/renderer/cache_storage/cache_storage_dispatcher.cc
@@ -177,7 +177,7 @@ query_params); } void dispatchKeys(CacheWithRequestsCallbacks* callbacks, - const blink::WebServiceWorkerRequest* request, + const blink::WebServiceWorkerRequest& request, const QueryParams& query_params) override { if (!dispatcher_) return; @@ -610,15 +610,14 @@ void CacheStorageDispatcher::dispatchKeysForCache( int cache_id, blink::WebServiceWorkerCache::CacheWithRequestsCallbacks* callbacks, - const blink::WebServiceWorkerRequest* request, + const blink::WebServiceWorkerRequest& request, const blink::WebServiceWorkerCache::QueryParams& query_params) { int request_id = cache_keys_callbacks_.Add(callbacks); cache_keys_times_[request_id] = base::TimeTicks::Now(); Send(new CacheStorageHostMsg_CacheKeys( CurrentWorkerId(), request_id, cache_id, - request ? FetchRequestFromWebRequest(*request) - : ServiceWorkerFetchRequest(), + FetchRequestFromWebRequest(request), QueryParamsFromWebQueryParams(query_params))); }
diff --git a/content/renderer/cache_storage/cache_storage_dispatcher.h b/content/renderer/cache_storage/cache_storage_dispatcher.h index 366cb7a..26f0592 100644 --- a/content/renderer/cache_storage/cache_storage_dispatcher.h +++ b/content/renderer/cache_storage/cache_storage_dispatcher.h
@@ -145,7 +145,7 @@ void dispatchKeysForCache( int cache_id, blink::WebServiceWorkerCache::CacheWithRequestsCallbacks* callbacks, - const blink::WebServiceWorkerRequest* request, + const blink::WebServiceWorkerRequest& request, const blink::WebServiceWorkerCache::QueryParams& query_params); void dispatchBatchForCache( int cache_id,
diff --git a/content/renderer/categorized_worker_pool.cc b/content/renderer/categorized_worker_pool.cc index 41814b4..8250071c 100644 --- a/content/renderer/categorized_worker_pool.cc +++ b/content/renderer/categorized_worker_pool.cc
@@ -136,9 +136,7 @@ for (int i = 0; i < num_threads; i++) { std::unique_ptr<base::SimpleThread> thread(new CategorizedWorkerPoolThread( - base::StringPrintf("CompositorTileWorker%u", - static_cast<unsigned>(threads_.size() + 1)) - .c_str(), + base::StringPrintf("CompositorTileWorker%d", i + 1).c_str(), base::SimpleThread::Options(), this, foreground_categories, &has_ready_to_run_foreground_tasks_cv_)); thread->Start();
diff --git a/content/renderer/gpu/compositor_dependencies.h b/content/renderer/gpu/compositor_dependencies.h index 8a07a92..0db1058 100644 --- a/content/renderer/gpu/compositor_dependencies.h +++ b/content/renderer/gpu/compositor_dependencies.h
@@ -27,9 +27,11 @@ class GpuMemoryBufferManager; } +namespace blink { namespace scheduler { class RendererScheduler; } +} namespace content { @@ -54,7 +56,7 @@ GetCompositorImplThreadTaskRunner() = 0; virtual cc::SharedBitmapManager* GetSharedBitmapManager() = 0; virtual gpu::GpuMemoryBufferManager* GetGpuMemoryBufferManager() = 0; - virtual scheduler::RendererScheduler* GetRendererScheduler() = 0; + virtual blink::scheduler::RendererScheduler* GetRendererScheduler() = 0; // TODO(danakj): This should be part of RenderThreadImpl (or some API from it // to RenderWidget). But RenderThreadImpl is null in RenderViewTest. virtual std::unique_ptr<cc::BeginFrameSource> CreateExternalBeginFrameSource(
diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc index ce6ea32..1ea1f2a7 100644 --- a/content/renderer/gpu/render_widget_compositor.cc +++ b/content/renderer/gpu/render_widget_compositor.cc
@@ -41,7 +41,6 @@ #include "cc/trees/latency_info_swap_promise_monitor.h" #include "cc/trees/layer_tree_host.h" #include "cc/trees/remote_proto_channel.h" -#include "components/scheduler/renderer/renderer_scheduler.h" #include "content/common/content_switches_internal.h" #include "content/common/gpu/client/context_provider_command_buffer.h" #include "content/public/common/content_client.h" @@ -54,6 +53,7 @@ #include "third_party/WebKit/public/platform/WebCompositorMutatorClient.h" #include "third_party/WebKit/public/platform/WebLayoutAndPaintAsyncCallback.h" #include "third_party/WebKit/public/platform/WebSize.h" +#include "third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h" #include "third_party/WebKit/public/web/WebKit.h" #include "third_party/WebKit/public/web/WebRuntimeFeatures.h" #include "third_party/WebKit/public/web/WebSelection.h" @@ -512,7 +512,8 @@ settings.use_cached_picture_raster = !cmd.HasSwitch(cc::switches::kDisableCachedPictureRaster); - if (cmd.HasSwitch(switches::kUseRemoteCompositing)) + if (cmd.HasSwitch(switches::kUseRemoteCompositing) || + cmd.HasSwitch(switches::kIsRunningInMash)) settings.use_external_begin_frame_source = false; return settings;
diff --git a/content/renderer/gpu/render_widget_compositor_unittest.cc b/content/renderer/gpu/render_widget_compositor_unittest.cc index 3246db3..01202369 100644 --- a/content/renderer/gpu/render_widget_compositor_unittest.cc +++ b/content/renderer/gpu/render_widget_compositor_unittest.cc
@@ -18,11 +18,9 @@ #include "cc/test/fake_output_surface.h" #include "cc/test/test_context_provider.h" #include "cc/trees/layer_tree_host.h" -#include "components/scheduler/renderer/renderer_scheduler.h" #include "content/public/test/mock_render_thread.h" #include "content/renderer/render_widget.h" #include "content/test/fake_compositor_dependencies.h" -#include "content/test/fake_renderer_scheduler.h" #include "gpu/GLES2/gl2extchromium.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/content/renderer/input/input_handler_manager.cc b/content/renderer/input/input_handler_manager.cc index 99a22ca..29ea2e4 100644 --- a/content/renderer/input/input_handler_manager.cc +++ b/content/renderer/input/input_handler_manager.cc
@@ -12,16 +12,16 @@ #include "base/threading/thread_task_runner_handle.h" #include "base/trace_event/trace_event.h" #include "cc/input/input_handler.h" -#include "components/scheduler/renderer/renderer_scheduler.h" #include "content/common/input/web_input_event_traits.h" #include "content/renderer/input/input_event_filter.h" #include "content/renderer/input/input_handler_manager_client.h" #include "content/renderer/input/input_handler_wrapper.h" +#include "third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h" #include "ui/events/blink/input_handler_proxy.h" using blink::WebInputEvent; using ui::InputHandlerProxy; -using scheduler::RendererScheduler; +using blink::scheduler::RendererScheduler; namespace content { @@ -49,7 +49,7 @@ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, InputHandlerManagerClient* client, SynchronousInputHandlerProxyClient* sync_handler_client, - scheduler::RendererScheduler* renderer_scheduler) + blink::scheduler::RendererScheduler* renderer_scheduler) : task_runner_(task_runner), client_(client), synchronous_handler_proxy_client_(sync_handler_client),
diff --git a/content/renderer/input/input_handler_manager.h b/content/renderer/input/input_handler_manager.h index 07f564e..f45dbf6 100644 --- a/content/renderer/input/input_handler_manager.h +++ b/content/renderer/input/input_handler_manager.h
@@ -26,9 +26,11 @@ class WebMouseWheelEvent; } +namespace blink { namespace scheduler { class RendererScheduler; } +} namespace content { @@ -49,7 +51,7 @@ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, InputHandlerManagerClient* client, SynchronousInputHandlerProxyClient* sync_handler_client, - scheduler::RendererScheduler* renderer_scheduler); + blink::scheduler::RendererScheduler* renderer_scheduler); virtual ~InputHandlerManager(); // Callable from the main thread only. @@ -120,7 +122,7 @@ InputHandlerManagerClient* const client_; // May be null. SynchronousInputHandlerProxyClient* const synchronous_handler_proxy_client_; - scheduler::RendererScheduler* const renderer_scheduler_; // Not owned. + blink::scheduler::RendererScheduler* const renderer_scheduler_; // Not owned. }; } // namespace content
diff --git a/content/renderer/input/main_thread_event_queue.cc b/content/renderer/input/main_thread_event_queue.cc index e44c83b8f..772d3be1 100644 --- a/content/renderer/input/main_thread_event_queue.cc +++ b/content/renderer/input/main_thread_event_queue.cc
@@ -125,7 +125,7 @@ void MainThreadEventQueue::SendEventNotificationToMainThread() { main_task_runner_->PostTask( FROM_HERE, base::Bind(&MainThreadEventQueue::PopEventOnMainThread, - base::Unretained(this))); + this)); } void MainThreadEventQueue::QueueEvent(
diff --git a/content/renderer/input/render_widget_input_handler.cc b/content/renderer/input/render_widget_input_handler.cc index ebc894b..e9b4cb5 100644 --- a/content/renderer/input/render_widget_input_handler.cc +++ b/content/renderer/input/render_widget_input_handler.cc
@@ -14,7 +14,6 @@ #include "base/trace_event/trace_event_synthetic_delay.h" #include "build/build_config.h" #include "cc/trees/swap_promise_monitor.h" -#include "components/scheduler/renderer/renderer_scheduler.h" #include "content/common/input/input_event_ack.h" #include "content/common/input/input_event_ack_state.h" #include "content/common/input/web_input_event_traits.h" @@ -26,6 +25,7 @@ #include "content/renderer/render_widget.h" #include "third_party/WebKit/public/platform/WebFloatPoint.h" #include "third_party/WebKit/public/platform/WebFloatSize.h" +#include "third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h" #include "ui/events/latency_info.h" #include "ui/gfx/geometry/point_conversions.h"
diff --git a/content/renderer/manifest/manifest_parser.cc b/content/renderer/manifest/manifest_parser.cc index 23dca88b..5f771a84 100644 --- a/content/renderer/manifest/manifest_parser.cc +++ b/content/renderer/manifest/manifest_parser.cc
@@ -15,6 +15,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/values.h" #include "content/public/common/manifest.h" +#include "content/public/common/manifest_util.h" #include "content/renderer/manifest/manifest_uma_util.h" #include "third_party/WebKit/public/platform/WebColor.h" #include "third_party/WebKit/public/platform/WebIconSizesParser.h" @@ -221,18 +222,11 @@ if (display.is_null()) return blink::WebDisplayModeUndefined; - if (base::LowerCaseEqualsASCII(display.string(), "fullscreen")) - return blink::WebDisplayModeFullscreen; - else if (base::LowerCaseEqualsASCII(display.string(), "standalone")) - return blink::WebDisplayModeStandalone; - else if (base::LowerCaseEqualsASCII(display.string(), "minimal-ui")) - return blink::WebDisplayModeMinimalUi; - else if (base::LowerCaseEqualsASCII(display.string(), "browser")) - return blink::WebDisplayModeBrowser; - else { + blink::WebDisplayMode display_enum = + WebDisplayModeFromString(base::UTF16ToUTF8(display.string())); + if (display_enum == blink::WebDisplayModeUndefined) AddErrorInfo("unknown 'display' value ignored."); - return blink::WebDisplayModeUndefined; - } + return display_enum; } blink::WebScreenOrientationLockType ManifestParser::ParseOrientation( @@ -243,30 +237,12 @@ if (orientation.is_null()) return blink::WebScreenOrientationLockDefault; - if (base::LowerCaseEqualsASCII(orientation.string(), "any")) - return blink::WebScreenOrientationLockAny; - else if (base::LowerCaseEqualsASCII(orientation.string(), "natural")) - return blink::WebScreenOrientationLockNatural; - else if (base::LowerCaseEqualsASCII(orientation.string(), "landscape")) - return blink::WebScreenOrientationLockLandscape; - else if (base::LowerCaseEqualsASCII(orientation.string(), - "landscape-primary")) - return blink::WebScreenOrientationLockLandscapePrimary; - else if (base::LowerCaseEqualsASCII(orientation.string(), - "landscape-secondary")) - return blink::WebScreenOrientationLockLandscapeSecondary; - else if (base::LowerCaseEqualsASCII(orientation.string(), "portrait")) - return blink::WebScreenOrientationLockPortrait; - else if (base::LowerCaseEqualsASCII(orientation.string(), - "portrait-primary")) - return blink::WebScreenOrientationLockPortraitPrimary; - else if (base::LowerCaseEqualsASCII(orientation.string(), - "portrait-secondary")) - return blink::WebScreenOrientationLockPortraitSecondary; - else { + blink::WebScreenOrientationLockType orientation_enum = + WebScreenOrientationLockTypeFromString( + base::UTF16ToUTF8(orientation.string())); + if (orientation_enum == blink::WebScreenOrientationLockDefault) AddErrorInfo("unknown 'orientation' value ignored."); - return blink::WebScreenOrientationLockDefault; - } + return orientation_enum; } GURL ManifestParser::ParseIconSrc(const base::DictionaryValue& icon) {
diff --git a/content/renderer/media/renderer_webaudiodevice_impl.cc b/content/renderer/media/renderer_webaudiodevice_impl.cc index 7f648538..b1f8037 100644 --- a/content/renderer/media/renderer_webaudiodevice_impl.cc +++ b/content/renderer/media/renderer_webaudiodevice_impl.cc
@@ -39,6 +39,7 @@ const url::Origin& security_origin) : params_(params), client_callback_(callback), + sink_is_running_(static_cast<base::AtomicRefCount>(0)), session_id_(session_id), task_runner_(base::ThreadTaskRunnerHandle::Get()), null_audio_sink_(new media::NullAudioSink(task_runner_)), @@ -76,6 +77,13 @@ render_frame ? render_frame->GetRoutingID() : MSG_ROUTING_NONE, session_id_, std::string(), security_origin_); sink_->Initialize(params_, this); + // TODO(miu): Remove this temporary instrumentation to root-cause a memory + // use-after-free issue. http://crbug.com/619463 + { + CHECK(base::AtomicRefCountIsZero(&sink_is_running_)) + << "Illegal state: sink_is_running_ should be 0."; + base::AtomicRefCountInc(&sink_is_running_); + } sink_->Start(); sink_->Play(); start_null_audio_sink_callback_.Reset( @@ -88,6 +96,10 @@ if (sink_) { sink_->Stop(); + // TODO(miu): Remove this temporary instrumentation to root-cause a memory + // use-after-free issue. http://crbug.com/619463 + CHECK(!base::AtomicRefCountDec(&sink_is_running_)) + << "Illegal state: sink_is_running_ should have been 1."; sink_ = NULL; } null_audio_sink_->Stop(); @@ -103,6 +115,11 @@ int RendererWebAudioDeviceImpl::Render(media::AudioBus* dest, uint32_t frames_delayed, uint32_t frames_skipped) { + // TODO(miu): Remove this temporary instrumentation to root-cause a memory + // use-after-free issue. http://crbug.com/619463 + CHECK(base::AtomicRefCountIsOne(&sink_is_running_)) + << "Contract violation: Render() being called after stop()."; + #if defined(OS_ANDROID) if (is_first_buffer_after_silence_) { DCHECK(!is_using_null_audio_sink_); @@ -160,6 +177,12 @@ } } #endif + + // TODO(miu): Remove this temporary instrumentation to root-cause a memory + // use-after-free issue. http://crbug.com/619463 + CHECK(base::AtomicRefCountIsOne(&sink_is_running_)) + << "Race condition: stop() was called during Render() operation."; + return dest->frames(); }
diff --git a/content/renderer/media/renderer_webaudiodevice_impl.h b/content/renderer/media/renderer_webaudiodevice_impl.h index 48e7fad..e52a506 100644 --- a/content/renderer/media/renderer_webaudiodevice_impl.h +++ b/content/renderer/media/renderer_webaudiodevice_impl.h
@@ -7,6 +7,7 @@ #include <stdint.h> +#include "base/atomic_ref_count.h" #include "base/cancelable_callback.h" #include "base/macros.h" #include "base/memory/ref_counted.h" @@ -62,6 +63,10 @@ // When non-NULL, we are started. When NULL, we are stopped. scoped_refptr<media::AudioRendererSink> sink_; + // TODO(miu): Remove this temporary instrumentation to root-cause a memory + // use-after-free issue. http://crbug.com/619463 + base::AtomicRefCount sink_is_running_; + // ID to allow browser to select the correct input device for unified IO. int session_id_;
diff --git a/content/renderer/mus/compositor_mus_connection.cc b/content/renderer/mus/compositor_mus_connection.cc index a814c55..101c3a3 100644 --- a/content/renderer/mus/compositor_mus_connection.cc +++ b/content/renderer/mus/compositor_mus_connection.cc
@@ -113,9 +113,10 @@ } } -void CompositorMusConnection::OnEventObserved(const ui::Event& event, - ui::Window* target) { - // Compositor does not use SetEventObserver(). +void CompositorMusConnection::OnPointerEventObserved( + const ui::PointerEvent& event, + ui::Window* target) { + // Compositor does not use StartPointerWatcher(). } void CompositorMusConnection::OnWindowInputEvent(
diff --git a/content/renderer/mus/compositor_mus_connection.h b/content/renderer/mus/compositor_mus_connection.h index e066b01..7dd4b3d 100644 --- a/content/renderer/mus/compositor_mus_connection.h +++ b/content/renderer/mus/compositor_mus_connection.h
@@ -68,7 +68,8 @@ // WindowTreeClientDelegate implementation: void OnDidDestroyClient(ui::WindowTreeClient* client) override; void OnEmbed(ui::Window* root) override; - void OnEventObserved(const ui::Event& event, ui::Window* target) override; + void OnPointerEventObserved(const ui::PointerEvent& event, + ui::Window* target) override; // InputEventHandler implementation: void OnWindowInputEvent(
diff --git a/content/renderer/mus/compositor_mus_connection_unittest.cc b/content/renderer/mus/compositor_mus_connection_unittest.cc index 34eb233..afc1085c 100644 --- a/content/renderer/mus/compositor_mus_connection_unittest.cc +++ b/content/renderer/mus/compositor_mus_connection_unittest.cc
@@ -20,10 +20,10 @@ #include "content/renderer/mus/render_widget_mus_connection.h" #include "content/renderer/render_widget.h" #include "content/test/fake_compositor_dependencies.h" -#include "content/test/fake_renderer_scheduler.h" #include "mojo/public/cpp/bindings/interface_request.h" #include "services/ui/public/cpp/tests/test_window.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/WebKit/public/platform/scheduler/test/fake_renderer_scheduler.h" #include "ui/events/event_utils.h" #include "ui/events/mojo/event.mojom.h" #include "ui/events/mojo/event_constants.mojom.h" @@ -66,7 +66,7 @@ TestInputHandlerManager( const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, content::InputHandlerManagerClient* client, - scheduler::RendererScheduler* renderer_scheduler) + blink::scheduler::RendererScheduler* renderer_scheduler) : InputHandlerManager(task_runner, client, nullptr, renderer_scheduler), override_result_(false), result_(content::InputEventAckState::INPUT_EVENT_ACK_STATE_UNKNOWN) {} @@ -248,7 +248,7 @@ // Mocks/Fakes of the testing environment. TestInputHandlerManagerClient input_handler_manager_client_; FakeCompositorDependencies compositor_dependencies_; - FakeRendererScheduler renderer_scheduler_; + blink::scheduler::FakeRendererScheduler renderer_scheduler_; MockRenderThread render_thread_; scoped_refptr<TestRenderWidget> render_widget_; mojo::InterfaceRequest<ui::mojom::WindowTreeClient> request_;
diff --git a/content/renderer/mus/render_widget_mus_connection.cc b/content/renderer/mus/render_widget_mus_connection.cc index 727b34d..ad68c210 100644 --- a/content/renderer/mus/render_widget_mus_connection.cc +++ b/content/renderer/mus/render_widget_mus_connection.cc
@@ -11,7 +11,6 @@ #include "content/renderer/mus/compositor_mus_connection.h" #include "content/renderer/render_thread_impl.h" #include "content/renderer/render_view_impl.h" -#include "services/ui/public/cpp/context_provider.h" #include "services/ui/public/cpp/output_surface.h" #include "services/ui/public/interfaces/command_buffer.mojom.h" #include "services/ui/public/interfaces/surface.mojom.h" @@ -44,10 +43,9 @@ RenderWidgetMusConnection::CreateOutputSurface() { DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(!window_surface_binding_); - scoped_refptr<cc::ContextProvider> context_provider(new ui::ContextProvider); std::unique_ptr<cc::OutputSurface> surface(new ui::OutputSurface( - context_provider, ui::WindowSurface::Create(&window_surface_binding_))); + ui::WindowSurface::Create(&window_surface_binding_))); if (compositor_mus_connection_) { compositor_mus_connection_->AttachSurfaceOnMainThread( std::move(window_surface_binding_));
diff --git a/content/renderer/pepper/pepper_webplugin_impl_browsertest.cc b/content/renderer/pepper/pepper_webplugin_impl_browsertest.cc index 7a08ef92..05b84d7 100644 --- a/content/renderer/pepper/pepper_webplugin_impl_browsertest.cc +++ b/content/renderer/pepper/pepper_webplugin_impl_browsertest.cc
@@ -169,7 +169,8 @@ blink::WebLocalFrame* frame, const blink::WebPluginParams& params, blink::WebPlugin** plugin) override { - current_test_->throttler_ = new PluginInstanceThrottlerImpl; + current_test_->throttler_ = + new PluginInstanceThrottlerImpl(RenderFrame::DONT_RECORD_DECISION); current_test_->throttler_->AddObserver(current_test_); *plugin = render_frame->CreatePlugin( frame, GetPluginInfo().ToWebPluginInfo(), params,
diff --git a/content/renderer/pepper/plugin_instance_throttler_impl.cc b/content/renderer/pepper/plugin_instance_throttler_impl.cc index 10c7f50..1fee278 100644 --- a/content/renderer/pepper/plugin_instance_throttler_impl.cc +++ b/content/renderer/pepper/plugin_instance_throttler_impl.cc
@@ -41,8 +41,9 @@ const int PluginInstanceThrottlerImpl::kMaximumFramesToExamine = 150; // static -std::unique_ptr<PluginInstanceThrottler> PluginInstanceThrottler::Create() { - return base::WrapUnique(new PluginInstanceThrottlerImpl); +std::unique_ptr<PluginInstanceThrottler> PluginInstanceThrottler::Create( + RenderFrame::RecordPeripheralDecision record_decision) { + return base::WrapUnique(new PluginInstanceThrottlerImpl(record_decision)); } // static @@ -53,8 +54,10 @@ PluginInstanceThrottler::UNTHROTTLE_METHOD_NUM_ITEMS); } -PluginInstanceThrottlerImpl::PluginInstanceThrottlerImpl() - : state_(THROTTLER_STATE_AWAITING_KEYFRAME), +PluginInstanceThrottlerImpl::PluginInstanceThrottlerImpl( + content::RenderFrame::RecordPeripheralDecision record_decision) + : record_decision_(record_decision), + state_(THROTTLER_STATE_AWAITING_KEYFRAME), is_hidden_for_placeholder_(false), web_plugin_(nullptr), frames_examined_(0), @@ -65,8 +68,7 @@ kAudioThrottledFrameTimeoutMilliseconds), this, &PluginInstanceThrottlerImpl::EngageThrottle), - weak_factory_(this) { -} + weak_factory_(this) {} PluginInstanceThrottlerImpl::~PluginInstanceThrottlerImpl() { FOR_EACH_OBSERVER(Observer, observer_list_, OnThrottlerDestroyed()); @@ -144,7 +146,8 @@ auto status = frame->GetPeripheralContentStatus( frame->GetWebFrame()->top()->getSecurityOrigin(), content_origin, gfx::Size(roundf(unobscured_size.width() / zoom_factor), - roundf(unobscured_size.height() / zoom_factor))); + roundf(unobscured_size.height() / zoom_factor)), + record_decision_); if (status != RenderFrame::CONTENT_STATUS_PERIPHERAL) { DCHECK_NE(THROTTLER_STATE_MARKED_ESSENTIAL, state_); state_ = THROTTLER_STATE_MARKED_ESSENTIAL;
diff --git a/content/renderer/pepper/plugin_instance_throttler_impl.h b/content/renderer/pepper/plugin_instance_throttler_impl.h index 8d6568b..991591c7d 100644 --- a/content/renderer/pepper/plugin_instance_throttler_impl.h +++ b/content/renderer/pepper/plugin_instance_throttler_impl.h
@@ -33,7 +33,8 @@ class CONTENT_EXPORT PluginInstanceThrottlerImpl : public PluginInstanceThrottler { public: - PluginInstanceThrottlerImpl(); + explicit PluginInstanceThrottlerImpl( + RenderFrame::RecordPeripheralDecision record_decision); ~PluginInstanceThrottlerImpl() override; @@ -90,6 +91,8 @@ void AudioThrottledFrameTimeout(); void EngageThrottle(); + RenderFrame::RecordPeripheralDecision record_decision_; + ThrottlerState state_; bool is_hidden_for_placeholder_;
diff --git a/content/renderer/pepper/plugin_instance_throttler_impl_unittest.cc b/content/renderer/pepper/plugin_instance_throttler_impl_unittest.cc index 48a9bb61..5c65873 100644 --- a/content/renderer/pepper/plugin_instance_throttler_impl_unittest.cc +++ b/content/renderer/pepper/plugin_instance_throttler_impl_unittest.cc
@@ -38,7 +38,8 @@ } void SetUp() override { - throttler_.reset(new PluginInstanceThrottlerImpl); + throttler_.reset( + new PluginInstanceThrottlerImpl(RenderFrame::DONT_RECORD_DECISION)); throttler_->Initialize(nullptr, url::Origin(GURL("http://example.com")), "Shockwave Flash", gfx::Size(100, 100)); throttler_->AddObserver(this);
diff --git a/content/renderer/pepper/plugin_power_saver_helper.cc b/content/renderer/pepper/plugin_power_saver_helper.cc index 1879b7e..e0969fd 100644 --- a/content/renderer/pepper/plugin_power_saver_helper.cc +++ b/content/renderer/pepper/plugin_power_saver_helper.cc
@@ -25,7 +25,7 @@ namespace { const char kPeripheralHeuristicHistogram[] = - "Plugin.PowerSaver.PeripheralHeuristic"; + "Plugin.PowerSaver.PeripheralHeuristicInitialDecision"; } // namespace @@ -102,7 +102,8 @@ PluginPowerSaverHelper::GetPeripheralContentStatus( const url::Origin& main_frame_origin, const url::Origin& content_origin, - const gfx::Size& unobscured_size) const { + const gfx::Size& unobscured_size, + RenderFrame::RecordPeripheralDecision record_decision) const { if (base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( switches::kOverridePluginPowerSaverForTesting) == "always") { return RenderFrame::CONTENT_STATUS_PERIPHERAL; @@ -110,15 +111,14 @@ auto status = PeripheralContentHeuristic::GetPeripheralStatus( origin_whitelist_, main_frame_origin, content_origin, unobscured_size); - if (status == RenderFrame::CONTENT_STATUS_ESSENTIAL_UNKNOWN_SIZE) { - // Early exit here to avoid recording a UMA. Every plugin will call this - // method once before the size is known (to faciliate early-exit for - // same-origin and whitelisted-origin content). - return status; + + // Never record ESSENTIAL_UNKNOWN_SIZE. Wait for retest after size is known. + if (record_decision == RenderFrame::RECORD_DECISION && + status != RenderFrame::CONTENT_STATUS_ESSENTIAL_UNKNOWN_SIZE) { + UMA_HISTOGRAM_ENUMERATION(kPeripheralHeuristicHistogram, status, + RenderFrame::CONTENT_STATUS_NUM_ITEMS); } - UMA_HISTOGRAM_ENUMERATION(kPeripheralHeuristicHistogram, status, - RenderFrame::CONTENT_STATUS_NUM_ITEMS); return status; }
diff --git a/content/renderer/pepper/plugin_power_saver_helper.h b/content/renderer/pepper/plugin_power_saver_helper.h index 0de22dd..778958c 100644 --- a/content/renderer/pepper/plugin_power_saver_helper.h +++ b/content/renderer/pepper/plugin_power_saver_helper.h
@@ -50,7 +50,8 @@ RenderFrame::PeripheralContentStatus GetPeripheralContentStatus( const url::Origin& main_frame_origin, const url::Origin& content_origin, - const gfx::Size& unobscured_size) const; + const gfx::Size& unobscured_size, + RenderFrame::RecordPeripheralDecision record_decision) const; void WhitelistContentOrigin(const url::Origin& content_origin); // RenderFrameObserver implementation.
diff --git a/content/renderer/pepper/plugin_power_saver_helper_browsertest.cc b/content/renderer/pepper/plugin_power_saver_helper_browsertest.cc index 35b8388f..91a2df5 100644 --- a/content/renderer/pepper/plugin_power_saver_helper_browsertest.cc +++ b/content/renderer/pepper/plugin_power_saver_helper_browsertest.cc
@@ -47,7 +47,8 @@ EXPECT_EQ(RenderFrame::CONTENT_STATUS_PERIPHERAL, frame()->GetPeripheralContentStatus( url::Origin(GURL("http://same.com")), - url::Origin(GURL("http://other.com")), gfx::Size(100, 100))); + url::Origin(GURL("http://other.com")), gfx::Size(100, 100), + RenderFrame::DONT_RECORD_DECISION)); // Clear out other messages so we find just the plugin power saver IPCs. sink_->ClearMessages(); @@ -57,7 +58,8 @@ EXPECT_EQ(RenderFrame::CONTENT_STATUS_ESSENTIAL_CROSS_ORIGIN_WHITELISTED, frame()->GetPeripheralContentStatus( url::Origin(GURL("http://same.com")), - url::Origin(GURL("http://other.com")), gfx::Size(100, 100))); + url::Origin(GURL("http://other.com")), gfx::Size(100, 100), + RenderFrame::DONT_RECORD_DECISION)); // Test that we've sent an IPC to the browser. ASSERT_EQ(1u, sink_->message_count()); @@ -89,14 +91,16 @@ EXPECT_EQ(RenderFrame::CONTENT_STATUS_ESSENTIAL_CROSS_ORIGIN_WHITELISTED, frame()->GetPeripheralContentStatus( url::Origin(GURL("http://same.com")), - url::Origin(GURL("http://other.com")), gfx::Size(100, 100))); + url::Origin(GURL("http://other.com")), gfx::Size(100, 100), + RenderFrame::DONT_RECORD_DECISION)); LoadHTML("<html></html>"); EXPECT_EQ(RenderFrame::CONTENT_STATUS_PERIPHERAL, frame()->GetPeripheralContentStatus( url::Origin(GURL("http://same.com")), - url::Origin(GURL("http://other.com")), gfx::Size(100, 100))); + url::Origin(GURL("http://other.com")), gfx::Size(100, 100), + RenderFrame::DONT_RECORD_DECISION)); } } // namespace content
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index ce82145..026c472 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -33,7 +33,6 @@ #include "base/trace_event/trace_event_argument.h" #include "build/build_config.h" #include "cc/base/switches.h" -#include "components/scheduler/renderer/renderer_scheduler.h" #include "content/child/appcache/appcache_dispatcher.h" #include "content/child/quota_dispatcher.h" #include "content/child/request_extra_data.h" @@ -170,6 +169,7 @@ #include "third_party/WebKit/public/platform/WebURLError.h" #include "third_party/WebKit/public/platform/WebURLResponse.h" #include "third_party/WebKit/public/platform/WebVector.h" +#include "third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h" #include "third_party/WebKit/public/web/WebColorSuggestion.h" #include "third_party/WebKit/public/web/WebConsoleMessage.h" #include "third_party/WebKit/public/web/WebDocument.h" @@ -1023,6 +1023,11 @@ return nullptr; } +blink::WebURL RenderFrameImpl::overrideFlashEmbedWithHTML( + const blink::WebURL& url) { + return GetContentClient()->renderer()->OverrideFlashEmbedWithHTML(url); +} + // RenderFrameImpl ---------------------------------------------------------- RenderFrameImpl::RenderFrameImpl(const CreateParams& params) : frame_(NULL), @@ -1210,20 +1215,6 @@ blame_context_->Initialize(); } -void RenderFrameImpl::OnGotZoomLevel(const GURL& url, double zoom_level) { - // TODO(wjmaclean): We should see if this restriction is really necessary, - // since it isn't enforced in other parts of the page zoom system (e.g. - // when a users changes the zoom of a currently displayed page). Android - // has no UI for this, so in theory the following code would normally just use - // the default zoom anyways. -#if !defined(OS_ANDROID) - // On Android, page zoom isn't used, and in case of WebView, text zoom is used - // for legacy WebView text scaling emulation. Thus, the code that resets - // the zoom level from this map will be effectively resetting text zoom level. - host_zoom_levels_[url] = zoom_level; -#endif -} - RenderWidget* RenderFrameImpl::GetRenderWidget() { RenderFrameImpl* local_root = RenderFrameImpl::FromWebFrame(frame_->localRoot()); @@ -1281,7 +1272,8 @@ return; Send(new InputHostMsg_ImeCancelComposition(render_view_->GetRoutingID())); #if defined(OS_MACOSX) || defined(USE_AURA) - GetRenderWidget()->UpdateCompositionInfo(true); + GetRenderWidget()->UpdateCompositionInfo( + false /* not an immediate request */); #endif } @@ -1848,7 +1840,7 @@ length += end_adjust - start_adjust; base::AutoReset<bool> handling_select_range(&handling_select_range_, true); - frame_->selectRange(WebRange::fromDocumentRange(frame_, start, length)); + frame_->selectRange(WebRange(start, length)); } void RenderFrameImpl::OnUnselect() { @@ -2216,7 +2208,7 @@ void RenderFrameImpl::OnTextSurroundingSelectionRequest(uint32_t max_length) { blink::WebSurroundingText surroundingText; - surroundingText.initialize(frame_->selectionRange(), max_length); + surroundingText.initializeFromCurrentSelection(frame_, max_length); if (surroundingText.isNull()) { // |surroundingText| might not be correctly initialized, for example if @@ -2423,9 +2415,10 @@ RenderFrameImpl::GetPeripheralContentStatus( const url::Origin& main_frame_origin, const url::Origin& content_origin, - const gfx::Size& unobscured_size) const { + const gfx::Size& unobscured_size, + RecordPeripheralDecision record_decision) const { return plugin_power_saver_helper_->GetPeripheralContentStatus( - main_frame_origin, content_origin, unobscured_size); + main_frame_origin, content_origin, unobscured_size, record_decision); } void RenderFrameImpl::WhitelistContentOrigin( @@ -4104,14 +4097,6 @@ if (!render_view_->renderer_preferences_.enable_referrers) request.setHTTPReferrer(WebString(), blink::WebReferrerPolicyDefault); - - if (extra_data->is_main_frame() && RenderThreadImpl::current()) { - RenderThreadImpl::current() - ->render_frame_message_filter() - ->GetHostZoomLevel(render_view_->GetRoutingID(), request_url, - base::Bind(&RenderFrameImpl::OnGotZoomLevel, - weak_factory_.GetWeakPtr(), request_url)); - } } void RenderFrameImpl::didReceiveResponse( @@ -4652,7 +4637,7 @@ // Set zoom level, but don't do it for full-page plugin since they don't use // the same zoom settings. HostZoomLevels::iterator host_zoom = - host_zoom_levels_.find(GURL(request.url())); + render_view_->host_zoom_levels_.find(GURL(request.url())); if (render_view_->webview()->mainFrame()->isWebLocalFrame() && render_view_->webview()->mainFrame()->document().isPluginDocument()) { // Reset the zoom levels for plugins. @@ -4660,15 +4645,15 @@ } else { // If the zoom level is not found, then do nothing. In-page navigation // relies on not changing the zoom level in this case. - if (host_zoom != host_zoom_levels_.end()) + if (host_zoom != render_view_->host_zoom_levels_.end()) render_view_->SetZoomLevel(host_zoom->second); } - if (host_zoom != host_zoom_levels_.end()) { + if (host_zoom != render_view_->host_zoom_levels_.end()) { // This zoom level was merely recorded transiently for this load. We can // erase it now. If at some point we reload this page, the browser will // send us a new, up-to-date zoom level. - host_zoom_levels_.erase(host_zoom); + render_view_->host_zoom_levels_.erase(host_zoom); } // Update contents MIME type for main frame. @@ -5508,14 +5493,27 @@ : blink::WebFrameLoadType::BackForward; should_load_request = true; - // If this navigation is to a history item for a new child frame, we - // should cancel it if we were interrupted by a Javascript navigation - // that has already committed, has started a provisional loader, or has - // scheduled a navigation. + // If this navigation is to a history item for a new child frame, we may + // want to ignore it in some cases. If a Javascript navigation (i.e., + // client redirect) interrupted it and has either been scheduled, + // started loading, or has committed, we should ignore the history item. + // Similarly, if the history item just says to stay on about:blank, + // don't load it again, which might clobber injected content. + bool interrupted_by_client_redirect = + frame_->isNavigationScheduledWithin(0) || + frame_->provisionalDataSource() || + !current_history_item_.isNull(); + bool staying_at_about_blank = + current_history_item_.isNull() && + item_for_history_navigation.urlString() == url::kAboutBlankURL; + if (staying_at_about_blank) { + // TODO(creis): We need to generate a commit for the initial empty + // document, rather than just faking a DidStopLoading. See + // https://crbug.com/626416. + frame_->stopLoading(); + } if (request_params.is_history_navigation_in_new_child && - (!current_history_item_.isNull() || - frame_->provisionalDataSource() || - frame_->isNavigationScheduledWithin(0))) { + (interrupted_by_client_redirect || staying_at_about_blank)) { should_load_request = false; has_history_navigation_in_frame = false; } @@ -5648,9 +5646,7 @@ else offset = 0; length = location + length - offset + kExtraCharsBeforeAndAfterSelection; - WebRange webrange = WebRange::fromDocumentRange(frame_, offset, length); - if (!webrange.isNull()) - text = webrange.toPlainText(); + text = frame_->rangeAsText(WebRange(offset, length)); } else { offset = location; text = frame_->selectionAsText(); @@ -5662,6 +5658,9 @@ } } + // TODO(dglazkov): Investigate if and why this would be happening, + // and resolve this. We shouldn't be carrying selection text here. + // http://crbug.com/632920. // Sometimes we get repeated didChangeSelection calls from webkit when // the selection hasn't actually changed. We don't want to report these // because it will cause us to continually claim the X clipboard.
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h index 6991c59..c04183e 100644 --- a/content/renderer/render_frame_impl.h +++ b/content/renderer/render_frame_impl.h
@@ -233,6 +233,9 @@ static blink::WebFrame* ResolveOpener(int opener_frame_routing_id, int* opener_view_routing_id); + // Overwrites the given URL to use an HTML5 embed if possible. + blink::WebURL overrideFlashEmbedWithHTML(const blink::WebURL& url) override; + ~RenderFrameImpl() override; // Called by RenderWidget when meaningful layout has happened. @@ -411,7 +414,8 @@ RenderFrame::PeripheralContentStatus GetPeripheralContentStatus( const url::Origin& main_frame_origin, const url::Origin& content_origin, - const gfx::Size& unobscured_size) const override; + const gfx::Size& unobscured_size, + RecordPeripheralDecision record_decision) const override; void WhitelistContentOrigin(const url::Origin& content_origin) override; #endif bool IsFTPDirectoryListing() override; @@ -706,7 +710,6 @@ FRIEND_TEST_ALL_PREFIXES(ExternalPopupMenuTest, ShowPopupThenNavigate); FRIEND_TEST_ALL_PREFIXES(RenderAccessibilityImplTest, AccessibilityMessagesQueueWhileSwappedOut); - FRIEND_TEST_ALL_PREFIXES(RenderFrameImplTest, ZoomLimit); // A wrapper class used as the callback for JavaScript executed // in an isolated world. @@ -1039,8 +1042,6 @@ void InitializeBlameContext(RenderFrameImpl* parent_frame); - void OnGotZoomLevel(const GURL& url, double zoom_level); - // Stores the WebLocalFrame we are associated with. This is null from the // constructor until BindToWebFrame is called, and it is null after // frameDetached is called until destruction (which is asynchronous in the @@ -1230,8 +1231,6 @@ std::unique_ptr<blink::WebBluetooth> bluetooth_; - HostZoomLevels host_zoom_levels_; - // Manages play, pause notifications for WebMediaPlayer implementations; its // lifetime is tied to the RenderFrame via the RenderFrameObserver interface. media::RendererWebMediaPlayerDelegate* media_player_delegate_;
diff --git a/content/renderer/render_frame_impl_browsertest.cc b/content/renderer/render_frame_impl_browsertest.cc index 0e5bed48..999a9b39 100644 --- a/content/renderer/render_frame_impl_browsertest.cc +++ b/content/renderer/render_frame_impl_browsertest.cc
@@ -18,14 +18,12 @@ #include "content/renderer/render_frame_impl.h" #include "content/renderer/render_view_impl.h" #include "content/test/fake_compositor_dependencies.h" -#include "content/test/test_render_frame.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/WebKit/public/platform/WebEffectiveConnectionType.h" #include "third_party/WebKit/public/platform/WebString.h" #include "third_party/WebKit/public/platform/WebURLRequest.h" #include "third_party/WebKit/public/web/WebHistoryItem.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" -#include "third_party/WebKit/public/web/WebView.h" using blink::WebString; @@ -345,32 +343,4 @@ EXPECT_FALSE(msg4); } -TEST_F(RenderFrameImplTest, ZoomLimit) { - const double kMinZoomLevel = ZoomFactorToZoomLevel(kMinimumZoomFactor); - const double kMaxZoomLevel = ZoomFactorToZoomLevel(kMaximumZoomFactor); - - // Verifies navigation to a URL with preset zoom level indeed sets the level. - // Regression test for http://crbug.com/139559, where the level was not - // properly set when it is out of the default zoom limits of WebView. - CommonNavigationParams common_params; - common_params.url = GURL("data:text/html,min_zoomlimit_test"); - GetMainRenderFrame()->OnGotZoomLevel(common_params.url, kMinZoomLevel); - TestRenderFrame* frame = static_cast<TestRenderFrame*>(GetMainRenderFrame()); - frame->Navigate(common_params, StartNavigationParams(), - RequestNavigationParams()); - - ProcessPendingMessages(); - EXPECT_DOUBLE_EQ(kMinZoomLevel, view_->GetWebView()->zoomLevel()); - - // It should work even when the zoom limit is temporarily changed in the page. - view_->GetWebView()->zoomLimitsChanged(ZoomFactorToZoomLevel(1.0), - ZoomFactorToZoomLevel(1.0)); - common_params.url = GURL("data:text/html,max_zoomlimit_test"); - GetMainRenderFrame()->OnGotZoomLevel(common_params.url, kMaxZoomLevel); - frame->Navigate(common_params, StartNavigationParams(), - RequestNavigationParams()); - ProcessPendingMessages(); - EXPECT_DOUBLE_EQ(kMaxZoomLevel, view_->GetWebView()->zoomLevel()); -} - } // namespace
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index 830fd3d6..f28d2c4a 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc
@@ -48,10 +48,6 @@ #include "cc/trees/layer_tree_host_common.h" #include "cc/trees/layer_tree_settings.h" #include "components/memory_coordinator/child/child_memory_coordinator_impl.h" -#include "components/scheduler/child/compositor_worker_scheduler.h" -#include "components/scheduler/child/webthread_base.h" -#include "components/scheduler/child/webthread_impl_for_worker_scheduler.h" -#include "components/scheduler/renderer/renderer_scheduler.h" #include "content/child/appcache/appcache_dispatcher.h" #include "content/child/appcache/appcache_frontend_impl.h" #include "content/child/blob_storage/blob_message_filter.h" @@ -150,6 +146,9 @@ #include "third_party/WebKit/public/platform/WebImageGenerator.h" #include "third_party/WebKit/public/platform/WebString.h" #include "third_party/WebKit/public/platform/WebThread.h" +#include "third_party/WebKit/public/platform/scheduler/child/compositor_worker_scheduler.h" +#include "third_party/WebKit/public/platform/scheduler/child/webthread_impl_for_worker_scheduler.h" +#include "third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h" #include "third_party/WebKit/public/web/WebCache.h" #include "third_party/WebKit/public/web/WebDatabase.h" #include "third_party/WebKit/public/web/WebDocument.h" @@ -220,7 +219,7 @@ using blink::WebSecurityPolicy; using blink::WebString; using blink::WebView; -using scheduler::WebThreadImplForWorkerScheduler; +using blink::scheduler::WebThreadImplForWorkerScheduler; namespace content { @@ -288,8 +287,10 @@ private: // WebThreadImplForWorkerScheduler: - std::unique_ptr<scheduler::WorkerScheduler> CreateWorkerScheduler() override { - return base::WrapUnique(new scheduler::CompositorWorkerScheduler(thread())); + std::unique_ptr<blink::scheduler::WorkerScheduler> CreateWorkerScheduler() + override { + return base::WrapUnique( + new blink::scheduler::CompositorWorkerScheduler(thread())); } DISALLOW_COPY_AND_ASSIGN(WebThreadForCompositor); @@ -573,8 +574,8 @@ // static RenderThreadImpl* RenderThreadImpl::Create( const InProcessChildThreadParams& params) { - std::unique_ptr<scheduler::RendererScheduler> renderer_scheduler = - scheduler::RendererScheduler::Create(); + std::unique_ptr<blink::scheduler::RendererScheduler> renderer_scheduler = + blink::scheduler::RendererScheduler::Create(); scoped_refptr<base::SingleThreadTaskRunner> test_task_counter; return new RenderThreadImpl( params, std::move(renderer_scheduler), test_task_counter); @@ -583,7 +584,7 @@ // static RenderThreadImpl* RenderThreadImpl::Create( std::unique_ptr<base::MessageLoop> main_message_loop, - std::unique_ptr<scheduler::RendererScheduler> renderer_scheduler) { + std::unique_ptr<blink::scheduler::RendererScheduler> renderer_scheduler) { return new RenderThreadImpl(std::move(main_message_loop), std::move(renderer_scheduler)); } @@ -594,7 +595,7 @@ RenderThreadImpl::RenderThreadImpl( const InProcessChildThreadParams& params, - std::unique_ptr<scheduler::RendererScheduler> scheduler, + std::unique_ptr<blink::scheduler::RendererScheduler> scheduler, scoped_refptr<base::SingleThreadTaskRunner>& resource_task_queue) : ChildThreadImpl(Options::Builder() .InBrowserProcess(params) @@ -611,7 +612,7 @@ // which means that we need to make the render thread pump UI events. RenderThreadImpl::RenderThreadImpl( std::unique_ptr<base::MessageLoop> main_message_loop, - std::unique_ptr<scheduler::RendererScheduler> scheduler) + std::unique_ptr<blink::scheduler::RendererScheduler> scheduler) : ChildThreadImpl(Options::Builder() .UseMojoChannel(true) .AutoStartMojoShellConnection(false) @@ -1614,7 +1615,7 @@ return gpu_memory_buffer_manager(); } -scheduler::RendererScheduler* RenderThreadImpl::GetRendererScheduler() { +blink::scheduler::RendererScheduler* RenderThreadImpl::GetRendererScheduler() { return renderer_scheduler_.get(); }
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h index c7660bd..979c22e1 100644 --- a/content/renderer/render_thread_impl.h +++ b/content/renderer/render_thread_impl.h
@@ -22,7 +22,6 @@ #include "base/threading/thread_checker.h" #include "base/timer/timer.h" #include "build/build_config.h" -#include "components/scheduler/renderer/renderer_scheduler.h" #include "content/child/child_thread_impl.h" #include "content/common/content_export.h" #include "content/common/frame.mojom.h" @@ -35,6 +34,7 @@ #include "gpu/ipc/client/gpu_channel_host.h" #include "net/base/network_change_notifier.h" #include "third_party/WebKit/public/platform/WebConnectionType.h" +#include "third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h" #include "ui/gfx/native_widget_types.h" #if defined(OS_MACOSX) @@ -49,6 +49,9 @@ struct WorkerProcessMsg_CreateWorker_Params; namespace blink { +namespace scheduler { +class WebThreadBase; +} class WebGamepads; class WebMediaStreamCenter; class WebMediaStreamCenterClient; @@ -82,10 +85,6 @@ class ChildMemoryCoordinatorImpl; } -namespace scheduler { -class WebThreadBase; -} - namespace ui { class GpuService; } @@ -153,13 +152,13 @@ : public RenderThread, public ChildThreadImpl, public gpu::GpuChannelHostFactory, - public scheduler::RendererScheduler::RAILModeObserver, + public blink::scheduler::RendererScheduler::RAILModeObserver, NON_EXPORTED_BASE(public CompositorDependencies) { public: static RenderThreadImpl* Create(const InProcessChildThreadParams& params); static RenderThreadImpl* Create( std::unique_ptr<base::MessageLoop> main_message_loop, - std::unique_ptr<scheduler::RendererScheduler> renderer_scheduler); + std::unique_ptr<blink::scheduler::RendererScheduler> renderer_scheduler); static RenderThreadImpl* current(); ~RenderThreadImpl() override; @@ -219,7 +218,7 @@ scoped_refptr<base::SingleThreadTaskRunner> GetCompositorImplThreadTaskRunner() override; gpu::GpuMemoryBufferManager* GetGpuMemoryBufferManager() override; - scheduler::RendererScheduler* GetRendererScheduler() override; + blink::scheduler::RendererScheduler* GetRendererScheduler() override; std::unique_ptr<cc::BeginFrameSource> CreateExternalBeginFrameSource( int routing_id) override; cc::ImageSerializationProcessor* GetImageSerializationProcessor() override; @@ -227,7 +226,7 @@ bool AreImageDecodeTasksEnabled() override; bool IsThreadedAnimationEnabled() override; - // scheduler::RendererScheduler::RAILModeObserver implementation. + // blink::scheduler::RendererScheduler::RAILModeObserver implementation. void OnRAILModeChanged(v8::RAILMode rail_mode) override; // Synchronously establish a channel to the GPU plugin if not previously @@ -458,10 +457,11 @@ protected: RenderThreadImpl( const InProcessChildThreadParams& params, - std::unique_ptr<scheduler::RendererScheduler> scheduler, + std::unique_ptr<blink::scheduler::RendererScheduler> scheduler, scoped_refptr<base::SingleThreadTaskRunner>& resource_task_queue); - RenderThreadImpl(std::unique_ptr<base::MessageLoop> main_message_loop, - std::unique_ptr<scheduler::RendererScheduler> scheduler); + RenderThreadImpl( + std::unique_ptr<base::MessageLoop> main_message_loop, + std::unique_ptr<blink::scheduler::RendererScheduler> scheduler); private: // IPC::Listener @@ -530,7 +530,7 @@ std::unique_ptr<AppCacheDispatcher> appcache_dispatcher_; std::unique_ptr<DomStorageDispatcher> dom_storage_dispatcher_; std::unique_ptr<IndexedDBDispatcher> main_thread_indexed_db_dispatcher_; - std::unique_ptr<scheduler::RendererScheduler> renderer_scheduler_; + std::unique_ptr<blink::scheduler::RendererScheduler> renderer_scheduler_; std::unique_ptr<RendererBlinkPlatformImpl> blink_platform_impl_; std::unique_ptr<ResourceDispatchThrottler> resource_dispatch_throttler_; std::unique_ptr<CacheStorageDispatcher> main_thread_cache_storage_dispatcher_; @@ -609,7 +609,7 @@ std::unique_ptr<base::Thread> file_thread_; // May be null if overridden by ContentRendererClient. - std::unique_ptr<scheduler::WebThreadBase> compositor_thread_; + std::unique_ptr<blink::scheduler::WebThreadBase> compositor_thread_; // Utility class to provide GPU functionalities to media. // TODO(dcastagna): This should be just one scoped_ptr once
diff --git a/content/renderer/render_thread_impl_browsertest.cc b/content/renderer/render_thread_impl_browsertest.cc index 46ee9ea..b5a0fb8 100644 --- a/content/renderer/render_thread_impl_browsertest.cc +++ b/content/renderer/render_thread_impl_browsertest.cc
@@ -17,7 +17,6 @@ #include "base/strings/string_number_conversions.h" #include "base/threading/thread_task_runner_handle.h" #include "cc/output/buffer_to_texture_target_map.h" -#include "components/scheduler/renderer/renderer_scheduler.h" #include "content/app/mojo/mojo_init.h" #include "content/common/in_process_child_thread_params.h" #include "content/common/resource_messages.h" @@ -31,6 +30,7 @@ #include "content/test/render_thread_impl_browser_test_ipc_helper.h" #include "gpu/GLES2/gl2extchromium.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h" // IPC messages for testing ---------------------------------------------------- @@ -105,7 +105,7 @@ public: RenderThreadImplForTest( const InProcessChildThreadParams& params, - std::unique_ptr<scheduler::RendererScheduler> scheduler, + std::unique_ptr<blink::scheduler::RendererScheduler> scheduler, scoped_refptr<base::SingleThreadTaskRunner>& test_task_counter) : RenderThreadImpl(params, std::move(scheduler), test_task_counter) {} @@ -173,8 +173,8 @@ cc::BufferToTextureTargetMapToString( cc::DefaultBufferToTextureTargetMapForTesting())); - std::unique_ptr<scheduler::RendererScheduler> renderer_scheduler = - scheduler::RendererScheduler::Create(); + std::unique_ptr<blink::scheduler::RendererScheduler> renderer_scheduler = + blink::scheduler::RendererScheduler::Create(); InitializeMojo(); scoped_refptr<base::SingleThreadTaskRunner> test_task_counter( test_task_counter_.get());
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc index 0f0f1a35..64556e6 100644 --- a/content/renderer/render_view_browsertest.cc +++ b/content/renderer/render_view_browsertest.cc
@@ -1628,6 +1628,32 @@ } #endif +TEST_F(RenderViewImplTest, ZoomLimit) { + const double kMinZoomLevel = ZoomFactorToZoomLevel(kMinimumZoomFactor); + const double kMaxZoomLevel = ZoomFactorToZoomLevel(kMaximumZoomFactor); + + // Verifies navigation to a URL with preset zoom level indeed sets the level. + // Regression test for http://crbug.com/139559, where the level was not + // properly set when it is out of the default zoom limits of WebView. + CommonNavigationParams common_params; + common_params.url = GURL("data:text/html,min_zoomlimit_test"); + view()->OnSetZoomLevelForLoadingURL(common_params.url, kMinZoomLevel); + frame()->Navigate(common_params, StartNavigationParams(), + RequestNavigationParams()); + ProcessPendingMessages(); + EXPECT_DOUBLE_EQ(kMinZoomLevel, view()->GetWebView()->zoomLevel()); + + // It should work even when the zoom limit is temporarily changed in the page. + view()->GetWebView()->zoomLimitsChanged(ZoomFactorToZoomLevel(1.0), + ZoomFactorToZoomLevel(1.0)); + common_params.url = GURL("data:text/html,max_zoomlimit_test"); + view()->OnSetZoomLevelForLoadingURL(common_params.url, kMaxZoomLevel); + frame()->Navigate(common_params, StartNavigationParams(), + RequestNavigationParams()); + ProcessPendingMessages(); + EXPECT_DOUBLE_EQ(kMaxZoomLevel, view()->GetWebView()->zoomLevel()); +} + TEST_F(RenderViewImplTest, SetEditableSelectionAndComposition) { // Load an HTML page consisting of an input field. LoadHTML("<html>"
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index f1f20107..81b2c975 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc
@@ -238,7 +238,6 @@ using blink::WebPeerConnectionHandlerClient; using blink::WebPluginAction; using blink::WebPoint; -using blink::WebRange; using blink::WebRect; using blink::WebReferrerPolicy; using blink::WebScriptSource; @@ -1283,6 +1282,8 @@ OnSetEditCommandsForNextKeyEvent) IPC_MESSAGE_HANDLER(ViewMsg_SetPageScale, OnSetPageScale) IPC_MESSAGE_HANDLER(ViewMsg_Zoom, OnZoom) + IPC_MESSAGE_HANDLER(ViewMsg_SetZoomLevelForLoadingURL, + OnSetZoomLevelForLoadingURL) IPC_MESSAGE_HANDLER(ViewMsg_SetPageEncoding, OnSetPageEncoding) IPC_MESSAGE_HANDLER(ViewMsg_ResetPageEncodingToDefault, OnResetPageEncodingToDefault) @@ -2255,6 +2256,21 @@ zoomLevelChanged(); } +void RenderViewImpl::OnSetZoomLevelForLoadingURL(const GURL& url, + double zoom_level) { + // TODO(wjmaclean): We should see if this restriction is really necessary, + // since it isn't enforced in other parts of the page zoom system (e.g. + // when a users changes the zoom of a currently displayed page). Android + // has no UI for this, so in theory the following code would normally just use + // the default zoom anyways. +#if !defined(OS_ANDROID) + // On Android, page zoom isn't used, and in case of WebView, text zoom is used + // for legacy WebView text scaling emulation. Thus, the code that resets + // the zoom level from this map will be effectively resetting text zoom level. + host_zoom_levels_[url] = zoom_level; +#endif +} + void RenderViewImpl::OnSetZoomLevel( PageMsg_SetZoomLevel_Command command, double zoom_level) {
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h index 4cbf00ed..67d9a5c7 100644 --- a/content/renderer/render_view_impl.h +++ b/content/renderer/render_view_impl.h
@@ -509,6 +509,7 @@ FRIEND_TEST_ALL_PREFIXES(RenderViewTest, MacTestCmdUp); #endif FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, SetHistoryLengthAndOffset); + FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, ZoomLimit); FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, NavigateFrame); FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, BasicRenderFrame); FRIEND_TEST_ALL_PREFIXES(RenderViewImplTest, TextInputTypeWithPepper); @@ -524,6 +525,8 @@ FRIEND_TEST_ALL_PREFIXES(RenderViewImplScaleFactorTest, GetCompositionCharacterBoundsTest); + typedef std::map<GURL, double> HostZoomLevels; + enum ErrorPageType { DNS_ERROR, HTTP_404, @@ -624,6 +627,7 @@ void OnSetPageEncoding(const std::string& encoding_name); void OnSetRendererPrefs(const RendererPreferences& renderer_prefs); void OnSetWebUIProperty(const std::string& name, const std::string& value); + void OnSetZoomLevelForLoadingURL(const GURL& url, double zoom_level); void OnSuppressDialogsUntilSwapOut(); void OnThemeChanged(); void OnUpdateTargetURLAck(); @@ -713,6 +717,8 @@ WebPreferences webkit_preferences_; RendererPreferences renderer_preferences_; + HostZoomLevels host_zoom_levels_; + // Whether content state (such as form state, scroll position and page // contents) should be sent to the browser immediately. This is normally // false, but set to true by some tests.
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc index b11681c..61cf0e2 100644 --- a/content/renderer/render_widget.cc +++ b/content/renderer/render_widget.cc
@@ -26,8 +26,6 @@ #include "cc/output/copy_output_request.h" #include "cc/output/output_surface.h" #include "cc/scheduler/begin_frame_source.h" -#include "components/scheduler/renderer/render_widget_scheduling_state.h" -#include "components/scheduler/renderer/renderer_scheduler.h" #include "content/common/content_switches_internal.h" #include "content/common/input/synthetic_gesture_packet.h" #include "content/common/input/web_input_event_traits.h" @@ -63,6 +61,8 @@ #include "third_party/WebKit/public/platform/WebScreenInfo.h" #include "third_party/WebKit/public/platform/WebSize.h" #include "third_party/WebKit/public/platform/WebString.h" +#include "third_party/WebKit/public/platform/scheduler/renderer/render_widget_scheduling_state.h" +#include "third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h" #include "third_party/WebKit/public/web/WebDeviceEmulationParams.h" #include "third_party/WebKit/public/web/WebFrameWidget.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" @@ -111,7 +111,6 @@ using blink::WebPagePopup; using blink::WebPoint; using blink::WebPopupType; -using blink::WebRange; using blink::WebRect; using blink::WebScreenInfo; using blink::WebSize; @@ -247,6 +246,7 @@ text_input_mode_(ui::TEXT_INPUT_MODE_DEFAULT), text_input_flags_(0), can_compose_inline_(true), + composition_range_(gfx::Range::InvalidRange()), popup_type_(popup_type), pending_window_rect_count_(0), screen_info_(screen_info), @@ -254,6 +254,7 @@ #if defined(OS_ANDROID) text_field_is_dirty_(false), #endif + monitor_composition_info_(false), popup_origin_scale_for_emulation_(0.f), frame_swap_message_queue_(new FrameSwapMessageQueue()), resizing_mode_selector_(new ResizingModeSelector()), @@ -495,6 +496,8 @@ IPC_MESSAGE_HANDLER(ViewMsg_SetSurfaceClientId, OnSetSurfaceClientId) IPC_MESSAGE_HANDLER(ViewMsg_WaitForNextFrameForTests, OnWaitNextFrameForTests) + IPC_MESSAGE_HANDLER(InputMsg_RequestCompositionUpdate, + OnRequestCompositionUpdate) #if defined(OS_ANDROID) IPC_MESSAGE_HANDLER(InputMsg_ImeEventAck, OnImeEventAck) IPC_MESSAGE_HANDLER(InputMsg_RequestTextInputStateUpdate, @@ -1365,7 +1368,7 @@ // sure we are in a consistent state. Send(new InputHostMsg_ImeCancelComposition(routing_id())); } - UpdateCompositionInfo(true); + UpdateCompositionInfo(false /* not an immediate request */); } void RenderWidget::OnImeConfirmComposition(const base::string16& text, @@ -1394,7 +1397,7 @@ else webwidget_->confirmComposition(WebWidget::DoNotKeepSelection); input_handler_->set_handling_input_event(false); - UpdateCompositionInfo(true); + UpdateCompositionInfo(false /* not an immediate request */); } void RenderWidget::OnDeviceScaleFactorChanged() { @@ -1479,19 +1482,26 @@ return ui::TEXT_INPUT_TYPE_NONE; } -void RenderWidget::UpdateCompositionInfo(bool should_update_range) { - TRACE_EVENT0("renderer", "RenderWidget::UpdateCompositionInfo"); - gfx::Range range = gfx::Range(); - if (should_update_range) { - GetCompositionRange(&range); - } else { - range = composition_range_; - } - std::vector<gfx::Rect> character_bounds; - GetCompositionCharacterBounds(&character_bounds); +void RenderWidget::UpdateCompositionInfo(bool immediate_request) { + if (!monitor_composition_info_ && !immediate_request) + return; // Do not calculate composition info if not requested. - if (!ShouldUpdateCompositionInfo(range, character_bounds)) + TRACE_EVENT0("renderer", "RenderWidget::UpdateCompositionInfo"); + gfx::Range range; + std::vector<gfx::Rect> character_bounds; + + if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE) { + // Composition information is only available on editable node. + range = gfx::Range::InvalidRange(); + } else { + GetCompositionRange(&range); + GetCompositionCharacterBounds(&character_bounds); + } + + if (!immediate_request && + !ShouldUpdateCompositionInfo(range, character_bounds)) { return; + } composition_character_bounds_ = character_bounds; composition_range_ = range; Send(new InputHostMsg_ImeCompositionRangeChanged( @@ -1550,6 +1560,14 @@ } #endif +void RenderWidget::OnRequestCompositionUpdate(bool immediate_request, + bool monitor_request) { + monitor_composition_info_ = monitor_request; + if (!immediate_request) + return; + UpdateCompositionInfo(true /* immediate request */); +} + bool RenderWidget::ShouldHandleImeEvent() { #if defined(OS_ANDROID) if (!webwidget_) @@ -1741,7 +1759,7 @@ } } - UpdateCompositionInfo(false); + UpdateCompositionInfo(false /* not an immediate request */); } void RenderWidget::SetDeviceColorProfileForTesting( @@ -1886,7 +1904,7 @@ Send(new InputHostMsg_ImeCancelComposition(routing_id())); } - UpdateCompositionInfo(true); + UpdateCompositionInfo(false /* not an immediate request */); } #if defined(OS_ANDROID)
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h index c91e0b8..449d377c4 100644 --- a/content/renderer/render_widget.h +++ b/content/renderer/render_widget.h
@@ -58,6 +58,9 @@ } namespace blink { +namespace scheduler { +class RenderWidgetSchedulingState; +} struct WebDeviceEmulationParams; class WebFrameWidget; class WebGestureEvent; @@ -76,10 +79,6 @@ class Range; } -namespace scheduler { -class RenderWidgetSchedulingState; -} - namespace content { class CompositorDependencies; class ExternalPopupMenu; @@ -352,7 +351,9 @@ // changed. If they are changed, the new value will be sent to the browser // process. This method does nothing when the browser process is not able to // handle composition range and composition character bounds. - void UpdateCompositionInfo(bool should_update_range); + // If immediate_request is true, render sends the latest composition info to + // the browser even if the composition info is not changed. + void UpdateCompositionInfo(bool immediate_request); // Change the device ICC color profile while running a layout test. void SetDeviceColorProfileForTesting(const std::vector<char>& color_profile); @@ -494,6 +495,10 @@ void OnRequestTextInputStateUpdate(); #endif + // Called by the browser process to update the cursor and composition + // information. + void OnRequestCompositionUpdate(bool immediate_request, bool monitor_request); + // Notify the compositor about a change in viewport size. This should be // used only with auto resize mode WebWidgets, as normal WebWidgets should // go through OnResize. @@ -738,6 +743,9 @@ std::deque<blink::WebTextInputInfo> text_input_info_history_; #endif + // True if the IME requests updated composition info. + bool monitor_composition_info_; + std::unique_ptr<RenderWidgetScreenMetricsEmulator> screen_metrics_emulator_; // Popups may be displaced when screen metrics emulation is enabled. @@ -764,7 +772,7 @@ bool has_host_context_menu_location_; gfx::Point host_context_menu_location_; - std::unique_ptr<scheduler::RenderWidgetSchedulingState> + std::unique_ptr<blink::scheduler::RenderWidgetSchedulingState> render_widget_scheduling_state_; // Mouse Lock dispatcher attached to this view.
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc index 96188e3..9b13722 100644 --- a/content/renderer/renderer_blink_platform_impl.cc +++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -21,10 +21,6 @@ #include "base/strings/utf_string_conversions.h" #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" -#include "components/scheduler/child/web_scheduler_impl.h" -#include "components/scheduler/child/web_task_runner_impl.h" -#include "components/scheduler/renderer/renderer_scheduler.h" -#include "components/scheduler/renderer/webthread_impl_for_renderer_scheduler.h" #include "components/url_formatter/url_formatter.h" #include "content/child/blob_storage/webblobregistry_impl.h" #include "content/child/database_util.h" @@ -103,6 +99,7 @@ #include "third_party/WebKit/public/platform/mime_registry.mojom.h" #include "third_party/WebKit/public/platform/modules/device_orientation/WebDeviceMotionListener.h" #include "third_party/WebKit/public/platform/modules/device_orientation/WebDeviceOrientationListener.h" +#include "third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" #include "url/gurl.h" @@ -252,7 +249,7 @@ //------------------------------------------------------------------------------ RendererBlinkPlatformImpl::RendererBlinkPlatformImpl( - scheduler::RendererScheduler* renderer_scheduler, + blink::scheduler::RendererScheduler* renderer_scheduler, base::WeakPtr<shell::InterfaceProvider> remote_interfaces) : BlinkPlatformImpl(renderer_scheduler->DefaultTaskRunner()), main_thread_(renderer_scheduler->CreateMainThread()), @@ -313,8 +310,7 @@ // There may be no child thread in RenderViewTests. These tests can still use // data URLs to bypass the ResourceDispatcher. return new content::WebURLLoaderImpl( - child_thread ? child_thread->resource_dispatcher() : NULL, - currentThread()->getWebTaskRunner()->clone()); + child_thread ? child_thread->resource_dispatcher() : NULL); } blink::WebThread* RendererBlinkPlatformImpl::currentThread() {
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h index c0704ab7..abcb969 100644 --- a/content/renderer/renderer_blink_platform_impl.h +++ b/content/renderer/renderer_blink_platform_impl.h
@@ -32,6 +32,10 @@ } namespace blink { +namespace scheduler { +class RendererScheduler; +class WebThreadImplForRendererScheduler; +} class WebCanvasCaptureHandler; class WebDeviceMotionData; class WebDeviceOrientationData; @@ -43,11 +47,6 @@ class WebServiceWorkerCacheStorage; } -namespace scheduler { -class RendererScheduler; -class WebThreadImplForRendererScheduler; -} - namespace shell { class InterfaceProvider; } @@ -67,7 +66,7 @@ class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl { public: RendererBlinkPlatformImpl( - scheduler::RendererScheduler* renderer_scheduler, + blink::scheduler::RendererScheduler* renderer_scheduler, base::WeakPtr<shell::InterfaceProvider> remote_interfaces); ~RendererBlinkPlatformImpl() override; @@ -296,7 +295,7 @@ IDMap<PlatformEventObserverBase, IDMapOwnPointer> platform_event_observers_; - scheduler::RendererScheduler* renderer_scheduler_; // NOT OWNED + blink::scheduler::RendererScheduler* renderer_scheduler_; // NOT OWNED TopLevelBlameContext top_level_blame_context_; WebTrialTokenValidatorImpl trial_token_validator_;
diff --git a/content/renderer/renderer_main.cc b/content/renderer/renderer_main.cc index 248b2a3..b875325 100644 --- a/content/renderer/renderer_main.cc +++ b/content/renderer/renderer_main.cc
@@ -21,7 +21,6 @@ #include "base/timer/hi_res_timer_manager.h" #include "base/trace_event/trace_event.h" #include "build/build_config.h" -#include "components/scheduler/renderer/renderer_scheduler.h" #include "content/child/child_process.h" #include "content/common/content_constants_internal.h" #include "content/common/mojo/mojo_shell_connection_impl.h" @@ -31,6 +30,7 @@ #include "content/renderer/render_process_impl.h" #include "content/renderer/render_thread_impl.h" #include "content/renderer/renderer_main_platform_delegate.h" +#include "third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h" #include "third_party/skia/include/core/SkGraphics.h" #include "ui/base/ui_base_switches.h" @@ -152,8 +152,8 @@ base::android::RecordLibraryLoaderRendererHistograms(); #endif - std::unique_ptr<scheduler::RendererScheduler> renderer_scheduler( - scheduler::RendererScheduler::Create()); + std::unique_ptr<blink::scheduler::RendererScheduler> renderer_scheduler( + blink::scheduler::RendererScheduler::Create()); // PlatformInitialize uses FieldTrials, so this must happen later. platform.PlatformInitialize();
diff --git a/content/renderer/scheduler/resource_dispatch_throttler.cc b/content/renderer/scheduler/resource_dispatch_throttler.cc index 0b8b1f8..661daa8b 100644 --- a/content/renderer/scheduler/resource_dispatch_throttler.cc +++ b/content/renderer/scheduler/resource_dispatch_throttler.cc
@@ -6,9 +6,9 @@ #include "base/auto_reset.h" #include "base/trace_event/trace_event.h" -#include "components/scheduler/renderer/renderer_scheduler.h" #include "content/common/resource_messages.h" #include "ipc/ipc_message_macros.h" +#include "third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h" namespace content { namespace { @@ -21,7 +21,7 @@ ResourceDispatchThrottler::ResourceDispatchThrottler( IPC::Sender* proxied_sender, - scheduler::RendererScheduler* scheduler, + blink::scheduler::RendererScheduler* scheduler, base::TimeDelta flush_period, uint32_t max_requests_per_flush) : proxied_sender_(proxied_sender),
diff --git a/content/renderer/scheduler/resource_dispatch_throttler.h b/content/renderer/scheduler/resource_dispatch_throttler.h index bf2e77f..3ccc788 100644 --- a/content/renderer/scheduler/resource_dispatch_throttler.h +++ b/content/renderer/scheduler/resource_dispatch_throttler.h
@@ -16,9 +16,11 @@ #include "content/common/content_export.h" #include "ipc/ipc_sender.h" +namespace blink { namespace scheduler { class RendererScheduler; } +} namespace content { @@ -36,7 +38,7 @@ // |flush_period| and |max_requests_per_flush| must be strictly positive // in duration/value. ResourceDispatchThrottler(IPC::Sender* proxied_sender, - scheduler::RendererScheduler* scheduler, + blink::scheduler::RendererScheduler* scheduler, base::TimeDelta flush_period, uint32_t max_requests_per_flush); ~ResourceDispatchThrottler() override; @@ -59,7 +61,7 @@ base::ThreadChecker thread_checker_; IPC::Sender* const proxied_sender_; - scheduler::RendererScheduler* const scheduler_; + blink::scheduler::RendererScheduler* const scheduler_; const base::TimeDelta flush_period_; const uint32_t max_requests_per_flush_;
diff --git a/content/renderer/scheduler/resource_dispatch_throttler_unittest.cc b/content/renderer/scheduler/resource_dispatch_throttler_unittest.cc index a3556c1..e3e9673 100644 --- a/content/renderer/scheduler/resource_dispatch_throttler_unittest.cc +++ b/content/renderer/scheduler/resource_dispatch_throttler_unittest.cc
@@ -11,8 +11,8 @@ #include "base/memory/scoped_vector.h" #include "content/common/resource_messages.h" #include "content/common/resource_request.h" -#include "content/test/fake_renderer_scheduler.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/WebKit/public/platform/scheduler/test/fake_renderer_scheduler.h" namespace content { namespace { @@ -47,7 +47,8 @@ return request_id; } -class RendererSchedulerForTest : public FakeRendererScheduler { +class RendererSchedulerForTest + : public blink::scheduler::FakeRendererScheduler { public: RendererSchedulerForTest() : high_priority_work_anticipated_(false) {} ~RendererSchedulerForTest() override {} @@ -69,8 +70,9 @@ class ResourceDispatchThrottlerForTest : public ResourceDispatchThrottler { public: - ResourceDispatchThrottlerForTest(IPC::Sender* sender, - scheduler::RendererScheduler* scheduler) + ResourceDispatchThrottlerForTest( + IPC::Sender* sender, + blink::scheduler::RendererScheduler* scheduler) : ResourceDispatchThrottler( sender, scheduler,
diff --git a/content/shell/android/browsertests/src/org/chromium/content_shell/browsertests/ContentShellBrowserTestActivity.java b/content/shell/android/browsertests/src/org/chromium/content_shell/browsertests/ContentShellBrowserTestActivity.java index 1262712..32a5816 100644 --- a/content/shell/android/browsertests/src/org/chromium/content_shell/browsertests/ContentShellBrowserTestActivity.java +++ b/content/shell/android/browsertests/src/org/chromium/content_shell/browsertests/ContentShellBrowserTestActivity.java
@@ -76,7 +76,7 @@ setContentView(getTestActivityViewId()); mShellManager = (ShellManager) findViewById(getShellManagerViewId()); mWindowAndroid = new ActivityWindowAndroid(this); - mShellManager.setWindow(mWindowAndroid); + mShellManager.setWindow(mWindowAndroid, false); Window wind = this.getWindow(); wind.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
diff --git a/content/shell/android/java/src/org/chromium/content_shell/ShellManager.java b/content/shell/android/java/src/org/chromium/content_shell/ShellManager.java index d41997f2..ab3ccce 100644 --- a/content/shell/android/java/src/org/chromium/content_shell/ShellManager.java +++ b/content/shell/android/java/src/org/chromium/content_shell/ShellManager.java
@@ -12,6 +12,7 @@ import android.widget.FrameLayout; import org.chromium.base.ThreadUtils; +import org.chromium.base.VisibleForTesting; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; import org.chromium.content.browser.ActivityContentVideoViewEmbedder; @@ -28,6 +29,7 @@ public class ShellManager extends FrameLayout { public static final String DEFAULT_SHELL_URL = "http://www.google.com"; + private static boolean sStartup = true; private WindowAndroid mWindow; private Shell mActiveShell; @@ -67,9 +69,26 @@ * @param window The window used to generate all shells. */ public void setWindow(WindowAndroid window) { + setWindow(window, true); + } + + /** + * @param window The window used to generate all shells. + * @param initialLoadingNeeded Whether initial loading is needed or not. + */ + @VisibleForTesting + public void setWindow(WindowAndroid window, final boolean initialLoadingNeeded) { assert window != null; mWindow = window; - mContentViewRenderView = new ContentViewRenderView(getContext()); + mContentViewRenderView = new ContentViewRenderView(getContext()) { + @Override + protected void onReadyToRender() { + if (sStartup) { + if (initialLoadingNeeded) mActiveShell.loadUrl(mStartupUrl); + sStartup = false; + } + } + }; mContentViewRenderView.onNativeLibraryLoaded(window); }
diff --git a/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellTestBase.java b/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellTestBase.java index 23675f9..8206ff5d 100644 --- a/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellTestBase.java +++ b/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellTestBase.java
@@ -121,14 +121,14 @@ updateFailureReason("Shell is null."); return false; } - if (shell.isLoading()) { - updateFailureReason("Shell is still loading."); - return false; - } if (TextUtils.isEmpty(shell.getContentViewCore().getWebContents().getUrl())) { updateFailureReason("Shell's URL is empty or null."); return false; } + if (!shell.getContentViewCore().getWebContents().isReady()) { + updateFailureReason("Shell's view is not ready."); + return false; + } return true; } }, WAIT_FOR_ACTIVE_SHELL_LOADING_TIMEOUT, CriteriaHelper.DEFAULT_POLLING_INTERVAL);
diff --git a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java index 881bfc0..af13bbf 100644 --- a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java +++ b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java
@@ -42,7 +42,6 @@ private ShellManager mShellManager; private ActivityWindowAndroid mWindowAndroid; private Intent mLastSentIntent; - private String mStartupUrl; @Override @SuppressFBWarnings("DM_EXIT") @@ -82,9 +81,9 @@ mWindowAndroid.setAnimationPlaceholderView( mShellManager.getContentViewRenderView().getSurfaceView()); - mStartupUrl = getUrlFromIntent(getIntent()); - if (!TextUtils.isEmpty(mStartupUrl)) { - mShellManager.setStartupUrl(Shell.sanitizeUrl(mStartupUrl)); + String startupUrl = getUrlFromIntent(getIntent()); + if (!TextUtils.isEmpty(startupUrl)) { + mShellManager.setStartupUrl(Shell.sanitizeUrl(startupUrl)); } if (CommandLine.getInstance().hasSwitch(ContentSwitches.RUN_LAYOUT_TEST)) { @@ -119,13 +118,7 @@ } private void finishInitialization(Bundle savedInstanceState) { - String shellUrl; - if (!TextUtils.isEmpty(mStartupUrl)) { - shellUrl = mStartupUrl; - } else { - shellUrl = ShellManager.DEFAULT_SHELL_URL; - } - + String shellUrl = ShellManager.DEFAULT_SHELL_URL; if (savedInstanceState != null && savedInstanceState.containsKey(ACTIVE_SHELL_URL_KEY)) { shellUrl = savedInstanceState.getString(ACTIVE_SHELL_URL_KEY);
diff --git a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc index 3edc48ce..16f613fb 100644 --- a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc +++ b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc
@@ -123,6 +123,14 @@ return result; } +// Notifies the adapter's observers for each device id the adapter. +void NotifyDevicesAdded(MockBluetoothAdapter* adapter) { + for (BluetoothDevice* device : adapter->GetMockDevices()) { + FOR_EACH_OBSERVER(BluetoothAdapter::Observer, adapter->GetObservers(), + DeviceAdded(adapter, device)); + } +} + // Notifies the adapter's observers that the services have been discovered. void NotifyServicesDiscovered(MockBluetoothAdapter* adapter, MockBluetoothDevice* device) { @@ -188,6 +196,8 @@ return GetFailingGATTOperationsAdapter(); if (fake_adapter_name == "SecondDiscoveryFindsHeartRateAdapter") return GetSecondDiscoveryFindsHeartRateAdapter(); + if (fake_adapter_name == "DeviceEventAdapter") + return GetDeviceEventAdapter(); if (fake_adapter_name == "DelayedServicesDiscoveryAdapter") return GetDelayedServicesDiscoveryAdapter(); if (fake_adapter_name.empty()) @@ -263,6 +273,7 @@ scoped_refptr<NiceMockBluetoothAdapter> LayoutTestBluetoothAdapterProvider::GetScanFilterCheckingAdapter() { scoped_refptr<NiceMockBluetoothAdapter> adapter(GetPoweredAdapter()); + MockBluetoothAdapter* adapter_ptr = adapter.get(); // This fails the test with an error message listing actual and expected UUIDs // if StartDiscoverySessionWithFilter() is called with the wrong argument. @@ -273,8 +284,14 @@ BluetoothUUID(kHeartRateServiceUUID), BluetoothUUID(kBatteryServiceUUID))), _, _)) - .WillRepeatedly(RunCallbackWithResult<1 /* success_callback */>( - []() { return GetDiscoverySession(); })); + .WillRepeatedly( + RunCallbackWithResult<1 /* success_callback */>([adapter_ptr]() { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(&NotifyDevicesAdded, + base::RetainedRef(adapter_ptr))); + + return GetDiscoverySession(); + })); // Any unexpected call results in the failure callback. ON_CALL(*adapter, StartDiscoverySessionWithFilterRaw(_, _, _)) @@ -302,9 +319,17 @@ LayoutTestBluetoothAdapterProvider::GetEmptyAdapter() { scoped_refptr<NiceMockBluetoothAdapter> adapter(GetPoweredAdapter()); + MockBluetoothAdapter* adapter_ptr = adapter.get(); + ON_CALL(*adapter, StartDiscoverySessionWithFilterRaw(_, _, _)) - .WillByDefault(RunCallbackWithResult<1 /* success_callback */>( - []() { return GetDiscoverySession(); })); + .WillByDefault( + RunCallbackWithResult<1 /* success_callback */>([adapter_ptr]() { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(&NotifyDevicesAdded, + base::RetainedRef(adapter_ptr))); + + return GetDiscoverySession(); + })); return adapter; } @@ -356,7 +381,6 @@ base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&AddDevice, make_scoped_refptr(adapter_ptr), - base::Passed(GetHeartRateDevice(adapter_ptr)))); return GetDiscoverySession(); })); @@ -366,6 +390,81 @@ // static scoped_refptr<NiceMockBluetoothAdapter> +LayoutTestBluetoothAdapterProvider::GetDeviceEventAdapter() { + scoped_refptr<NiceMockBluetoothAdapter> adapter(GetPoweredAdapter()); + NiceMockBluetoothAdapter* adapter_ptr = adapter.get(); + + // Add ConnectedHeartRateDevice. + std::unique_ptr<NiceMockBluetoothDevice> connected_hr(GetBaseDevice( + adapter.get(), "Connected Heart Rate Device", + {BluetoothUUID(kHeartRateServiceUUID)}, makeMACAddress(0x0))); + connected_hr->SetConnected(true); + adapter->AddMockDevice(std::move(connected_hr)); + + // Add ChangingBatteryDevice with no uuids. + std::unique_ptr<NiceMockBluetoothDevice> changing_battery( + GetBaseDevice(adapter.get(), "Changing Battery Device", + BluetoothDevice::UUIDList(), makeMACAddress(0x1))); + changing_battery->SetConnected(false); + + NiceMockBluetoothDevice* changing_battery_ptr = changing_battery.get(); + adapter->AddMockDevice(std::move(changing_battery)); + + // Add Non Connected Tx Power Device. + std::unique_ptr<NiceMockBluetoothDevice> non_connected_tx_power( + GetBaseDevice(adapter.get(), "Non Connected Tx Power Device", + {BluetoothUUID(kTxPowerServiceUUID)}, makeMACAddress(0x2))); + non_connected_tx_power->SetConnected(false); + adapter->AddMockDevice(std::move(non_connected_tx_power)); + + // Add Discovery Generic Access Device with no uuids. + std::unique_ptr<NiceMockBluetoothDevice> discovery_generic_access( + GetBaseDevice(adapter.get(), "Discovery Generic Access Device", + BluetoothDevice::UUIDList(), makeMACAddress(0x3))); + discovery_generic_access->SetConnected(true); + + NiceMockBluetoothDevice* discovery_generic_access_ptr = + discovery_generic_access.get(); + adapter->AddMockDevice(std::move(discovery_generic_access)); + + ON_CALL(*adapter, StartDiscoverySessionWithFilterRaw(_, _, _)) + .WillByDefault(RunCallbackWithResult<1 /* success_callback */>( + [adapter_ptr, changing_battery_ptr, discovery_generic_access_ptr]() { + if (adapter_ptr->GetDevices().size() == 4) { + // Post task to add NewGlucoseDevice. + std::unique_ptr<NiceMockBluetoothDevice> glucose_device( + GetBaseDevice(adapter_ptr, "New Glucose Device", + {BluetoothUUID(kGlucoseServiceUUID)}, + makeMACAddress(0x4))); + + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::Bind(&AddDevice, make_scoped_refptr(adapter_ptr), + base::Passed(&glucose_device))); + + // Add uuid and notify of device changed. + changing_battery_ptr->AddUUID(BluetoothUUID(kBatteryServiceUUID)); + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(&NotifyDeviceChanged, + base::RetainedRef(adapter_ptr), + changing_battery_ptr)); + + // Add uuid and notify of services discovered. + discovery_generic_access_ptr->AddUUID( + BluetoothUUID(kGenericAccessServiceUUID)); + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(&NotifyServicesDiscovered, + base::RetainedRef(adapter_ptr), + discovery_generic_access_ptr)); + } + return GetDiscoverySession(); + })); + + return adapter; +} + +// static +scoped_refptr<NiceMockBluetoothAdapter> LayoutTestBluetoothAdapterProvider::GetMissingServiceHeartRateAdapter() { scoped_refptr<NiceMockBluetoothAdapter> adapter(GetEmptyAdapter()); @@ -753,9 +852,11 @@ const std::string& address) { std::unique_ptr<NiceMockBluetoothDevice> device(new NiceMockBluetoothDevice( adapter, 0x1F00 /* Bluetooth class */, device_name, address, - true /* paired */, true /* connected */)); + false /* paired */, false /* connected */)); - ON_CALL(*device, GetUUIDs()).WillByDefault(Return(uuids)); + for (const auto& uuid : uuids) { + device->AddUUID(uuid); + } // Using Invoke allows the device returned from this method to be futher // modified and have more services added to it. The call to ::GetGattServices
diff --git a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h index 57ccefcc..1ab6e0c 100644 --- a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h +++ b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h
@@ -143,6 +143,39 @@ static scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>> GetSecondDiscoveryFindsHeartRateAdapter(); + // |DeviceEventAdapter| + // Inherits from |PoweredAdapter| + // Internal Structure: + // - Connected Heart Rate Device + // - IsGattConnected: Returns true. + // - UUIDs: + // - Heart Rate UUID (0x180d) + // - Changing Battery Device + // - IsGattConnected: Returns false. + // - No UUIDs (A Battery UUID (0x180f) is added by + // StartDiscoverySessionWithFilter). + // - Non Connected Tx Power Device + // - IsGattConnected: Returns false. + // - UUIDs: + // - Tx Power (0x1804) + // - Discovery Generic Access Device + // - IsGattConnected: Returns true. + // - No UUIDs (A Generic Access UUID (0x1800) is added by + // StartDiscoverySessionWithFilter). + // Mock Functions: + // - StartDiscoverySessionWithFilter: Performs the following steps the first + // time is called: + // 1. Post a task to add New Glucose Device (Contains a single + // Glucose UUID (0x1808) and no services). + // 2. Adds a Battery UUID to Changing Battery Device and posts a task + // that notifies observers that the device changed. + // 3. Adds a Generic Access UUID to Discovery Generic Access Device and + // posts a task to Notify its services have been discovered. + // 4. Return a discovery session. + // Successive calls just return a discovery session. + static scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>> + GetDeviceEventAdapter(); + // |MissingServiceHeartRateAdapter| // Inherits from |EmptyAdapter| // Internal Structure: @@ -421,7 +454,11 @@ // - GetName: // Returns: device_name. // - IsPaired: - // Returns true. + // Returns false. + // - IsConnected: + // Returns false. + // - IsGattConnected: + // Returns false. // - ConnectGatt: // Calls error callback with // BluetoothDevice::ConnectErrorCode::ERROR_UNSUPPORTED_DEVICE.
diff --git a/content/shell/browser/layout_test/layout_test_bluetooth_chooser_factory.cc b/content/shell/browser/layout_test/layout_test_bluetooth_chooser_factory.cc index 66b6233..a91c1ce 100644 --- a/content/shell/browser/layout_test/layout_test_bluetooth_chooser_factory.cc +++ b/content/shell/browser/layout_test/layout_test_bluetooth_chooser_factory.cc
@@ -61,8 +61,12 @@ } } - void AddDevice(const std::string& device_id, - const base::string16& device_name) override { + void AddOrUpdateDevice(const std::string& device_id, + bool should_update_name, + const base::string16& device_name, + bool is_gatt_connected, + bool is_paired, + const int8_t* rssi) override { CheckFactory(); std::string event = "add-device("; event += base::UTF16ToUTF8(device_name);
diff --git a/content/shell/browser/layout_test/layout_test_first_device_bluetooth_chooser.cc b/content/shell/browser/layout_test/layout_test_first_device_bluetooth_chooser.cc index f4f4c30..d888d18 100644 --- a/content/shell/browser/layout_test/layout_test_first_device_bluetooth_chooser.cc +++ b/content/shell/browser/layout_test/layout_test_first_device_bluetooth_chooser.cc
@@ -45,10 +45,14 @@ } } -void LayoutTestFirstDeviceBluetoothChooser::AddDevice( - const std::string& deviceId, - const base::string16& deviceName) { - event_handler_.Run(Event::SELECTED, deviceId); +void LayoutTestFirstDeviceBluetoothChooser::AddOrUpdateDevice( + const std::string& device_id, + bool should_update_name, + const base::string16& deviceName, + bool is_gatt_connected, + bool is_paired, + const int8_t* rssi) { + event_handler_.Run(Event::SELECTED, device_id); } } // namespace content
diff --git a/content/shell/browser/layout_test/layout_test_first_device_bluetooth_chooser.h b/content/shell/browser/layout_test/layout_test_first_device_bluetooth_chooser.h index 391151b0..d8bea2e1 100644 --- a/content/shell/browser/layout_test/layout_test_first_device_bluetooth_chooser.h +++ b/content/shell/browser/layout_test/layout_test_first_device_bluetooth_chooser.h
@@ -26,8 +26,12 @@ // BluetoothChooser: void SetAdapterPresence(AdapterPresence presence) override; void ShowDiscoveryState(DiscoveryState state) override; - void AddDevice(const std::string& device_id, - const base::string16& device_name) override; + void AddOrUpdateDevice(const std::string& device_id, + bool should_update_name, + const base::string16& device_name, + bool is_gatt_connected, + bool is_paired, + const int8_t* rssi) override; void RemoveDevice(const std::string& device_id) override {} private:
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index e190bee0..2e0f4f5 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -64,8 +64,6 @@ "//cc/ipc", "//cc/surfaces", "//components/display_compositor", - "//components/scheduler:scheduler", - "//components/scheduler:test_support", "//content/app:both_for_content_tests", "//content/browser:for_content_tests", "//content/browser/speech/proto", @@ -297,7 +295,6 @@ ":test_support", "//cc", "//cc/blink", - "//components/scheduler:test_support", "//components/test_runner:test_runner", "//content/browser:for_content_tests", "//content/child:for_content_tests", @@ -426,7 +423,6 @@ ":web_ui_test_mojo_bindings", "//base/test:test_support", "//components/memory_coordinator/browser", - "//components/scheduler", "//content:resources", "//content/app:both_for_content_tests", "//content/browser:for_content_tests", @@ -632,7 +628,6 @@ "//cc/ipc", "//cc/surfaces", "//components/display_compositor", - "//components/scheduler", "//content:resources", "//content/app:both_for_content_tests", "//content/browser:for_content_tests",
diff --git a/content/test/OWNERS b/content/test/OWNERS index 728ae2c..7fbf43bc 100644 --- a/content/test/OWNERS +++ b/content/test/OWNERS
@@ -8,11 +8,6 @@ per-file test_expectations.txt=* per-file test_expectations_chrome.txt=* -# For Renderer Scheduler files. -per-file fake_renderer_scheduler.*=alexclarke@chromium.org -per-file fake_renderer_scheduler.*=rmcilroy@chromium.org -per-file fake_renderer_scheduler.*=skyostil@chromium.org - # Make the mojom security presubmit happy with the following lines, despite also # allowing wildcard ownership for any test mojom here. per-file *.mojom=set noparent
diff --git a/content/test/data/gpu/filter_effects.html b/content/test/data/gpu/filter_effects.html index 9205bc0..8150397 100644 --- a/content/test/data/gpu/filter_effects.html +++ b/content/test/data/gpu/filter_effects.html
@@ -67,6 +67,18 @@ from {-webkit-filter: opacity(70%)} to {-webkit-filter: opacity(70%)} } +@-webkit-keyframes drop-shadow-invert-anim { + from {-webkit-filter: drop-shadow(8px 8px 10px blue) invert(70%)} + to {-webkit-filter: drop-shadow(8px 8px 10px blue) invert(70%)} +} +@-webkit-keyframes hue-rotate-invert-anim { + from {-webkit-filter: hue-rotate(50deg) invert(70%)} + to {-webkit-filter: hue-rotate(50deg) invert(70%)} +} +@-webkit-keyframes opacity-anim { + from {-webkit-filter: opacity(70%)} + to {-webkit-filter: opacity(70%)} +} .gradient { float: left; height: 50px; @@ -80,14 +92,24 @@ <canvas class="gradient" style="-webkit-animation: blur-anim 150000s;"></canvas> <canvas class="gradient" style="-webkit-animation: grayscale-anim 150000s;"></canvas> <canvas class="gradient" style="-webkit-animation: drop-shadow-anim 150000s;"></canvas> - <canvas class="gradient" style="-webkit-animation: sepia-anim 150000s;"></canvas> + <canvas class="gradient" style="-webkit-animation: sepia-anim 150000s; + -webkit-mask-image: linear-gradient(rgba(0, 0, 0, 1.0), transparent);"></canvas> <canvas class="gradient" style="-webkit-animation: brightness-anim 150000s;"></canvas> <canvas class="gradient" style="-webkit-animation: contrast-anim 150000s;"></canvas> <canvas class="gradient" style="-webkit-animation: hue-rotate-anim 150000s;"></canvas> <canvas class="gradient" style="-webkit-animation: invert-anim 150000s;"></canvas> <canvas class="gradient" style="-webkit-animation: saturate-anim 150000s;"></canvas> <canvas class="gradient" style="-webkit-animation: opacity-anim 150000s;"></canvas> - <canvas class="gradient" style="-webkit-animation: opacity-anim 150000s; transform: scale(1.3, 0.8)"></canvas> + <canvas class="gradient" style="-webkit-animation: drop-shadow-invert-anim 150000s;"></canvas> + <canvas class="gradient" style="-webkit-animation: hue-rotate-invert-anim 150000s;"></canvas> + <canvas class="gradient" style="-webkit-animation: opacity-anim 150000s; + transform: scale(1.3, 0.8)"></canvas> + <canvas class="gradient" style="-webkit-animation: drop-shadow-invert-anim + 150000s; transform: scale(1.3, 0.8) rotate(53deg) translate(-3px, 10px); + -webkit-mask-image: linear-gradient(rgba(0, 0, 0, 1.0), transparent);"> + </canvas> + <canvas class="gradient" style="-webkit-animation: drop-shadow-anim 150000s; + transform: scale(1.3, 0.8);"></canvas> </div> </body> @@ -98,7 +120,7 @@ var canvas = elements[i]; var ctx = canvas.getContext("2d"); - var grd=ctx.createLinearGradient(0,0,canvas.width,0); + var grd=ctx.createLinearGradient(0,0,canvas.width,canvas.height); grd.addColorStop(0,"yellow"); grd.addColorStop(0.5,"blue"); grd.addColorStop(0.75,"red");
diff --git a/content/test/data/navigation_controller/inject_into_blank_iframe.html b/content/test/data/navigation_controller/inject_into_blank_iframe.html new file mode 100644 index 0000000..f4f95e0 --- /dev/null +++ b/content/test/data/navigation_controller/inject_into_blank_iframe.html
@@ -0,0 +1,11 @@ +<html> +<head></head> +<body> + <p>This page injects content into its blank iframe. + <p><iframe id="frame1"></iframe> + <script> + var f = document.getElementById("frame1"); + f.contentDocument.body.innerHTML = "Injected text"; + </script> +</body> +</html>
diff --git a/content/test/fake_compositor_dependencies.cc b/content/test/fake_compositor_dependencies.cc index 1c5bdb0..15de2d9 100644 --- a/content/test/fake_compositor_dependencies.cc +++ b/content/test/fake_compositor_dependencies.cc
@@ -85,7 +85,7 @@ return &gpu_memory_buffer_manager_; } -scheduler::RendererScheduler* +blink::scheduler::RendererScheduler* FakeCompositorDependencies::GetRendererScheduler() { return &renderer_scheduler_; }
diff --git a/content/test/fake_compositor_dependencies.h b/content/test/fake_compositor_dependencies.h index 348c6cb..6893ddca 100644 --- a/content/test/fake_compositor_dependencies.h +++ b/content/test/fake_compositor_dependencies.h
@@ -11,7 +11,7 @@ #include "cc/test/test_shared_bitmap_manager.h" #include "cc/test/test_task_graph_runner.h" #include "content/renderer/gpu/compositor_dependencies.h" -#include "content/test/fake_renderer_scheduler.h" +#include "third_party/WebKit/public/platform/scheduler/test/fake_renderer_scheduler.h" namespace content { @@ -38,7 +38,7 @@ GetCompositorImplThreadTaskRunner() override; cc::SharedBitmapManager* GetSharedBitmapManager() override; gpu::GpuMemoryBufferManager* GetGpuMemoryBufferManager() override; - scheduler::RendererScheduler* GetRendererScheduler() override; + blink::scheduler::RendererScheduler* GetRendererScheduler() override; std::unique_ptr<cc::BeginFrameSource> CreateExternalBeginFrameSource( int routing_id) override; cc::ImageSerializationProcessor* GetImageSerializationProcessor() override; @@ -50,7 +50,7 @@ cc::TestSharedBitmapManager shared_bitmap_manager_; cc::TestGpuMemoryBufferManager gpu_memory_buffer_manager_; cc::TestTaskGraphRunner task_graph_runner_; - FakeRendererScheduler renderer_scheduler_; + blink::scheduler::FakeRendererScheduler renderer_scheduler_; cc::BufferToTextureTargetMap buffer_to_texture_target_map_; DISALLOW_COPY_AND_ASSIGN(FakeCompositorDependencies);
diff --git a/content/test/fake_renderer_scheduler.cc b/content/test/fake_renderer_scheduler.cc deleted file mode 100644 index 95debf0..0000000 --- a/content/test/fake_renderer_scheduler.cc +++ /dev/null
@@ -1,141 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/test/fake_renderer_scheduler.h" - -#include "third_party/WebKit/public/platform/WebThread.h" - -namespace content { - -FakeRendererScheduler::FakeRendererScheduler() { -} - -FakeRendererScheduler::~FakeRendererScheduler() { -} - -std::unique_ptr<blink::WebThread> FakeRendererScheduler::CreateMainThread() { - return nullptr; -} - -scoped_refptr<scheduler::TaskQueue> FakeRendererScheduler::DefaultTaskRunner() { - return nullptr; -} - -scoped_refptr<scheduler::TaskQueue> -FakeRendererScheduler::CompositorTaskRunner() { - return nullptr; -} - -scoped_refptr<scheduler::TaskQueue> FakeRendererScheduler::LoadingTaskRunner() { - return nullptr; -} - -scoped_refptr<scheduler::SingleThreadIdleTaskRunner> -FakeRendererScheduler::IdleTaskRunner() { - return nullptr; -} - -scoped_refptr<scheduler::TaskQueue> FakeRendererScheduler::TimerTaskRunner() { - return nullptr; -} - -scoped_refptr<scheduler::TaskQueue> FakeRendererScheduler::NewLoadingTaskRunner( - const char* name) { - return nullptr; -} - -scoped_refptr<scheduler::TaskQueue> FakeRendererScheduler::NewTimerTaskRunner( - const char* name) { - return nullptr; -} - -scoped_refptr<scheduler::TaskQueue> -FakeRendererScheduler::NewUnthrottledTaskRunner(const char* name) { - return nullptr; -} - -std::unique_ptr<scheduler::RenderWidgetSchedulingState> -FakeRendererScheduler::NewRenderWidgetSchedulingState() { - return nullptr; -} - -void FakeRendererScheduler::WillBeginFrame(const cc::BeginFrameArgs& args) { -} - -void FakeRendererScheduler::BeginFrameNotExpectedSoon() { -} - -void FakeRendererScheduler::DidCommitFrameToCompositor() { -} - -void FakeRendererScheduler::DidHandleInputEventOnCompositorThread( - const blink::WebInputEvent& web_input_event, - InputEventState event_state) { -} - -void FakeRendererScheduler::DidHandleInputEventOnMainThread( - const blink::WebInputEvent& web_input_event) { -} - -void FakeRendererScheduler::DidAnimateForInputOnCompositorThread() { -} - -bool FakeRendererScheduler::IsHighPriorityWorkAnticipated() { - return false; -} - -void FakeRendererScheduler::OnRendererBackgrounded() { -} - -void FakeRendererScheduler::OnRendererForegrounded() { -} - -void FakeRendererScheduler::SuspendRenderer() { -} - -void FakeRendererScheduler::AddPendingNavigation( - blink::WebScheduler::NavigatingFrameType type) { -} - -void FakeRendererScheduler::RemovePendingNavigation( - blink::WebScheduler::NavigatingFrameType type) { -} - -void FakeRendererScheduler::OnNavigationStarted() { -} - -bool FakeRendererScheduler::ShouldYieldForHighPriorityWork() { - return false; -} - -bool FakeRendererScheduler::CanExceedIdleDeadlineIfRequired() const { - return false; -} - -void FakeRendererScheduler::AddTaskObserver( - base::MessageLoop::TaskObserver* task_observer) { -} - -void FakeRendererScheduler::RemoveTaskObserver( - base::MessageLoop::TaskObserver* task_observer) { -} - -void FakeRendererScheduler::Shutdown() { -} - -void FakeRendererScheduler::SuspendTimerQueue() { -} - -void FakeRendererScheduler::ResumeTimerQueue() { -} - -void FakeRendererScheduler::SetTimerQueueSuspensionWhenBackgroundedEnabled( - bool enabled) {} - -void FakeRendererScheduler::SetTopLevelBlameContext( - base::trace_event::BlameContext* blame_context) {} - -void FakeRendererScheduler::SetRAILModeObserver(RAILModeObserver* observer) {} - -} // namespace content
diff --git a/content/test/fake_renderer_scheduler.h b/content/test/fake_renderer_scheduler.h deleted file mode 100644 index 5de64e46..0000000 --- a/content/test/fake_renderer_scheduler.h +++ /dev/null
@@ -1,71 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_TEST_FAKE_RENDERER_SCHEDULER_H_ -#define CONTENT_TEST_FAKE_RENDERER_SCHEDULER_H_ - -#include "base/macros.h" -#include "components/scheduler/renderer/renderer_scheduler.h" - -namespace content { - -class FakeRendererScheduler : public scheduler::RendererScheduler { - public: - FakeRendererScheduler(); - ~FakeRendererScheduler() override; - - // RendererScheduler implementation. - std::unique_ptr<blink::WebThread> CreateMainThread() override; - scoped_refptr<scheduler::TaskQueue> DefaultTaskRunner() override; - scoped_refptr<scheduler::TaskQueue> CompositorTaskRunner() override; - scoped_refptr<scheduler::TaskQueue> LoadingTaskRunner() override; - scoped_refptr<scheduler::SingleThreadIdleTaskRunner> IdleTaskRunner() - override; - scoped_refptr<scheduler::TaskQueue> TimerTaskRunner() override; - scoped_refptr<scheduler::TaskQueue> NewLoadingTaskRunner( - const char* name) override; - scoped_refptr<scheduler::TaskQueue> NewTimerTaskRunner( - const char* name) override; - scoped_refptr<scheduler::TaskQueue> NewUnthrottledTaskRunner( - const char* name) override; - std::unique_ptr<scheduler::RenderWidgetSchedulingState> - NewRenderWidgetSchedulingState() override; - void WillBeginFrame(const cc::BeginFrameArgs& args) override; - void BeginFrameNotExpectedSoon() override; - void DidCommitFrameToCompositor() override; - void DidHandleInputEventOnCompositorThread( - const blink::WebInputEvent& web_input_event, - InputEventState event_state) override; - void DidHandleInputEventOnMainThread( - const blink::WebInputEvent& web_input_event) override; - void DidAnimateForInputOnCompositorThread() override; - void OnRendererBackgrounded() override; - void OnRendererForegrounded() override; - void SuspendRenderer() override; - void AddPendingNavigation( - blink::WebScheduler::NavigatingFrameType type) override; - void RemovePendingNavigation( - blink::WebScheduler::NavigatingFrameType type) override; - void OnNavigationStarted() override; - bool IsHighPriorityWorkAnticipated() override; - bool CanExceedIdleDeadlineIfRequired() const override; - bool ShouldYieldForHighPriorityWork() override; - void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer) override; - void RemoveTaskObserver( - base::MessageLoop::TaskObserver* task_observer) override; - void Shutdown() override; - void SuspendTimerQueue() override; - void ResumeTimerQueue() override; - void SetTimerQueueSuspensionWhenBackgroundedEnabled(bool enabled) override; - void SetTopLevelBlameContext( - base::trace_event::BlameContext* blame_context) override; - void SetRAILModeObserver(RAILModeObserver* observer) override; - - private: - DISALLOW_COPY_AND_ASSIGN(FakeRendererScheduler); -}; - -} // namespace content - -#endif // CONTENT_TEST_FAKE_RENDERER_SCHEDULER_H_
diff --git a/content/test/gpu/gpu_tests/gpu_process_expectations.py b/content/test/gpu/gpu_tests/gpu_process_expectations.py index bc7247ee..08010ac 100644 --- a/content/test/gpu/gpu_tests/gpu_process_expectations.py +++ b/content/test/gpu/gpu_tests/gpu_process_expectations.py
@@ -13,22 +13,6 @@ self.Fail('GpuProcess.video', ['linux'], bug=257109) - # Android - self.Fail('GpuProcess.no_gpu_process', - ['android'], bug=611930) - self.Fail('GpuProcess.identify_active_gpu1', - ['android'], bug=611930) - self.Fail('GpuProcess.identify_active_gpu2', - ['android'], bug=611930) - self.Fail('GpuProcess.identify_active_gpu3', - ['android'], bug=611930) - self.Fail('GpuProcess.identify_active_gpu4', - ['android'], bug=611930) - self.Fail('GpuProcess.readback_webgl_gpu_process', - ['android'], bug=611930) - self.Fail('GpuProcess.driver_bug_workarounds_upon_gl_renderer', - ['android'], bug=611930) - # Nexus 5X # Skip this test because expecting it to fail will still run it. self.Skip('GpuProcess.skip_gpu_process',
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py index 09f0305..8c0fbcdd 100644 --- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py +++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -42,6 +42,10 @@ 'invariant-does-not-leak-across-shaders.html', bug=634813) + self.Fail('conformance2/textures/' + + 'misc/copy-texture-image-webgl-specific.html', + bug=631934) + self.Flaky('conformance2/query/occlusion-query.html', bug=603168) # All platforms with AMD GPU. @@ -160,6 +164,8 @@ # Mac only. self.Fail('conformance/glsl/misc/shaders-with-invariance.html', ['mac'], bug=483282) + self.Fail('conformance2/extensions/ext-color-buffer-float.html', + ['mac'], bug=633022) self.Fail('deqp/functional/gles3/shaderloop_do_while.html', ['mac'], bug=617820) self.Fail('deqp/functional/gles3/fbocompleteness.html',
diff --git a/content/test/gpu/page_sets/gpu_process_tests.py b/content/test/gpu/page_sets/gpu_process_tests.py index 87fa7e5..ddfdd71 100644 --- a/content/test/gpu/page_sets/gpu_process_tests.py +++ b/content/test/gpu/page_sets/gpu_process_tests.py
@@ -174,7 +174,11 @@ test, finder_options, story_set) options = finder_options.browser_options - if sys.platform in ('cygwin', 'win32'): + if options.browser_type.startswith('android'): + # Hit id 8 from kSoftwareRenderingListJson, which applies to any platform. + options.AppendExtraBrowserArgs('--gpu-testing-vendor-id=0x10de') + options.AppendExtraBrowserArgs('--gpu-testing-device-id=0x0324') + elif sys.platform in ('cygwin', 'win32'): # Hit id 34 from kSoftwareRenderingListJson. options.AppendExtraBrowserArgs('--gpu-testing-vendor-id=0x5333') options.AppendExtraBrowserArgs('--gpu-testing-device-id=0x8811') @@ -195,15 +199,19 @@ class NoGpuProcessPage(gpu_test_base.PageBase): - def __init__(self, story_set, expectations): + def __init__(self, story_set, expectations, is_platform_android): super(NoGpuProcessPage, self).__init__( url='about:blank', name='GpuProcess.no_gpu_process', page_set=story_set, shared_page_state_class=NoGpuProcessSharedPageState, expectations=expectations) + self.is_platform_android = is_platform_android def Validate(self, tab, results): + if self.is_platform_android: + return + has_gpu_process_js = 'chrome.gpuBenchmarking.hasGpuProcess()' has_gpu_process = tab.EvaluateJavaScript(has_gpu_process_js) if has_gpu_process: @@ -215,11 +223,13 @@ super(SoftwareGpuProcessSharedPageState, self).__init__( test, finder_options, story_set) options = finder_options.browser_options + + # Hit exception from id 50 from kSoftwareRenderingListJson. options.AppendExtraBrowserArgs('--gpu-testing-vendor-id=0x10de') options.AppendExtraBrowserArgs('--gpu-testing-device-id=0x0de1') options.AppendExtraBrowserArgs('--gpu-testing-gl-vendor=VMware') options.AppendExtraBrowserArgs('--gpu-testing-gl-renderer=SVGA3D') - options.AppendExtraBrowserArgs('--gpu-testing-gl-version="2.1 Mesa 10.1"') + options.AppendExtraBrowserArgs('--gpu-testing-gl-version=2.1 Mesa 10.1') class SoftwareGpuProcessPage(gpu_test_base.PageBase): @@ -286,7 +296,10 @@ super(DriverBugWorkaroundsUponGLRendererShared, self).__init__( test, finder_options, story_set) options = finder_options.browser_options - if sys.platform in ('cygwin', 'win32'): + if options.browser_type.startswith('android'): + # Hit id 108 from kGpuDriverBugListJson. + options.AppendExtraBrowserArgs('--gpu-testing-gl-vendor=Qualcomm') + elif sys.platform in ('cygwin', 'win32'): # Hit id 51 and 87 from kGpuDriverBugListJson. options.AppendExtraBrowserArgs('--gpu-testing-vendor-id=0x1002') options.AppendExtraBrowserArgs('--gpu-testing-device-id=0x6779') @@ -309,11 +322,13 @@ class DriverBugWorkaroundsUponGLRendererPage(DriverBugWorkaroundsTestsPage): - def __init__(self, story_set, expectations): + def __init__(self, story_set, expectations, is_platform_android): self.expected_workaround = None self.unexpected_workaround = None - if sys.platform in ('cygwin', 'win32'): + if is_platform_android: + self.expected_workaround = "wake_up_gpu_before_drawing" + elif sys.platform in ('cygwin', 'win32'): self.expected_workaround = "texsubimage_faster_than_teximage" self.unexpected_workaround = "disable_d3d11" elif sys.platform.startswith('linux'): @@ -461,8 +476,9 @@ super(ReadbackWebGLGpuProcessSharedPageState, self).__init__( test, finder_options, story_set) options = finder_options.browser_options + is_platform_android = options.browser_type.startswith('android') - if sys.platform.startswith('linux'): + if sys.platform.startswith('linux') and not is_platform_android: # Hit id 110 from kSoftwareRenderingListJson. options.AppendExtraBrowserArgs('--gpu-testing-vendor-id=0x10de') options.AppendExtraBrowserArgs('--gpu-testing-device-id=0x0de1') @@ -472,16 +488,17 @@ options.AppendExtraBrowserArgs('--gpu-testing-gl-version="3.0 Mesa 11.2"') class ReadbackWebGLGpuProcessPage(gpu_test_base.PageBase): - def __init__(self, story_set, expectations): + def __init__(self, story_set, expectations, is_platform_android): super(ReadbackWebGLGpuProcessPage, self).__init__( url='chrome:gpu', name='GpuProcess.readback_webgl_gpu_process', page_set=story_set, shared_page_state_class=ReadbackWebGLGpuProcessSharedPageState, expectations=expectations) + self.is_platform_android = is_platform_android def Validate(self, tab, results): - if sys.platform.startswith('linux'): + if sys.platform.startswith('linux') and not self.is_platform_android: feature_status_js = 'browserBridge.gpuInfo.featureStatus.featureStatus' feature_status_list = tab.EvaluateJavaScript(feature_status_js) result = True @@ -592,15 +609,12 @@ self.AddStory(FunctionalVideoPage(self, expectations)) self.AddStory(GpuInfoCompletePage(self, expectations)) - self.AddStory(NoGpuProcessPage(self, expectations)) - self.AddStory(SoftwareGpuProcessPage(self, expectations)) + self.AddStory(NoGpuProcessPage(self, expectations, is_platform_android)) self.AddStory(DriverBugWorkaroundsInGpuProcessPage(self, expectations)) - self.AddStory(IdentifyActiveGpuPage1(self, expectations)) - self.AddStory(IdentifyActiveGpuPage2(self, expectations)) - self.AddStory(IdentifyActiveGpuPage3(self, expectations)) - self.AddStory(IdentifyActiveGpuPage4(self, expectations)) - self.AddStory(ReadbackWebGLGpuProcessPage(self, expectations)) - self.AddStory(DriverBugWorkaroundsUponGLRendererPage(self, expectations)) + self.AddStory(ReadbackWebGLGpuProcessPage(self, expectations, + is_platform_android)) + self.AddStory(DriverBugWorkaroundsUponGLRendererPage(self, expectations, + is_platform_android)) self.AddStory(EqualBugWorkaroundsInBrowserAndGpuProcessPage(self, expectations)) if not is_platform_android: @@ -608,6 +622,17 @@ self.AddStory(HasTransparentVisualsGpuProcessPage(self, expectations)) self.AddStory(NoTransparentVisualsGpuProcessPage(self, expectations)) + # There is no Android multi-gpu configuration and the helper + # gpu_info_collector.cc::IdentifyActiveGPU is not even called. + self.AddStory(IdentifyActiveGpuPage1(self, expectations)) + self.AddStory(IdentifyActiveGpuPage2(self, expectations)) + self.AddStory(IdentifyActiveGpuPage3(self, expectations)) + self.AddStory(IdentifyActiveGpuPage4(self, expectations)) + + # There is currently no entry in kSoftwareRenderingListJson that enables + # a software GL driver on Android. + self.AddStory(SoftwareGpuProcessPage(self, expectations)) + @property def allow_mixed_story_states(self): # Return True here in order to be able to run pages with different browser
diff --git a/content/test/layouttest_support.cc b/content/test/layouttest_support.cc index 7e2a5be..746d0ad 100644 --- a/content/test/layouttest_support.cc +++ b/content/test/layouttest_support.cc
@@ -15,7 +15,6 @@ #include "cc/output/copy_output_request.h" #include "cc/test/pixel_test_output_surface.h" #include "cc/test/test_delegating_output_surface.h" -#include "components/scheduler/test/renderer_scheduler_test_support.h" #include "components/test_runner/test_common.h" #include "components/test_runner/web_frame_test_proxy.h" #include "components/test_runner/web_view_test_proxy.h" @@ -41,6 +40,7 @@ #include "third_party/WebKit/public/platform/WebGamepads.h" #include "third_party/WebKit/public/platform/modules/device_orientation/WebDeviceMotionData.h" #include "third_party/WebKit/public/platform/modules/device_orientation/WebDeviceOrientationData.h" +#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h" #include "third_party/WebKit/public/web/WebHistoryItem.h" #include "third_party/WebKit/public/web/WebView.h" @@ -571,9 +571,9 @@ } void SchedulerRunIdleTasks(const base::Closure& callback) { - scheduler::RendererScheduler* scheduler = - content::RenderThreadImpl::current()->GetRendererScheduler(); - scheduler::RunIdleTasksForTesting(scheduler, callback); + blink::scheduler::RendererScheduler* scheduler = + content::RenderThreadImpl::current()->GetRendererScheduler(); + blink::scheduler::RunIdleTasksForTesting(scheduler, callback); } } // namespace content
diff --git a/content/test/test_blink_web_unit_test_support.cc b/content/test/test_blink_web_unit_test_support.cc index b6ed473..db37bfc 100644 --- a/content/test/test_blink_web_unit_test_support.cc +++ b/content/test/test_blink_web_unit_test_support.cc
@@ -18,9 +18,6 @@ #include "build/build_config.h" #include "cc/blink/web_layer_impl.h" #include "cc/trees/layer_tree_settings.h" -#include "components/scheduler/renderer/renderer_scheduler_impl.h" -#include "components/scheduler/renderer/webthread_impl_for_renderer_scheduler.h" -#include "components/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.h" #include "content/child/web_url_loader_impl.h" #include "content/test/mock_webclipboard_impl.h" #include "content/test/web_gesture_curve_mock.h" @@ -31,9 +28,10 @@ #include "third_party/WebKit/public/platform/WebData.h" #include "third_party/WebKit/public/platform/WebPluginListBuilder.h" #include "third_party/WebKit/public/platform/WebString.h" -#include "third_party/WebKit/public/platform/WebTaskRunner.h" #include "third_party/WebKit/public/platform/WebThread.h" #include "third_party/WebKit/public/platform/WebURL.h" +#include "third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h" +#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h" #include "third_party/WebKit/public/web/WebKit.h" #include "third_party/WebKit/public/web/WebNetworkStateNotifier.h" #include "third_party/WebKit/public/web/WebRuntimeFeatures.h" @@ -111,8 +109,7 @@ dummy_task_runner_handle.reset( new base::ThreadTaskRunnerHandle(dummy_task_runner)); } - renderer_scheduler_ = base::WrapUnique(new scheduler::RendererSchedulerImpl( - scheduler::LazySchedulerMessageLoopDelegateForTests::Create())); + renderer_scheduler_ = blink::scheduler::CreateRendererSchedulerForTests(); web_thread_ = renderer_scheduler_->CreateMainThread(); // Set up a FeatureList instance, so that code using that API will not hit a @@ -187,11 +184,9 @@ } blink::WebURLLoader* TestBlinkWebUnitTestSupport::createURLLoader() { - blink::WebThread* currentThread = Platform::current()->currentThread(); // This loader should be used only for process-local resources such as // data URLs. - blink::WebURLLoader* default_loader = new WebURLLoaderImpl( - nullptr, currentThread->getWebTaskRunner()->clone()); + blink::WebURLLoader* default_loader = new WebURLLoaderImpl(nullptr); return url_loader_factory_->createURLLoader(default_loader); }
diff --git a/content/test/test_blink_web_unit_test_support.h b/content/test/test_blink_web_unit_test_support.h index 33a896f..a265f16 100644 --- a/content/test/test_blink_web_unit_test_support.h +++ b/content/test/test_blink_web_unit_test_support.h
@@ -27,9 +27,11 @@ class WebLayerTreeView; } +namespace blink { namespace scheduler { class RendererScheduler; } +} namespace content { @@ -84,7 +86,7 @@ base::ScopedTempDir file_system_root_; std::unique_ptr<blink::WebURLLoaderMockFactory> url_loader_factory_; cc_blink::WebCompositorSupportImpl compositor_support_; - std::unique_ptr<scheduler::RendererScheduler> renderer_scheduler_; + std::unique_ptr<blink::scheduler::RendererScheduler> renderer_scheduler_; std::unique_ptr<blink::WebThread> web_thread_; #if defined(OS_WIN) || defined(OS_MACOSX)
diff --git a/content/test/test_render_view_host.h b/content/test/test_render_view_host.h index 082d369..314267b2d6 100644 --- a/content/test/test_render_view_host.h +++ b/content/test/test_render_view_host.h
@@ -100,7 +100,6 @@ void Focus() override {} void SetIsLoading(bool is_loading) override {} void UpdateCursor(const WebCursor& cursor) override {} - void ImeCancelComposition() override {} void RenderProcessGone(base::TerminationStatus status, int error_code) override; void Destroy() override;
diff --git a/content/utility/BUILD.gn b/content/utility/BUILD.gn index 883fbd1d..51b8b6b9 100644 --- a/content/utility/BUILD.gn +++ b/content/utility/BUILD.gn
@@ -20,7 +20,6 @@ deps = [ "//base", - "//components/scheduler", "//content:export", "//content/child", "//content/public/child:child_sources",
diff --git a/content/utility/utility_blink_platform_impl.cc b/content/utility/utility_blink_platform_impl.cc index b3b73bc..7559196 100644 --- a/content/utility/utility_blink_platform_impl.cc +++ b/content/utility/utility_blink_platform_impl.cc
@@ -4,13 +4,12 @@ #include "content/utility/utility_blink_platform_impl.h" -#include "content/utility/webthread_impl_for_utility_thread.h" +#include "third_party/WebKit/public/platform/scheduler/utility/webthread_impl_for_utility_thread.h" namespace content { UtilityBlinkPlatformImpl::UtilityBlinkPlatformImpl() - : main_thread_(new WebThreadImplForUtilityThread()) { -} + : main_thread_(new blink::scheduler::WebThreadImplForUtilityThread()) {} UtilityBlinkPlatformImpl::~UtilityBlinkPlatformImpl() { }
diff --git a/content/utility/utility_blink_platform_impl.h b/content/utility/utility_blink_platform_impl.h index 32f9007..f8bc8dc 100644 --- a/content/utility/utility_blink_platform_impl.h +++ b/content/utility/utility_blink_platform_impl.h
@@ -10,9 +10,13 @@ #include "base/macros.h" #include "content/child/blink_platform_impl.h" -namespace content { - +namespace blink { +namespace scheduler { class WebThreadImplForUtilityThread; +} +} + +namespace content { class UtilityBlinkPlatformImpl : public BlinkPlatformImpl { public: @@ -23,7 +27,7 @@ blink::WebThread* currentThread() override; private: - std::unique_ptr<WebThreadImplForUtilityThread> main_thread_; + std::unique_ptr<blink::scheduler::WebThreadImplForUtilityThread> main_thread_; DISALLOW_COPY_AND_ASSIGN(UtilityBlinkPlatformImpl); };
diff --git a/content/utility/utility_process_control_impl.cc b/content/utility/utility_process_control_impl.cc deleted file mode 100644 index 76e4f5a..0000000 --- a/content/utility/utility_process_control_impl.cc +++ /dev/null
@@ -1,44 +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 "content/utility/utility_process_control_impl.h" - -#include "base/bind.h" -#include "content/public/common/content_client.h" -#include "content/public/utility/content_utility_client.h" -#include "content/public/utility/utility_thread.h" -#include "content/utility/utility_thread_impl.h" - -#if defined(ENABLE_MOJO_MEDIA_IN_UTILITY_PROCESS) -#include "media/mojo/services/mojo_media_application_factory.h" // nogncheck -#endif - -namespace content { - -UtilityProcessControlImpl::UtilityProcessControlImpl() {} - -UtilityProcessControlImpl::~UtilityProcessControlImpl() {} - -void UtilityProcessControlImpl::RegisterApplications(ApplicationMap* apps) { - GetContentClient()->utility()->RegisterMojoApplications(apps); - -#if defined(ENABLE_MOJO_MEDIA_IN_UTILITY_PROCESS) - MojoApplicationInfo app_info; - app_info.application_factory = base::Bind(&media::CreateMojoMediaApplication); - apps->insert(std::make_pair("mojo:media", app_info)); -#endif -} - -void UtilityProcessControlImpl::OnApplicationQuit() { - UtilityThread::Get()->ReleaseProcessIfNeeded(); -} - -void UtilityProcessControlImpl::OnLoadFailed() { - UtilityThreadImpl* utility_thread = - static_cast<UtilityThreadImpl*>(UtilityThread::Get()); - utility_thread->Shutdown(); - utility_thread->ReleaseProcessIfNeeded(); -} - -} // namespace content
diff --git a/content/utility/utility_process_control_impl.h b/content/utility/utility_process_control_impl.h deleted file mode 100644 index ff8bc41..0000000 --- a/content/utility/utility_process_control_impl.h +++ /dev/null
@@ -1,32 +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 CONTENT_UTILITY_UTILITY_PROCESS_CONTROL_IMPL_H_ -#define CONTENT_UTILITY_UTILITY_PROCESS_CONTROL_IMPL_H_ - -#include "base/macros.h" -#include "content/child/process_control_impl.h" - -namespace content { - -// Customization of ProcessControlImpl for the utility process. Exposed to the -// browser via the utility process's InterfaceRegistry. -class UtilityProcessControlImpl : public ProcessControlImpl { - public: - UtilityProcessControlImpl(); - ~UtilityProcessControlImpl() override; - - // ProcessControlImpl: - void RegisterApplications(ApplicationMap* apps) override; - void OnApplicationQuit() override; - - private: - void OnLoadFailed() override; - - DISALLOW_COPY_AND_ASSIGN(UtilityProcessControlImpl); -}; - -} // namespace content - -#endif // CONTENT_UTILITY_UTILITY_PROCESS_CONTROL_IMPL_H_
diff --git a/content/utility/utility_service_factory.cc b/content/utility/utility_service_factory.cc new file mode 100644 index 0000000..230a98f6 --- /dev/null +++ b/content/utility/utility_service_factory.cc
@@ -0,0 +1,45 @@ +// 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 "content/utility/utility_service_factory.h" + +#include "base/bind.h" +#include "content/public/common/content_client.h" +#include "content/public/utility/content_utility_client.h" +#include "content/public/utility/utility_thread.h" +#include "content/utility/utility_thread_impl.h" + +#if defined(ENABLE_MOJO_MEDIA_IN_UTILITY_PROCESS) +#include "media/mojo/services/mojo_media_application_factory.h" // nogncheck +#endif + +namespace content { + +UtilityServiceFactory::UtilityServiceFactory() {} + +UtilityServiceFactory::~UtilityServiceFactory() {} + +void UtilityServiceFactory::RegisterServices(ServiceMap* services) { + GetContentClient()->utility()->RegisterMojoApplications(services); + +#if defined(ENABLE_MOJO_MEDIA_IN_UTILITY_PROCESS) + MojoApplicationInfo service_info; + service_info.application_factory = + base::Bind(&media::CreateMojoMediaApplication); + services->insert(std::make_pair("mojo:media", service_info)); +#endif +} + +void UtilityServiceFactory::OnServiceQuit() { + UtilityThread::Get()->ReleaseProcessIfNeeded(); +} + +void UtilityServiceFactory::OnLoadFailed() { + UtilityThreadImpl* utility_thread = + static_cast<UtilityThreadImpl*>(UtilityThread::Get()); + utility_thread->Shutdown(); + utility_thread->ReleaseProcessIfNeeded(); +} + +} // namespace content
diff --git a/content/utility/utility_service_factory.h b/content/utility/utility_service_factory.h new file mode 100644 index 0000000..0e561bd --- /dev/null +++ b/content/utility/utility_service_factory.h
@@ -0,0 +1,32 @@ +// 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 CONTENT_UTILITY_UTILITY_SERVICE_FACTORY_H_ +#define CONTENT_UTILITY_UTILITY_SERVICE_FACTORY_H_ + +#include "base/macros.h" +#include "content/child/service_factory.h" + +namespace content { + +// Customization of ServiceFactory for the utility process. Exposed to the +// browser via the utility process's InterfaceRegistry. +class UtilityServiceFactory : public ServiceFactory { + public: + UtilityServiceFactory(); + ~UtilityServiceFactory() override; + + // ServiceFactory overrides: + void RegisterServices(ServiceMap* services) override; + void OnServiceQuit() override; + + private: + void OnLoadFailed() override; + + DISALLOW_COPY_AND_ASSIGN(UtilityServiceFactory); +}; + +} // namespace content + +#endif // CONTENT_UTILITY_UTILITY_SERVICE_FACTORY_H_
diff --git a/content/utility/utility_thread_impl.cc b/content/utility/utility_thread_impl.cc index 8425e664..dfbfd7d 100644 --- a/content/utility/utility_thread_impl.cc +++ b/content/utility/utility_thread_impl.cc
@@ -16,7 +16,7 @@ #include "content/public/common/content_switches.h" #include "content/public/utility/content_utility_client.h" #include "content/utility/utility_blink_platform_impl.h" -#include "content/utility/utility_process_control_impl.h" +#include "content/utility/utility_service_factory.h" #include "ipc/ipc_sync_channel.h" #include "services/shell/public/cpp/interface_registry.h" #include "third_party/WebKit/public/web/WebKit.h" @@ -95,9 +95,9 @@ ChildProcess::current()->AddRefProcess(); GetContentClient()->utility()->UtilityThreadStarted(); - process_control_.reset(new UtilityProcessControlImpl); + service_factory_.reset(new UtilityServiceFactory); GetInterfaceRegistry()->AddInterface(base::Bind( - &UtilityThreadImpl::BindProcessControlRequest, base::Unretained(this))); + &UtilityThreadImpl::BindServiceFactoryRequest, base::Unretained(this))); GetContentClient()->utility()->ExposeInterfacesToBrowser( GetInterfaceRegistry()); @@ -125,10 +125,10 @@ ReleaseProcessIfNeeded(); } -void UtilityThreadImpl::BindProcessControlRequest( - mojo::InterfaceRequest<mojom::ProcessControl> request) { - DCHECK(process_control_); - process_control_bindings_.AddBinding(process_control_.get(), +void UtilityThreadImpl::BindServiceFactoryRequest( + shell::mojom::ServiceFactoryRequest request) { + DCHECK(service_factory_); + service_factory_bindings_.AddBinding(service_factory_.get(), std::move(request)); }
diff --git a/content/utility/utility_thread_impl.h b/content/utility/utility_thread_impl.h index 72d2547..c7e88381 100644 --- a/content/utility/utility_thread_impl.h +++ b/content/utility/utility_thread_impl.h
@@ -14,9 +14,9 @@ #include "build/build_config.h" #include "content/child/child_thread_impl.h" #include "content/common/content_export.h" -#include "content/common/process_control.mojom.h" #include "content/public/utility/utility_thread.h" #include "mojo/public/cpp/bindings/binding_set.h" +#include "services/shell/public/interfaces/service_factory.mojom.h" namespace base { class FilePath; @@ -25,7 +25,7 @@ namespace content { class BlinkPlatformImpl; class UtilityBlinkPlatformImpl; -class UtilityProcessControlImpl; +class UtilityServiceFactory; #if defined(COMPILER_MSVC) // See explanation for other RenderViewHostImpl which is the same issue. @@ -56,19 +56,18 @@ void OnBatchModeStarted(); void OnBatchModeFinished(); - void BindProcessControlRequest( - mojo::InterfaceRequest<content::mojom::ProcessControl> request); + void BindServiceFactoryRequest(shell::mojom::ServiceFactoryRequest request); // True when we're running in batch mode. bool batch_mode_; std::unique_ptr<UtilityBlinkPlatformImpl> blink_platform_impl_; - // Process control for Mojo application hosting. - std::unique_ptr<UtilityProcessControlImpl> process_control_; + // shell::mojom::ServiceFactory for shell::Service hosting. + std::unique_ptr<UtilityServiceFactory> service_factory_; - // Bindings to the mojom::ProcessControl impl. - mojo::BindingSet<mojom::ProcessControl> process_control_bindings_; + // Bindings to the shell::mojom::ServiceFactory impl. + mojo::BindingSet<shell::mojom::ServiceFactory> service_factory_bindings_; DISALLOW_COPY_AND_ASSIGN(UtilityThreadImpl); };
diff --git a/content/utility/webthread_impl_for_utility_thread.cc b/content/utility/webthread_impl_for_utility_thread.cc deleted file mode 100644 index c949a74..0000000 --- a/content/utility/webthread_impl_for_utility_thread.cc +++ /dev/null
@@ -1,39 +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 "content/utility/webthread_impl_for_utility_thread.h" - -#include "base/threading/thread_task_runner_handle.h" - -namespace content { - -WebThreadImplForUtilityThread::WebThreadImplForUtilityThread() - : task_runner_(base::ThreadTaskRunnerHandle::Get()), - thread_id_(base::PlatformThread::CurrentId()) { -} - -WebThreadImplForUtilityThread::~WebThreadImplForUtilityThread() { -} - -blink::WebScheduler* WebThreadImplForUtilityThread::scheduler() const { - NOTIMPLEMENTED(); - return nullptr; -} - -blink::PlatformThreadId WebThreadImplForUtilityThread::threadId() const { - return thread_id_; -} - -base::SingleThreadTaskRunner* WebThreadImplForUtilityThread::GetTaskRunner() - const { - return task_runner_.get(); -} - -scheduler::SingleThreadIdleTaskRunner* -WebThreadImplForUtilityThread::GetIdleTaskRunner() const { - NOTIMPLEMENTED(); - return nullptr; -} - -} // namespace content
diff --git a/content/utility/webthread_impl_for_utility_thread.h b/content/utility/webthread_impl_for_utility_thread.h deleted file mode 100644 index a5220fe..0000000 --- a/content/utility/webthread_impl_for_utility_thread.h +++ /dev/null
@@ -1,36 +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 CONTENT_UTILITY_WEBTHREAD_IMPL_FOR_UTILITY_THREAD_H_ -#define CONTENT_UTILITY_WEBTHREAD_IMPL_FOR_UTILITY_THREAD_H_ - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "components/scheduler/child/webthread_base.h" - -namespace content { - -class WebThreadImplForUtilityThread : public scheduler::WebThreadBase { - public: - WebThreadImplForUtilityThread(); - ~WebThreadImplForUtilityThread() override; - - // blink::WebThread implementation. - blink::WebScheduler* scheduler() const override; - blink::PlatformThreadId threadId() const override; - - // WebThreadBase implementation. - base::SingleThreadTaskRunner* GetTaskRunner() const override; - scheduler::SingleThreadIdleTaskRunner* GetIdleTaskRunner() const override; - - private: - scoped_refptr<base::SingleThreadTaskRunner> task_runner_; - blink::PlatformThreadId thread_id_; - - DISALLOW_COPY_AND_ASSIGN(WebThreadImplForUtilityThread); -}; - -} // namespace content - -#endif // CONTENT_UTILITY_WEBTHREAD_IMPL_FOR_UTILITY_THREAD_H_
diff --git a/device/bluetooth/bluetooth_adapter.cc b/device/bluetooth/bluetooth_adapter.cc index 7b30fad1..878d3b4 100644 --- a/device/bluetooth/bluetooth_adapter.cc +++ b/device/bluetooth/bluetooth_adapter.cc
@@ -55,6 +55,11 @@ observers_.RemoveObserver(observer); } +bool BluetoothAdapter::HasObserver(BluetoothAdapter::Observer* observer) { + DCHECK(observer); + return observers_.HasObserver(observer); +} + void BluetoothAdapter::StartDiscoverySession( const DiscoverySessionCallback& callback, const ErrorCallback& error_callback) {
diff --git a/device/bluetooth/bluetooth_adapter.h b/device/bluetooth/bluetooth_adapter.h index ba81281a..e89f544 100644 --- a/device/bluetooth/bluetooth_adapter.h +++ b/device/bluetooth/bluetooth_adapter.h
@@ -272,6 +272,7 @@ // methods to determine which adapter is issuing the event. virtual void AddObserver(BluetoothAdapter::Observer* observer); virtual void RemoveObserver(BluetoothAdapter::Observer* observer); + virtual bool HasObserver(BluetoothAdapter::Observer* observer); // The address of this adapter. The address format is "XX:XX:XX:XX:XX:XX", // where each XX is a hexadecimal number.
diff --git a/device/bluetooth/bluetooth_classic_device_mac.h b/device/bluetooth/bluetooth_classic_device_mac.h index ec9434a..bf87f5813 100644 --- a/device/bluetooth/bluetooth_classic_device_mac.h +++ b/device/bluetooth/bluetooth_classic_device_mac.h
@@ -43,8 +43,8 @@ bool IsConnectable() const override; bool IsConnecting() const override; UUIDList GetUUIDs() const override; - int16_t GetInquiryRSSI() const override; - int16_t GetInquiryTxPower() const override; + base::Optional<int8_t> GetInquiryRSSI() const override; + base::Optional<int8_t> GetInquiryTxPower() const override; bool ExpectingPinCode() const override; bool ExpectingPasskey() const override; bool ExpectingConfirmation() const override;
diff --git a/device/bluetooth/bluetooth_classic_device_mac.mm b/device/bluetooth/bluetooth_classic_device_mac.mm index eaeba2c..0e471e6 100644 --- a/device/bluetooth/bluetooth_classic_device_mac.mm +++ b/device/bluetooth/bluetooth_classic_device_mac.mm
@@ -148,13 +148,12 @@ return uuids; } -int16_t BluetoothClassicDeviceMac::GetInquiryRSSI() const { - return kUnknownPower; +base::Optional<int8_t> BluetoothClassicDeviceMac::GetInquiryRSSI() const { + return base::nullopt; } -int16_t BluetoothClassicDeviceMac::GetInquiryTxPower() const { - NOTIMPLEMENTED(); - return kUnknownPower; +base::Optional<int8_t> BluetoothClassicDeviceMac::GetInquiryTxPower() const { + return base::nullopt; } bool BluetoothClassicDeviceMac::ExpectingPinCode() const {
diff --git a/device/bluetooth/bluetooth_device.h b/device/bluetooth/bluetooth_device.h index 8b4c5b0..bc346e8 100644 --- a/device/bluetooth/bluetooth_device.h +++ b/device/bluetooth/bluetooth_device.h
@@ -305,15 +305,13 @@ virtual UUIDList GetUUIDs() const; // The received signal strength, in dBm. This field is avaliable and valid - // only during discovery. If not during discovery, or RSSI wasn't reported, - // this method will return |kUnknownPower|. - virtual int16_t GetInquiryRSSI() const = 0; + // only during discovery. + virtual base::Optional<int8_t> GetInquiryRSSI() const = 0; // The transmitted power level. This field is avaliable only for LE devices // that include this field in AD. It is avaliable and valid only during - // discovery. If not during discovery, or TxPower wasn't reported, this - // method will return |kUnknownPower|. - virtual int16_t GetInquiryTxPower() const = 0; + // discovery. + virtual base::Optional<int8_t> GetInquiryTxPower() const = 0; // The ErrorCallback is used for methods that can fail in which case it // is called, in the success case the callback is simply not called.
diff --git a/device/bluetooth/bluetooth_device_android.cc b/device/bluetooth/bluetooth_device_android.cc index bfd2ea6..15a2e92 100644 --- a/device/bluetooth/bluetooth_device_android.cc +++ b/device/bluetooth/bluetooth_device_android.cc
@@ -139,14 +139,14 @@ return false; } -int16_t BluetoothDeviceAndroid::GetInquiryRSSI() const { +base::Optional<int8_t> BluetoothDeviceAndroid::GetInquiryRSSI() const { NOTIMPLEMENTED(); - return kUnknownPower; + return base::nullopt; } -int16_t BluetoothDeviceAndroid::GetInquiryTxPower() const { +base::Optional<int8_t> BluetoothDeviceAndroid::GetInquiryTxPower() const { NOTIMPLEMENTED(); - return kUnknownPower; + return base::nullopt; } bool BluetoothDeviceAndroid::ExpectingPinCode() const {
diff --git a/device/bluetooth/bluetooth_device_android.h b/device/bluetooth/bluetooth_device_android.h index d4d9ca6..76a7bf8a 100644 --- a/device/bluetooth/bluetooth_device_android.h +++ b/device/bluetooth/bluetooth_device_android.h
@@ -67,8 +67,8 @@ bool IsGattConnected() const override; bool IsConnectable() const override; bool IsConnecting() const override; - int16_t GetInquiryRSSI() const override; - int16_t GetInquiryTxPower() const override; + base::Optional<int8_t> GetInquiryRSSI() const override; + base::Optional<int8_t> GetInquiryTxPower() const override; bool ExpectingPinCode() const override; bool ExpectingPasskey() const override; bool ExpectingConfirmation() const override;
diff --git a/device/bluetooth/bluetooth_device_win.cc b/device/bluetooth/bluetooth_device_win.cc index f71c137..9436651 100644 --- a/device/bluetooth/bluetooth_device_win.cc +++ b/device/bluetooth/bluetooth_device_win.cc
@@ -116,13 +116,16 @@ return uuids_; } -int16_t BluetoothDeviceWin::GetInquiryRSSI() const { - return kUnknownPower; +base::Optional<int8_t> BluetoothDeviceWin::GetInquiryRSSI() const { + // In windows, we can only get connected devices and connected + // devices don't have an Inquiry RSSI. + return base::nullopt; } -int16_t BluetoothDeviceWin::GetInquiryTxPower() const { - NOTIMPLEMENTED(); - return kUnknownPower; +base::Optional<int8_t> BluetoothDeviceWin::GetInquiryTxPower() const { + // In windows, we can only get connected devices and connected + // devices don't have an Inquiry Tx Power. + return base::nullopt; } bool BluetoothDeviceWin::ExpectingPinCode() const {
diff --git a/device/bluetooth/bluetooth_device_win.h b/device/bluetooth/bluetooth_device_win.h index 4c434486..01e5ca9 100644 --- a/device/bluetooth/bluetooth_device_win.h +++ b/device/bluetooth/bluetooth_device_win.h
@@ -48,8 +48,8 @@ bool IsConnectable() const override; bool IsConnecting() const override; UUIDList GetUUIDs() const override; - int16_t GetInquiryRSSI() const override; - int16_t GetInquiryTxPower() const override; + base::Optional<int8_t> GetInquiryRSSI() const override; + base::Optional<int8_t> GetInquiryTxPower() const override; bool ExpectingPinCode() const override; bool ExpectingPasskey() const override; bool ExpectingConfirmation() const override;
diff --git a/device/bluetooth/bluetooth_low_energy_device_mac.h b/device/bluetooth/bluetooth_low_energy_device_mac.h index 123015cd..3101f13 100644 --- a/device/bluetooth/bluetooth_low_energy_device_mac.h +++ b/device/bluetooth/bluetooth_low_energy_device_mac.h
@@ -56,8 +56,8 @@ bool IsGattConnected() const override; bool IsConnectable() const override; bool IsConnecting() const override; - int16_t GetInquiryRSSI() const override; - int16_t GetInquiryTxPower() const override; + base::Optional<int8_t> GetInquiryRSSI() const override; + base::Optional<int8_t> GetInquiryTxPower() const override; bool ExpectingPinCode() const override; bool ExpectingPasskey() const override; bool ExpectingConfirmation() const override;
diff --git a/device/bluetooth/bluetooth_low_energy_device_mac.mm b/device/bluetooth/bluetooth_low_energy_device_mac.mm index 0db9ce1..32259983 100644 --- a/device/bluetooth/bluetooth_low_energy_device_mac.mm +++ b/device/bluetooth/bluetooth_low_energy_device_mac.mm
@@ -143,13 +143,14 @@ return ([peripheral_ state] == CBPeripheralStateConnecting); } -int16_t BluetoothLowEnergyDeviceMac::GetInquiryRSSI() const { - return kUnknownPower; +base::Optional<int8_t> BluetoothLowEnergyDeviceMac::GetInquiryRSSI() const { + NOTIMPLEMENTED(); + return base::nullopt; } -int16_t BluetoothLowEnergyDeviceMac::GetInquiryTxPower() const { +base::Optional<int8_t> BluetoothLowEnergyDeviceMac::GetInquiryTxPower() const { NOTIMPLEMENTED(); - return kUnknownPower; + return base::nullopt; } bool BluetoothLowEnergyDeviceMac::ExpectingPinCode() const {
diff --git a/device/bluetooth/bluez/bluetooth_bluez_unittest.cc b/device/bluetooth/bluez/bluetooth_bluez_unittest.cc index c26a5d5..3b42c000 100644 --- a/device/bluetooth/bluez/bluetooth_bluez_unittest.cc +++ b/device/bluetooth/bluez/bluetooth_bluez_unittest.cc
@@ -2490,7 +2490,13 @@ properties->rssi.ReplaceValue(-75); properties->rssi.set_valid(true); - ASSERT_EQ(-75, devices[idx]->GetInquiryRSSI()); + ASSERT_EQ(-75, devices[idx]->GetInquiryRSSI().value()); + + properties->rssi.ReplaceValue(INT8_MAX + 1); + ASSERT_EQ(INT8_MAX, devices[idx]->GetInquiryRSSI().value()); + + properties->rssi.ReplaceValue(INT8_MIN - 1); + ASSERT_EQ(INT8_MIN, devices[idx]->GetInquiryRSSI().value()); // Install an observer; expect the DeviceChanged method to be called when // we invalidate the RSSI of the device. @@ -2503,8 +2509,7 @@ EXPECT_EQ(1, observer.device_changed_count()); EXPECT_EQ(devices[idx], observer.last_device()); - int unknown_power = BluetoothDevice::kUnknownPower; - EXPECT_EQ(unknown_power, devices[idx]->GetInquiryRSSI()); + EXPECT_FALSE(devices[idx]->GetInquiryRSSI()); } TEST_F(BluetoothBlueZTest, DeviceInquiryTxPowerInvalidated) { @@ -2527,7 +2532,13 @@ properties->tx_power.ReplaceValue(0); properties->tx_power.set_valid(true); - ASSERT_EQ(0, devices[idx]->GetInquiryTxPower()); + ASSERT_EQ(0, devices[idx]->GetInquiryTxPower().value()); + + properties->tx_power.ReplaceValue(INT8_MAX + 1); + ASSERT_EQ(INT8_MAX, devices[idx]->GetInquiryTxPower().value()); + + properties->tx_power.ReplaceValue(INT8_MIN - 1); + ASSERT_EQ(INT8_MIN, devices[idx]->GetInquiryTxPower().value()); // Install an observer; expect the DeviceChanged method to be called when // we invalidate the tx_power of the device. @@ -2540,8 +2551,7 @@ EXPECT_EQ(1, observer.device_changed_count()); EXPECT_EQ(devices[idx], observer.last_device()); - int unknown_power = BluetoothDevice::kUnknownPower; - EXPECT_EQ(unknown_power, devices[idx]->GetInquiryTxPower()); + EXPECT_FALSE(devices[idx]->GetInquiryTxPower()); } TEST_F(BluetoothBlueZTest, ForgetDevice) {
diff --git a/device/bluetooth/bluez/bluetooth_device_bluez.cc b/device/bluetooth/bluez/bluetooth_device_bluez.cc index 7cd7041..222a47fec 100644 --- a/device/bluetooth/bluez/bluetooth_device_bluez.cc +++ b/device/bluetooth/bluez/bluetooth_device_bluez.cc
@@ -6,6 +6,7 @@ #include <stdio.h> +#include <algorithm> #include <memory> #include <utility> @@ -87,6 +88,16 @@ *device_id = device_value; } +int8_t ClampPower(int16_t power) { + if (power < INT8_MIN) { + return INT8_MIN; + } + if (power > INT8_MAX) { + return INT8_MAX; + } + return static_cast<int8_t>(power); +} + void RecordPairingResult(BluetoothDevice::ConnectErrorCode error_code) { UMAPairingResult pairing_result; switch (error_code) { @@ -353,28 +364,34 @@ return uuids; } -int16_t BluetoothDeviceBlueZ::GetInquiryRSSI() const { +base::Optional<int8_t> BluetoothDeviceBlueZ::GetInquiryRSSI() const { bluez::BluetoothDeviceClient::Properties* properties = bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties( object_path_); DCHECK(properties); if (!properties->rssi.is_valid()) - return kUnknownPower; + return base::nullopt; - return properties->rssi.value(); + // BlueZ uses int16_t because there is no int8_t for DBus, so we should never + // get an int16_t that cannot be represented by an int8_t. But just in case + // clamp the value. + return ClampPower(properties->rssi.value()); } -int16_t BluetoothDeviceBlueZ::GetInquiryTxPower() const { +base::Optional<int8_t> BluetoothDeviceBlueZ::GetInquiryTxPower() const { bluez::BluetoothDeviceClient::Properties* properties = bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties( object_path_); DCHECK(properties); if (!properties->tx_power.is_valid()) - return kUnknownPower; + return base::nullopt; - return properties->tx_power.value(); + // BlueZ uses int16_t because there is no int8_t for DBus, so we should never + // get an int16_t that cannot be represented by an int8_t. But just in case + // clamp the value. + return ClampPower(properties->tx_power.value()); } bool BluetoothDeviceBlueZ::ExpectingPinCode() const {
diff --git a/device/bluetooth/bluez/bluetooth_device_bluez.h b/device/bluetooth/bluez/bluetooth_device_bluez.h index 33750fb..521405e8 100644 --- a/device/bluetooth/bluez/bluetooth_device_bluez.h +++ b/device/bluetooth/bluez/bluetooth_device_bluez.h
@@ -62,8 +62,8 @@ bool IsConnectable() const override; bool IsConnecting() const override; UUIDList GetUUIDs() const override; - int16_t GetInquiryRSSI() const override; - int16_t GetInquiryTxPower() const override; + base::Optional<int8_t> GetInquiryRSSI() const override; + base::Optional<int8_t> GetInquiryTxPower() const override; bool ExpectingPinCode() const override; bool ExpectingPasskey() const override; bool ExpectingConfirmation() const override;
diff --git a/device/bluetooth/test/mock_bluetooth_device.cc b/device/bluetooth/test/mock_bluetooth_device.cc index 39d27c82..b593da0 100644 --- a/device/bluetooth/test/mock_bluetooth_device.cc +++ b/device/bluetooth/test/mock_bluetooth_device.cc
@@ -48,11 +48,13 @@ .WillByDefault(testing::Return(paired)); ON_CALL(*this, IsConnected()) .WillByDefault(testing::ReturnPointee(&connected_)); + ON_CALL(*this, IsGattConnected()) + .WillByDefault(testing::ReturnPointee(&connected_)); ON_CALL(*this, IsConnectable()) .WillByDefault(testing::Return(false)); ON_CALL(*this, IsConnecting()) .WillByDefault(testing::Return(false)); - ON_CALL(*this, GetUUIDs()).WillByDefault(testing::Return(uuids_)); + ON_CALL(*this, GetUUIDs()).WillByDefault(testing::ReturnPointee(&uuids_)); ON_CALL(*this, ExpectingPinCode()) .WillByDefault(testing::Return(false)); ON_CALL(*this, ExpectingPasskey())
diff --git a/device/bluetooth/test/mock_bluetooth_device.h b/device/bluetooth/test/mock_bluetooth_device.h index a7ed03ab..eeae2cdd 100644 --- a/device/bluetooth/test/mock_bluetooth_device.h +++ b/device/bluetooth/test/mock_bluetooth_device.h
@@ -52,8 +52,8 @@ MOCK_CONST_METHOD0(IsConnectable, bool()); MOCK_CONST_METHOD0(IsConnecting, bool()); MOCK_CONST_METHOD0(GetUUIDs, UUIDList()); - MOCK_CONST_METHOD0(GetInquiryRSSI, int16_t()); - MOCK_CONST_METHOD0(GetInquiryTxPower, int16_t()); + MOCK_CONST_METHOD0(GetInquiryRSSI, base::Optional<int8_t>()); + MOCK_CONST_METHOD0(GetInquiryTxPower, base::Optional<int8_t>()); MOCK_CONST_METHOD0(ExpectingPinCode, bool()); MOCK_CONST_METHOD0(ExpectingPasskey, bool()); MOCK_CONST_METHOD0(ExpectingConfirmation, bool()); @@ -114,6 +114,8 @@ BluetoothRemoteGattService* GetMockService( const std::string& identifier) const; + void AddUUID(const BluetoothUUID& uuid) { uuids_.push_back(uuid); } + void SetConnected(bool connected) { connected_ = connected; } private:
diff --git a/device/usb/usb_service.cc b/device/usb/usb_service.cc index e571b96..b6e6dca0 100644 --- a/device/usb/usb_service.cc +++ b/device/usb/usb_service.cc
@@ -90,6 +90,40 @@ observer_list_.RemoveObserver(observer); } +void UsbService::AddDeviceForTesting(scoped_refptr<UsbDevice> device) { + DCHECK(CalledOnValidThread()); + DCHECK(!ContainsKey(devices_, device->guid())); + devices_[device->guid()] = device; + testing_devices_.insert(device->guid()); + NotifyDeviceAdded(device); +} + +void UsbService::RemoveDeviceForTesting(const std::string& device_guid) { + DCHECK(CalledOnValidThread()); + // Allow only devices added with AddDeviceForTesting to be removed with this + // method. + auto testing_devices_it = testing_devices_.find(device_guid); + if (testing_devices_it != testing_devices_.end()) { + auto devices_it = devices_.find(device_guid); + DCHECK(devices_it != devices_.end()); + scoped_refptr<UsbDevice> device = devices_it->second; + devices_.erase(devices_it); + testing_devices_.erase(testing_devices_it); + UsbService::NotifyDeviceRemoved(device); + } +} + +void UsbService::GetTestDevices( + std::vector<scoped_refptr<UsbDevice>>* devices) { + devices->clear(); + devices->reserve(testing_devices_.size()); + for (const std::string& guid : testing_devices_) { + auto it = devices_.find(guid); + DCHECK(it != devices_.end()); + devices->push_back(it->second); + } +} + void UsbService::NotifyDeviceAdded(scoped_refptr<UsbDevice> device) { DCHECK(CalledOnValidThread());
diff --git a/device/usb/usb_service.h b/device/usb/usb_service.h index a78fa83..b3949a7 100644 --- a/device/usb/usb_service.h +++ b/device/usb/usb_service.h
@@ -8,6 +8,7 @@ #include <memory> #include <string> #include <unordered_map> +#include <unordered_set> #include <vector> #include "base/bind_helpers.h" @@ -64,6 +65,12 @@ void AddObserver(Observer* observer); void RemoveObserver(Observer* observer); + // Methods to add and remove devices for testing purposes. Only a device added + // by this method can be removed by RemoveDeviceForTesting(). + void AddDeviceForTesting(scoped_refptr<UsbDevice> device); + void RemoveDeviceForTesting(const std::string& device_guid); + void GetTestDevices(std::vector<scoped_refptr<UsbDevice>>* devices); + protected: UsbService(scoped_refptr<base::SingleThreadTaskRunner> task_runner, scoped_refptr<base::SequencedTaskRunner> blocking_task_runner); @@ -89,6 +96,7 @@ scoped_refptr<base::SingleThreadTaskRunner> task_runner_; scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; std::unordered_map<std::string, scoped_refptr<UsbDevice>> devices_; + std::unordered_set<std::string> testing_devices_; base::ObserverList<Observer, true> observer_list_; DISALLOW_COPY_AND_ASSIGN(UsbService);
diff --git a/docs/linux_sublime_dev.md b/docs/linux_sublime_dev.md index 52adad4..8580b04 100644 --- a/docs/linux_sublime_dev.md +++ b/docs/linux_sublime_dev.md
@@ -73,6 +73,9 @@ "draw_white_space": "all", "enable_tab_scrolling": false, "highlight_line": true, + + // Mainly for Windows, but harmless on Mac/Linux + "default_line_ending": "unix", } ```
diff --git a/docs/mac_build_instructions.md b/docs/mac_build_instructions.md index 818b2e3c..cd6f4f5 100644 --- a/docs/mac_build_instructions.md +++ b/docs/mac_build_instructions.md
@@ -5,19 +5,14 @@ ## Prerequisites * A Mac running 10.9+. -* [Xcode](https://developer.apple.com/xcode) 5+. +* [Xcode](https://developer.apple.com/xcode) 7.3+. * [depot\_tools](http://dev.chromium.org/developers/how-tos/depottools). -* Xcode Command Line Tools. Run - ``` - xcode-select --install - ``` - to install them. * The OSX 10.10 SDK. Run ``` ls `xcode-select -p`/Platforms/MacOSX.platform/Developer/SDKs ``` - to check whether you have it. If you don't have it, you need to get one from - an install of Xcode 6, and place it in the above directory. + to check whether you have it. Building with the 10.11 SDK works too, but + the releases currently use the 10.10 SDK. ## Getting the code @@ -34,50 +29,52 @@ ## Building -Chromium on OS X can only be built using the [Ninja](ninja_build.md) tool and +Chromium on OS X is built using the [Ninja](ninja_build.md) tool and the [Clang](clang.md) compiler. See both of those pages for further details on how to tune the build. +Run + + gn gen out/gn + +to generate build files (replace "gn" in "out/gn" with whatever you like), and +then run + + ninja -C out/gn chrome + +to build. You can edit out/gn/args.gn to configure the build. + Before you build, you may want to [install API keys](https://sites.google.com/a/chromium.org/dev/developers/how-tos/api-keys) so that Chrome-integrated Google services work. This step is optional if you aren't testing those features. -### Raising system-wide and per-user process limits - -If you see errors like the following: - -``` -clang: error: unable to execute command: posix_spawn failed: Resource temporarily unavailable -clang: error: clang frontend command failed due to signal (use -v to see invocation) -``` - -you may be running into too-low limits on the number of concurrent processes -allowed on the machine. Check: - - sysctl kern.maxproc - sysctl kern.maxprocperuid - -You can increase them with e.g.: - - sudo sysctl -w kern.maxproc=2500 - sudo sysctl -w kern.maxprocperuid=2500 - -But normally this shouldn't be necessary if you're building on 10.7 or higher. -If you see this, check if some rogue program spawned hundreds of processes and -kill them first. - ## Faster builds Full rebuilds are about the same speed in Debug and Release, but linking is a lot faster in Release builds. -Run +Put - GYP_DEFINES=fastbuild=1 build/gyp_chromium + is_debug = false -to disable debug symbols altogether, this makes both full rebuilds and linking -faster (at the cost of not getting symbolized backtraces in gdb). +in your args.gn to do a release build. + +Put + + is_component_build = true + +in your args.gn to build many small dylibs instead of a single large executable. +This makes incremental builds much faster, at the cost of producing a binary +that opens less quickly. Component builds work in both debug and release. + +Put + + symbol_level = 1 + +in your args.gn to disable debug symbols altogether. This makes both full +rebuilds and linking faster (at the cost of not getting symbolized backtraces +in gdb). You might also want to [install ccache](ccache_mac.md) to speed up the build. @@ -85,8 +82,7 @@ All build output is located in the `out` directory (in the example above, `~/chromium/src/out`). You can find the applications at -`{Debug|Release}/ContentShell.app` and `{Debug|Release}/Chromium.app`, depending -on the selected configuration. +`gn/Content Shell.app` and `gn/Chromium.app`. ## Unit Tests @@ -98,10 +94,10 @@ * `net_unittests` from `net/net.gyp` * `url_unittests` from `url/url.gyp` -When these tests are built, you will find them in the `out/{Debug|Release}` +When these tests are built, you will find them in the `out/gn` directory. You can run them from the command line: - ~/chromium/src/out/Release/unit_tests + ~/chromium/src/out/gn/unit_tests ## Coding @@ -109,12 +105,9 @@ According to the [Chromium style guide](http://dev.chromium.org/developers/coding-style) code is [not allowed to have whitespace on the ends of lines](https://google.github.io/styleguide/cppguide.html#Horizontal_Whitespace). -If you edit in Xcode, know that it loves adding whitespace to the ends of lines -which can make editing in Xcode more painful than it should be. The -[GTM Xcode Plugin](http://code.google.com/p/google-toolbox-for-mac/downloads/list) -adds a preference panel to Xcode that allows you to strip whitespace off of the -ends of lines on save. Documentation on how to install it is -[here](http://code.google.com/p/google-toolbox-for-mac/wiki/GTMXcodePlugin). + +Run `git cl format` after committing to your local branch and before uploading +to clang-format your code. ## Debugging @@ -122,7 +115,7 @@ [here](http://dev.chromium.org/developers/how-tos/debugging-on-os-x). If you would like to debug in a graphical environment, rather than using `lldb` at the command line, that is possible without building in Xcode. See -[Debugging in Xcode](http://www.chromium.org/developers/debugging-on-os-x/building-with-ninja-debugging-with-xcode) +[Debugging in Xcode](http://www.chromium.org/developers/how-tos/debugging-on-os-x/building-with-ninja-debugging-with-xcode) for information on how. ## Contributing @@ -133,46 +126,25 @@ ## Using Xcode-Ninja Hybrid -While using Xcode is unsupported, GYP supports a hybrid approach of using ninja -for building, but Xcode for editing and driving compilation. Xcode can still be -slow, but it runs fairly well even **with indexing enabled**. +While using Xcode is unsupported, gn supports a hybrid approach of using ninja +for building, but Xcode for editing and driving compilation. Xcode is still +slow, but it runs fairly well even **with indexing enabled**. Most people +build in the Terminal and write code with a text editor though. With hybrid builds, compilation is still handled by ninja, and can be run by the -command line (e.g. ninja -C out/Debug chrome) or by choosing the chrome target +command line (e.g. ninja -C out/gn chrome) or by choosing the chrome target in the hybrid workspace and choosing build. -To use Xcode-Ninja Hybrid, set GYP\_GENERATORS like the following: +To use Xcode-Ninja Hybrid pass --ide=xcode to `gn gen` ```shell -export GYP_GENERATORS="ninja,xcode-ninja" +gn gen out/gn --ide=xcode ``` -Due to the way Xcode parses ninja output paths, it's also necessary to change -the main gyp location to anything two directories deep. Otherwise Xcode build -output will not be clickable. -To make this change permanent, you can edit `chromium.gyp_env` (or create it if -it does not exists) and define GYP\_GENERATOR\_FLAGS. In general, to use hybrid -mode, your `chromium.gyp_env` could contain the following: - -```json -{ - "GYP_GENERATORS" : "ninja,xcode-ninja", - "GYP_GENERATOR_FLAGS": - "xcode_project_version=3.2 " + - "xcode_ninja_main_gyp=src/build/ninja/all.ninja.gyp", -} -``` - -After, generate the project files with: +Open it: ```shell -gclient runhooks -``` - -And finally, open it: - -```shell -open build/ninja/all.ninja.xcworkspace +open out/gn/ninja/all.xcworkspace ``` You may run into a problem where http://YES is opened as a new tab every time @@ -182,52 +154,11 @@ `--NSDocumentRevisionsDebugMode YES` to the launch arguments, and the `YES` gets interpreted as a URL to open. -If you want to limit the number of targets visible, which is known to improve -Xcode performance, add `xcode_ninja_executable_target_pattern=%target%` where -`%target%` is a regular expression matching executable targets you'd like to -include. - -To include non-executable targets, use `xcode_ninja_target_pattern=All_iOS`. - If you have problems building, join us in `#chromium` on `irc.freenode.net` and ask there. As mentioned above, be sure that the [waterfall](http://build.chromium.org/buildbot/waterfall/) is green and the tree is open before checking out. This will increase your chances of success. -## Using Emacs as `EDITOR` for `git commit` - -Using the [Cocoa version of Emacs](http://emacsformacosx.com/) as the `EDITOR` -environment variable on Mac OS will cause `git commit` to open the message in a -window underneath all the others. To fix this, create a shell script somewhere -(call it `$HOME/bin/EmacsEditor` in this example) containing the following: - -``` -#!/bin/sh - -# All of these hacks are needed to get "git commit" to launch a new -# instance of Emacs on top of everything else, properly pointing to -# the COMMIT_EDITMSG. - -realpath() { - [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}" -} - -i=0 -full_paths=() -for arg in "$@" -do - full_paths[$i]=$(realpath $arg) - ((++i)) -done - -open -nWa /Applications/Emacs.app/Contents/MacOS/Emacs --args --no-desktop \ - "${full_paths[@]}" -``` - -and in your `.bashrc` or similar, - - export EDITOR=$HOME/bin/EmacsEditor - ## Improving performance of `git status` `git status` is used frequently to determine the status of your checkout. Due
diff --git a/extensions/BUILD.gn b/extensions/BUILD.gn index d105499..3e8c5aca 100644 --- a/extensions/BUILD.gn +++ b/extensions/BUILD.gn
@@ -95,7 +95,7 @@ "//net:test_support", "//testing/gmock", "//testing/gtest", - "//third_party/cld_2", + "//third_party/cld", ] public_deps = [ @@ -158,6 +158,7 @@ "test/data/", "//chrome/test/data/extensions/", "//components/test/data/cast_certificate/", + "$root_out_dir/content_shell.pak", "$root_out_dir/extensions_shell_and_test.pak", ]
diff --git a/extensions/browser/api/bluetooth/bluetooth_api_utils.cc b/extensions/browser/api/bluetooth/bluetooth_api_utils.cc index 5176c68..f6b3b2ca 100644 --- a/extensions/browser/api/bluetooth/bluetooth_api_utils.cc +++ b/extensions/browser/api/bluetooth/bluetooth_api_utils.cc
@@ -122,13 +122,13 @@ string_uuids->push_back(iter->canonical_value()); out->uuids.reset(string_uuids); - if (device.GetInquiryRSSI() != device::BluetoothDevice::kUnknownPower) - out->inquiry_rssi.reset(new int(device.GetInquiryRSSI())); + if (device.GetInquiryRSSI()) + out->inquiry_rssi.reset(new int(device.GetInquiryRSSI().value())); else out->inquiry_rssi.reset(); - if (device.GetInquiryTxPower() != device::BluetoothDevice::kUnknownPower) - out->inquiry_tx_power.reset(new int(device.GetInquiryTxPower())); + if (device.GetInquiryTxPower()) + out->inquiry_tx_power.reset(new int(device.GetInquiryTxPower().value())); else out->inquiry_tx_power.reset(); }
diff --git a/extensions/browser/api/bluetooth/bluetooth_event_router_unittest.cc b/extensions/browser/api/bluetooth/bluetooth_event_router_unittest.cc index 29e501a..68f9a1d7 100644 --- a/extensions/browser/api/bluetooth/bluetooth_event_router_unittest.cc +++ b/extensions/browser/api/bluetooth/bluetooth_event_router_unittest.cc
@@ -11,7 +11,6 @@ #include "base/memory/ref_counted.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" -#include "content/public/browser/notification_service.h" #include "content/public/test/test_browser_context.h" #include "content/public/test/test_browser_thread.h" #include "device/bluetooth/bluetooth_common.h" @@ -44,7 +43,6 @@ BluetoothEventRouterTest() : ui_thread_(content::BrowserThread::UI, &message_loop_), mock_adapter_(new testing::StrictMock<device::MockBluetoothAdapter>()), - notification_service_(content::NotificationService::Create()), router_(new BluetoothEventRouter(browser_context())) { router_->SetAdapterForTest(mock_adapter_); } @@ -61,7 +59,6 @@ // Note: |ui_thread_| must be declared before |router_|. content::TestBrowserThread ui_thread_; testing::StrictMock<device::MockBluetoothAdapter>* mock_adapter_; - std::unique_ptr<content::NotificationService> notification_service_; std::unique_ptr<BluetoothEventRouter> router_; };
diff --git a/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc b/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc index 3b55079..74493cfc 100644 --- a/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc +++ b/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc
@@ -440,7 +440,7 @@ url_fetcher_.reset(new WebUIURLFetcher( this->browser_context(), render_frame_host()->GetProcess()->GetID(), - render_view_host_do_not_use()->GetRoutingID(), file_url, callback)); + render_frame_host()->GetRoutingID(), file_url, callback)); url_fetcher_->Start(); return true; } @@ -515,8 +515,8 @@ DCHECK(manager); manager->AddContentScripts( - sender_web_contents->GetRenderProcessHost()->GetID(), - render_view_host_do_not_use(), params->instance_id, host_id, result); + sender_web_contents->GetRenderProcessHost()->GetID(), render_frame_host(), + params->instance_id, host_id, result); return RespondNow(NoArguments()); }
diff --git a/extensions/browser/api_unittest.cc b/extensions/browser/api_unittest.cc index c8faa210..9dda18c 100644 --- a/extensions/browser/api_unittest.cc +++ b/extensions/browser/api_unittest.cc
@@ -9,7 +9,6 @@ #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/content_browser_client.h" -#include "content/public/browser/notification_service.h" #include "content/public/browser/site_instance.h" #include "content/public/browser/web_contents.h" #include "content/public/common/content_client.h" @@ -30,12 +29,9 @@ namespace extensions { -ApiUnitTest::ApiUnitTest() - : notification_service_(content::NotificationService::Create()) { -} +ApiUnitTest::ApiUnitTest() {} -ApiUnitTest::~ApiUnitTest() { -} +ApiUnitTest::~ApiUnitTest() {} void ApiUnitTest::SetUp() { ExtensionsTest::SetUp();
diff --git a/extensions/browser/api_unittest.h b/extensions/browser/api_unittest.h index ad46d88..e4a9157b 100644 --- a/extensions/browser/api_unittest.h +++ b/extensions/browser/api_unittest.h
@@ -19,7 +19,6 @@ } namespace content { -class NotificationService; class TestBrowserThreadBundle; class WebContents; } @@ -87,8 +86,6 @@ const std::string& args); private: - std::unique_ptr<content::NotificationService> notification_service_; - std::unique_ptr<content::TestBrowserThreadBundle> thread_bundle_; user_prefs::TestingPrefServiceSyncable testing_pref_service_;
diff --git a/extensions/browser/declarative_user_script_master.cc b/extensions/browser/declarative_user_script_master.cc index 68fc0c6..bd21cfd 100644 --- a/extensions/browser/declarative_user_script_master.cc +++ b/extensions/browser/declarative_user_script_master.cc
@@ -40,8 +40,8 @@ void DeclarativeUserScriptMaster::AddScripts( const std::set<UserScript>& scripts, int render_process_id, - int render_view_id) { - loader_->AddScripts(scripts, render_process_id, render_view_id); + int render_frame_id) { + loader_->AddScripts(scripts, render_process_id, render_frame_id); } void DeclarativeUserScriptMaster::RemoveScript(const UserScript& script) {
diff --git a/extensions/browser/declarative_user_script_master.h b/extensions/browser/declarative_user_script_master.h index 422b747..2b05ff3 100644 --- a/extensions/browser/declarative_user_script_master.h +++ b/extensions/browser/declarative_user_script_master.h
@@ -37,11 +37,11 @@ // Adds a set of scripts to shared meomory region. The fetch of the content // of the script on WebUI requires to start URL request to the associated - // render specified by |render_process_id, render_view_id|. + // render specified by |render_process_id, render_frame_id|. // This may not happen right away if a script load is in progress. void AddScripts(const std::set<UserScript>& scripts, int render_process_id, - int render_view_id); + int render_frame_id); // Removes script from shared memory region. This may not happen right away if // a script load is in progress.
diff --git a/extensions/browser/event_router_unittest.cc b/extensions/browser/event_router_unittest.cc index eaaab11..f5b4c816 100644 --- a/extensions/browser/event_router_unittest.cc +++ b/extensions/browser/event_router_unittest.cc
@@ -14,7 +14,6 @@ #include "base/memory/ptr_util.h" #include "base/test/histogram_tester.h" #include "base/values.h" -#include "content/public/browser/notification_service.h" #include "content/public/test/test_browser_thread_bundle.h" #include "extensions/browser/event_listener_map.h" #include "extensions/browser/extensions_test.h" @@ -111,8 +110,7 @@ class EventRouterTest : public ExtensionsTest { public: - EventRouterTest() - : notification_service_(content::NotificationService::Create()) {} + EventRouterTest() {} protected: // Tests adding and removing observers from EventRouter. @@ -159,7 +157,6 @@ } private: - std::unique_ptr<content::NotificationService> notification_service_; content::TestBrowserThreadBundle thread_bundle_; base::HistogramTester histogram_tester_;
diff --git a/extensions/browser/extension_icon_image_unittest.cc b/extensions/browser/extension_icon_image_unittest.cc index d8396357..e48afcf 100644 --- a/extensions/browser/extension_icon_image_unittest.cc +++ b/extensions/browser/extension_icon_image_unittest.cc
@@ -11,7 +11,6 @@ #include "base/message_loop/message_loop.h" #include "base/path_service.h" #include "base/run_loop.h" -#include "content/public/browser/notification_service.h" #include "content/public/test/test_browser_context.h" #include "content/public/test/test_browser_thread.h" #include "extensions/browser/extensions_test.h" @@ -76,8 +75,7 @@ quit_in_image_loaded_(false), ui_thread_(BrowserThread::UI, &ui_loop_), file_thread_(BrowserThread::FILE), - io_thread_(BrowserThread::IO), - notification_service_(content::NotificationService::Create()) {} + io_thread_(BrowserThread::IO) {} ~ExtensionIconImageTest() override {} @@ -145,7 +143,6 @@ content::TestBrowserThread ui_thread_; content::TestBrowserThread file_thread_; content::TestBrowserThread io_thread_; - std::unique_ptr<content::NotificationService> notification_service_; DISALLOW_COPY_AND_ASSIGN(ExtensionIconImageTest); };
diff --git a/extensions/browser/extension_user_script_loader.cc b/extensions/browser/extension_user_script_loader.cc index 12e488e7..b28821b 100644 --- a/extensions/browser/extension_user_script_loader.cc +++ b/extensions/browser/extension_user_script_loader.cc
@@ -131,16 +131,19 @@ for (UserScript& script : *user_scripts) { if (added_script_ids.count(script.id()) == 0) continue; - std::unique_ptr<SubstitutionMap> localization_messages( - GetLocalizationMessages(hosts_info, script.host_id())); for (UserScript::File& script_file : script.js_scripts()) { if (script_file.GetContent().empty()) LoadScriptContent(script.host_id(), &script_file, nullptr, verifier); } - for (UserScript::File& script_file : script.css_scripts()) { - if (script_file.GetContent().empty()) - LoadScriptContent(script.host_id(), &script_file, - localization_messages.get(), verifier); + if (script.css_scripts().size() > 0) { + std::unique_ptr<SubstitutionMap> localization_messages( + GetLocalizationMessages(hosts_info, script.host_id())); + for (UserScript::File& script_file : script.css_scripts()) { + if (script_file.GetContent().empty()) { + LoadScriptContent(script.host_id(), &script_file, + localization_messages.get(), verifier); + } + } } } }
diff --git a/extensions/browser/extensions_test.cc b/extensions/browser/extensions_test.cc index bb37b3a..4d1ccf30 100644 --- a/extensions/browser/extensions_test.cc +++ b/extensions/browser/extensions_test.cc
@@ -22,25 +22,20 @@ // } // }; ExtensionsTest::ExtensionsTest() - : content_client_(new content::ContentClient), - content_utility_client_(new TestContentUtilityClient), - content_browser_client_(new content::ContentBrowserClient), + : content_utility_client_(new TestContentUtilityClient), browser_context_(new content::TestBrowserContext), extensions_browser_client_( new TestExtensionsBrowserClient(browser_context_.get())) { - content::SetContentClient(content_client_.get()); content::SetUtilityClientForTesting(content_utility_client_.get()); - content::SetBrowserClientForTesting(content_browser_client_.get()); ExtensionsBrowserClient::Set(extensions_browser_client_.get()); extensions_browser_client_->set_extension_system_factory( &extension_system_factory_); } ExtensionsTest::~ExtensionsTest() { - ExtensionsBrowserClient::Set(NULL); - content::SetBrowserClientForTesting(NULL); - content::SetUtilityClientForTesting(NULL); - content::SetContentClient(NULL); + ExtensionsBrowserClient::Set(nullptr); + content::SetBrowserClientForTesting(nullptr); + content::SetUtilityClientForTesting(nullptr); } void ExtensionsTest::SetUp() {
diff --git a/extensions/browser/extensions_test.h b/extensions/browser/extensions_test.h index f4462e26..6f62a29 100644 --- a/extensions/browser/extensions_test.h +++ b/extensions/browser/extensions_test.h
@@ -9,6 +9,7 @@ #include "base/compiler_specific.h" #include "base/macros.h" +#include "content/public/test/test_content_client_initializer.h" #include "content/public/test/test_renderer_host.h" #include "extensions/browser/mock_extension_system.h" #include "testing/gtest/include/gtest/gtest.h" @@ -52,10 +53,8 @@ void TearDown() override; private: - // TODO(yoz): Add a NotificationService here; it's used widely enough. - std::unique_ptr<content::ContentClient> content_client_; + content::TestContentClientInitializer content_client_initializer_; std::unique_ptr<content::ContentUtilityClient> content_utility_client_; - std::unique_ptr<content::ContentBrowserClient> content_browser_client_; std::unique_ptr<content::BrowserContext> browser_context_; std::unique_ptr<TestExtensionsBrowserClient> extensions_browser_client_;
diff --git a/extensions/browser/guest_view/web_view/web_ui/web_ui_url_fetcher.cc b/extensions/browser/guest_view/web_view/web_ui/web_ui_url_fetcher.cc index 69319de3..6293c21 100644 --- a/extensions/browser/guest_view/web_view/web_ui/web_ui_url_fetcher.cc +++ b/extensions/browser/guest_view/web_view/web_ui/web_ui_url_fetcher.cc
@@ -12,15 +12,14 @@ WebUIURLFetcher::WebUIURLFetcher(content::BrowserContext* context, int render_process_id, - int render_view_id, + int render_frame_id, const GURL& url, const WebUILoadFileCallback& callback) : context_(context), render_process_id_(render_process_id), - render_view_id_(render_view_id), + render_frame_id_(render_frame_id), url_(url), - callback_(callback) { -} + callback_(callback) {} WebUIURLFetcher::~WebUIURLFetcher() { } @@ -33,7 +32,7 @@ fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES); content::AssociateURLFetcherWithRenderFrame( - fetcher_.get(), url_, render_process_id_, render_view_id_); + fetcher_.get(), url_, render_process_id_, render_frame_id_); fetcher_->Start(); }
diff --git a/extensions/browser/guest_view/web_view/web_ui/web_ui_url_fetcher.h b/extensions/browser/guest_view/web_view/web_ui/web_ui_url_fetcher.h index b8bc717..cdf2bdc9 100644 --- a/extensions/browser/guest_view/web_view/web_ui/web_ui_url_fetcher.h +++ b/extensions/browser/guest_view/web_view/web_ui/web_ui_url_fetcher.h
@@ -33,7 +33,7 @@ WebUIURLFetcher(content::BrowserContext* context, int render_process_id, - int render_view_id, + int render_frame_id, const GURL& url, const WebUILoadFileCallback& callback); ~WebUIURLFetcher() override; @@ -46,7 +46,7 @@ content::BrowserContext* context_; int render_process_id_; - int render_view_id_; + int render_frame_id_; GURL url_; WebUILoadFileCallback callback_; std::unique_ptr<net::URLFetcher> fetcher_;
diff --git a/extensions/browser/guest_view/web_view/web_view_content_script_manager.cc b/extensions/browser/guest_view/web_view/web_view_content_script_manager.cc index 8a5592b..75d485ea 100644 --- a/extensions/browser/guest_view/web_view/web_view_content_script_manager.cc +++ b/extensions/browser/guest_view/web_view/web_view_content_script_manager.cc
@@ -7,8 +7,8 @@ #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/navigation_details.h" +#include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" -#include "content/public/browser/render_view_host.h" #include "extensions/browser/declarative_user_script_manager.h" #include "extensions/browser/declarative_user_script_master.h" #include "extensions/browser/extension_system.h" @@ -43,7 +43,7 @@ void WebViewContentScriptManager::AddContentScripts( int embedder_process_id, - content::RenderViewHost* render_view_host, + content::RenderFrameHost* render_frame_host, int view_instance_id, const HostID& host_id, const std::set<UserScript>& scripts) { @@ -97,7 +97,7 @@ // Step 4: adds new scripts to the master. master->AddScripts(scripts, embedder_process_id, - render_view_host->GetRoutingID()); + render_frame_host->GetRoutingID()); // Step 5: creates an entry in |webview_host_id_map_| for the given // |embedder_process_id| and |view_instance_id| if it doesn't exist.
diff --git a/extensions/browser/guest_view/web_view/web_view_content_script_manager.h b/extensions/browser/guest_view/web_view/web_view_content_script_manager.h index fa1dc87..e1b7278 100644 --- a/extensions/browser/guest_view/web_view/web_view_content_script_manager.h +++ b/extensions/browser/guest_view/web_view/web_view_content_script_manager.h
@@ -19,7 +19,7 @@ namespace content { class BrowserContext; -class RenderViewHost; +class RenderFrameHost; class WebContents; } @@ -41,7 +41,7 @@ // Adds content scripts for the WebView specified by // |embedder_process_id| and |view_instance_id|. void AddContentScripts(int embedder_process_id, - content::RenderViewHost* render_view_host, + content::RenderFrameHost* render_frame_host, int view_instance_id, const HostID& host_id, const std::set<UserScript>& user_scripts);
diff --git a/extensions/browser/image_loader_unittest.cc b/extensions/browser/image_loader_unittest.cc index 689bf1d8..569cef5 100644 --- a/extensions/browser/image_loader_unittest.cc +++ b/extensions/browser/image_loader_unittest.cc
@@ -13,7 +13,6 @@ #include "base/path_service.h" #include "base/run_loop.h" #include "base/strings/string_util.h" -#include "content/public/browser/notification_service.h" #include "content/public/test/test_browser_context.h" #include "content/public/test/test_browser_thread.h" #include "extensions/browser/extension_registry.h" @@ -34,7 +33,6 @@ #include "ui/gfx/image/image_skia.h" using content::BrowserThread; -using content::NotificationService; namespace extensions { @@ -45,8 +43,7 @@ quit_in_image_loaded_(false), ui_thread_(BrowserThread::UI, &ui_loop_), file_thread_(BrowserThread::FILE), - io_thread_(BrowserThread::IO), - notification_service_(NotificationService::Create()) {} + io_thread_(BrowserThread::IO) {} void OnImageLoaded(const gfx::Image& image) { image_loaded_count_++; @@ -118,7 +115,6 @@ content::TestBrowserThread ui_thread_; content::TestBrowserThread file_thread_; content::TestBrowserThread io_thread_; - std::unique_ptr<NotificationService> notification_service_; }; // Tests loading an image works correctly.
diff --git a/extensions/browser/lazy_background_task_queue_unittest.cc b/extensions/browser/lazy_background_task_queue_unittest.cc index c464c5b..fc6d731 100644 --- a/extensions/browser/lazy_background_task_queue_unittest.cc +++ b/extensions/browser/lazy_background_task_queue_unittest.cc
@@ -13,7 +13,6 @@ #include "components/pref_registry/testing_pref_service_syncable.h" #include "components/prefs/testing_pref_service.h" #include "components/user_prefs/user_prefs.h" -#include "content/public/browser/notification_service.h" #include "content/public/test/test_browser_context.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_registry_factory.h" @@ -68,10 +67,7 @@ // initialization. class LazyBackgroundTaskQueueTest : public ExtensionsTest { public: - LazyBackgroundTaskQueueTest() - : notification_service_(content::NotificationService::Create()), - task_run_count_(0) { - } + LazyBackgroundTaskQueueTest() : task_run_count_(0) {} ~LazyBackgroundTaskQueueTest() override {} int task_run_count() { return task_run_count_; } @@ -122,8 +118,6 @@ } private: - std::unique_ptr<content::NotificationService> notification_service_; - user_prefs::TestingPrefServiceSyncable testing_pref_service_; // The total number of pending tasks that have been executed.
diff --git a/extensions/browser/mojo/keep_alive_impl_unittest.cc b/extensions/browser/mojo/keep_alive_impl_unittest.cc index 4a6732d5..cdd360cc 100644 --- a/extensions/browser/mojo/keep_alive_impl_unittest.cc +++ b/extensions/browser/mojo/keep_alive_impl_unittest.cc
@@ -9,7 +9,6 @@ #include "base/macros.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" -#include "content/public/browser/notification_service.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/extensions_test.h" #include "extensions/browser/process_manager.h" @@ -19,8 +18,7 @@ class KeepAliveTest : public ExtensionsTest { public: - KeepAliveTest() - : notification_service_(content::NotificationService::Create()) {} + KeepAliveTest() {} ~KeepAliveTest() override {} void SetUp() override { @@ -73,7 +71,6 @@ private: std::unique_ptr<base::MessageLoop> message_loop_; - std::unique_ptr<content::NotificationService> notification_service_; scoped_refptr<const Extension> extension_; DISALLOW_COPY_AND_ASSIGN(KeepAliveTest);
diff --git a/extensions/browser/process_manager_unittest.cc b/extensions/browser/process_manager_unittest.cc index aa6b1083..89d376a 100644 --- a/extensions/browser/process_manager_unittest.cc +++ b/extensions/browser/process_manager_unittest.cc
@@ -62,9 +62,7 @@ class ProcessManagerTest : public ExtensionsTest { public: - ProcessManagerTest() - : notification_service_(content::NotificationService::Create()), - extension_registry_(browser_context()) { + ProcessManagerTest() : extension_registry_(browser_context()) { extensions_browser_client()->SetIncognitoContext(&incognito_context_); extensions_browser_client()->set_process_manager_delegate( &process_manager_delegate_); @@ -90,7 +88,6 @@ } private: - std::unique_ptr<content::NotificationService> notification_service_; TestBrowserContextIncognito incognito_context_; ExtensionRegistry extension_registry_; // Shared between BrowserContexts. TestProcessManagerDelegate process_manager_delegate_;
diff --git a/extensions/browser/user_script_loader.cc b/extensions/browser/user_script_loader.cc index b230c4a..36e20b6 100644 --- a/extensions/browser/user_script_loader.cc +++ b/extensions/browser/user_script_loader.cc
@@ -173,7 +173,7 @@ void UserScriptLoader::AddScripts(const std::set<UserScript>& scripts, int render_process_id, - int render_view_id) { + int render_frame_id) { AddScripts(scripts); }
diff --git a/extensions/browser/user_script_loader.h b/extensions/browser/user_script_loader.h index daab8a76..5d110a3 100644 --- a/extensions/browser/user_script_loader.h +++ b/extensions/browser/user_script_loader.h
@@ -63,12 +63,12 @@ // Add |scripts| to the set of scripts managed by this loader. // The fetch of the content of the script starts URL request // to the associated render specified by - // |render_process_id, render_view_id|. + // |render_process_id, render_frame_id|. // TODO(hanxi): The renderer information doesn't really belong in this base // class, but it's not an easy fix. virtual void AddScripts(const std::set<UserScript>& scripts, int render_process_id, - int render_view_id); + int render_frame_id); // Remove |scripts| from the set of scripts managed by this loader. void RemoveScripts(const std::set<UserScript>& scripts);
diff --git a/extensions/browser/web_ui_user_script_loader.cc b/extensions/browser/web_ui_user_script_loader.cc index 2b01879..ee8fd098 100644 --- a/extensions/browser/web_ui_user_script_loader.cc +++ b/extensions/browser/web_ui_user_script_loader.cc
@@ -29,12 +29,13 @@ struct WebUIUserScriptLoader::UserScriptRenderInfo { int render_process_id; - int render_view_id; + int render_frame_id; - UserScriptRenderInfo() : render_process_id(-1), render_view_id(-1) {} + UserScriptRenderInfo() : render_process_id(-1), render_frame_id(-1) {} - UserScriptRenderInfo(int render_process_id, int render_view_id) - : render_process_id(render_process_id), render_view_id(render_view_id) {} + UserScriptRenderInfo(int render_process_id, int render_frame_id) + : render_process_id(render_process_id), + render_frame_id(render_frame_id) {} }; WebUIUserScriptLoader::WebUIUserScriptLoader( @@ -50,8 +51,8 @@ void WebUIUserScriptLoader::AddScripts( const std::set<extensions::UserScript>& scripts, int render_process_id, - int render_view_id) { - UserScriptRenderInfo info(render_process_id, render_view_id); + int render_frame_id) { + UserScriptRenderInfo info(render_process_id, render_frame_id); for (const extensions::UserScript& script : scripts) { script_render_info_map_.insert( std::pair<int, UserScriptRenderInfo>(script.id(), info)); @@ -81,16 +82,16 @@ auto iter = script_render_info_map_.find(script.id()); DCHECK(iter != script_render_info_map_.end()); int render_process_id = iter->second.render_process_id; - int render_view_id = iter->second.render_view_id; + int render_frame_id = iter->second.render_frame_id; content::BrowserContext* browser_context = content::RenderProcessHost::FromID(render_process_id) ->GetBrowserContext(); CreateWebUIURLFetchers(&script.js_scripts(), browser_context, - render_process_id, render_view_id); + render_process_id, render_frame_id); CreateWebUIURLFetchers(&script.css_scripts(), browser_context, - render_process_id, render_view_id); + render_process_id, render_frame_id); script_render_info_map_.erase(script.id()); } @@ -108,14 +109,14 @@ extensions::UserScript::FileList* script_files, content::BrowserContext* browser_context, int render_process_id, - int render_view_id) { + int render_frame_id) { for (extensions::UserScript::File& file : *script_files) { if (file.GetContent().empty()) { // The WebUIUserScriptLoader owns these WebUIURLFetchers. Once the // loader is destroyed, all the fetchers will be destroyed. Therefore, // we are sure it is safe to use base::Unretained(this) here. std::unique_ptr<WebUIURLFetcher> fetcher(new WebUIURLFetcher( - browser_context, render_process_id, render_view_id, file.url(), + browser_context, render_process_id, render_frame_id, file.url(), base::Bind(&WebUIUserScriptLoader::OnSingleWebUIURLFetchComplete, base::Unretained(this), &file))); fetchers_.push_back(std::move(fetcher));
diff --git a/extensions/browser/web_ui_user_script_loader.h b/extensions/browser/web_ui_user_script_loader.h index fa75e19..ea77161 100644 --- a/extensions/browser/web_ui_user_script_loader.h +++ b/extensions/browser/web_ui_user_script_loader.h
@@ -34,7 +34,7 @@ // UserScriptLoader: void AddScripts(const std::set<extensions::UserScript>& scripts, int render_process_id, - int render_view_id) override; + int render_frame_id) override; void LoadScripts(std::unique_ptr<extensions::UserScriptList> user_scripts, const std::set<HostID>& changed_hosts, const std::set<int>& added_script_ids, @@ -52,7 +52,7 @@ void CreateWebUIURLFetchers(extensions::UserScript::FileList* script_files, content::BrowserContext* browser_context, int render_process_id, - int render_view_id); + int render_frame_id); // Caches the render info of script from WebUI when AddScripts is called. // When starting to load the script, we look up this map to retrieve the
diff --git a/extensions/renderer/BUILD.gn b/extensions/renderer/BUILD.gn index cdc9353..ba4b4bd4 100644 --- a/extensions/renderer/BUILD.gn +++ b/extensions/renderer/BUILD.gn
@@ -30,6 +30,7 @@ "//mojo/public/js", "//skia", "//third_party/WebKit/public:blink", + "//third_party/cld", ] if (proprietary_codecs && enable_wifi_display) {
diff --git a/extensions/renderer/DEPS b/extensions/renderer/DEPS index bd0ed525..2eae9acd 100644 --- a/extensions/renderer/DEPS +++ b/extensions/renderer/DEPS
@@ -7,8 +7,9 @@ "+mojo/edk/js", "+third_party/skia/include/core", - "+third_party/cld_2/src/public/compact_lang_det.h", - "+third_party/cld_2/src/public/encodings.h", + "+third_party/cld", + "+third_party/cld_2", + "+third_party/cld_3", "+third_party/WebKit/public/platform", "+third_party/WebKit/public/web",
diff --git a/extensions/renderer/i18n_custom_bindings.cc b/extensions/renderer/i18n_custom_bindings.cc index d17e94b6..a68e7ba 100644 --- a/extensions/renderer/i18n_custom_bindings.cc +++ b/extensions/renderer/i18n_custom_bindings.cc
@@ -19,8 +19,16 @@ #include "extensions/common/message_bundle.h" #include "extensions/renderer/script_context.h" #include "extensions/renderer/v8_helpers.h" +#include "third_party/cld/cld_version.h" + +#if BUILDFLAG(CLD_VERSION) == 2 #include "third_party/cld_2/src/public/compact_lang_det.h" #include "third_party/cld_2/src/public/encodings.h" +#elif BUILDFLAG(CLD_VERSION) == 3 +#include "third_party/cld_3/src/src/nnet_language_identifier.h" +#else +# error "CLD_VERSION must be 2 or 3" +#endif namespace extensions { @@ -28,7 +36,7 @@ namespace { -// Max number of languages detected by CLD2. +// Max number of languages to detect. const int kCldNumLangs = 3; struct DetectedLanguage { @@ -50,6 +58,7 @@ // LanguageDetectionResult object that holds detected langugae reliability and // array of DetectedLanguage struct LanguageDetectionResult { + LanguageDetectionResult() {} explicit LanguageDetectionResult(bool is_reliable) : is_reliable(is_reliable) {} ~LanguageDetectionResult() {} @@ -95,6 +104,7 @@ return handle_scope.Escape(result); } +#if BUILDFLAG(CLD_VERSION) == 2 void InitDetectedLanguages( CLD2::Language* languages, int* percents, @@ -117,6 +127,41 @@ } } +#elif BUILDFLAG(CLD_VERSION) == 3 +void InitDetectedLanguages( + const std::vector<chrome_lang_id::NNetLanguageIdentifier::Result>& + lang_results, + LanguageDetectionResult* result) { + std::vector<std::unique_ptr<DetectedLanguage>>* detected_languages = + &result->languages; + bool* is_reliable = &result->is_reliable; + + // is_reliable is set to "true", so that the reliability can be calculated by + // &&'ing the reliability of each predicted language. + *is_reliable = true; + for (size_t i = 0; i < lang_results.size(); ++i) { + const chrome_lang_id::NNetLanguageIdentifier::Result& lang_result = + lang_results.at(i); + const std::string& language_code = lang_result.language; + if (language_code == chrome_lang_id::NNetLanguageIdentifier::kUnknown) { + // If the first language is kUnknown, then all languages are kUnknown. + // Thus, is_reliable is set to "false". + if (i == 0) { + *is_reliable = false; + } + break; + } + + *is_reliable = *is_reliable && lang_result.is_reliable; + const int percent = static_cast<int>(100 * lang_result.proportion); + detected_languages->push_back( + base::WrapUnique(new DetectedLanguage(language_code, percent))); + } +} +#else +# error "CLD_VERSION must be 2 or 3" +#endif + } // namespace I18NCustomBindings::I18NCustomBindings(ScriptContext* context) @@ -205,6 +250,7 @@ CHECK(args[0]->IsString()); std::string text = *v8::String::Utf8Value(args[0]); +#if BUILDFLAG(CLD_VERSION) == 2 CLD2::CLDHints cldhints = {nullptr, "", CLD2::UNKNOWN_ENCODING, CLD2::UNKNOWN_LANGUAGE}; @@ -240,8 +286,22 @@ LanguageDetectionResult result(is_reliable); // populate LanguageDetectionResult with languages and percents InitDetectedLanguages(languages, percents, &result.languages); - args.GetReturnValue().Set(result.ToValue(context())); + +#elif BUILDFLAG(CLD_VERSION) == 3 + chrome_lang_id::NNetLanguageIdentifier nnet_lang_id(/*min_num_bytes=*/0, + /*max_num_bytes=*/512); + const std::vector<chrome_lang_id::NNetLanguageIdentifier::Result> + lang_results = nnet_lang_id.FindTopNMostLikelyLangs(text, kCldNumLangs); + LanguageDetectionResult result; + + // Populate LanguageDetectionResult with prediction reliability, languages, + // and the corresponding percentages. + InitDetectedLanguages(lang_results, &result); + args.GetReturnValue().Set(result.ToValue(context())); +#else +# error "CLD_VERSION must be 2 or 3" +#endif } } // namespace extensions
diff --git a/extensions/shell/BUILD.gn b/extensions/shell/BUILD.gn index 0d31a068..454073c5 100644 --- a/extensions/shell/BUILD.gn +++ b/extensions/shell/BUILD.gn
@@ -57,7 +57,7 @@ "//extensions/utility", "//skia", "//third_party/WebKit/public:blink", - "//third_party/cld_2", + "//third_party/cld", "//ui/base", "//ui/base/ime", "//v8",
diff --git a/extensions/shell/browser/shell_native_app_window_aura_unittest.cc b/extensions/shell/browser/shell_native_app_window_aura_unittest.cc index 67eef83..d09f9f1 100644 --- a/extensions/shell/browser/shell_native_app_window_aura_unittest.cc +++ b/extensions/shell/browser/shell_native_app_window_aura_unittest.cc
@@ -8,7 +8,6 @@ #include "base/memory/ptr_util.h" #include "content/public/browser/browser_context.h" -#include "content/public/browser/notification_service.h" #include "content/public/browser/web_contents.h" #include "content/public/test/test_browser_context.h" #include "content/public/test/test_browser_thread_bundle.h" @@ -26,8 +25,7 @@ class ShellNativeAppWindowAuraTest : public ExtensionsTest { public: - ShellNativeAppWindowAuraTest() - : notification_service_(content::NotificationService::Create()) { + ShellNativeAppWindowAuraTest() { AppWindowClient::Set(&app_window_client_); } @@ -35,7 +33,6 @@ protected: content::TestBrowserThreadBundle thread_bundle_; - std::unique_ptr<content::NotificationService> notification_service_; ShellAppWindowClient app_window_client_; };
diff --git a/google_apis/BUILD.gn b/google_apis/BUILD.gn index 4ce63ba..7be06fd 100644 --- a/google_apis/BUILD.gn +++ b/google_apis/BUILD.gn
@@ -173,6 +173,17 @@ "drive/time_util.h", ] } + + if (is_mac || is_ios) { + set_sources_assignment_filter([]) + sources += [ + "google_api_keys_mac.h", + "google_api_keys_mac.mm", + ] + set_sources_assignment_filter(sources_assignment_filter) + + libs = [ "Foundation.framework" ] + } } } @@ -230,6 +241,7 @@ "gaia/oauth_request_signer_unittest.cc", "gaia/ubertoken_fetcher_unittest.cc", "google_api_keys_unittest.cc", + "google_api_keys_unittest.h", ] data = [ @@ -260,4 +272,12 @@ "drive/time_util_unittest.cc", ] } + + if (is_mac || is_ios) { + set_sources_assignment_filter([]) + sources += [ "google_api_keys_mac_unittest.mm" ] + set_sources_assignment_filter(sources_assignment_filter) + + deps += [ "//third_party/ocmock" ] + } }
diff --git a/google_apis/DEPS b/google_apis/DEPS index 367bfb8..54031e7 100644 --- a/google_apis/DEPS +++ b/google_apis/DEPS
@@ -3,4 +3,5 @@ "-content", "+crypto", "+net", + "+third_party/ocmock", ]
diff --git a/google_apis/google_api_keys.cc b/google_apis/google_api_keys.cc index 66de07a..f107fd8f 100644 --- a/google_apis/google_api_keys.cc +++ b/google_apis/google_api_keys.cc
@@ -18,6 +18,10 @@ #include "base/strings/stringize_macros.h" #include "google_apis/gaia/gaia_switches.h" +#if defined(OS_MACOSX) +#include "google_apis/google_api_keys_mac.h" +#endif + #if defined(GOOGLE_CHROME_BUILD) || defined(USE_OFFICIAL_GOOGLE_API_KEYS) #include "google_apis/internal/google_chrome_api_keys.h" #endif @@ -236,6 +240,16 @@ base::CommandLine* command_line) { std::string key_value = baked_in_value; std::string temp; +#if defined(OS_MACOSX) + // macOS and iOS can also override the API key with a value from the + // Info.plist. + temp = ::google_apis::GetAPIKeyFromInfoPlist(environment_variable_name); + if (!temp.empty()) { + key_value = temp; + VLOG(1) << "Overriding API key " << environment_variable_name + << " with value " << key_value << " from Info.plist."; + } +#endif if (environment->GetVar(environment_variable_name, &temp)) { key_value = temp; VLOG(1) << "Overriding API key " << environment_variable_name
diff --git a/google_apis/google_api_keys_mac.h b/google_apis/google_api_keys_mac.h new file mode 100644 index 0000000..6ee268e --- /dev/null +++ b/google_apis/google_api_keys_mac.h
@@ -0,0 +1,16 @@ +// 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 GOOGLE_API_KEYS_MAC_H_ +#define GOOGLE_API_KEYS_MAC_H_ + +#include <string> + +namespace google_apis { + +std::string GetAPIKeyFromInfoPlist(const std::string& key_name); + +} // namespace google_apis + +#endif // GOOGLE_API_KEYS_MAC_H_
diff --git a/google_apis/google_api_keys_mac.mm b/google_apis/google_api_keys_mac.mm new file mode 100644 index 0000000..e7c8c1e --- /dev/null +++ b/google_apis/google_api_keys_mac.mm
@@ -0,0 +1,22 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "google_api_keys_mac.h" + +#import <Foundation/Foundation.h> + +#include "base/mac/bundle_locations.h" +#include "base/mac/foundation_util.h" +#include "base/strings/sys_string_conversions.h" + +namespace google_apis { + +std::string GetAPIKeyFromInfoPlist(const std::string& key_name) { + NSString* keyName = base::SysUTF8ToNSString(key_name); + NSString* keyValue = base::mac::ObjCCast<NSString>( + [base::mac::FrameworkBundle() objectForInfoDictionaryKey:keyName]); + return base::SysNSStringToUTF8(keyValue); +} + +} // namespace google_apis
diff --git a/google_apis/google_api_keys_mac_unittest.mm b/google_apis/google_api_keys_mac_unittest.mm new file mode 100644 index 0000000..90115c8 --- /dev/null +++ b/google_apis/google_api_keys_mac_unittest.mm
@@ -0,0 +1,124 @@ +// 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. + +// Unit tests for implementation of google_api_keys namespace. +// +// Because the file deals with a lot of preprocessor defines and +// optionally includes an internal header, the way we test is by +// including the .cc file multiple times with different defines set. +// This is a little unorthodox, but it lets us test the behavior as +// close to unmodified as possible. + +#include "google_apis/google_api_keys_unittest.h" + +#include "base/mac/bundle_locations.h" +#include "base/macros.h" +#include "build/build_config.h" +#include "google_apis/gaia/gaia_switches.h" +#include "testing/gtest/include/gtest/gtest.h" +#import "third_party/ocmock/OCMock/OCMock.h" + +// We need to include everything included by google_api_keys.cc once +// at global scope so that things like STL and classes from base don't +// get defined when we re-include the google_api_keys.cc file +// below. We used to include that file in its entirety here, but that +// can cause problems if the linker decides the version of symbols +// from that file included here is the "right" version. + +#include <stddef.h> + +#include <string> +#include "base/command_line.h" +#include "base/lazy_instance.h" +#include "base/logging.h" +#include "base/strings/stringize_macros.h" +#include "google_apis/google_api_keys_mac.h" + +// After this test, for the remainder of this compilation unit, we +// need official keys to not be used. +#undef GOOGLE_CHROME_BUILD +#undef USE_OFFICIAL_GOOGLE_API_KEYS + +// Override some keys using both preprocessor defines and Info.plist entries. +// The Info.plist entries should win. +namespace override_some_keys_info_plist { + +// We start every test by creating a clean environment for the +// preprocessor defines used in google_api_keys.cc +#undef DUMMY_API_TOKEN +#undef GOOGLE_API_KEY +#undef GOOGLE_CLIENT_ID_MAIN +#undef GOOGLE_CLIENT_SECRET_MAIN +#undef GOOGLE_CLIENT_ID_CLOUD_PRINT +#undef GOOGLE_CLIENT_SECRET_CLOUD_PRINT +#undef GOOGLE_CLIENT_ID_REMOTING +#undef GOOGLE_CLIENT_SECRET_REMOTING +#undef GOOGLE_CLIENT_ID_REMOTING_HOST +#undef GOOGLE_CLIENT_SECRET_REMOTING_HOST +#undef GOOGLE_DEFAULT_CLIENT_ID +#undef GOOGLE_DEFAULT_CLIENT_SECRET + +#define GOOGLE_API_KEY "API_KEY" +#define GOOGLE_CLIENT_ID_MAIN "ID_MAIN" +#define GOOGLE_CLIENT_SECRET_MAIN "SECRET_MAIN" +#define GOOGLE_CLIENT_ID_CLOUD_PRINT "ID_CLOUD_PRINT" +#define GOOGLE_CLIENT_SECRET_CLOUD_PRINT "SECRET_CLOUD_PRINT" +#define GOOGLE_CLIENT_ID_REMOTING "ID_REMOTING" +#define GOOGLE_CLIENT_SECRET_REMOTING "SECRET_REMOTING" +#define GOOGLE_CLIENT_ID_REMOTING_HOST "ID_REMOTING_HOST" +#define GOOGLE_CLIENT_SECRET_REMOTING_HOST "SECRET_REMOTING_HOST" + +// Undef include guard so things get defined again, within this namespace. +#undef GOOGLE_APIS_GOOGLE_API_KEYS_H_ +#undef GOOGLE_APIS_INTERNAL_GOOGLE_CHROME_API_KEYS_ +#include "google_apis/google_api_keys.cc" + +} // namespace override_all_keys_env + +TEST_F(GoogleAPIKeysTest, OverrideSomeKeysUsingInfoPlist) { + namespace testcase = override_some_keys_info_plist::google_apis; + + id mock_bundle = [OCMockObject mockForClass:[NSBundle class]]; + [[[mock_bundle stub] andReturn:@"plist-API_KEY"] + objectForInfoDictionaryKey:@"GOOGLE_API_KEY"]; + [[[mock_bundle stub] andReturn:@"plist-ID_MAIN"] + objectForInfoDictionaryKey:@"GOOGLE_CLIENT_ID_MAIN"]; + [[[mock_bundle stub] andReturn:nil] objectForInfoDictionaryKey:[OCMArg any]]; + base::mac::SetOverrideFrameworkBundle(mock_bundle); + + EXPECT_TRUE(testcase::HasKeysConfigured()); + + // Once the keys have been configured, the bundle isn't used anymore. + base::mac::SetOverrideFrameworkBundle(nil); + + std::string api_key = testcase::g_api_key_cache.Get().api_key(); + std::string id_main = + testcase::g_api_key_cache.Get().GetClientID(testcase::CLIENT_MAIN); + std::string secret_main = + testcase::g_api_key_cache.Get().GetClientSecret(testcase::CLIENT_MAIN); + std::string id_cloud_print = + testcase::g_api_key_cache.Get().GetClientID(testcase::CLIENT_CLOUD_PRINT); + std::string secret_cloud_print = + testcase::g_api_key_cache.Get().GetClientSecret( + testcase::CLIENT_CLOUD_PRINT); + std::string id_remoting = + testcase::g_api_key_cache.Get().GetClientID(testcase::CLIENT_REMOTING); + std::string secret_remoting = testcase::g_api_key_cache.Get().GetClientSecret( + testcase::CLIENT_REMOTING); + std::string id_remoting_host = testcase::g_api_key_cache.Get().GetClientID( + testcase::CLIENT_REMOTING_HOST); + std::string secret_remoting_host = + testcase::g_api_key_cache.Get().GetClientSecret( + testcase::CLIENT_REMOTING_HOST); + + EXPECT_EQ("plist-API_KEY", api_key); + EXPECT_EQ("plist-ID_MAIN", id_main); + EXPECT_EQ("SECRET_MAIN", secret_main); + EXPECT_EQ("ID_CLOUD_PRINT", id_cloud_print); + EXPECT_EQ("SECRET_CLOUD_PRINT", secret_cloud_print); + EXPECT_EQ("ID_REMOTING", id_remoting); + EXPECT_EQ("SECRET_REMOTING", secret_remoting); + EXPECT_EQ("ID_REMOTING_HOST", id_remoting_host); + EXPECT_EQ("SECRET_REMOTING_HOST", secret_remoting_host); +}
diff --git a/google_apis/google_api_keys_unittest.cc b/google_apis/google_api_keys_unittest.cc index a04b322..5ce1fb316 100644 --- a/google_apis/google_api_keys_unittest.cc +++ b/google_apis/google_api_keys_unittest.cc
@@ -10,14 +10,11 @@ // This is a little unorthodox, but it lets us test the behavior as // close to unmodified as possible. -#include "google_apis/google_api_keys.h" - -#include <memory> +#include "google_apis/google_api_keys_unittest.h" #include "base/macros.h" #include "build/build_config.h" #include "google_apis/gaia/gaia_switches.h" -#include "testing/gtest/include/gtest/gtest.h" // The Win builders fail (with a linker crash) when trying to link // unit_tests, and the Android builders complain about multiply @@ -38,75 +35,59 @@ #include <string> #include "base/command_line.h" -#include "base/environment.h" #include "base/lazy_instance.h" #include "base/logging.h" #include "base/strings/stringize_macros.h" +#if defined(OS_MACOSX) +#include "google_apis/google_api_keys_mac.h" +#endif + +GoogleAPIKeysTest::GoogleAPIKeysTest() : env_(base::Environment::Create()) { + static_assert(11 == 3 + 2 * google_apis::CLIENT_NUM_ITEMS, + "Unexpected number of key entries."); + env_cache_[0].variable_name = "GOOGLE_API_KEY"; + env_cache_[1].variable_name = "GOOGLE_CLIENT_ID_MAIN"; + env_cache_[2].variable_name = "GOOGLE_CLIENT_SECRET_MAIN"; + env_cache_[3].variable_name = "GOOGLE_CLIENT_ID_CLOUD_PRINT"; + env_cache_[4].variable_name = "GOOGLE_CLIENT_SECRET_CLOUD_PRINT"; + env_cache_[5].variable_name = "GOOGLE_CLIENT_ID_REMOTING"; + env_cache_[6].variable_name = "GOOGLE_CLIENT_SECRET_REMOTING"; + env_cache_[7].variable_name = "GOOGLE_CLIENT_ID_REMOTING_HOST"; + env_cache_[8].variable_name = "GOOGLE_CLIENT_SECRET_REMOTING_HOST"; + env_cache_[9].variable_name = "GOOGLE_DEFAULT_CLIENT_ID"; + env_cache_[10].variable_name = "GOOGLE_DEFAULT_CLIENT_SECRET"; +} + +GoogleAPIKeysTest::~GoogleAPIKeysTest() {} + +void GoogleAPIKeysTest::SetUp() { + // Unset all environment variables that can affect these tests, + // for the duration of the tests. + for (size_t i = 0; i < arraysize(env_cache_); ++i) { + EnvironmentCache& cache = env_cache_[i]; + cache.was_set = env_->HasVar(cache.variable_name); + cache.value.clear(); + if (cache.was_set) { + env_->GetVar(cache.variable_name, &cache.value); + env_->UnSetVar(cache.variable_name); + } + } +} + +void GoogleAPIKeysTest::TearDown() { + // Restore environment. + for (size_t i = 0; i < arraysize(env_cache_); ++i) { + EnvironmentCache& cache = env_cache_[i]; + if (cache.was_set) { + env_->SetVar(cache.variable_name, cache.value); + } + } +} + // This is the default baked-in value for OAuth IDs and secrets. static const char kDummyToken[] = "dummytoken"; -struct EnvironmentCache { - public: - EnvironmentCache() : variable_name(NULL), was_set(false) {} - - const char* variable_name; - bool was_set; - std::string value; -}; - -class GoogleAPIKeysTest : public testing::Test { - public: - GoogleAPIKeysTest() : env_(base::Environment::Create()) { - env_cache_[0].variable_name = "GOOGLE_API_KEY"; - env_cache_[1].variable_name = "GOOGLE_CLIENT_ID_MAIN"; - env_cache_[2].variable_name = "GOOGLE_CLIENT_SECRET_MAIN"; - env_cache_[3].variable_name = "GOOGLE_CLIENT_ID_CLOUD_PRINT"; - env_cache_[4].variable_name = "GOOGLE_CLIENT_SECRET_CLOUD_PRINT"; - env_cache_[5].variable_name = "GOOGLE_CLIENT_ID_REMOTING"; - env_cache_[6].variable_name = "GOOGLE_CLIENT_SECRET_REMOTING"; - env_cache_[7].variable_name = "GOOGLE_CLIENT_ID_REMOTING_HOST"; - env_cache_[8].variable_name = "GOOGLE_CLIENT_SECRET_REMOTING_HOST"; - env_cache_[9].variable_name = "GOOGLE_DEFAULT_CLIENT_ID"; - env_cache_[10].variable_name = "GOOGLE_DEFAULT_CLIENT_SECRET"; - } - - void SetUp() override { - // Unset all environment variables that can affect these tests, - // for the duration of the tests. - for (size_t i = 0; i < arraysize(env_cache_); ++i) { - EnvironmentCache& cache = env_cache_[i]; - cache.was_set = env_->HasVar(cache.variable_name); - cache.value.clear(); - if (cache.was_set) { - env_->GetVar(cache.variable_name, &cache.value); - env_->UnSetVar(cache.variable_name); - } - } - } - - void TearDown() override { - // Restore environment. - for (size_t i = 0; i < arraysize(env_cache_); ++i) { - EnvironmentCache& cache = env_cache_[i]; - if (cache.was_set) { - env_->SetVar(cache.variable_name, cache.value); - } - } - } - - private: - std::unique_ptr<base::Environment> env_; - - // Why 3? It is for GOOGLE_API_KEY, GOOGLE_DEFAULT_CLIENT_ID and - // GOOGLE_DEFAULT_CLIENT_SECRET. - // - // Why 2 times CLIENT_NUM_ITEMS? This is the number of different - // clients in the OAuth2Client enumeration, and for each of these we - // have both an ID and a secret. - EnvironmentCache env_cache_[3 + 2 * google_apis::CLIENT_NUM_ITEMS]; -}; - #if defined(GOOGLE_CHROME_BUILD) || defined(USE_OFFICIAL_GOOGLE_API_KEYS) // Test official build behavior, since we are in a checkout where this // is possible.
diff --git a/google_apis/google_api_keys_unittest.h b/google_apis/google_api_keys_unittest.h new file mode 100644 index 0000000..05bf1bf --- /dev/null +++ b/google_apis/google_api_keys_unittest.h
@@ -0,0 +1,42 @@ +// 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 GOOGLE_APIS_GOOGLE_API_KEYS_UNITTEST_H_ +#define GOOGLE_APIS_GOOGLE_API_KEYS_UNITTEST_H_ + +#include <memory> +#include <string> + +#include "base/environment.h" +#include "google_apis/google_api_keys.h" +#include "testing/gtest/include/gtest/gtest.h" + +struct EnvironmentCache { + EnvironmentCache() : variable_name(nullptr), was_set(false) {} + + const char* variable_name; + bool was_set; + std::string value; +}; + +class GoogleAPIKeysTest : public testing::Test { + public: + GoogleAPIKeysTest(); + ~GoogleAPIKeysTest() override; + void SetUp() override; + void TearDown() override; + + private: + std::unique_ptr<base::Environment> env_; + + // Why 3? It is for GOOGLE_API_KEY, GOOGLE_DEFAULT_CLIENT_ID and + // GOOGLE_DEFAULT_CLIENT_SECRET. + // + // Why 2 times CLIENT_NUM_ITEMS? This is the number of different + // clients in the OAuth2Client enumeration, and for each of these we + // have both an ID and a secret. + EnvironmentCache env_cache_[3 + 2 * google_apis::CLIENT_NUM_ITEMS]; +}; + +#endif // GOOGLE_APIS_GOOGLE_API_KEYS_UNITTEST_H_
diff --git a/gpu/config/gpu_info_collector_android.cc b/gpu/config/gpu_info_collector_android.cc index 1312e35..3ae3d66 100644 --- a/gpu/config/gpu_info_collector_android.cc +++ b/gpu/config/gpu_info_collector_android.cc
@@ -18,6 +18,7 @@ #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" +#include "gpu/config/gpu_switches.h" #include "ui/gl/egl_util.h" #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_context.h" @@ -205,6 +206,20 @@ gpu_info->gl_extensions = reinterpret_cast<const char*>(glGetStringFn(GL_EXTENSIONS)); + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + if (command_line->HasSwitch(switches::kGpuTestingGLVendor)) { + gpu_info->gl_vendor = + command_line->GetSwitchValueASCII(switches::kGpuTestingGLVendor); + } + if (command_line->HasSwitch(switches::kGpuTestingGLRenderer)) { + gpu_info->gl_renderer = + command_line->GetSwitchValueASCII(switches::kGpuTestingGLRenderer); + } + if (command_line->HasSwitch(switches::kGpuTestingGLVersion)) { + gpu_info->gl_version = + command_line->GetSwitchValueASCII(switches::kGpuTestingGLVersion); + } + GLint max_samples = 0; glGetIntegervFn(GL_MAX_SAMPLES, &max_samples); gpu_info->max_msaa_samples = base::IntToString(max_samples);
diff --git a/gpu/config/gpu_info_collector_ozone.cc b/gpu/config/gpu_info_collector_ozone.cc index d8fef20a..d5cc632 100644 --- a/gpu/config/gpu_info_collector_ozone.cc +++ b/gpu/config/gpu_info_collector_ozone.cc
@@ -8,7 +8,6 @@ namespace gpu { std::string CollectDriverVersionNVidia() { - NOTIMPLEMENTED(); return std::string(); }
diff --git a/gpu/ipc/client/command_buffer_proxy_impl.cc b/gpu/ipc/client/command_buffer_proxy_impl.cc index faf69b980..395dcdd 100644 --- a/gpu/ipc/client/command_buffer_proxy_impl.cc +++ b/gpu/ipc/client/command_buffer_proxy_impl.cc
@@ -262,9 +262,11 @@ last_barrier_put_offset_ = put_offset; if (channel_) { + uint32_t highest_verified_flush_id; const uint32_t flush_id = channel_->OrderingBarrier( route_id_, stream_id_, put_offset, ++flush_count_, latency_info_, - put_offset_changed, true); + put_offset_changed, true, &highest_verified_flush_id); + UpdateVerifiedReleases(highest_verified_flush_id); if (put_offset_changed) { DCHECK(flush_id); const uint64_t fence_sync_release = next_fence_sync_release_ - 1; @@ -292,9 +294,12 @@ last_barrier_put_offset_ = put_offset; if (channel_) { + uint32_t highest_verified_flush_id; const uint32_t flush_id = channel_->OrderingBarrier( route_id_, stream_id_, put_offset, ++flush_count_, latency_info_, - put_offset_changed, false); + put_offset_changed, false, &highest_verified_flush_id); + UpdateVerifiedReleases(highest_verified_flush_id); + if (put_offset_changed) { DCHECK(flush_id); const uint64_t fence_sync_release = next_fence_sync_release_ - 1;
diff --git a/gpu/ipc/client/gpu_channel_host.cc b/gpu/ipc/client/gpu_channel_host.cc index beeaa15..876aa253 100644 --- a/gpu/ipc/client/gpu_channel_host.cc +++ b/gpu/ipc/client/gpu_channel_host.cc
@@ -135,12 +135,15 @@ uint32_t flush_count, const std::vector<ui::LatencyInfo>& latency_info, bool put_offset_changed, - bool do_flush) { + bool do_flush, + uint32_t* highest_verified_flush_id) { AutoLock lock(context_lock_); StreamFlushInfo& flush_info = stream_flush_info_[stream_id]; if (flush_info.flush_pending && flush_info.route_id != route_id) InternalFlush(&flush_info); + *highest_verified_flush_id = flush_info.verified_stream_flush_id; + if (put_offset_changed) { const uint32_t flush_id = flush_info.next_stream_flush_id++; flush_info.flush_pending = true;
diff --git a/gpu/ipc/client/gpu_channel_host.h b/gpu/ipc/client/gpu_channel_host.h index 733a7e41..fd9cfeac 100644 --- a/gpu/ipc/client/gpu_channel_host.h +++ b/gpu/ipc/client/gpu_channel_host.h
@@ -100,13 +100,15 @@ // Set an ordering barrier. AsyncFlushes any pending barriers on other // routes. Combines multiple OrderingBarriers into a single AsyncFlush. // Returns the flush ID for the stream or 0 if put offset was not changed. + // Outputs *highest_verified_flush_id. uint32_t OrderingBarrier(int32_t route_id, int32_t stream_id, int32_t put_offset, uint32_t flush_count, const std::vector<ui::LatencyInfo>& latency_info, bool put_offset_changed, - bool do_flush); + bool do_flush, + uint32_t* highest_verified_flush_id); void FlushPendingStream(int32_t stream_id);
diff --git a/headless/lib/browser/client_api_generator.py b/headless/lib/browser/client_api_generator.py index e5276c4..a264b32 100644 --- a/headless/lib/browser/client_api_generator.py +++ b/headless/lib/browser/client_api_generator.py
@@ -361,26 +361,27 @@ domain['types'].append(event_type) -def PatchHiddenCommandsAndEvents(json_api): +def PatchExperimentalCommandsAndEvents(json_api): """ - Mark all commands and events in hidden domains as hidden and make sure hidden - commands have at least empty parameters and return values. + Mark all commands and events in experimental domains as experimental + and make sure experimental commands have at least empty parameters + and return values. """ for domain in json_api['domains']: - if domain.get('hidden', False): + if domain.get('experimental', False): for command in domain.get('commands', []): - command['hidden'] = True + command['experimental'] = True for event in domain.get('events', []): - event['hidden'] = True + event['experimental'] = True for command in domain.get('commands', []): - if not command.get('hidden', False): + if not command.get('experimental', False): continue if not 'parameters' in command: command['parameters'] = [] if not 'returns' in command: command['returns'] = [] for event in domain.get('events', []): - if not event.get('hidden', False): + if not event.get('experimental', False): continue if not 'parameters' in event: event['parameters'] = [] @@ -420,7 +421,7 @@ if __name__ == '__main__': json_api, output_dirname = ParseArguments(sys.argv[1:]) jinja_env = InitializeJinjaEnv(output_dirname) - PatchHiddenCommandsAndEvents(json_api) + PatchExperimentalCommandsAndEvents(json_api) SynthesizeCommandTypes(json_api) SynthesizeEventTypes(json_api) PatchFullQualifiedRefs(json_api)
diff --git a/headless/lib/browser/client_api_generator_unittest.py b/headless/lib/browser/client_api_generator_unittest.py index 67ff253..cf101d3 100644 --- a/headless/lib/browser/client_api_generator_unittest.py +++ b/headless/lib/browser/client_api_generator_unittest.py
@@ -351,12 +351,12 @@ types = json_api['domains'][0]['types'] self.assertListEqual(types, expected_types) - def test_PatchHiddenDomains(self): + def test_PatchExperimentalDomains(self): json_api = { 'domains': [ { 'domain': 'domain', - 'hidden': True, + 'experimental': True, 'commands': [ { 'name': 'FooCommand', @@ -390,17 +390,17 @@ 'properties': [], } ] - client_api_generator.PatchHiddenCommandsAndEvents(json_api) + client_api_generator.PatchExperimentalCommandsAndEvents(json_api) client_api_generator.SynthesizeCommandTypes(json_api) client_api_generator.SynthesizeEventTypes(json_api) for command in json_api['domains'][0]['commands']: - self.assertTrue(command['hidden']) + self.assertTrue(command['experimental']) for event in json_api['domains'][0]['events']: - self.assertTrue(command['hidden']) + self.assertTrue(command['experimental']) types = json_api['domains'][0]['types'] self.assertListEqual(types, expected_types) - def test_PatchHiddenCommandsAndEvents(self): + def test_PatchExperimentalCommandsAndEvents(self): json_api = { 'domains': [ { @@ -408,13 +408,13 @@ 'commands': [ { 'name': 'FooCommand', - 'hidden': True, + 'experimental': True, } ], 'events': [ { 'name': 'BarEvent', - 'hidden': True, + 'experimental': True, } ] } @@ -440,13 +440,13 @@ 'properties': [], } ] - client_api_generator.PatchHiddenCommandsAndEvents(json_api) + client_api_generator.PatchExperimentalCommandsAndEvents(json_api) client_api_generator.SynthesizeCommandTypes(json_api) client_api_generator.SynthesizeEventTypes(json_api) for command in json_api['domains'][0]['commands']: - self.assertTrue(command['hidden']) + self.assertTrue(command['experimental']) for event in json_api['domains'][0]['events']: - self.assertTrue(command['hidden']) + self.assertTrue(command['experimental']) types = json_api['domains'][0]['types'] self.assertListEqual(types, expected_types)
diff --git a/headless/lib/browser/domain_cc.template b/headless/lib/browser/domain_cc.template index 118d996..adff89b 100644 --- a/headless/lib/browser/domain_cc.template +++ b/headless/lib/browser/domain_cc.template
@@ -30,7 +30,7 @@ {# Skip redirected commands. #} {% if "redirect" in command %}{% continue %}{% endif %} - {% set class_name = 'ExperimentalDomain' if command.hidden else 'Domain' %} + {% set class_name = 'ExperimentalDomain' if command.experimental else 'Domain' %} {% set method_name = command.name | to_title_case %} {% if "parameters" in command and "returns" in command %} void {{class_name}}::{{method_name}}(std::unique_ptr<{{method_name}}Params> params, base::Callback<void(std::unique_ptr<{{method_name}}Result>)> callback) { @@ -48,8 +48,8 @@ } {# Generate convenience methods that take the required parameters directly. #} {% if not "parameters" in command %}{% continue %}{% endif %} - {# Don't generate these for hidden commands. #} - {% if command.hidden %}{% continue %}{% endif %} + {# Don't generate these for experimental commands. #} + {% if command.experimental %}{% continue %}{% endif %} void {{class_name}}::{{method_name}}({##} {% for parameter in command.parameters -%}
diff --git a/headless/lib/browser/domain_h.template b/headless/lib/browser/domain_h.template index 607b5be..cc0e8eb4 100644 --- a/headless/lib/browser/domain_h.template +++ b/headless/lib/browser/domain_h.template
@@ -30,8 +30,8 @@ void {{method_name}}(base::Callback<void()> callback = base::Callback<void()>()); {% endif %} {# Generate convenience methods that take the required parameters directly. #} - {# Don't generate these for hidden commands. #} - {% if "parameters" in command and not command.hidden %} + {# Don't generate these for experimental commands. #} + {% if "parameters" in command and not command.experimental %} void {{method_name}}({##} {% for parameter in command.parameters -%} {% if parameter.get("optional", False) -%} @@ -71,9 +71,9 @@ virtual ~Observer() {} {% for event in domain.events %} {% if event.description %} - // {% if event.hidden %}Experimental: {% endif %}{{event.description}} + // {% if event.experimental %}Experimental: {% endif %}{{event.description}} {% endif %} - virtual void On{{event.name | to_title_case}}(const {{event.name | to_title_case}}Params& params) {% if event.hidden %}final {% endif %}{} + virtual void On{{event.name | to_title_case}}(const {{event.name | to_title_case}}Params& params) {% if event.experimental %}final {% endif %}{} {% endfor %} }; {% endif %} @@ -98,8 +98,8 @@ {% for command in domain.commands %} {# Skip redirected commands. #} {% if "redirect" in command %}{% continue %}{% endif %} - {# Skip hidden commands. #} - {% if command.hidden %}{% continue %}{% endif %} + {# Skip experimental commands. #} + {% if command.experimental %}{% continue %}{% endif %} {{ command_decl(command) }} {% endfor %} protected: @@ -143,8 +143,8 @@ {% for command in domain.commands %} {# Skip redirected commands. #} {% if "redirect" in command %}{% continue %}{% endif %} - {# Skip non-hidden commands. #} - {% if not command.hidden %}{% continue %}{% endif %} + {# Skip non-experimental commands. #} + {% if not command.experimental %}{% continue %}{% endif %} {{ command_decl(command) }} {% endfor %}
diff --git a/headless/lib/browser/headless_browser_impl.cc b/headless/lib/browser/headless_browser_impl.cc index 57f32e5..98fcac8 100644 --- a/headless/lib/browser/headless_browser_impl.cc +++ b/headless/lib/browser/headless_browser_impl.cc
@@ -63,17 +63,23 @@ } scoped_refptr<base::SingleThreadTaskRunner> -HeadlessBrowserImpl::BrowserMainThread() const { - return content::BrowserThread::GetTaskRunnerForThread( - content::BrowserThread::UI); -} - -scoped_refptr<base::SingleThreadTaskRunner> HeadlessBrowserImpl::BrowserFileThread() const { return content::BrowserThread::GetTaskRunnerForThread( content::BrowserThread::FILE); } +scoped_refptr<base::SingleThreadTaskRunner> +HeadlessBrowserImpl::BrowserIOThread() const { + return content::BrowserThread::GetTaskRunnerForThread( + content::BrowserThread::IO); +} + +scoped_refptr<base::SingleThreadTaskRunner> +HeadlessBrowserImpl::BrowserMainThread() const { + return content::BrowserThread::GetTaskRunnerForThread( + content::BrowserThread::UI); +} + void HeadlessBrowserImpl::Shutdown() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
diff --git a/headless/lib/browser/headless_browser_impl.h b/headless/lib/browser/headless_browser_impl.h index a97410e..a313918 100644 --- a/headless/lib/browser/headless_browser_impl.h +++ b/headless/lib/browser/headless_browser_impl.h
@@ -38,10 +38,11 @@ // HeadlessBrowser implementation: HeadlessBrowserContext::Builder CreateBrowserContextBuilder() override; - scoped_refptr<base::SingleThreadTaskRunner> BrowserMainThread() - const override; scoped_refptr<base::SingleThreadTaskRunner> BrowserFileThread() const override; + scoped_refptr<base::SingleThreadTaskRunner> BrowserIOThread() const override; + scoped_refptr<base::SingleThreadTaskRunner> BrowserMainThread() + const override; void Shutdown() override;
diff --git a/headless/public/headless_browser.h b/headless/public/headless_browser.h index 6c7dfe4..954b79e 100644 --- a/headless/public/headless_browser.h +++ b/headless/public/headless_browser.h
@@ -55,14 +55,18 @@ virtual HeadlessBrowserContext* GetBrowserContextForId( const std::string& id) = 0; - // Returns a task runner for submitting work to the browser main thread. - virtual scoped_refptr<base::SingleThreadTaskRunner> BrowserMainThread() - const = 0; - // Returns a task runner for submitting work to the browser file thread. virtual scoped_refptr<base::SingleThreadTaskRunner> BrowserFileThread() const = 0; + // Returns a task runner for submitting work to the browser io thread. + virtual scoped_refptr<base::SingleThreadTaskRunner> BrowserIOThread() + const = 0; + + // Returns a task runner for submitting work to the browser main thread. + virtual scoped_refptr<base::SingleThreadTaskRunner> BrowserMainThread() + const = 0; + // Requests browser to stop as soon as possible. |Run| will return as soon as // browser stops. // IMPORTANT: All pointers to HeadlessBrowserContexts and HeadlessWebContents
diff --git a/headless/testserver.log b/headless/testserver.log deleted file mode 100644 index e69de29..0000000 --- a/headless/testserver.log +++ /dev/null
diff --git a/infra/config/recipes.cfg b/infra/config/recipes.cfg index 012c74a..f5200da6d 100644 --- a/infra/config/recipes.cfg +++ b/infra/config/recipes.cfg
@@ -5,17 +5,17 @@ project_id: "build" url: "https://chromium.googlesource.com/chromium/tools/build.git" branch: "master" - revision: "c6d5023583562d95e3f309a86c97929490265cc2" + revision: "a661277f9f72d06f313dba599b4e6a4a7dd9887f" } deps { project_id: "depot_tools" url: "https://chromium.googlesource.com/chromium/tools/depot_tools.git" branch: "master" - revision: "13f9c37185750d4212a125204d22302376c77f8e" + revision: "fff0635af2a79778a23be93802f2cabd6c9aedc4" } deps { project_id: "recipe_engine" url: "https://chromium.googlesource.com/external/github.com/luci/recipes-py.git" branch: "master" - revision: "28882da017c8638118faba38890c54d2507fabc0" + revision: "87823726a3c8ef0016780ac1b752a758f2191a55" }
diff --git a/ios/BUILD.gn b/ios/BUILD.gn index 8aadf88c..5a799b2 100644 --- a/ios/BUILD.gn +++ b/ios/BUILD.gn
@@ -9,7 +9,6 @@ group("all") { testonly = true deps = [ - "//components/sync:sync_unit_tests", "//ios/chrome:ios_chrome_unittests", "//ios/chrome/app", "//ios/chrome/browser",
diff --git a/ios/build/bots/tests/common_tests.json b/ios/build/bots/tests/common_tests.json index f5aca97..81f4634 100644 --- a/ios/build/bots/tests/common_tests.json +++ b/ios/build/bots/tests/common_tests.json
@@ -37,9 +37,6 @@ "app": "sql_unittests" }, { - "app": "sync_unit_tests" - }, - { "app": "ui_base_unittests" }, {
diff --git a/ios/chrome/browser/BUILD.gn b/ios/chrome/browser/BUILD.gn index dfe7d60bb..a7bc329c 100644 --- a/ios/chrome/browser/BUILD.gn +++ b/ios/chrome/browser/BUILD.gn
@@ -317,6 +317,8 @@ "passwords/passwords_ui_delegate.h", "passwords/update_password_infobar_controller.h", "passwords/update_password_infobar_controller.mm", + "physical_web/create_physical_web_data_source.h", + "physical_web/create_physical_web_data_source.mm", "physical_web/physical_web_constants.h", "pref_names.cc", "pref_names.h", @@ -337,6 +339,8 @@ "reading_list/reading_list_entry.h", "reading_list/reading_list_model.cc", "reading_list/reading_list_model.h", + "reading_list/reading_list_model_bridge_observer.h", + "reading_list/reading_list_model_bridge_observer.mm", "reading_list/reading_list_model_factory.cc", "reading_list/reading_list_model_factory.h", "reading_list/reading_list_model_impl.cc", @@ -650,6 +654,7 @@ "//components/password_manager/core/browser", "//components/password_manager/core/common", "//components/password_manager/sync/browser", + "//components/physical_web/data_source", "//components/policy:policy_component_common", "//components/pref_registry", "//components/prefs", @@ -690,6 +695,7 @@ "//ios/chrome/browser/variations:ios_chrome_ui_string_overrider_factory", "//ios/chrome/common", "//ios/chrome/common/app_group", + "//ios/chrome/common/physical_web", "//ios/net", "//ios/public/provider/chrome/browser", "//ios/public/provider/web",
diff --git a/ios/chrome/browser/DEPS b/ios/chrome/browser/DEPS index 2f18ab61..94dab69 100644 --- a/ios/chrome/browser/DEPS +++ b/ios/chrome/browser/DEPS
@@ -44,6 +44,7 @@ "+components/password_manager/core/browser", "+components/password_manager/core/common", "+components/password_manager/sync/browser", + "+components/physical_web/data_source", "+components/pref_registry", "+components/prefs", "+components/profile_metrics",
diff --git a/ios/chrome/browser/about_flags.mm b/ios/chrome/browser/about_flags.mm index cde3c2b3..a04fae1 100644 --- a/ios/chrome/browser/about_flags.mm +++ b/ios/chrome/browser/about_flags.mm
@@ -176,14 +176,6 @@ } } - // Populate command line flags from EnableWKWebView. - NSString* enableWKWebViewValue = [defaults stringForKey:@"EnableWKWebView"]; - if ([enableWKWebViewValue isEqualToString:@"Enabled"]) { - command_line->AppendSwitch(switches::kEnableIOSWKWebView); - } else if ([enableWKWebViewValue isEqualToString:@"Disabled"]) { - command_line->AppendSwitch(switches::kDisableIOSWKWebView); - } - // Set the UA flag if UseMobileSafariUA is enabled. if ([defaults boolForKey:@"UseMobileSafariUA"]) { // Safari uses "Vesion/", followed by the OS version excluding bugfix, where
diff --git a/ios/chrome/browser/application_context.h b/ios/chrome/browser/application_context.h index 2e7fbf7a..7d14884 100644 --- a/ios/chrome/browser/application_context.h +++ b/ios/chrome/browser/application_context.h
@@ -56,6 +56,7 @@ class ApplicationContext; class CRLSetFetcher; class IOSChromeIOThread; +class PhysicalWebDataSource; class PrefService; // Gets the global application context. Cannot return null. @@ -124,6 +125,9 @@ // Gets the CRLSetFetcher. virtual CRLSetFetcher* GetCRLSetFetcher() = 0; + // Gets the PhysicalWebDataSource. + virtual PhysicalWebDataSource* GetPhysicalWebDataSource() = 0; + protected: // Sets the global ApplicationContext instance. static void SetApplicationContext(ApplicationContext* context);
diff --git a/ios/chrome/browser/application_context_impl.cc b/ios/chrome/browser/application_context_impl.cc index 704a6b1f..83b6a89 100644 --- a/ios/chrome/browser/application_context_impl.cc +++ b/ios/chrome/browser/application_context_impl.cc
@@ -28,6 +28,7 @@ #include "components/metrics_services_manager/metrics_services_manager.h" #include "components/net_log/chrome_net_log.h" #include "components/network_time/network_time_tracker.h" +#include "components/physical_web/data_source/physical_web_data_source.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" #include "components/translate/core/browser/translate_download_manager.h" @@ -43,6 +44,7 @@ #include "ios/chrome/browser/ios_chrome_io_thread.h" #include "ios/chrome/browser/metrics/ios_chrome_metrics_services_manager_client.h" #include "ios/chrome/browser/net/crl_set_fetcher.h" +#include "ios/chrome/browser/physical_web/create_physical_web_data_source.h" #include "ios/chrome/browser/pref_names.h" #include "ios/chrome/browser/prefs/browser_prefs.h" #include "ios/chrome/browser/prefs/ios_chrome_pref_service_factory.h" @@ -88,8 +90,6 @@ false); registry->RegisterBooleanPref(prefs::kLastSessionExitedCleanly, true); registry->RegisterBooleanPref(prefs::kMetricsReportingWifiOnly, true); - registry->RegisterBooleanPref(prefs::kLastSessionUsedWKWebViewControlGroup, - false); } void ApplicationContextImpl::PreCreateThreads() { @@ -296,6 +296,15 @@ return crl_set_fetcher_.get(); } +PhysicalWebDataSource* ApplicationContextImpl::GetPhysicalWebDataSource() { + DCHECK(thread_checker_.CalledOnValidThread()); + if (!physical_web_data_source_) { + physical_web_data_source_ = CreateIOSChromePhysicalWebDataSource(); + DCHECK(physical_web_data_source_); + } + return physical_web_data_source_.get(); +} + void ApplicationContextImpl::SetApplicationLocale(const std::string& locale) { DCHECK(thread_checker_.CalledOnValidThread()); application_locale_ = locale;
diff --git a/ios/chrome/browser/application_context_impl.h b/ios/chrome/browser/application_context_impl.h index f33e34f0..ba961f2 100644 --- a/ios/chrome/browser/application_context_impl.h +++ b/ios/chrome/browser/application_context_impl.h
@@ -64,6 +64,7 @@ component_updater::ComponentUpdateService* GetComponentUpdateService() override; CRLSetFetcher* GetCRLSetFetcher() override; + PhysicalWebDataSource* GetPhysicalWebDataSource() override; private: // Sets the locale used by the application. @@ -87,6 +88,7 @@ scoped_refptr<CRLSetFetcher> crl_set_fetcher_; std::unique_ptr<ios::ChromeBrowserStateManager> chrome_browser_state_manager_; std::string application_locale_; + std::unique_ptr<PhysicalWebDataSource> physical_web_data_source_; // Sequenced task runner for local state related I/O tasks. const scoped_refptr<base::SequencedTaskRunner> local_state_task_runner_;
diff --git a/ios/chrome/browser/chrome_switches.cc b/ios/chrome/browser/chrome_switches.cc index 53018490..049376e 100644 --- a/ios/chrome/browser/chrome_switches.cc +++ b/ios/chrome/browser/chrome_switches.cc
@@ -34,9 +34,6 @@ const char kDisableIOSPasswordSuggestions[] = "disable-ios-password-suggestions"; -// Disables the use of WKWebView instead of UIWebView. -const char kDisableIOSWKWebView[] = "disable-wkwebview"; - // Disable the snapshots lru cache. const char kDisableLRUSnapshotCache[] = "disable-lru-snapshot-cache"; @@ -74,9 +71,6 @@ // Enable password generation for iOS. const char kEnableIOSPasswordGeneration[] = "enable-ios-password-generation"; -// Enables the use of WKWebView instead of UIWebView. -const char kEnableIOSWKWebView[] = "enable-wkwebview"; - // Enables the snapshot lru cache. const char kEnableLRUSnapshotCache[] = "enable-lru-snapshot-cache";
diff --git a/ios/chrome/browser/chrome_switches.h b/ios/chrome/browser/chrome_switches.h index 5445fce..00d2fb4f 100644 --- a/ios/chrome/browser/chrome_switches.h +++ b/ios/chrome/browser/chrome_switches.h
@@ -15,7 +15,6 @@ extern const char kDisableIOSFeatures[]; extern const char kDisableIOSPasswordGeneration[]; extern const char kDisableIOSPasswordSuggestions[]; -extern const char kDisableIOSWKWebView[]; extern const char kDisableLRUSnapshotCache[]; extern const char kDisableNTPFavicons[]; extern const char kDisableOfflineAutoReload[]; @@ -29,7 +28,6 @@ extern const char kEnableIOSFeatures[]; extern const char kEnableIOSHandoffToOtherDevices[]; extern const char kEnableIOSPasswordGeneration[]; -extern const char kEnableIOSWKWebView[]; extern const char kEnableLRUSnapshotCache[]; extern const char kEnableNTPFavicons[]; extern const char kEnableOfflineAutoReload[];
diff --git a/ios/chrome/browser/find_in_page/js_findinpage_manager.mm b/ios/chrome/browser/find_in_page/js_findinpage_manager.mm index 5302ec35..fe708492 100644 --- a/ios/chrome/browser/find_in_page/js_findinpage_manager.mm +++ b/ios/chrome/browser/find_in_page/js_findinpage_manager.mm
@@ -17,10 +17,6 @@ namespace { -// Global variable defined in find_in_page.js that can be used for testing -// whether JavaScript bas heen loaded. -NSString* const kFindInPageBeacon = @"window.__gCrWeb.findInPage"; - // Initializes Find In Page JavaScript with the width and height of the window. NSString* const kFindInPageInit = @"window.__gCrWeb.findInPage && " "window.__gCrWeb.findInPage.init(%.f, %.f);"; @@ -264,8 +260,4 @@ return @"find_in_page"; } -- (NSString*)presenceBeacon { - return kFindInPageBeacon; -} - @end
diff --git a/ios/chrome/browser/passwords/credential_manager_js_unittest.mm b/ios/chrome/browser/passwords/credential_manager_js_unittest.mm index 42382ba8..37f0d66 100644 --- a/ios/chrome/browser/passwords/credential_manager_js_unittest.mm +++ b/ios/chrome/browser/passwords/credential_manager_js_unittest.mm
@@ -95,7 +95,7 @@ // Adds handlers for resolving and rejecting the promise returned by // executing the code in |promise|. void PrepareResolverAndRejecter(NSString* promise) { - EvaluateJavaScriptAsString( + ExecuteJavaScript( [NSString stringWithFormat:@"var resolved = false; " @"var rejected = false; " @"var resolvedCredential = null; " @@ -112,49 +112,46 @@ promise]); // Wait until the promise executor has executed. WaitForCondition(^bool { - return [EvaluateJavaScriptAsString( + return [ExecuteJavaScript( @"Object.keys(__gCrWeb.credentialManager.resolvers_).length > 0") - isEqualToString:@"true"]; + boolValue]; }); } // Checks that the Credential returned to the resolve handler in JavaScript // matches the structure of |test_credential()|. void CheckResolvedCredentialMatchesTestCredential() { - EXPECT_NSEQ(@"true", EvaluateJavaScriptAsString(@"resolved")); - EXPECT_NSEQ( - @"PasswordCredential", - EvaluateJavaScriptAsString(@"resolvedCredential.constructor.name")); - EXPECT_NSEQ(@"bob", EvaluateJavaScriptAsString(@"resolvedCredential.id")); + EXPECT_NSEQ(@YES, ExecuteJavaScript(@"resolved")); + EXPECT_NSEQ(@"PasswordCredential", + ExecuteJavaScript(@"resolvedCredential.constructor.name")); + EXPECT_NSEQ(@"bob", ExecuteJavaScript(@"resolvedCredential.id")); EXPECT_NSEQ(@"bobiscool", - EvaluateJavaScriptAsString(@"resolvedCredential.password_")); - EXPECT_NSEQ(@"Bob Boblaw", - EvaluateJavaScriptAsString(@"resolvedCredential.name")); + ExecuteJavaScript(@"resolvedCredential.password_")); + EXPECT_NSEQ(@"Bob Boblaw", ExecuteJavaScript(@"resolvedCredential.name")); EXPECT_NSEQ(@"https://bobboblawslawblog.com/bob.jpg", - EvaluateJavaScriptAsString(@"resolvedCredential.avatarURL")); + ExecuteJavaScript(@"resolvedCredential.avatarURL")); } // Checks that the promise set up by |PrepareResolverAndRejecter| was resolved // without a credential. void CheckResolvedWithoutCredential() { - EXPECT_NSEQ(@"true", EvaluateJavaScriptAsString(@"resolved")); - EXPECT_NSEQ(@"false", EvaluateJavaScriptAsString(@"!!resolvedCredential")); + EXPECT_NSEQ(@YES, ExecuteJavaScript(@"resolved")); + EXPECT_NSEQ(@NO, ExecuteJavaScript(@"!!resolvedCredential")); } // Checks that the promise set up by |PrepareResolverAndRejecter| was rejected // with an error with name |error_name| and |message|. void CheckRejected(NSString* error_name, NSString* message) { - EXPECT_NSEQ(@"true", EvaluateJavaScriptAsString(@"rejected")); - EXPECT_NSEQ(error_name, EvaluateJavaScriptAsString(@"rejectedError.name")); - EXPECT_NSEQ(message, EvaluateJavaScriptAsString(@"rejectedError.message")); + EXPECT_NSEQ(@YES, ExecuteJavaScript(@"rejected")); + EXPECT_NSEQ(error_name, ExecuteJavaScript(@"rejectedError.name")); + EXPECT_NSEQ(message, ExecuteJavaScript(@"rejectedError.message")); } // Waits until the promise set up by |PrepareResolverAndRejecter| has been // either resolved or rejected. void WaitUntilPromiseResolvedOrRejected() { WaitForCondition(^bool { - return [EvaluateJavaScriptAsString(@"resolved || rejected") - isEqualToString:@"true"]; + return [ExecuteJavaScript(@"resolved || rejected") boolValue]; }); } @@ -209,13 +206,13 @@ // Tests that the promise set up by |PrepareResolverAndRejecter| wasn't // rejected. void CheckNeverRejected() { - EXPECT_NSEQ(@"false", EvaluateJavaScriptAsString(@"rejected")); + EXPECT_NSEQ(@NO, ExecuteJavaScript(@"rejected")); } // Tests that the promise set up by |PrepareResolverAndRejecter| wasn't // resolved. void CheckNeverResolved() { - EXPECT_NSEQ(@"false", EvaluateJavaScriptAsString(@"resolved")); + EXPECT_NSEQ(@NO, ExecuteJavaScript(@"resolved")); } // Returns the JSCredentialManager for testing. @@ -270,17 +267,17 @@ TEST_F(CredentialManagerJsTest, RequestIdentifiersDiffer) { Inject(); EXPECT_CALL(observer(), CredentialsRequested(0, _, _, _, _)); - EvaluateJavaScriptAsString(@"navigator.credentials.request()"); + ExecuteJavaScript(@"navigator.credentials.request()"); EXPECT_CALL(observer(), SignInFailed(1, _)); - EvaluateJavaScriptAsString(@"navigator.credentials.notifyFailedSignIn()"); + ExecuteJavaScript(@"navigator.credentials.notifyFailedSignIn()"); EXPECT_CALL(observer(), SignInFailed(2, _)); - EvaluateJavaScriptAsString(@"navigator.credentials.notifyFailedSignIn()"); + ExecuteJavaScript(@"navigator.credentials.notifyFailedSignIn()"); EXPECT_CALL(observer(), SignedIn(3, _)); - EvaluateJavaScriptAsString(@"navigator.credentials.notifySignedIn()"); + ExecuteJavaScript(@"navigator.credentials.notifySignedIn()"); EXPECT_CALL(observer(), SignedOut(4, _)); - EvaluateJavaScriptAsString(@"navigator.credentials.notifySignedOut()"); + ExecuteJavaScript(@"navigator.credentials.notifySignedOut()"); EXPECT_CALL(observer(), CredentialsRequested(5, _, _, _, _)); - EvaluateJavaScriptAsString(@"navigator.credentials.request()"); + ExecuteJavaScript(@"navigator.credentials.request()"); } // Tests that navigator.credentials.request() creates and forwards the right @@ -295,32 +292,30 @@ EXPECT_CALL(observer(), CredentialsRequested(0, _, false, empty_federations, _)); - EvaluateJavaScriptAsString(@"navigator.credentials.request()"); + ExecuteJavaScript(@"navigator.credentials.request()"); EXPECT_CALL(observer(), CredentialsRequested(1, _, false, empty_federations, _)); - EvaluateJavaScriptAsString(@"navigator.credentials.request({})"); + ExecuteJavaScript(@"navigator.credentials.request({})"); EXPECT_CALL(observer(), CredentialsRequested(2, _, true, empty_federations, _)); - EvaluateJavaScriptAsString( - @"navigator.credentials.request({suppressUI: true})"); + ExecuteJavaScript(@"navigator.credentials.request({suppressUI: true})"); EXPECT_CALL(observer(), CredentialsRequested(3, _, false, nonempty_federations, _)); - EvaluateJavaScriptAsString( + ExecuteJavaScript( @"navigator.credentials.request({federations: ['foo', 'bar']})"); EXPECT_CALL(observer(), CredentialsRequested(4, _, true, nonempty_federations, _)); - EvaluateJavaScriptAsString( - @"navigator.credentials.request(" - @" { suppressUI: true, federations: ['foo', 'bar'] })"); + ExecuteJavaScript(@"navigator.credentials.request(" + @" { suppressUI: true, federations: ['foo', 'bar'] })"); EXPECT_CALL(observer(), CredentialsRequested(5, _, false, empty_federations, _)); - EvaluateJavaScriptAsString(@"navigator.credentials.request(" - @" { suppressUI: false, federations: [] })"); + ExecuteJavaScript(@"navigator.credentials.request(" + @" { suppressUI: false, federations: [] })"); } // Tests that navigator.credentials.notifySignedIn() creates and forwards the @@ -328,10 +323,10 @@ TEST_F(CredentialManagerJsTest, NotifySignedInToApp) { Inject(); EXPECT_CALL(observer(), SignedIn(0, _)); - EvaluateJavaScriptAsString(@"navigator.credentials.notifySignedIn()"); + ExecuteJavaScript(@"navigator.credentials.notifySignedIn()"); EXPECT_CALL(observer(), SignedIn(1, _, IsEqualTo(test_credential()))); - EvaluateJavaScriptAsString( + ExecuteJavaScript( [NSString stringWithFormat:@"navigator.credentials.notifySignedIn(%@)", test_credential_js()]); } @@ -341,7 +336,7 @@ TEST_F(CredentialManagerJsTest, NotifySignedOutToApp) { Inject(); EXPECT_CALL(observer(), SignedOut(0, _)); - EvaluateJavaScriptAsString(@"navigator.credentials.notifySignedOut()"); + ExecuteJavaScript(@"navigator.credentials.notifySignedOut()"); } // Tests that navigator.credentials.notifyFailedSignIn() creates and forwards @@ -349,10 +344,10 @@ TEST_F(CredentialManagerJsTest, NotifyFailedSignInToApp) { Inject(); EXPECT_CALL(observer(), SignInFailed(0, _)); - EvaluateJavaScriptAsString(@"navigator.credentials.notifyFailedSignIn()"); + ExecuteJavaScript(@"navigator.credentials.notifyFailedSignIn()"); EXPECT_CALL(observer(), SignInFailed(1, _, IsEqualTo(test_credential()))); - EvaluateJavaScriptAsString([NSString + ExecuteJavaScript([NSString stringWithFormat:@"navigator.credentials.notifyFailedSignIn(%@)", test_credential_js()]); }
diff --git a/ios/chrome/browser/passwords/js_credential_manager.mm b/ios/chrome/browser/passwords/js_credential_manager.mm index abdbd41d..330050f 100644 --- a/ios/chrome/browser/passwords/js_credential_manager.mm +++ b/ios/chrome/browser/passwords/js_credential_manager.mm
@@ -96,8 +96,4 @@ return @"credential_manager"; } -- (NSString*)presenceBeacon { - return @"__gCrWeb.credentialManager"; -} - @end
diff --git a/ios/chrome/browser/passwords/password_controller_js_unittest.mm b/ios/chrome/browser/passwords/password_controller_js_unittest.mm index 966edc5e..5b557d2 100644 --- a/ios/chrome/browser/passwords/password_controller_js_unittest.mm +++ b/ios/chrome/browser/passwords/password_controller_js_unittest.mm
@@ -70,14 +70,14 @@ NSString* const username = @"john.doe@gmail.com"; NSString* const password = @"super!secret"; LoadHtmlAndInject(GAIASignInForm(formAction, username, YES)); - EXPECT_NSEQ(@"true", EvaluateJavaScriptWithFormat( - @"__gCrWeb.fillPasswordForm(%@, '%@', '%@', '%@')", - GAIASignInFormData(formAction), username, password, - formAction)); + EXPECT_NSEQ(@YES, ExecuteJavaScriptWithFormat( + @"__gCrWeb.fillPasswordForm(%@, '%@', '%@', '%@')", + GAIASignInFormData(formAction), username, password, + formAction)); // Verifies that the sign-in form has been filled with username/password. - EvaluateJavaScriptOnElementsAndCheck(@"document.getElementById('%@').value", - @[ kEmailInputID, kPasswordInputID ], - @[ username, password ]); + ExecuteJavaScriptOnElementsAndCheck(@"document.getElementById('%@').value", + @[ kEmailInputID, kPasswordInputID ], + @[ username, password ]); } // Loads a page with a password form containing a username value already. @@ -90,14 +90,14 @@ NSString* const username2 = @"jean.dubois@gmail.com"; NSString* const password = @"super!secret"; LoadHtmlAndInject(GAIASignInForm(formAction, username1, YES)); - EXPECT_NSEQ(@"false", EvaluateJavaScriptWithFormat( - @"__gCrWeb.fillPasswordForm(%@, '%@', '%@', '%@')", - GAIASignInFormData(formAction), username2, password, - formAction)); + EXPECT_NSEQ(@NO, ExecuteJavaScriptWithFormat( + @"__gCrWeb.fillPasswordForm(%@, '%@', '%@', '%@')", + GAIASignInFormData(formAction), username2, password, + formAction)); // Verifies that the sign-in form has not been filled. - EvaluateJavaScriptOnElementsAndCheck(@"document.getElementById('%@').value", - @[ kEmailInputID, kPasswordInputID ], - @[ username1, @"" ]); + ExecuteJavaScriptOnElementsAndCheck(@"document.getElementById('%@').value", + @[ kEmailInputID, kPasswordInputID ], + @[ username1, @"" ]); } // Loads a page with a password form containing a username value already. @@ -110,15 +110,15 @@ NSString* const username2 = @"jane.doe@gmail.com"; NSString* const password = @"super!secret"; LoadHtmlAndInject(GAIASignInForm(formAction, username1, NO)); - EXPECT_NSEQ(@"true", EvaluateJavaScriptWithFormat( - @"__gCrWeb.fillPasswordForm(%@, '%@', '%@', '%@')", - GAIASignInFormData(formAction), username2, password, - formAction)); + EXPECT_NSEQ(@YES, ExecuteJavaScriptWithFormat( + @"__gCrWeb.fillPasswordForm(%@, '%@', '%@', '%@')", + GAIASignInFormData(formAction), username2, password, + formAction)); // Verifies that the sign-in form has been filled with the new username // and password. - EvaluateJavaScriptOnElementsAndCheck(@"document.getElementById('%@').value", - @[ kEmailInputID, kPasswordInputID ], - @[ username2, password ]); + ExecuteJavaScriptOnElementsAndCheck(@"document.getElementById('%@').value", + @[ kEmailInputID, kPasswordInputID ], + @[ username2, password ]); } // Check that when instructed to fill a form named "bar", a form named "foo" @@ -134,8 +134,8 @@ "</html>"); NSString* const formName = @"bar"; NSString* const password = @"abc"; - EXPECT_NSEQ(@"false", - EvaluateJavaScriptWithFormat( + EXPECT_NSEQ(@NO, + ExecuteJavaScriptWithFormat( @"__gCrWeb.fillPasswordFormWithGeneratedPassword('%@', '%@')", formName, password)); } @@ -153,8 +153,8 @@ "</html>"); NSString* const formName = @"foo"; NSString* const password = @"abc"; - EXPECT_NSEQ(@"false", - EvaluateJavaScriptWithFormat( + EXPECT_NSEQ(@NO, + ExecuteJavaScriptWithFormat( @"__gCrWeb.fillPasswordFormWithGeneratedPassword('%@', '%@')", formName, password)); } @@ -175,18 +175,18 @@ "</html>"); NSString* const formName = @"foo"; NSString* const password = @"abc"; - EXPECT_NSEQ(@"true", - EvaluateJavaScriptWithFormat( + EXPECT_NSEQ(@YES, + ExecuteJavaScriptWithFormat( @"__gCrWeb.fillPasswordFormWithGeneratedPassword('%@', '%@')", formName, password)); - EXPECT_NSEQ(@"true", - EvaluateJavaScriptWithFormat( + EXPECT_NSEQ(@YES, + ExecuteJavaScriptWithFormat( @"document.getElementById('ps1').value == '%@'", password)); - EXPECT_NSEQ(@"true", - EvaluateJavaScriptWithFormat( + EXPECT_NSEQ(@YES, + ExecuteJavaScriptWithFormat( @"document.getElementById('ps2').value == '%@'", password)); - EXPECT_NSEQ(@"false", - EvaluateJavaScriptWithFormat( + EXPECT_NSEQ(@NO, + ExecuteJavaScriptWithFormat( @"document.getElementById('user').value == '%@'", password)); } @@ -217,7 +217,7 @@ "\"passwords\":[{\"element\":\"password\",\"value\":\"\"}]}]", base_url.c_str()]; EXPECT_NSEQ(result, - EvaluateJavaScriptWithFormat(@"__gCrWeb.findPasswordForms()")); + ExecuteJavaScriptWithFormat(@"__gCrWeb.findPasswordForms()")); }; // Check that multiple password forms are identified and serialized correctly. @@ -262,7 +262,7 @@ "\"passwords\":[{\"element\":\"password2\",\"value\":\"\"}]}]", base_url.c_str(), base_url.c_str()]; EXPECT_NSEQ(result, - EvaluateJavaScriptWithFormat(@"__gCrWeb.findPasswordForms()")); + ExecuteJavaScriptWithFormat(@"__gCrWeb.findPasswordForms()")); }; // Test serializing of password forms. @@ -293,7 +293,7 @@ base_url.c_str()]; EXPECT_NSEQ( result, - EvaluateJavaScriptWithFormat( + ExecuteJavaScriptWithFormat( @"__gCrWeb.stringify(__gCrWeb.getPasswordFormData(%@))", parameter)); };
diff --git a/ios/chrome/browser/passwords/password_controller_unittest.mm b/ios/chrome/browser/passwords/password_controller_unittest.mm index 56148f2..8d3e4ac 100644 --- a/ios/chrome/browser/passwords/password_controller_unittest.mm +++ b/ios/chrome/browser/passwords/password_controller_unittest.mm
@@ -194,7 +194,7 @@ NSString* kFormNamingScript = @"__gCrWeb.common.getFormIdentifier(" " document.querySelectorAll('form')[%d]);"; - return base::SysNSStringToUTF8(EvaluateJavaScriptAsString( + return base::SysNSStringToUTF8(ExecuteJavaScript( [NSString stringWithFormat:kFormNamingScript, form_number])); } @@ -649,7 +649,7 @@ << " and number_of_forms_to_submit=" << data.number_of_forms_to_submit); LoadHtml(data.html_string); - EvaluateJavaScriptAsString(data.java_script); + ExecuteJavaScript(data.java_script); __block BOOL block_was_called = NO; id completion_handler = ^(BOOL found, const PasswordForm& form) { block_was_called = YES; @@ -767,8 +767,7 @@ TEST_F(PasswordControllerTest, FillPasswordForm) { LoadHtml(kHtmlWithMultiplePasswordForms); - EXPECT_NSEQ(@"true", - EvaluateJavaScriptAsString(@"__gCrWeb.hasPasswordField()")); + EXPECT_NSEQ(@YES, ExecuteJavaScript(@"__gCrWeb.hasPasswordField()")); const std::string base_url = BaseUrl(); // clang-format off @@ -866,7 +865,7 @@ // clang-format on for (const FillPasswordFormTestData& data : test_data) { - EvaluateJavaScriptAsString(kClearInputFieldsScript); + ExecuteJavaScript(kClearInputFieldsScript); PasswordFormFillData form_data; SetPasswordFormFillData(form_data, data.origin, data.action, @@ -884,8 +883,7 @@ return block_was_called; }); - NSString* result = - EvaluateJavaScriptAsString(kInputFieldValueVerificationScript); + id result = ExecuteJavaScript(kInputFieldValueVerificationScript); EXPECT_NSEQ(data.expected_result, result); } } @@ -908,8 +906,7 @@ return call_counter == 1; }); EXPECT_EQ(1, success_counter); - NSString* result = - EvaluateJavaScriptAsString(kInputFieldValueVerificationScript); + id result = ExecuteJavaScript(kInputFieldValueVerificationScript); EXPECT_NSEQ(@"un=john.doe@gmail.com;pw=super!secret;", result); } @@ -941,8 +938,7 @@ return call_counter == 3; }); EXPECT_EQ(2, success_counter); - NSString* result = - EvaluateJavaScriptAsString(kInputFieldValueVerificationScript); + id result = ExecuteJavaScript(kInputFieldValueVerificationScript); EXPECT_NSEQ(@"u2=john.doe@gmail.com;p2=super!secret;" "u3=john.doe@gmail.com;p3=super!secret;", result); @@ -950,8 +946,7 @@ BOOL PasswordControllerTest::BasicFormFill(NSString* html) { LoadHtml(html); - EXPECT_NSEQ(@"true", - EvaluateJavaScriptAsString(@"__gCrWeb.hasPasswordField()")); + EXPECT_NSEQ(@YES, ExecuteJavaScript(@"__gCrWeb.hasPasswordField()")); const std::string base_url = BaseUrl(); PasswordFormFillData form_data; SetPasswordFormFillData(form_data, base_url, base_url, "u0", "test_user", @@ -1037,7 +1032,7 @@ TEST_F(PasswordControllerTest, SuggestionUpdateTests) { LoadHtml(kHtmlWithPasswordForm); const std::string base_url = BaseUrl(); - EvaluateJavaScriptAsString(kUsernameAndPasswordTestPreparationScript); + ExecuteJavaScript(kUsernameAndPasswordTestPreparationScript); // Initialize |form_data| with test data and an indicator that autofill // should not be performed while the user is entering the username so that @@ -1061,7 +1056,7 @@ // Verify that the form has not been autofilled. EXPECT_NSEQ(@"[]=, onkeyup=false, onchange=false", - EvaluateJavaScriptAsString(kUsernamePasswordVerificationScript)); + ExecuteJavaScript(kUsernamePasswordVerificationScript)); // clang-format off SuggestionTestData test_data[] = { @@ -1134,19 +1129,19 @@ << "for description=" << data.description << " and eval_scripts=" << data.eval_scripts); // Prepare the test. - EvaluateJavaScriptAsString(kUsernameAndPasswordTestPreparationScript); + ExecuteJavaScript(kUsernameAndPasswordTestPreparationScript); for (NSString* script in data.eval_scripts) { // Trigger events. - EvaluateJavaScriptAsString(script); + ExecuteJavaScript(script); // Pump the run loop so that the host can respond. WaitForBackgroundTasks(); } EXPECT_NSEQ(data.expected_suggestions, GetSortedSuggestionValues()); - EXPECT_NSEQ(data.expected_result, EvaluateJavaScriptAsString( - kUsernamePasswordVerificationScript)); + EXPECT_NSEQ(data.expected_result, + ExecuteJavaScript(kUsernamePasswordVerificationScript)); // Clear all suggestions. [suggestionController_ setSuggestions:nil]; } @@ -1156,7 +1151,7 @@ TEST_F(PasswordControllerTest, SelectingSuggestionShouldFillPasswordForm) { LoadHtml(kHtmlWithPasswordForm); const std::string base_url = BaseUrl(); - EvaluateJavaScriptAsString(kUsernameAndPasswordTestPreparationScript); + ExecuteJavaScript(kUsernameAndPasswordTestPreparationScript); // Initialize |form_data| with test data and an indicator that autofill // should not be performed while the user is entering the username so that @@ -1179,7 +1174,7 @@ // Verify that the form has not been autofilled. EXPECT_NSEQ(@"[]=, onkeyup=false, onchange=false", - EvaluateJavaScriptAsString(kUsernamePasswordVerificationScript)); + ExecuteJavaScript(kUsernamePasswordVerificationScript)); // Tell PasswordController that a suggestion was selected. It should fill // out the password form with the corresponding credentials.
diff --git a/ios/chrome/browser/physical_web/create_physical_web_data_source.h b/ios/chrome/browser/physical_web/create_physical_web_data_source.h new file mode 100644 index 0000000..098a853 --- /dev/null +++ b/ios/chrome/browser/physical_web/create_physical_web_data_source.h
@@ -0,0 +1,16 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_PHYSICAL_WEB_CREATE_PHYSICAL_WEB_DATA_SOURCE_H_ +#define IOS_CHROME_BROWSER_PHYSICAL_WEB_CREATE_PHYSICAL_WEB_DATA_SOURCE_H_ + +#include <memory> + +class PhysicalWebDataSource; + +// Creates a new instance of IOSChromePhysicalWebDataSource. The returned object +// is fully initialized and can be registered as global singleton. +std::unique_ptr<PhysicalWebDataSource> CreateIOSChromePhysicalWebDataSource(); + +#endif // IOS_CHROME_BROWSER_PHYSICAL_WEB_CREATE_PHYSICAL_WEB_DATA_SOURCE_H_
diff --git a/ios/chrome/browser/physical_web/create_physical_web_data_source.mm b/ios/chrome/browser/physical_web/create_physical_web_data_source.mm new file mode 100644 index 0000000..055952a --- /dev/null +++ b/ios/chrome/browser/physical_web/create_physical_web_data_source.mm
@@ -0,0 +1,12 @@ +// 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 "ios/chrome/browser/physical_web/create_physical_web_data_source.h" + +#include "base/memory/ptr_util.h" +#import "ios/chrome/common/physical_web/ios_chrome_physical_web_data_source.h" + +std::unique_ptr<PhysicalWebDataSource> CreateIOSChromePhysicalWebDataSource() { + return base::MakeUnique<IOSChromePhysicalWebDataSource>(); +}
diff --git a/ios/chrome/browser/pref_names.cc b/ios/chrome/browser/pref_names.cc index a440c26..fea3b7a 100644 --- a/ios/chrome/browser/pref_names.cc +++ b/ios/chrome/browser/pref_names.cc
@@ -80,10 +80,6 @@ const char kLastSessionExitedCleanly[] = "ios.user_experience_metrics.last_session_exited_cleanly"; -// True if the previous session was selected into the WKWebView control group. -const char kLastSessionUsedWKWebViewControlGroup[] = - "ios.wkwebview_trial.was_control"; - // Preference that hold a boolean indicating whether metrics reporting should // be limited to wifi (when enabled). const char kMetricsReportingWifiOnly[] =
diff --git a/ios/chrome/browser/pref_names.h b/ios/chrome/browser/pref_names.h index 7613854..6161bd1 100644 --- a/ios/chrome/browser/pref_names.h +++ b/ios/chrome/browser/pref_names.h
@@ -25,7 +25,6 @@ extern const char kIosHandoffToOtherDevices[]; extern const char kIosPhysicalWebEnabled[]; extern const char kLastSessionExitedCleanly[]; -extern const char kLastSessionUsedWKWebViewControlGroup[]; extern const char kMetricsReportingWifiOnly[]; extern const char kNtpShownPage[]; extern const char kSavingBrowserHistoryDisabled[];
diff --git a/ios/chrome/browser/reading_list/reading_list_model_bridge_observer.h b/ios/chrome/browser/reading_list/reading_list_model_bridge_observer.h new file mode 100644 index 0000000..23a4945a --- /dev/null +++ b/ios/chrome/browser/reading_list/reading_list_model_bridge_observer.h
@@ -0,0 +1,85 @@ + +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_INTERNAL_CHROME_BROWSER_UI_READING_LIST_READING_LIST_MODEL_BRIDGE_OBSERVER_H_ +#define IOS_INTERNAL_CHROME_BROWSER_UI_READING_LIST_READING_LIST_MODEL_BRIDGE_OBSERVER_H_ + +#import <Foundation/Foundation.h> + +#include "base/macros.h" +#include "ios/chrome/browser/reading_list/reading_list_model_observer.h" + +// Protocol duplicating all Reading List Model Observer methods in Objective-C. +@protocol ReadingListModelBridgeObserver<NSObject> + +@required +- (void)readingListModelLoaded:(const ReadingListModel*)model; +- (void)readingListModelDidApplyChanges:(const ReadingListModel*)model; + +@optional +- (void)readingListModel:(const ReadingListModel*)model + willRemoveUnreadEntryAtIndex:(size_t)index; +- (void)readingListModel:(const ReadingListModel*)model + willRemoveReadEntryAtIndex:(size_t)index; + +- (void)readingListModel:(const ReadingListModel*)model + willMoveEntry:(size_t)unreadIndex; + +- (void)readingListModel:(const ReadingListModel*)model + willAddUnreadEntry:(const ReadingListEntry&)entry; +- (void)readingListModel:(const ReadingListModel*)model + willAddReadEntry:(const ReadingListEntry&)entry; + +- (void)readingListModelBeganBatchUpdates:(const ReadingListModel*)model; +- (void)readingListModelCompletedBatchUpdates:(const ReadingListModel*)model; + +- (void)readingListModelBeingDeleted:(const ReadingListModel*)model; + +- (void)readingListModel:(const ReadingListModel*)model + willUpdateUnreadEntryAtIndex:(size_t)index; +- (void)readingListModel:(const ReadingListModel*)model + willUpdateReadEntryAtIndex:(size_t)index; + +@end + +// Observer for the Reading List model that translates all the callbacks to +// Objective-C calls. +class ReadingListModelBridge : public ReadingListModelObserver { + public: + explicit ReadingListModelBridge(id<ReadingListModelBridgeObserver> observer, + ReadingListModel* model); + ~ReadingListModelBridge() override; + + private: + void ReadingListModelBeganBatchUpdates( + const ReadingListModel* model) override; + + void ReadingListModelCompletedBatchUpdates( + const ReadingListModel* model) override; + void ReadingListModelLoaded(const ReadingListModel* model) override; + void ReadingListModelBeingDeleted(const ReadingListModel* model) override; + void ReadingListWillRemoveUnreadEntry(const ReadingListModel* model, + size_t index) override; + void ReadingListWillRemoveReadEntry(const ReadingListModel* model, + size_t index) override; + void ReadingListWillMoveEntry(const ReadingListModel* model, + size_t index) override; + void ReadingListWillAddUnreadEntry(const ReadingListModel* model, + const ReadingListEntry& entry) override; + void ReadingListWillAddReadEntry(const ReadingListModel* model, + const ReadingListEntry& entry) override; + void ReadingListDidApplyChanges(ReadingListModel* model) override; + void ReadingListWillUpdateUnreadEntry(const ReadingListModel* model, + size_t index) override; + void ReadingListWillUpdateReadEntry(const ReadingListModel* model, + size_t index) override; + + __unsafe_unretained id<ReadingListModelBridgeObserver> observer_; + ReadingListModel* model_; // weak + + DISALLOW_COPY_AND_ASSIGN(ReadingListModelBridge); +}; + +#endif // IOS_INTERNAL_CHROME_BROWSER_UI_READING_LIST_READING_LIST_MODEL_BRIDGE_OBSERVER_H_
diff --git a/ios/chrome/browser/reading_list/reading_list_model_bridge_observer.mm b/ios/chrome/browser/reading_list/reading_list_model_bridge_observer.mm new file mode 100644 index 0000000..4bca226 --- /dev/null +++ b/ios/chrome/browser/reading_list/reading_list_model_bridge_observer.mm
@@ -0,0 +1,118 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/reading_list/reading_list_model_bridge_observer.h" + +#import "ios/chrome/browser/reading_list/reading_list_entry.h" +#import "ios/chrome/browser/reading_list/reading_list_model.h" + +ReadingListModelBridge::ReadingListModelBridge( + id<ReadingListModelBridgeObserver> observer, + ReadingListModel* model) + : observer_(observer), model_(model) { + DCHECK(model); + model_->AddObserver(this); +} + +ReadingListModelBridge::~ReadingListModelBridge() { + DCHECK(model_); + model_->RemoveObserver(this); +} + +void ReadingListModelBridge::ReadingListModelLoaded( + const ReadingListModel* model) { + [observer_ readingListModelLoaded:model]; +} + +void ReadingListModelBridge::ReadingListModelBeingDeleted( + const ReadingListModel* model) { + if ([observer_ respondsToSelector:@selector(readingListModelBeingDeleted:)]) { + [observer_ readingListModelBeingDeleted:model]; + } +} + +void ReadingListModelBridge::ReadingListWillRemoveUnreadEntry( + const ReadingListModel* model, + size_t index) { + if ([observer_ respondsToSelector:@selector(readingListModel: + willRemoveUnreadEntryAtIndex:)]) { + [observer_ readingListModel:model willRemoveUnreadEntryAtIndex:index]; + } +} + +void ReadingListModelBridge::ReadingListWillRemoveReadEntry( + const ReadingListModel* model, + size_t index) { + if ([observer_ respondsToSelector:@selector(readingListModel: + willRemoveReadEntryAtIndex:)]) { + [observer_ readingListModel:model willRemoveReadEntryAtIndex:index]; + } +} + +void ReadingListModelBridge::ReadingListWillAddReadEntry( + const ReadingListModel* model, + const ReadingListEntry& entry) { + if ([observer_ + respondsToSelector:@selector(readingListModel:willAddReadEntry:)]) { + [observer_ readingListModel:model willAddReadEntry:entry]; + } +} + +void ReadingListModelBridge::ReadingListWillAddUnreadEntry( + const ReadingListModel* model, + const ReadingListEntry& entry) { + if ([observer_ + respondsToSelector:@selector(readingListModel:willAddUnreadEntry:)]) { + [observer_ readingListModel:model willAddUnreadEntry:entry]; + } +} + +void ReadingListModelBridge::ReadingListDidApplyChanges( + ReadingListModel* model) { + [observer_ readingListModelDidApplyChanges:model]; +} + +void ReadingListModelBridge::ReadingListModelBeganBatchUpdates( + const ReadingListModel* model) { + if ([observer_ + respondsToSelector:@selector(readingListModelBeganBatchUpdates:)]) { + [observer_ readingListModelBeganBatchUpdates:model]; + } +} + +void ReadingListModelBridge::ReadingListModelCompletedBatchUpdates( + const ReadingListModel* model) { + if ([observer_ + respondsToSelector:@selector( + readingListModelCompletedBatchUpdates:)]) { + [observer_ readingListModelCompletedBatchUpdates:model]; + } +} + +void ReadingListModelBridge::ReadingListWillMoveEntry( + const ReadingListModel* model, + size_t index) { + if ([observer_ + respondsToSelector:@selector(readingListModel:willMoveEntry:)]) { + [observer_ readingListModel:model willMoveEntry:index]; + } +} + +void ReadingListModelBridge::ReadingListWillUpdateUnreadEntry( + const ReadingListModel* model, + size_t index) { + if ([observer_ respondsToSelector:@selector(readingListModel: + willRemoveUnreadEntryAtIndex:)]) { + [observer_ readingListModel:model willUpdateUnreadEntryAtIndex:index]; + } +} + +void ReadingListModelBridge::ReadingListWillUpdateReadEntry( + const ReadingListModel* model, + size_t index) { + if ([observer_ respondsToSelector:@selector(readingListModel: + willRemoveReadEntryAtIndex:)]) { + [observer_ readingListModel:model willUpdateReadEntryAtIndex:index]; + } +}
diff --git a/ios/chrome/browser/ssl/ios_chrome_security_state_model_client.mm b/ios/chrome/browser/ssl/ios_chrome_security_state_model_client.mm index 0e93841b..8098575 100644 --- a/ios/chrome/browser/ssl/ios_chrome_security_state_model_client.mm +++ b/ios/chrome/browser/ssl/ios_chrome_security_state_model_client.mm
@@ -89,7 +89,7 @@ return; } - state->initialized = true; + state->connection_info_initialized = true; state->url = item->GetURL(); const web::SSLStatus& ssl = item->GetSSL(); state->initial_security_level =
diff --git a/ios/chrome/common/BUILD.gn b/ios/chrome/common/BUILD.gn index 126dea6..688f7fd2 100644 --- a/ios/chrome/common/BUILD.gn +++ b/ios/chrome/common/BUILD.gn
@@ -16,6 +16,7 @@ "//base", "//components/version_info", "//ios/chrome/common/app_group:main_app", + "//ios/chrome/common/physical_web:physical_web", ] libs = [
diff --git a/ios/chrome/common/DEPS b/ios/chrome/common/DEPS index 857ff62..2a9c66d 100644 --- a/ios/chrome/common/DEPS +++ b/ios/chrome/common/DEPS
@@ -1,3 +1,4 @@ include_rules = [ + "+components/physical_web/data_source", "+components/version_info", ]
diff --git a/ios/chrome/common/physical_web/BUILD.gn b/ios/chrome/common/physical_web/BUILD.gn index 52cec63..f56f06b2 100644 --- a/ios/chrome/common/physical_web/BUILD.gn +++ b/ios/chrome/common/physical_web/BUILD.gn
@@ -4,6 +4,8 @@ source_set("physical_web") { sources = [ + "ios_chrome_physical_web_data_source.h", + "ios_chrome_physical_web_data_source.mm", "physical_web_device.h", "physical_web_device.mm", "physical_web_request.h", @@ -16,6 +18,7 @@ deps = [ "//base", + "//components/physical_web/data_source", "//components/version_info", "//device/bluetooth/uribeacon", "//google_apis",
diff --git a/ios/chrome/common/physical_web/ios_chrome_physical_web_data_source.h b/ios/chrome/common/physical_web/ios_chrome_physical_web_data_source.h new file mode 100644 index 0000000..2960830 --- /dev/null +++ b/ios/chrome/common/physical_web/ios_chrome_physical_web_data_source.h
@@ -0,0 +1,46 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_COMMON_PHYSICAL_WEB_IOS_CHROME_PHYSICAL_WEB_DATA_SOURCE_H_ +#define IOS_CHROME_COMMON_PHYSICAL_WEB_IOS_CHROME_PHYSICAL_WEB_DATA_SOURCE_H_ + +#include "base/macros.h" +#import "base/mac/scoped_nsobject.h" +#include "components/physical_web/data_source/physical_web_data_source.h" + +namespace base { +class ListValue; +} + +@class PhysicalWebScanner; + +// iOS implementation of PhysicalWebDataSource +class IOSChromePhysicalWebDataSource : public PhysicalWebDataSource { + public: + IOSChromePhysicalWebDataSource(); + ~IOSChromePhysicalWebDataSource() override; + + // Starts scanning for Physical Web URLs. If |network_request_enabled| is + // true, discovered URLs will be sent to a resolution service. + void StartDiscovery(bool network_request_enabled) override; + + // Stops scanning for Physical Web URLs and clears cached URL content. + void StopDiscovery() override; + + // Returns a list of resolved URLs and associated page metadata. If network + // requests are disabled, the list will be empty. + std::unique_ptr<base::ListValue> GetMetadata() override; + + // Returns boolean |true| if network requests are disabled and there are one + // or more discovered URLs that have not been sent to the resolution service. + bool HasUnresolvedDiscoveries() override; + + private: + // Scanner for nearby Physical Web URL devices. + base::scoped_nsobject<PhysicalWebScanner> scanner_; + + DISALLOW_COPY_AND_ASSIGN(IOSChromePhysicalWebDataSource); +}; + +#endif // IOS_CHROME_COMMON_PHYSICAL_WEB_IOS_CHROME_PHYSICAL_WEB_DATA_SOURCE_H_
diff --git a/ios/chrome/common/physical_web/ios_chrome_physical_web_data_source.mm b/ios/chrome/common/physical_web/ios_chrome_physical_web_data_source.mm new file mode 100644 index 0000000..d2762f2 --- /dev/null +++ b/ios/chrome/common/physical_web/ios_chrome_physical_web_data_source.mm
@@ -0,0 +1,47 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/common/physical_web/ios_chrome_physical_web_data_source.h" + +#include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "base/values.h" +#import "ios/chrome/common/physical_web/physical_web_scanner.h" + +IOSChromePhysicalWebDataSource::IOSChromePhysicalWebDataSource() {} + +IOSChromePhysicalWebDataSource::~IOSChromePhysicalWebDataSource() { + StopDiscovery(); +} + +void IOSChromePhysicalWebDataSource::StartDiscovery( + bool network_request_enabled) { + // If there are unresolved beacons it means the scanner is started but does + // not have network requests enabled. In this case we should avoid recreating + // the scanner as it would clear the cache of nearby beacons. + if (network_request_enabled && HasUnresolvedDiscoveries()) { + [scanner_ setNetworkRequestEnabled:YES]; + return; + } + + [scanner_ stop]; + scanner_.reset([[PhysicalWebScanner alloc] initWithDelegate:nil]); + [scanner_ setNetworkRequestEnabled:network_request_enabled]; + [scanner_ start]; +} + +void IOSChromePhysicalWebDataSource::StopDiscovery() { + [scanner_ stop]; + scanner_.reset(); +} + +std::unique_ptr<base::ListValue> IOSChromePhysicalWebDataSource::GetMetadata() { + std::unique_ptr<base::ListValue> metadata = [scanner_ metadata]; + DCHECK(metadata); + return metadata; +} + +bool IOSChromePhysicalWebDataSource::HasUnresolvedDiscoveries() { + return [scanner_ unresolvedBeaconsCount] > 0; +}
diff --git a/ios/chrome/common/physical_web/physical_web.gyp b/ios/chrome/common/physical_web/physical_web.gyp index 887c0af7..4b0342b69 100644 --- a/ios/chrome/common/physical_web/physical_web.gyp +++ b/ios/chrome/common/physical_web/physical_web.gyp
@@ -9,6 +9,8 @@ 'target_name': 'physical_web', 'type': 'static_library', 'sources': [ + 'ios_chrome_physical_web_data_source.h', + 'ios_chrome_physical_web_data_source.mm', 'physical_web_device.h', 'physical_web_device.mm', 'physical_web_request.h', @@ -20,6 +22,7 @@ ], 'dependencies': [ '../../../../base/base.gyp:base', + '../../../../components/components.gyp:physical_web_data_source', '../../../../components/components.gyp:version_info', '../../../../device/bluetooth/bluetooth.gyp:uribeacon', '../../../../google_apis/google_apis.gyp:google_apis',
diff --git a/ios/chrome/common/physical_web/physical_web_scanner.h b/ios/chrome/common/physical_web/physical_web_scanner.h index 8f28f90c..c147bc29 100644 --- a/ios/chrome/common/physical_web/physical_web_scanner.h +++ b/ios/chrome/common/physical_web/physical_web_scanner.h
@@ -7,7 +7,11 @@ #import <Foundation/Foundation.h> -@class PhysicalWebDevice; +#include <memory> + +namespace base { +class ListValue; +} @protocol PhysicalWebScannerDelegate; @@ -43,6 +47,11 @@ // Returns a list of physical web devices (PhysicalWebDevice). - (NSArray*)devices; +// Returns the metadata for all resolved physical web URLs. The returned value +// will never be nil; if no metadata has been received then an empty list is +// returned. +- (std::unique_ptr<base::ListValue>)metadata; + @end @protocol PhysicalWebScannerDelegate<NSObject>
diff --git a/ios/chrome/common/physical_web/physical_web_scanner.mm b/ios/chrome/common/physical_web/physical_web_scanner.mm index 2457f225..02c5d0c0 100644 --- a/ios/chrome/common/physical_web/physical_web_scanner.mm +++ b/ios/chrome/common/physical_web/physical_web_scanner.mm
@@ -4,20 +4,21 @@ #import "ios/chrome/common/physical_web/physical_web_scanner.h" +#import <CoreBluetooth/CoreBluetooth.h> + #include <string> #include <vector> -#import <CoreBluetooth/CoreBluetooth.h> - -#include "base/ios/weak_nsobject.h" +#import "base/ios/weak_nsobject.h" #include "base/logging.h" -#include "base/mac/scoped_nsobject.h" -#include "base/macros.h" +#import "base/mac/scoped_nsobject.h" +#include "base/memory/ptr_util.h" #include "base/strings/sys_string_conversions.h" +#include "base/values.h" #include "device/bluetooth/uribeacon/uri_encoder.h" -#include "ios/chrome/common/physical_web/physical_web_device.h" +#import "ios/chrome/common/physical_web/physical_web_device.h" #import "ios/chrome/common/physical_web/physical_web_request.h" -#include "ios/chrome/common/physical_web/physical_web_types.h" +#import "ios/chrome/common/physical_web/physical_web_types.h" namespace { @@ -149,6 +150,30 @@ }]; } +- (std::unique_ptr<base::ListValue>)metadata { + auto metadataList = base::MakeUnique<base::ListValue>(); + + for (PhysicalWebDevice* device in [self devices]) { + std::string scannedUrl = + base::SysNSStringToUTF8([[device requestURL] absoluteString]); + std::string resolvedUrl = + base::SysNSStringToUTF8([[device url] absoluteString]); + std::string icon = base::SysNSStringToUTF8([[device icon] absoluteString]); + std::string title = base::SysNSStringToUTF8([device title]); + std::string description = base::SysNSStringToUTF8([device description]); + + auto metadataItem = base::MakeUnique<base::DictionaryValue>(); + metadataItem->SetString("scannedUrl", scannedUrl); + metadataItem->SetString("resolvedUrl", resolvedUrl); + metadataItem->SetString("icon", icon); + metadataItem->SetString("title", title); + metadataItem->SetString("description", description); + metadataList->Append(std::move(metadataItem)); + } + + return metadataList; +} + - (void)setNetworkRequestEnabled:(BOOL)enabled { if (networkRequestEnabled_ == enabled) { return; @@ -294,7 +319,13 @@ std::string utf8URI; device::DecodeUriBeaconUri(encodedURI, utf8URI); NSString* uriString = base::SysUTF8ToNSString(utf8URI); - return [[PhysicalWebDevice alloc] initWithURL:[NSURL URLWithString:uriString] + NSURL* url = [NSURL URLWithString:uriString]; + + // Ensure URL is valid. + if (!url) + return nil; + + return [[PhysicalWebDevice alloc] initWithURL:url requestURL:nil icon:nil title:nil
diff --git a/ios/chrome/ios_chrome.gyp b/ios/chrome/ios_chrome.gyp index 2230263..0f738c73 100644 --- a/ios/chrome/ios_chrome.gyp +++ b/ios/chrome/ios_chrome.gyp
@@ -89,6 +89,7 @@ '../../components/components.gyp:open_from_clipboard', '../../components/components.gyp:password_manager_core_browser', '../../components/components.gyp:password_manager_sync_browser', + '../../components/components.gyp:physical_web_data_source', '../../components/components.gyp:pref_registry', '../../components/components.gyp:profile_metrics', '../../components/components.gyp:proxy_config', @@ -453,6 +454,8 @@ 'browser/passwords/passwords_ui_delegate.h', 'browser/passwords/update_password_infobar_controller.h', 'browser/passwords/update_password_infobar_controller.mm', + 'browser/physical_web/create_physical_web_data_source.h', + 'browser/physical_web/create_physical_web_data_source.mm', 'browser/physical_web/physical_web_constants.h', 'browser/pref_names.cc', 'browser/pref_names.h', @@ -791,6 +794,7 @@ '../../base/base.gyp:base', '../../components/components.gyp:version_info', 'app_group_mainapp', + 'common/physical_web/physical_web.gyp:physical_web', ], 'link_settings': { 'libraries': [
diff --git a/ios/chrome/test/testing_application_context.h b/ios/chrome/test/testing_application_context.h index 35421b5..53909da 100644 --- a/ios/chrome/test/testing_application_context.h +++ b/ios/chrome/test/testing_application_context.h
@@ -49,6 +49,7 @@ component_updater::ComponentUpdateService* GetComponentUpdateService() override; CRLSetFetcher* GetCRLSetFetcher() override; + PhysicalWebDataSource* GetPhysicalWebDataSource() override; private: base::ThreadChecker thread_checker_;
diff --git a/ios/chrome/test/testing_application_context.mm b/ios/chrome/test/testing_application_context.mm index 75251b2..e03bd89 100644 --- a/ios/chrome/test/testing_application_context.mm +++ b/ios/chrome/test/testing_application_context.mm
@@ -154,3 +154,8 @@ DCHECK(thread_checker_.CalledOnValidThread()); return nullptr; } + +PhysicalWebDataSource* TestingApplicationContext::GetPhysicalWebDataSource() { + DCHECK(thread_checker_.CalledOnValidThread()); + return nullptr; +}
diff --git a/ios/net/protocol_handler_util.mm b/ios/net/protocol_handler_util.mm index 7199add..0609d31 100644 --- a/ios/net/protocol_handler_util.mm +++ b/ios/net/protocol_handler_util.mm
@@ -7,7 +7,7 @@ #include <string> #include "base/base64.h" -#include "base/i18n/icu_encoding_detection.h" +#include "base/i18n/encoding_detection.h" #include "base/i18n/icu_string_conversions.h" #include "base/logging.h" #include "base/mac/scoped_nsobject.h"
diff --git a/ios/public/provider/web/web_controller_provider.h b/ios/public/provider/web/web_controller_provider.h index 1fe9aef..d11dca7 100644 --- a/ios/public/provider/web/web_controller_provider.h +++ b/ios/public/provider/web/web_controller_provider.h
@@ -50,8 +50,15 @@ // Injects |script| into the previously loaded page, if any, and calls // |completion| with the result. Calls |completion| with nil parameters // when there is no previously loaded page. + // DEPRECATED. TODO(crbug.com/595761): Remove this API. virtual void InjectScript(const std::string& script, web::JavaScriptCompletion completion); + + // Injects |script| into the previously loaded page, if any, and calls + // |completion| with the result. Calls |completion| with nil parameters + // when there is no previously loaded page. + virtual void InjectScript(const std::string& script, + web::JavaScriptResultBlock completion); }; class WebControllerProviderFactory {
diff --git a/ios/public/provider/web/web_controller_provider.mm b/ios/public/provider/web/web_controller_provider.mm index 70fde984..34eab70 100644 --- a/ios/public/provider/web/web_controller_provider.mm +++ b/ios/public/provider/web/web_controller_provider.mm
@@ -37,6 +37,13 @@ completion(nil, nil); } +void WebControllerProvider::InjectScript( + const std::string& script, + web::JavaScriptResultBlock completion) { + if (completion) + completion(nil, nil); +} + WebControllerProviderFactory::WebControllerProviderFactory() { }
diff --git a/ios/testing/earl_grey/BUILD.gn b/ios/testing/earl_grey/BUILD.gn index a8e6ecf..9a21bf0d1 100644 --- a/ios/testing/earl_grey/BUILD.gn +++ b/ios/testing/earl_grey/BUILD.gn
@@ -16,6 +16,7 @@ ] sources = [ + "disabled_test_macros.h", "wait_util.h", "wait_util.mm", ]
diff --git a/ios/testing/earl_grey/disabled_test_macros.h b/ios/testing/earl_grey/disabled_test_macros.h new file mode 100644 index 0000000..5adb429 --- /dev/null +++ b/ios/testing/earl_grey/disabled_test_macros.h
@@ -0,0 +1,39 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_TESTING_EARL_GREY_DISABLED_TEST_MACROS_H_ +#define IOS_TESTING_EARL_GREY_DISABLED_TEST_MACROS_H_ + +// A macro that forces an Earl Grey test to pass. It should be used to disable +// tests that fail due to a bug. This macro should be used when the +// configuration for which the test should be disabled can only be determined +// at runtime. Disabling at compile-time is always preferred. +// Example: +// - (void)testFoo +// if (base::ios::IsRunningOnIOS10OrLater()) { +// EARL_GREY_TEST_DISABLED(@"Disabled on iOS 10."); +// } +#define EARL_GREY_TEST_DISABLED(message) \ + while (true) { \ + NSLog(@"-- Earl Grey Test Disabled -- %@", message); \ + return; \ + } + +// A macro that forces an Earl Grey test to pass. This should be used when a +// test fails for a specific configuration because it is not supported, but +// there is no error. This macro should only be used when the configuration for +// which the test should be disabled can only be determined at runtime. +// Disabling at compile-time is always preferred. +// Example: +// - (void)testFoo +// if (base::ios::IsRunningOnIOS10OrLater()) { +// EARL_GREY_TEST_SKIPPED(@"Test not supported on iOS 10."); +// } +#define EARL_GREY_TEST_SKIPPED(message) \ + while (true) { \ + NSLog(@"-- Earl Grey Test Skipped -- %@", message); \ + return; \ + } + +#endif // IOS_TESTING_EARL_GREY_DISABLED_TEST_MACROS_H_
diff --git a/ios/testing/earl_grey/earl_grey_support.gyp b/ios/testing/earl_grey/earl_grey_support.gyp index 96c72ebf..8be3c74d4 100644 --- a/ios/testing/earl_grey/earl_grey_support.gyp +++ b/ios/testing/earl_grey/earl_grey_support.gyp
@@ -14,6 +14,7 @@ '<(DEPTH)/ios/third_party/earl_grey/earl_grey.gyp:EarlGrey', ], 'sources': [ + 'disabled_test_macros.h', 'wait_util.h', 'wait_util.mm', ],
diff --git a/ios/third_party/earl_grey/BUILD.gn b/ios/third_party/earl_grey/BUILD.gn index 1c515ef6..277f5f5 100644 --- a/ios/third_party/earl_grey/BUILD.gn +++ b/ios/third_party/earl_grey/BUILD.gn
@@ -233,6 +233,7 @@ "src/EarlGrey/Synchronization/GREYUIThreadExecutor.h", ] deps = [ + "//build/config/ios:xctest", "//ios/third_party/fishhook", "//third_party/google_toolbox_for_mac", ] @@ -251,12 +252,11 @@ "XCTest.framework", ] - public_configs = [ - ":config", - "//build/config/ios:xctest_config", - ] + public_configs = [ ":config" ] - configs += [ "//build/config/compiler:enable_arc" ] configs -= [ "//build/config/gcc:symbol_visibility_hidden" ] - configs += [ "//build/config/gcc:symbol_visibility_default" ] + configs += [ + "//build/config/compiler:enable_arc", + "//build/config/gcc:symbol_visibility_default", + ] }
diff --git a/ios/web/public/test/crw_test_js_injection_receiver.mm b/ios/web/public/test/crw_test_js_injection_receiver.mm index cbcdc55..27c7f358 100644 --- a/ios/web/public/test/crw_test_js_injection_receiver.mm +++ b/ios/web/public/test/crw_test_js_injection_receiver.mm
@@ -40,9 +40,8 @@ web::ExecuteJavaScript(_webView, script, completionHandler); } -- (BOOL)scriptHasBeenInjectedForClass:(Class)JSInjectionManagerClass - presenceBeacon:(NSString*)beacon { - return [_injectedScriptManagers containsObject:JSInjectionManagerClass]; +- (BOOL)scriptHasBeenInjectedForClass:(Class)injectionManagerClass { + return [_injectedScriptManagers containsObject:injectionManagerClass]; } - (void)injectScript:(NSString*)script forClass:(Class)JSInjectionManagerClass {
diff --git a/ios/web/public/test/js_test_util.h b/ios/web/public/test/js_test_util.h index 968adea..a3b0ce8b 100644 --- a/ios/web/public/test/js_test_util.h +++ b/ios/web/public/test/js_test_util.h
@@ -14,16 +14,29 @@ namespace web { // Evaluates JavaScript on the |manager| and returns the result as a string. +// DEPRECATED. TODO(crbug.com/595761): Remove this API. NSString* EvaluateJavaScriptAsString(CRWJSInjectionManager* manager, NSString* script); +// Executes JavaScript on the |manager| and returns the result as an id. +id ExecuteJavaScript(CRWJSInjectionManager* manager, NSString* script); + // Evaluates JavaScript on the |receiver| and returns the result as a string. +// DEPRECATED. TODO(crbug.com/595761): Remove this API. NSString* EvaluateJavaScriptAsString(CRWJSInjectionReceiver* receiver, NSString* script); +// Executes JavaScript on the |receiver| and returns the result as an id. +id ExecuteJavaScript(CRWJSInjectionReceiver* receiver, NSString* script); + // Evaluates JavaScript on |web_view| and returns the result as an id. +// DEPRECATED. TODO(crbug.com/595761): Remove this API, which has inconsistent +// name (evaluate instead of execute which is used in Chromium). id EvaluateJavaScript(WKWebView* web_view, NSString* script); +// Executes JavaScript on |web_view| and returns the result as an id. +id ExecuteJavaScript(WKWebView* web_view, NSString* script); + } // namespace web #endif // IOS_WEB_PUBLIC_TEST_JS_TEST_UTIL_H_
diff --git a/ios/web/public/test/js_test_util.mm b/ios/web/public/test/js_test_util.mm index 83e1dcb..267fcbf 100644 --- a/ios/web/public/test/js_test_util.mm +++ b/ios/web/public/test/js_test_util.mm
@@ -46,6 +46,22 @@ return [[evaluationResult retain] autorelease]; } +id ExecuteJavaScript(CRWJSInjectionManager* manager, NSString* script) { + __block base::scoped_nsobject<NSString> result; + __block bool completed = false; + [manager executeJavaScript:script + completionHandler:^(id execution_result, NSError* error) { + DCHECK(!error); + result.reset([execution_result copy]); + completed = true; + }]; + + base::test::ios::WaitUntilCondition(^{ + return completed; + }); + return [[result retain] autorelease]; +} + NSString* EvaluateJavaScriptAsString(CRWJSInjectionReceiver* receiver, NSString* script) { base::scoped_nsobject<CRWJSInjectionManager> manager( @@ -53,14 +69,24 @@ return EvaluateJavaScriptAsString(manager, script); } +id ExecuteJavaScript(CRWJSInjectionReceiver* receiver, NSString* script) { + base::scoped_nsobject<CRWJSInjectionManager> manager( + [[CRWJSInjectionManager alloc] initWithReceiver:receiver]); + return ExecuteJavaScript(manager, script); +} + id EvaluateJavaScript(WKWebView* web_view, NSString* script) { + return ExecuteJavaScript(web_view, script); +} + +id ExecuteJavaScript(WKWebView* web_view, NSString* script) { __block base::scoped_nsobject<id> result; __block bool completed = false; [web_view evaluateJavaScript:script - completionHandler:^(id evaluationResult, NSError* error) { + completionHandler:^(id evaluation_result, NSError* error) { DCHECK(!error); + result.reset([evaluation_result copy]); completed = true; - result.reset([evaluationResult copy]); }]; base::test::ios::WaitUntilCondition(^{ return completed;
diff --git a/ios/web/public/test/web_js_test.h b/ios/web/public/test/web_js_test.h index d4dac04..f13ea1a 100644 --- a/ios/web/public/test/web_js_test.h +++ b/ios/web/public/test/web_js_test.h
@@ -31,26 +31,51 @@ // Returns a NSString representation of the JavaScript's evaluation results; // the JavaScript is passed in as a |format| and its arguments. + // DEPRECATED. TODO(crbug.com/595761): Remove this API. NSString* EvaluateJavaScriptWithFormat(NSString* format, ...) __attribute__((format(__NSString__, 2, 3))); + // Returns an id representation of the JavaScript's evaluation results; + // the JavaScript is passed in as a |format| and its arguments. + id ExecuteJavaScriptWithFormat(NSString* format, ...) + __attribute__((format(__NSString__, 2, 3))); + // Helper method that EXPECTs the |java_script| evaluation results on each // element obtained by scripts in |get_element_javas_cripts|; the expected - // result is the corresponding entry in |expected_results|. + // result string is the corresponding entry in |expected_results|. + // DEPRECATED. TODO(crbug.com/595761): Remove this API. void EvaluateJavaScriptOnElementsAndCheck(NSString* java_script, NSArray* get_element_java_scripts, NSArray* expected_results); // Helper method that EXPECTs the |java_script| evaluation results on each + // element obtained by scripts in |get_element_javas_cripts|; the expected + // result is the corresponding entry in |expected_results|. + void ExecuteJavaScriptOnElementsAndCheck(NSString* java_script, + NSArray* get_element_java_scripts, + NSArray* expected_results); + + // Helper method that EXPECTs the |java_script| evaluation results on each // element obtained by JavaScripts in |get_element_java_scripts|. The // expected results are boolean and are true only for elements in // |get_element_java_scripts_expecting_true| which is subset of // |get_element_java_scripts|. + // DEPRECATED. TODO(crbug.com/595761): Remove this API. void EvaluateBooleanJavaScriptOnElementsAndCheck( NSString* java_script, NSArray* get_element_java_scripts, NSArray* get_element_java_scripts_expecting_true); + // Helper method that EXPECTs the |java_script| evaluation results on each + // element obtained by JavaScripts in |get_element_java_scripts|. The + // expected results are boolean and are true only for elements in + // |get_element_java_scripts_expecting_true| which is subset of + // |get_element_java_scripts|. + void ExecuteBooleanJavaScriptOnElementsAndCheck( + NSString* java_script, + NSArray* get_element_java_scripts, + NSArray* get_element_java_scripts_expecting_true); + private: // Injects JavaScript at |java_script_paths_|. void Inject(); @@ -61,14 +86,13 @@ template <class WebTestT> void WebJsTest<WebTestT>::Inject() { // Main web injection should have occured. - ASSERT_NSEQ(@"object", - WebTestT::EvaluateJavaScriptAsString(@"typeof __gCrWeb")); + ASSERT_NSEQ(@"object", WebTestT::ExecuteJavaScript(@"typeof __gCrWeb")); for (NSString* java_script_path in java_script_paths_.get()) { NSString* path = [base::mac::FrameworkBundle() pathForResource:java_script_path ofType:@"js"]; - WebTestT::EvaluateJavaScriptAsString([NSString + WebTestT::ExecuteJavaScript([NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil]); @@ -88,6 +112,17 @@ } template <class WebTestT> +id WebJsTest<WebTestT>::ExecuteJavaScriptWithFormat(NSString* format, ...) { + va_list args; + va_start(args, format); + base::scoped_nsobject<NSString> java_script( + [[NSString alloc] initWithFormat:format arguments:args]); + va_end(args); + + return WebTestT::ExecuteJavaScript(java_script); +} + +template <class WebTestT> void WebJsTest<WebTestT>::EvaluateJavaScriptOnElementsAndCheck( NSString* java_script, NSArray* get_element_java_scripts, @@ -100,6 +135,18 @@ } template <class WebTestT> +void WebJsTest<WebTestT>::ExecuteJavaScriptOnElementsAndCheck( + NSString* java_script, + NSArray* get_element_java_scripts, + NSArray* expected_results) { + for (NSUInteger i = 0; i < get_element_java_scripts.count; ++i) { + EXPECT_NSEQ( + expected_results[i], + ExecuteJavaScriptWithFormat(java_script, get_element_java_scripts[i])); + } +} + +template <class WebTestT> void WebJsTest<WebTestT>::EvaluateBooleanJavaScriptOnElementsAndCheck( NSString* java_script, NSArray* get_element_java_scripts, @@ -117,6 +164,21 @@ } } +template <class WebTestT> +void WebJsTest<WebTestT>::ExecuteBooleanJavaScriptOnElementsAndCheck( + NSString* java_script, + NSArray* get_element_java_scripts, + NSArray* get_element_java_scripts_expecting_true) { + for (NSString* get_element_java_script in get_element_java_scripts) { + BOOL expected = [get_element_java_scripts_expecting_true + containsObject:get_element_java_script]; + EXPECT_NSEQ(@(expected), ExecuteJavaScriptWithFormat( + java_script, get_element_java_script)) + << [NSString stringWithFormat:@"%@ on %@ should return %d", java_script, + get_element_java_script, expected]; + } +} + } // namespace web #endif // IOS_INTERNAL_CHROME_BROWSER_WEB_WEB_JS_TEST_H_
diff --git a/ios/web/public/test/web_test_with_web_state.mm b/ios/web/public/test/web_test_with_web_state.mm index 0ab646a0..4b6c2f7 100644 --- a/ios/web/public/test/web_test_with_web_state.mm +++ b/ios/web/public/test/web_test_with_web_state.mm
@@ -188,7 +188,7 @@ } bool WebTestWithWebState::ResetPageIfNavigationStalled(NSString* load_check) { - NSString* inner_html = EvaluateJavaScriptAsString( + id inner_html = ExecuteJavaScript( @"(document && document.body && document.body.innerHTML) || 'undefined'"); if ([inner_html rangeOfString:load_check].location == NSNotFound) { web_state_->SetWebUsageEnabled(false);
diff --git a/ios/web/public/web_state/js/crw_js_injection_evaluator.h b/ios/web/public/web_state/js/crw_js_injection_evaluator.h index 2286e16..17d2c4f 100644 --- a/ios/web/public/web_state/js/crw_js_injection_evaluator.h +++ b/ios/web/public/web_state/js/crw_js_injection_evaluator.h
@@ -27,15 +27,13 @@ completionHandler:(web::JavaScriptResultBlock)completionHandler; // Checks to see if the script for a class has been injected into the -// current page already, given the class and the script's presence -// beacon (a JS object that should exist iff the script has been injected). -- (BOOL)scriptHasBeenInjectedForClass:(Class)jsInjectionManagerClass - presenceBeacon:(NSString*)beacon; +// current page already. +- (BOOL)scriptHasBeenInjectedForClass:(Class)injectionManagerClass; // Injects the given script into the current page on behalf of -// |jsInjectionManagerClass|. This should only be used for injecting +// |injectionManagerClass|. This should only be used for injecting // the manager's script, and not for evaluating arbitrary JavaScript. -- (void)injectScript:(NSString*)script forClass:(Class)jsInjectionManagerClass; +- (void)injectScript:(NSString*)script forClass:(Class)injectionManagerClass; @end
diff --git a/ios/web/public/web_state/js/crw_js_injection_manager.h b/ios/web/public/web_state/js/crw_js_injection_manager.h index 916970ba..a7deb01 100644 --- a/ios/web/public/web_state/js/crw_js_injection_manager.h +++ b/ios/web/public/web_state/js/crw_js_injection_manager.h
@@ -39,13 +39,22 @@ // Evaluates the provided JavaScript expression, slightly deferred. Designed for // scripts where the chance of crwebinvoke:// being triggered indirectly is // high, and that aren't required to return a value. +// DEPRECATED. TODO(crbug.com/595761): Remove this API which was created for +// UIWebView. - (void)deferredEvaluate:(NSString*)script; // Evaluate the provided JavaScript asynchronously calling completionHandler // after execution. The |completionHandler| can be nil. +// DEPRECATED. TODO(crbug.com/595761): Remove this API. - (void)evaluate:(NSString*)script stringResultHandler:(web::JavaScriptCompletion)completionHandler; +// Executes the supplied JavaScript asynchronously. Calls |completionHandler| +// with results of the execution (which may be nil) or an NSError if there is an +// error. The |completionHandler| can be nil. +- (void)executeJavaScript:(NSString*)script + completionHandler:(web::JavaScriptResultBlock)completionHandler; + @end @interface CRWJSInjectionManager (ProtectedMethods) @@ -59,12 +68,6 @@ // that needs to be injected. - (NSString*)scriptPath; -// The JavaScript function that returns the JavaScript constant of undefined -// if the JavaScript has not been injected. Default to be nil. Subclasses -// should override this if their script should only be injected into a page -// once. -- (NSString*)presenceBeacon; - // Returns the content that should be injected. This is called every time // injection content is needed; by default is uses a cached copy of // staticInjectionContent.
diff --git a/ios/web/shell/test/BUILD.gn b/ios/web/shell/test/BUILD.gn index db90f52b..c9b547d 100644 --- a/ios/web/shell/test/BUILD.gn +++ b/ios/web/shell/test/BUILD.gn
@@ -53,6 +53,10 @@ "//url", ] + public_deps = [ + "//build/config/ios:xctest", + ] + sources = [ "app/navigation_test_util.h", "app/navigation_test_util.mm",
diff --git a/ios/web/web_state/js/common_js_unittest.mm b/ios/web/web_state/js/common_js_unittest.mm index b0292fef..b25c06099 100644 --- a/ios/web/web_state/js/common_js_unittest.mm +++ b/ios/web/web_state/js/common_js_unittest.mm
@@ -77,11 +77,11 @@ {"submit", 0, false}}; for (size_t i = 0; i < arraysize(testElements); ++i) { TextFieldTestElement element = testElements[i]; - NSString* result = EvaluateJavaScriptAsString([NSString + id result = ExecuteJavaScript([NSString stringWithFormat:@"__gCrWeb.common.isTextField(" "window.document.getElementsByName('%s')[%d])", element.element_name, element.element_index]); - EXPECT_NSEQ(element.expected_is_text_field ? @"true" : @"false", result) + EXPECT_NSEQ(element.expected_is_text_field ? @YES : @NO, result) << element.element_name << " with index " << element.element_index << " isTextField(): " << element.expected_is_text_field; }
diff --git a/ios/web/web_state/js/core_js_unittest.mm b/ios/web/web_state/js/core_js_unittest.mm index fbe9178b..9d99579 100644 --- a/ios/web/web_state/js/core_js_unittest.mm +++ b/ios/web/web_state/js/core_js_unittest.mm
@@ -61,7 +61,7 @@ for (size_t i = 0; i < arraysize(testData); i++) { TestScriptAndExpectedValue& data = testData[i]; LoadHtml(pageContent); - NSString* result = EvaluateJavaScriptAsString(data.testScript); + id result = ExecuteJavaScript(data.testScript); EXPECT_NSEQ(data.expectedValue, result) << " in test " << i << ": " << [data.testScript UTF8String]; } @@ -126,7 +126,7 @@ for (size_t i = 0; i < arraysize(testData); i++) { TestScriptAndExpectedValue& data = testData[i]; LoadHtml(pageContent); - NSString* result = EvaluateJavaScriptAsString(data.testScript); + id result = ExecuteJavaScript(data.testScript); EXPECT_NSEQ(data.expectedValue, result) << " in test " << i << ": " << [data.testScript UTF8String]; } @@ -134,27 +134,19 @@ struct TestDataForPasswordFormDetection { NSString* pageContent; - NSString* containsPassword; + NSNumber* containsPassword; }; TEST_F(CoreJsTest, HasPasswordField) { TestDataForPasswordFormDetection testData[] = { - // Form without a password field. - { - @"<form><input type='text' name='password'></form>", - @"false" - }, - // Form with a password field. - { - @"<form><input type='password' name='password'></form>", - @"true" - } - }; + // Form without a password field. + {@"<form><input type='text' name='password'></form>", @NO}, + // Form with a password field. + {@"<form><input type='password' name='password'></form>", @YES}}; for (size_t i = 0; i < arraysize(testData); i++) { TestDataForPasswordFormDetection& data = testData[i]; LoadHtml(data.pageContent); - NSString* result = - EvaluateJavaScriptAsString(@"__gCrWeb.hasPasswordField()"); + id result = ExecuteJavaScript(@"__gCrWeb.hasPasswordField()"); EXPECT_NSEQ(data.containsPassword, result) << " in test " << i << ": " << [data.pageContent UTF8String]; } @@ -164,15 +156,15 @@ TestDataForPasswordFormDetection data = { // Form with a password field in a nested iframe. @"<iframe name='pf'></iframe>" - "<script>" - " var doc = frames['pf'].document.open();" - " doc.write('<form><input type=\\'password\\'></form>');" - " doc.close();" - "</script>", - @"true" + "<script>" + " var doc = frames['pf'].document.open();" + " doc.write('<form><input type=\\'password\\'></form>');" + " doc.close();" + "</script>", + @YES }; LoadHtml(data.pageContent); - NSString* result = EvaluateJavaScriptAsString(@"__gCrWeb.hasPasswordField()"); + id result = ExecuteJavaScript(@"__gCrWeb.hasPasswordField()"); EXPECT_NSEQ(data.containsPassword, result) << [data.pageContent UTF8String]; } @@ -232,7 +224,7 @@ // Load a sample HTML page. As a side-effect, loading HTML via // |webController_| will also inject core.js. LoadHtml(@"<p>"); - NSString* result = EvaluateJavaScriptAsString(data.testScript); + id result = ExecuteJavaScript(data.testScript); EXPECT_NSEQ(data.expectedValue, result) << " in test " << i << ": " << [data.testScript UTF8String]; } @@ -246,8 +238,7 @@ // A page with a link to a destination URL. LoadHtml(base::StringPrintf(image, "http://destination")); - NSString* result = - EvaluateJavaScriptAsString(@"__gCrWeb['getElementFromPoint'](200, 200)"); + id result = ExecuteJavaScript(@"__gCrWeb['getElementFromPoint'](200, 200)"); std::string expected_result = R"({"src":"foo","referrerPolicy":"default",)" R"("href":"http://destination/"})"; @@ -255,8 +246,7 @@ // A page with a link with some JavaScript that does not result in a NOP. LoadHtml(base::StringPrintf(image, "javascript:console.log('whatever')")); - result = - EvaluateJavaScriptAsString(@"__gCrWeb['getElementFromPoint'](200, 200)"); + result = ExecuteJavaScript(@"__gCrWeb['getElementFromPoint'](200, 200)"); expected_result = R"({"src":"foo","referrerPolicy":"default",)" R"("href":"javascript:console.log("})"; @@ -272,8 +262,7 @@ // A page with a link with some JavaScript that results in a NOP. const std::string javascript = std::string("javascript:") + js; LoadHtml(base::StringPrintf(image, javascript.c_str())); - result = EvaluateJavaScriptAsString( - @"__gCrWeb['getElementFromPoint'](200, 200)"); + result = ExecuteJavaScript(@"__gCrWeb['getElementFromPoint'](200, 200)"); expected_result = R"({"src":"foo","referrerPolicy":"default"})"; // Make sure the returned JSON does not have an 'href' key.
diff --git a/ios/web/web_state/js/crw_js_injection_manager.mm b/ios/web/web_state/js/crw_js_injection_manager.mm index 3b8e5dd..92fa7352 100644 --- a/ios/web/web_state/js/crw_js_injection_manager.mm +++ b/ios/web/web_state/js/crw_js_injection_manager.mm
@@ -42,9 +42,7 @@ } - (BOOL)hasBeenInjected { - DCHECK(self.presenceBeacon); - return [_receiver scriptHasBeenInjectedForClass:[self class] - presenceBeacon:self.presenceBeacon]; + return [_receiver scriptHasBeenInjectedForClass:[self class]]; } - (void)inject { @@ -70,6 +68,11 @@ [_receiver evaluateJavaScript:script stringResultHandler:completionHandler]; } +- (void)executeJavaScript:(NSString*)script + completionHandler:(web::JavaScriptResultBlock)completionHandler { + [_receiver executeJavaScript:script completionHandler:completionHandler]; +} + - (NSArray*)directDependencies { return @[]; } @@ -101,10 +104,6 @@ return nil; } -- (NSString*)presenceBeacon { - return nil; -} - - (NSString*)injectionContent { if (!_injectObject) _injectObject.reset([[self staticInjectionContent] copy]);
diff --git a/ios/web/web_state/js/crw_js_injection_manager_unittest.mm b/ios/web/web_state/js/crw_js_injection_manager_unittest.mm index 7478d9a..1ab804c5 100644 --- a/ios/web/web_state/js/crw_js_injection_manager_unittest.mm +++ b/ios/web/web_state/js/crw_js_injection_manager_unittest.mm
@@ -18,10 +18,6 @@ @implementation TestingCRWJSBaseManager -- (NSString*)presenceBeacon { - return @"base"; -} - - (NSString*)staticInjectionContent { return @"base = {};"; } @@ -34,10 +30,6 @@ @implementation TestingAnotherCRWJSBaseManager -- (NSString*)presenceBeacon { - return @"anotherbase"; -} - - (NSString*)staticInjectionContent { return @"anotherbase = {};"; } @@ -50,10 +42,6 @@ @implementation TestingJsManager -- (NSString*)presenceBeacon { - return @"base['testingjs']"; -} - - (NSString*)staticInjectionContent { return @"base['testingjs'] = {};"; } @@ -70,10 +58,6 @@ @implementation TestingDynamicJsManager -- (NSString*)presenceBeacon { - return @"dynamic"; -} - - (NSString*)injectionContent { static int i = 0; return [NSString stringWithFormat:@"dynamic = {}; dynamic['foo'] = %d;", ++i]; @@ -94,10 +78,6 @@ @implementation TestingAnotherJsManager -- (NSString*)presenceBeacon { - return @"base['anothertestingjs']"; -} - - (NSString*)staticInjectionContent { return @"base['anothertestingjs'] = {};"; } @@ -115,10 +95,6 @@ @implementation TestingJsManagerWithNestedDependencies -- (NSString*)presenceBeacon { - return @"base['testingjswithnesteddependencies']"; -} - - (NSString*)staticInjectionContent { return @"base['testingjswithnesteddependencies'] = {};"; } @@ -135,10 +111,6 @@ @implementation TestingJsManagerComplex -- (NSString*)presenceBeacon { - return @"base['testingjswithnesteddependencies']['complex']"; -} - - (NSString*)staticInjectionContent { return @"base['testingjswithnesteddependencies']['complex'] = {};"; } @@ -290,8 +262,7 @@ // Tests that checking for an uninjected presence beacon returns false. TEST_F(JsInjectionManagerTest, WebControllerCheckForUninjectedScript) { EXPECT_FALSE([web_state()->GetJSInjectionReceiver() - scriptHasBeenInjectedForClass:Nil - presenceBeacon:@"__gCrWeb.dummyBeacon"]); + scriptHasBeenInjectedForClass:Nil]); } TEST_F(JsInjectionManagerTest, AllDependencies) {
diff --git a/ios/web/web_state/js/crw_js_injection_receiver.mm b/ios/web/web_state/js/crw_js_injection_receiver.mm index 3094f9ad..ffab34ea 100644 --- a/ios/web/web_state/js/crw_js_injection_receiver.mm +++ b/ios/web/web_state/js/crw_js_injection_receiver.mm
@@ -46,10 +46,8 @@ [_evaluator executeJavaScript:script completionHandler:completionHandler]; } -- (BOOL)scriptHasBeenInjectedForClass:(Class)jsInjectionManagerClass - presenceBeacon:(NSString*)beacon { - return [_evaluator scriptHasBeenInjectedForClass:jsInjectionManagerClass - presenceBeacon:beacon]; +- (BOOL)scriptHasBeenInjectedForClass:(Class)injectionManagerClass { + return [_evaluator scriptHasBeenInjectedForClass:injectionManagerClass]; } - (void)injectScript:(NSString*)script forClass:(Class)jsInjectionManagerClass {
diff --git a/ios/web/web_state/js/crw_js_plugin_placeholder_manager.mm b/ios/web/web_state/js/crw_js_plugin_placeholder_manager.mm index 6378d87b..f41ca7ea 100644 --- a/ios/web/web_state/js/crw_js_plugin_placeholder_manager.mm +++ b/ios/web/web_state/js/crw_js_plugin_placeholder_manager.mm
@@ -33,10 +33,6 @@ return @"plugin_placeholder"; } -- (NSString*)presenceBeacon { - return @"__gCrWeb.plugin"; -} - - (NSString*)staticInjectionContent { NSString* baseContent = [super staticInjectionContent]; DCHECK(web::GetWebClient());
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm index be0d8c4..b253921a 100644 --- a/ios/web/web_state/ui/crw_web_controller.mm +++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -2496,9 +2496,8 @@ web::ExecuteJavaScript(_webView, safeScript, completionHandler); } -- (BOOL)scriptHasBeenInjectedForClass:(Class)JSInjectionManagerClass - presenceBeacon:(NSString*)beacon { - return [_injectedScriptManagers containsObject:JSInjectionManagerClass]; +- (BOOL)scriptHasBeenInjectedForClass:(Class)injectionManagerClass { + return [_injectedScriptManagers containsObject:injectionManagerClass]; } - (void)injectScript:(NSString*)script forClass:(Class)JSInjectionManagerClass {
diff --git a/ios/web/web_state/ui/crw_web_controller_observer_unittest.mm b/ios/web/web_state/ui/crw_web_controller_observer_unittest.mm index b070e30..28aa09b 100644 --- a/ios/web/web_state/ui/crw_web_controller_observer_unittest.mm +++ b/ios/web/web_state/ui/crw_web_controller_observer_unittest.mm
@@ -51,7 +51,7 @@ command.SetString("command", "test.testMessage"); std::string message; base::JSONWriter::Write(command, &message); - EvaluateJavaScriptAsString([NSString + ExecuteJavaScript([NSString stringWithFormat:@"__gCrWeb.message.invokeOnHost(%s)", message.c_str()]); WaitForBackgroundTasks(); ASSERT_EQ(1U, [fake_web_controller_observer_ commandsReceived].size()); @@ -72,7 +72,7 @@ command.SetString("referrerPolicy", "referrerPolicy"); std::string message; base::JSONWriter::Write(command, &message); - EvaluateJavaScriptAsString( + ExecuteJavaScript( [NSString stringWithFormat:@"__gCrWeb.message.invokeOnHostImmediate(%s)", message.c_str()]); WaitForBackgroundTasks(); @@ -92,7 +92,7 @@ command.SetInteger("number", count); base::JSONWriter::Write(command, &message); ASSERT_EQ(0U, [fake_web_controller_observer_ commandsReceived].size()); - EvaluateJavaScriptAsString( + ExecuteJavaScript( [NSString stringWithFormat:@"__gCrWeb.message.invokeOnHost(%s)", message.c_str()]); WaitForBackgroundTasks();
diff --git a/ios/web/web_state/ui/crw_web_controller_unittest.mm b/ios/web/web_state/ui/crw_web_controller_unittest.mm index 7f27fa7..8dc28c1 100644 --- a/ios/web/web_state/ui/crw_web_controller_unittest.mm +++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm
@@ -510,7 +510,7 @@ [[web_delegate_mock() expect] webControllerDidSuppressDialog:web_controller()]; [web_controller() setShouldSuppressDialogs:YES]; - EvaluateJavaScriptAsString(@"alert('test')"); + ExecuteJavaScript(@"alert('test')"); }; // Tests that window.alert dialog is shown for DIALOG_POLICY_ALLOW. @@ -531,7 +531,7 @@ }]; [web_controller() setShouldSuppressDialogs:NO]; - EvaluateJavaScriptAsString(@"alert('test')"); + ExecuteJavaScript(@"alert('test')"); }; // Tests that window.confirm dialog is suppressed for DIALOG_POLICY_SUPPRESS. @@ -539,7 +539,7 @@ [[web_delegate_mock() expect] webControllerDidSuppressDialog:web_controller()]; [web_controller() setShouldSuppressDialogs:YES]; - EXPECT_NSEQ(@"false", EvaluateJavaScriptAsString(@"confirm('test')")); + EXPECT_NSEQ(@NO, ExecuteJavaScript(@"confirm('test')")); }; // Tests that window.confirm dialog is shown for DIALOG_POLICY_ALLOW and @@ -562,7 +562,7 @@ }]; [web_controller() setShouldSuppressDialogs:NO]; - EXPECT_NSEQ(@"true", EvaluateJavaScriptAsString(@"confirm('test')")); + EXPECT_NSEQ(@YES, ExecuteJavaScript(@"confirm('test')")); } // Tests that window.confirm dialog is shown for DIALOG_POLICY_ALLOW and @@ -585,7 +585,7 @@ }]; [web_controller() setShouldSuppressDialogs:NO]; - EXPECT_NSEQ(@"false", EvaluateJavaScriptAsString(@"confirm('test')")); + EXPECT_NSEQ(@NO, ExecuteJavaScript(@"confirm('test')")); } // Tests that window.prompt dialog is suppressed for DIALOG_POLICY_SUPPRESS. @@ -593,7 +593,7 @@ [[web_delegate_mock() expect] webControllerDidSuppressDialog:web_controller()]; [web_controller() setShouldSuppressDialogs:YES]; - EXPECT_NSEQ(@"", EvaluateJavaScriptAsString(@"prompt('Yes?', 'No')")); + EXPECT_EQ([NSNull null], ExecuteJavaScript(@"prompt('Yes?', 'No')")); } // Tests that window.prompt dialog is shown for DIALOG_POLICY_ALLOW. @@ -617,7 +617,7 @@ }]; [web_controller() setShouldSuppressDialogs:NO]; - EXPECT_NSEQ(@"Maybe", EvaluateJavaScriptAsString(@"prompt('Yes?', 'No')")); + EXPECT_NSEQ(@"Maybe", ExecuteJavaScript(@"prompt('Yes?', 'No')")); } // Tests that geolocation dialog is suppressed for DIALOG_POLICY_SUPPRESS. @@ -631,7 +631,7 @@ [[web_delegate_mock() expect] webControllerDidSuppressDialog:web_controller()]; [web_controller() setShouldSuppressDialogs:YES]; - EvaluateJavaScriptAsString(@"navigator.geolocation.getCurrentPosition()"); + ExecuteJavaScript(@"navigator.geolocation.getCurrentPosition()"); } // Tests that window.open is suppressed for DIALOG_POLICY_SUPPRESS. @@ -639,7 +639,7 @@ [[web_delegate_mock() expect] webControllerDidSuppressDialog:web_controller()]; [web_controller() setShouldSuppressDialogs:YES]; - EvaluateJavaScriptAsString(@"window.open('')"); + ExecuteJavaScript(@"window.open('')"); } // A separate test class, as none of the |CRWWebControllerTest| setup is @@ -758,8 +758,8 @@ // Tests that a script correctly evaluates to string. TEST_F(CRWWebControllerJSExecutionTest, LegacyAPIExecution) { LoadHtml(@"<p></p>"); - EXPECT_NSEQ(@"true", EvaluateJavaScriptAsString(@"true")); - EXPECT_NSEQ(@"false", EvaluateJavaScriptAsString(@"false")); + EXPECT_NSEQ(@YES, ExecuteJavaScript(@"true")); + EXPECT_NSEQ(@NO, ExecuteJavaScript(@"false")); } // Tests that a script correctly evaluates to boolean. @@ -773,15 +773,15 @@ TEST_F(CRWWebControllerJSExecutionTest, LegacyAPIWindowIdMissmatch) { LoadHtml(@"<p></p>"); // Script is evaluated since windowID is matched. - EvaluateJavaScriptAsString(@"window.test1 = '1';"); - EXPECT_NSEQ(@"1", EvaluateJavaScriptAsString(@"window.test1")); + ExecuteJavaScript(@"window.test1 = '1';"); + EXPECT_NSEQ(@"1", ExecuteJavaScript(@"window.test1")); // Change windowID. - EvaluateJavaScriptAsString(@"__gCrWeb['windowId'] = '';"); + ExecuteJavaScript(@"__gCrWeb['windowId'] = '';"); // Script is not evaluated because of windowID mismatch. - EvaluateJavaScriptAsString(@"window.test2 = '2';"); - EXPECT_NSEQ(@"", EvaluateJavaScriptAsString(@"window.test2")); + ExecuteJavaScript(@"window.test2 = '2';"); + EXPECT_FALSE(ExecuteJavaScript(@"window.test2")); } // Tests that a script is not executed on windowID mismatch. @@ -890,11 +890,11 @@ } // Executes JavaScript that opens a new window and returns evaluation result // as a string. - NSString* OpenWindowByDOM() { + id OpenWindowByDOM() { NSString* const kOpenWindowScript = @"var w = window.open('javascript:void(0);', target='_blank');" "w.toString();"; - NSString* windowJSObject = EvaluateJavaScriptAsString(kOpenWindowScript); + id windowJSObject = ExecuteJavaScript(kOpenWindowScript); WaitForBackgroundTasks(); return windowJSObject; } @@ -908,7 +908,7 @@ TEST_F(CRWWebControllerWindowOpenTest, NoDelegate) { [web_controller() setDelegate:nil]; - EXPECT_NSEQ(@"", OpenWindowByDOM()); + EXPECT_FALSE(OpenWindowByDOM()); EXPECT_FALSE([delegate_ blockedPopupInfo]); } @@ -942,7 +942,7 @@ }]; ASSERT_FALSE([web_controller() userIsInteracting]); - EXPECT_NSEQ(@"", OpenWindowByDOM()); + EXPECT_FALSE(OpenWindowByDOM()); base::test::ios::WaitUntilCondition(^bool() { return [delegate_ blockedPopupInfo]; }); @@ -973,7 +973,7 @@ // Tests that window.open executed w/o user gesture does not open a new window. TEST_F(CRWWebControllerWindowOpenTest, BlockPopup) { ASSERT_FALSE([web_controller() userIsInteracting]); - EXPECT_NSEQ(@"", OpenWindowByDOM()); + EXPECT_FALSE(OpenWindowByDOM()); base::test::ios::WaitUntilCondition(^bool() { return [delegate_ blockedPopupInfo]; });
diff --git a/ipc/ipc.mojom b/ipc/ipc.mojom index 2896fc2..292a53b 100644 --- a/ipc/ipc.mojom +++ b/ipc/ipc.mojom
@@ -32,3 +32,6 @@ // Requests a Channel-associated interface. GetAssociatedInterface(string name, associated GenericInterface& request); }; + +// A strictly nominal interface used to identify Channel bootstrap requests. +interface ChannelBootstrap {};
diff --git a/ipc/ipc_channel_mojo_unittest.cc b/ipc/ipc_channel_mojo_unittest.cc index 26b4e3f..a133ba4 100644 --- a/ipc/ipc_channel_mojo_unittest.cc +++ b/ipc/ipc_channel_mojo_unittest.cc
@@ -46,25 +46,23 @@ #include "ipc/ipc_platform_file_attachment_posix.h" #endif -#define DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(client_name, test_base) \ - class client_name##_MainFixture : public test_base { \ - public: \ - void Main(); \ - }; \ - MULTIPROCESS_TEST_MAIN_WITH_SETUP( \ - client_name##TestChildMain, \ - ::mojo::edk::test::MultiprocessTestHelper::ChildSetup) { \ - CHECK(!mojo::edk::test::MultiprocessTestHelper::primordial_pipe_token \ - .empty()); \ - client_name##_MainFixture test; \ - test.Init(mojo::edk::CreateChildMessagePipe( \ - mojo::edk::test::MultiprocessTestHelper::primordial_pipe_token)); \ - test.Main(); \ - return (::testing::Test::HasFatalFailure() || \ - ::testing::Test::HasNonfatalFailure()) \ - ? 1 \ - : 0; \ - } \ +#define DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(client_name, test_base) \ + class client_name##_MainFixture : public test_base { \ + public: \ + void Main(); \ + }; \ + MULTIPROCESS_TEST_MAIN_WITH_SETUP( \ + client_name##TestChildMain, \ + ::mojo::edk::test::MultiprocessTestHelper::ChildSetup) { \ + client_name##_MainFixture test; \ + test.Init( \ + std::move(mojo::edk::test::MultiprocessTestHelper::primordial_pipe)); \ + test.Main(); \ + return (::testing::Test::HasFatalFailure() || \ + ::testing::Test::HasNonfatalFailure()) \ + ? 1 \ + : 0; \ + } \ void client_name##_MainFixture::Main() namespace {
diff --git a/ipc/ipc_message_start.h b/ipc/ipc_message_start.h index c1e1b9f..26f6973f 100644 --- a/ipc/ipc_message_start.h +++ b/ipc/ipc_message_start.h
@@ -86,7 +86,6 @@ ScreenOrientationMsgStart, MediaStreamTrackMetricsHostMsgStart, ChromeExtensionMsgStart, - TranslateMsgStart, PushMessagingMsgStart, GinJavaBridgeMsgStart, ChromeUtilityPrintingMsgStart,
diff --git a/ipc/ipc_mojo_bootstrap_unittest.cc b/ipc/ipc_mojo_bootstrap_unittest.cc index 9d4aaf732..b8ed0ee 100644 --- a/ipc/ipc_mojo_bootstrap_unittest.cc +++ b/ipc/ipc_mojo_bootstrap_unittest.cc
@@ -77,8 +77,7 @@ base::RunLoop run_loop; TestingDelegate delegate(run_loop.QuitClosure()); std::unique_ptr<IPC::MojoBootstrap> bootstrap = IPC::MojoBootstrap::Create( - mojo::edk::CreateChildMessagePipe( - mojo::edk::test::MultiprocessTestHelper::primordial_pipe_token), + std::move(mojo::edk::test::MultiprocessTestHelper::primordial_pipe), IPC::Channel::MODE_CLIENT, &delegate, base::ThreadTaskRunnerHandle::Get());
diff --git a/mash/example/window_type_launcher/window_type_launcher.cc b/mash/example/window_type_launcher/window_type_launcher.cc index 9372c8c..a8eb929 100644 --- a/mash/example/window_type_launcher/window_type_launcher.cc +++ b/mash/example/window_type_launcher/window_type_launcher.cc
@@ -22,6 +22,7 @@ #include "ui/aura/window_event_dispatcher.h" #include "ui/compositor/layer.h" #include "ui/gfx/canvas.h" +#include "ui/views/background.h" #include "ui/views/context_menu_controller.h" #include "ui/views/controls/button/button.h" #include "ui/views/controls/button/label_button.h" @@ -55,7 +56,9 @@ PANEL = 1 << 2, }; - explicit WindowDelegateView(uint32_t traits) : traits_(traits) {} + explicit WindowDelegateView(uint32_t traits) : traits_(traits) { + set_background(views::Background::CreateSolidBackground(SK_ColorRED)); + } ~WindowDelegateView() override {} // Creates and shows a window with the specified traits. @@ -84,6 +87,8 @@ base::string16 GetWindowTitle() const override { return base::ASCIIToUTF16("Window"); } + gfx::Size GetPreferredSize() const override { return gfx::Size(300, 300); } + View* GetContentsView() override { return this; } private: const uint32_t traits_;
diff --git a/mash/session/BUILD.gn b/mash/session/BUILD.gn index 87119b59..f250359 100644 --- a/mash/session/BUILD.gn +++ b/mash/session/BUILD.gn
@@ -26,7 +26,6 @@ data_deps = [ "//ash/mus", - "//ash/sysui", "//mash/app_driver", "//mash/quick_launch", ]
diff --git a/mash/session/session.cc b/mash/session/session.cc index 8b137576..ff37536 100644 --- a/mash/session/session.cc +++ b/mash/session/session.cc
@@ -30,8 +30,9 @@ void Session::OnStart(const shell::Identity& identity) { StartAppDriver(); StartWindowManager(); - StartSystemUI(); StartQuickLaunch(); + // Launch a chrome window for dev convience; don't do this in the long term. + connector()->Connect("exe:chrome"); } bool Session::OnConnect(const shell::Identity& remote_identity, @@ -95,12 +96,6 @@ base::Unretained(this))); } -void Session::StartSystemUI() { - StartRestartableService("mojo:ash_sysui", - base::Bind(&Session::StartSystemUI, - base::Unretained(this))); -} - void Session::StartAppDriver() { StartRestartableService( "mojo:app_driver",
diff --git a/mash/session/session.h b/mash/session/session.h index b71f613..c644214 100644 --- a/mash/session/session.h +++ b/mash/session/session.h
@@ -49,7 +49,6 @@ mojom::SessionRequest request) override; void StartWindowManager(); - void StartSystemUI(); void StartAppDriver(); void StartQuickLaunch();
diff --git a/mash/test/mash_test_suite.cc b/mash/test/mash_test_suite.cc index 98e0f1b..3e60b21 100644 --- a/mash/test/mash_test_suite.cc +++ b/mash/test/mash_test_suite.cc
@@ -9,6 +9,8 @@ #include "ui/aura/env.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/ui_base_paths.h" +#include "ui/compositor/test/context_factories_for_test.h" +#include "ui/gl/test/gl_surface_test_support.h" namespace mash { namespace test { @@ -28,6 +30,10 @@ base::DiscardableMemoryAllocator::SetInstance(&discardable_memory_allocator_); env_ = aura::Env::CreateInstance(); + gl::GLSurfaceTestSupport::InitializeOneOff(); + const bool enable_pixel_output = false; + env_->set_context_factory( + ui::InitializeContextFactoryForTests(enable_pixel_output)); } void MashTestSuite::Shutdown() {
diff --git a/mash/unittests_manifest.json b/mash/unittests_manifest.json index 83742122..0190bde 100644 --- a/mash/unittests_manifest.json +++ b/mash/unittests_manifest.json
@@ -7,8 +7,7 @@ "*": { "classes": [ "app", "test" ] }, "mojo:ash": { "interfaces": [ - "ui::mojom::AcceleratorRegistrar", - "ash::mojom::UserWindowController" + "ui::mojom::AcceleratorRegistrar" ] } }
diff --git a/media/BUILD.gn b/media/BUILD.gn index 96e6cbe..e6e4368 100644 --- a/media/BUILD.gn +++ b/media/BUILD.gn
@@ -113,6 +113,10 @@ "cdm/player_tracker_impl.h", "cdm/supported_cdm_versions.cc", "cdm/supported_cdm_versions.h", + "device_monitors/device_monitor_mac.h", + "device_monitors/device_monitor_mac.mm", + "device_monitors/system_message_window_win.cc", + "device_monitors/system_message_window_win.h", "filters/audio_clock.cc", "filters/audio_clock.h", "filters/audio_renderer_algorithm.cc", @@ -134,8 +138,6 @@ "filters/decrypting_demuxer_stream.h", "filters/decrypting_video_decoder.cc", "filters/decrypting_video_decoder.h", - "filters/default_media_permission.cc", - "filters/default_media_permission.h", "filters/file_data_source.cc", "filters/frame_processor.cc", "filters/frame_processor.h", @@ -456,6 +458,14 @@ ] } + if (use_udev) { + deps += [ "//device/udev_linux" ] + sources += [ + "device_monitors/device_monitor_udev.cc", + "device_monitors/device_monitor_udev.h", + ] + } + public_deps += [ ":media_features", ":shared_memory_support", @@ -526,6 +536,7 @@ "cdm/simple_cdm_allocator_unittest.cc", "cdm/simple_cdm_buffer.cc", "cdm/simple_cdm_buffer.h", + "device_monitors/system_message_window_win_unittest.cc", "filters/audio_clock_unittest.cc", "filters/audio_decoder_selector_unittest.cc", "filters/audio_renderer_algorithm_unittest.cc",
diff --git a/media/base/BUILD.gn b/media/base/BUILD.gn index 6e74b688..c1dbdca 100644 --- a/media/base/BUILD.gn +++ b/media/base/BUILD.gn
@@ -206,6 +206,7 @@ "stream_parser.h", "stream_parser_buffer.cc", "stream_parser_buffer.h", + "subsample_entry.h", "surface_manager.h", "text_cue.cc", "text_cue.h", @@ -480,6 +481,7 @@ "//base/test:test_support", "//gpu/command_buffer/common", "//media", + "//media/base/android:anywhere_unittests", "//skia", "//testing/gmock", "//testing/gtest",
diff --git a/media/base/android/BUILD.gn b/media/base/android/BUILD.gn index 2b0a35a..a552319 100644 --- a/media/base/android/BUILD.gn +++ b/media/base/android/BUILD.gn
@@ -3,144 +3,184 @@ # found in the LICENSE file. import("//build/config/android/config.gni") -import("//build/config/android/rules.gni") import("//build/config/arm.gni") import("//build/config/ui.gni") import("//media/media_options.gni") -assert(is_android) - -source_set("android") { +# These should compile on non-android platforms too. +source_set("anywhere") { sources = [ - "access_unit_queue.cc", - "access_unit_queue.h", - "android_cdm_factory.cc", - "android_cdm_factory.h", - "audio_decoder_job.cc", - "audio_decoder_job.h", - "audio_media_codec_decoder.cc", - "audio_media_codec_decoder.h", - "demuxer_android.h", - "demuxer_stream_player_params.cc", - "demuxer_stream_player_params.h", - "media_client_android.cc", - "media_client_android.h", "media_codec_bridge.cc", "media_codec_bridge.h", - "media_codec_decoder.cc", - "media_codec_decoder.h", + "media_codec_direction.h", "media_codec_loop.cc", "media_codec_loop.h", - "media_codec_player.cc", - "media_codec_player.h", - "media_codec_util.cc", - "media_codec_util.h", - "media_decoder_job.cc", - "media_decoder_job.h", - "media_drm_bridge.cc", - "media_drm_bridge.h", - "media_drm_bridge_cdm_context.cc", - "media_drm_bridge_cdm_context.h", - "media_drm_bridge_delegate.cc", - "media_drm_bridge_delegate.h", - "media_jni_registrar.cc", - "media_jni_registrar.h", - "media_player_android.cc", - "media_player_android.h", - "media_player_bridge.cc", - "media_player_bridge.h", - "media_player_listener.cc", - "media_player_listener.h", - "media_player_manager.h", - "media_resource_getter.cc", - "media_resource_getter.h", - "media_source_player.cc", - "media_source_player.h", - "media_statistics.cc", - "media_statistics.h", - "media_task_runner.cc", - "media_task_runner.h", - "media_url_demuxer.cc", - "media_url_demuxer.h", - "media_url_interceptor.h", - "provision_fetcher.h", - "sdk_media_codec_bridge.cc", - "sdk_media_codec_bridge.h", - "stream_texture_wrapper.h", - "video_decoder_job.cc", - "video_decoder_job.h", - "video_media_codec_decoder.cc", - "video_media_codec_decoder.h", ] configs += [ "//media:media_config", "//media:media_implementation", ] deps = [ - ":media_jni_headers", "//media:media_features", "//media:shared_memory_support", - "//third_party/widevine/cdm:version_h", "//ui/gl", "//url", ] } -source_set("unittests") { +# These should compile on non-android platforms too. +source_set("anywhere_unittests") { testonly = true sources = [ - "access_unit_queue_unittest.cc", - "media_codec_decoder_unittest.cc", "media_codec_loop_unittest.cc", - "media_drm_bridge_unittest.cc", - "media_player_bridge_unittest.cc", - "media_source_player_unittest.cc", - "media_url_demuxer_unittest.cc", - "sdk_media_codec_bridge_unittest.cc", - "test_data_factory.cc", - "test_data_factory.h", - "test_statistics.h", + "mock_media_codec_bridge.cc", + "mock_media_codec_bridge.h", ] - - if (proprietary_codecs) { - sources += [ "media_codec_player_unittest.cc" ] - } - + configs += [ + "//media:media_config", + "//media:media_implementation", + ] deps = [ - ":android", + ":anywhere", "//media/base:test_support", "//testing/gmock", "//testing/gtest", - "//third_party/widevine/cdm:version_h", ] - configs += [ "//media:media_config" ] } -generate_jni("media_jni_headers") { - sources = [ - "java/src/org/chromium/media/AudioManagerAndroid.java", - "java/src/org/chromium/media/AudioRecordInput.java", - "java/src/org/chromium/media/MediaCodecBridge.java", - "java/src/org/chromium/media/MediaCodecUtil.java", - "java/src/org/chromium/media/MediaDrmBridge.java", - "java/src/org/chromium/media/MediaPlayerBridge.java", - "java/src/org/chromium/media/MediaPlayerListener.java", - ] - jni_package = "media" -} +if (is_android) { + import("//build/config/android/rules.gni") -android_library("media_java") { - deps = [ - "//base:base_java", - ] + source_set("android") { + sources = [ + "access_unit_queue.cc", + "access_unit_queue.h", + "android_cdm_factory.cc", + "android_cdm_factory.h", + "audio_decoder_job.cc", + "audio_decoder_job.h", + "audio_media_codec_decoder.cc", + "audio_media_codec_decoder.h", + "demuxer_android.h", + "demuxer_stream_player_params.cc", + "demuxer_stream_player_params.h", + "media_client_android.cc", + "media_client_android.h", + "media_codec_decoder.cc", + "media_codec_decoder.h", + "media_codec_player.cc", + "media_codec_player.h", + "media_codec_util.cc", + "media_codec_util.h", + "media_decoder_job.cc", + "media_decoder_job.h", + "media_drm_bridge.cc", + "media_drm_bridge.h", + "media_drm_bridge_cdm_context.cc", + "media_drm_bridge_cdm_context.h", + "media_drm_bridge_delegate.cc", + "media_drm_bridge_delegate.h", + "media_jni_registrar.cc", + "media_jni_registrar.h", + "media_player_android.cc", + "media_player_android.h", + "media_player_bridge.cc", + "media_player_bridge.h", + "media_player_listener.cc", + "media_player_listener.h", + "media_player_manager.h", + "media_resource_getter.cc", + "media_resource_getter.h", + "media_source_player.cc", + "media_source_player.h", + "media_statistics.cc", + "media_statistics.h", + "media_task_runner.cc", + "media_task_runner.h", + "media_url_demuxer.cc", + "media_url_demuxer.h", + "media_url_interceptor.h", + "provision_fetcher.h", + "sdk_media_codec_bridge.cc", + "sdk_media_codec_bridge.h", + "stream_texture_wrapper.h", + "video_decoder_job.cc", + "video_decoder_job.h", + "video_media_codec_decoder.cc", + "video_media_codec_decoder.h", + ] + configs += [ + "//media:media_config", + "//media:media_implementation", + ] + deps = [ + ":media_jni_headers", + "//media:media_features", + "//media:shared_memory_support", + "//third_party/widevine/cdm:version_h", + "//ui/gl", + "//url", + ] + public_deps = [ + ":anywhere", + ] + } - java_files = [ - "java/src/org/chromium/media/AudioManagerAndroid.java", - "java/src/org/chromium/media/AudioRecordInput.java", - "java/src/org/chromium/media/MediaCodecBridge.java", - "java/src/org/chromium/media/MediaCodecUtil.java", - "java/src/org/chromium/media/MediaDrmBridge.java", - "java/src/org/chromium/media/MediaPlayerBridge.java", - "java/src/org/chromium/media/MediaPlayerListener.java", - ] + source_set("unittests") { + testonly = true + sources = [ + "access_unit_queue_unittest.cc", + "media_codec_decoder_unittest.cc", + "media_drm_bridge_unittest.cc", + "media_player_bridge_unittest.cc", + "media_source_player_unittest.cc", + "media_url_demuxer_unittest.cc", + "sdk_media_codec_bridge_unittest.cc", + "test_data_factory.cc", + "test_data_factory.h", + "test_statistics.h", + ] + + if (proprietary_codecs) { + sources += [ "media_codec_player_unittest.cc" ] + } + + deps = [ + ":android", + "//media/base:test_support", + "//testing/gmock", + "//testing/gtest", + "//third_party/widevine/cdm:version_h", + ] + configs += [ "//media:media_config" ] + } + + generate_jni("media_jni_headers") { + sources = [ + "java/src/org/chromium/media/AudioManagerAndroid.java", + "java/src/org/chromium/media/AudioRecordInput.java", + "java/src/org/chromium/media/MediaCodecBridge.java", + "java/src/org/chromium/media/MediaCodecUtil.java", + "java/src/org/chromium/media/MediaDrmBridge.java", + "java/src/org/chromium/media/MediaPlayerBridge.java", + "java/src/org/chromium/media/MediaPlayerListener.java", + ] + jni_package = "media" + } + + android_library("media_java") { + deps = [ + "//base:base_java", + ] + + java_files = [ + "java/src/org/chromium/media/AudioManagerAndroid.java", + "java/src/org/chromium/media/AudioRecordInput.java", + "java/src/org/chromium/media/MediaCodecBridge.java", + "java/src/org/chromium/media/MediaCodecUtil.java", + "java/src/org/chromium/media/MediaDrmBridge.java", + "java/src/org/chromium/media/MediaPlayerBridge.java", + "java/src/org/chromium/media/MediaPlayerListener.java", + ] + } }
diff --git a/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java b/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java index 8d313c1..a8adcd7 100644 --- a/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java +++ b/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java
@@ -24,7 +24,7 @@ class MediaCodecUtil { private static final String TAG = "MediaCodecUtil"; - // Codec direction. Keep this in sync with media_codec_bridge.h. + // Codec direction. Keep this in sync with media_codec_direction.h. static final int MEDIA_CODEC_DECODER = 0; static final int MEDIA_CODEC_ENCODER = 1;
diff --git a/media/base/android/media_codec_bridge.cc b/media/base/android/media_codec_bridge.cc index c28d460..de8bac3 100644 --- a/media/base/android/media_codec_bridge.cc +++ b/media/base/android/media_codec_bridge.cc
@@ -7,19 +7,9 @@ #include <algorithm> #include <limits> -#include "base/android/build_info.h" -#include "base/android/jni_android.h" -#include "base/android/jni_array.h" -#include "base/android/jni_string.h" #include "base/logging.h" #include "base/strings/string_util.h" -#include "media/base/decrypt_config.h" - -using base::android::AttachCurrentThread; -using base::android::ConvertJavaStringToUTF8; -using base::android::ConvertUTF8ToJavaString; -using base::android::JavaIntArrayToIntVector; -using base::android::ScopedJavaLocalRef; +#include "media/base/subsample_entry.h" namespace media { @@ -39,7 +29,7 @@ const std::vector<char> iv_vec(iv.begin(), iv.end()); return QueueSecureInputBuffer(index, data, data_size, key_vec, iv_vec, subsamples.empty() ? nullptr : &subsamples[0], - subsamples.size(), presentation_time); + (int)subsamples.size(), presentation_time); } MediaCodecStatus MediaCodecBridge::CopyFromOutputBuffer(int index,
diff --git a/media/base/android/media_codec_bridge.h b/media/base/android/media_codec_bridge.h index 49a76c89..34c0823 100644 --- a/media/base/android/media_codec_bridge.h +++ b/media/base/android/media_codec_bridge.h
@@ -15,7 +15,7 @@ #include "base/compiler_specific.h" #include "base/macros.h" #include "base/time/time.h" -#include "media/base/android/media_codec_util.h" +#include "media/base/android/media_codec_direction.h" #include "media/base/media_export.h" #include "ui/gfx/geometry/size.h"
diff --git a/media/base/android/media_codec_direction.h b/media/base/android/media_codec_direction.h new file mode 100644 index 0000000..8212646 --- /dev/null +++ b/media/base/android/media_codec_direction.h
@@ -0,0 +1,18 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_BASE_ANDROID_MEDIA_CODEC_DIRECTION_H_ +#define MEDIA_BASE_ANDROID_MEDIA_CODEC_DIRECTION_H_ + +namespace media { + +// Codec direction. Keep this in sync with MediaCodecUtil.java. +enum MediaCodecDirection { + MEDIA_CODEC_DECODER, + MEDIA_CODEC_ENCODER, +}; + +} // namespace media + +#endif // MEDIA_BASE_ANDROID_MEDIA_CODEC_DIRECTION_H_
diff --git a/media/base/android/media_codec_loop.cc b/media/base/android/media_codec_loop.cc index 96c5251..1c6ce5e5 100644 --- a/media/base/android/media_codec_loop.cc +++ b/media/base/android/media_codec_loop.cc
@@ -4,29 +4,29 @@ #include "media/base/android/media_codec_loop.h" -#include "base/android/build_info.h" #include "base/bind.h" #include "base/callback_helpers.h" #include "base/logging.h" -#include "base/threading/thread_task_runner_handle.h" -#include "media/base/android/sdk_media_codec_bridge.h" -#include "media/base/audio_buffer.h" -#include "media/base/audio_timestamp_helper.h" #include "media/base/bind_to_current_loop.h" #include "media/base/timestamp_constants.h" namespace media { -constexpr base::TimeDelta kDecodePollDelay = - base::TimeDelta::FromMilliseconds(10); -constexpr base::TimeDelta kNoWaitTimeout = base::TimeDelta::FromMicroseconds(0); -constexpr base::TimeDelta kIdleTimerTimeout = base::TimeDelta::FromSeconds(1); +// Declaring these as constexpr variables doesn't work in windows -- they +// always are 0. The exception is FromMicroseconds, which doesn't do any +// conversion. However, declaring these as constexpr functions seesm to work +// fine everywhere. We care that this works in windows because our unit tests +// run on non-android platforms. +constexpr base::TimeDelta DecodePollDelay() { + return base::TimeDelta::FromMilliseconds(10); +} -static inline bool codec_flush_requires_destruction() { - // Return true if and only if Flush() isn't supported / doesn't work. - // Prior to JellyBean-MR2, flush() had several bugs (b/8125974, b/8347958) so - // we have to completely destroy and recreate the codec there. - return base::android::BuildInfo::GetInstance()->sdk_int() < 18; +constexpr base::TimeDelta NoWaitTimeout() { + return base::TimeDelta::FromMicroseconds(0); +} + +constexpr base::TimeDelta IdleTimerTimeout() { + return base::TimeDelta::FromSeconds(1); } MediaCodecLoop::InputData::InputData() {} @@ -43,13 +43,19 @@ MediaCodecLoop::InputData::~InputData() {} -MediaCodecLoop::MediaCodecLoop(Client* client, - std::unique_ptr<MediaCodecBridge> media_codec) +MediaCodecLoop::MediaCodecLoop( + int sdk_int, + Client* client, + std::unique_ptr<MediaCodecBridge> media_codec, + scoped_refptr<base::SingleThreadTaskRunner> task_runner) : state_(STATE_READY), client_(client), media_codec_(std::move(media_codec)), pending_input_buf_index_(kInvalidBufferIndex), + sdk_int_(sdk_int), weak_factory_(this) { + if (task_runner) + io_timer_.SetTaskRunner(task_runner); // TODO(liberato): should this DCHECK? if (media_codec_ == nullptr) SetState(STATE_ERROR); @@ -59,6 +65,10 @@ io_timer_.Stop(); } +void MediaCodecLoop::SetTestTickClock(base::TickClock* test_tick_clock) { + test_tick_clock_ = test_tick_clock; +} + void MediaCodecLoop::OnKeyAdded() { if (state_ == STATE_WAITING_FOR_KEY) SetState(STATE_READY); @@ -76,7 +86,7 @@ if (state_ == STATE_ERROR || state_ == STATE_DRAINED) return false; - if (codec_flush_requires_destruction()) + if (CodecNeedsFlushWorkaround()) return false; // Actually try to flush! @@ -147,7 +157,7 @@ int input_buf_index = kInvalidBufferIndex; media::MediaCodecStatus status = - media_codec_->DequeueInputBuffer(kNoWaitTimeout, &input_buf_index); + media_codec_->DequeueInputBuffer(NoWaitTimeout(), &input_buf_index); switch (status) { case media::MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER: break; @@ -249,8 +259,8 @@ OutputBuffer out; MediaCodecStatus status = media_codec_->DequeueOutputBuffer( - kNoWaitTimeout, &out.index, &out.offset, &out.size, &out.pts, &out.is_eos, - &out.is_key_frame); + NoWaitTimeout(), &out.index, &out.offset, &out.size, &out.pts, + &out.is_eos, &out.is_key_frame); bool did_work = false; switch (status) { @@ -310,17 +320,19 @@ void MediaCodecLoop::ManageTimer(bool did_work) { bool should_be_running = true; - base::TimeTicks now = base::TimeTicks::Now(); + // One might also use DefaultTickClock, but then ownership becomes harder. + base::TimeTicks now = (test_tick_clock_ ? test_tick_clock_->NowTicks() + : base::TimeTicks::Now()); if (did_work || idle_time_begin_ == base::TimeTicks()) { idle_time_begin_ = now; } else { // Make sure that we have done work recently enough, else stop the timer. - if (now - idle_time_begin_ > kIdleTimerTimeout) + if (now - idle_time_begin_ > IdleTimerTimeout()) should_be_running = false; } if (should_be_running && !io_timer_.IsRunning()) { - io_timer_.Start(FROM_HERE, kDecodePollDelay, this, + io_timer_.Start(FROM_HERE, DecodePollDelay(), this, &MediaCodecLoop::DoPendingWork); } else if (!should_be_running && io_timer_.IsRunning()) { io_timer_.Stop(); @@ -338,6 +350,15 @@ return media_codec_.get(); } +bool MediaCodecLoop::CodecNeedsFlushWorkaround() const { + // Return true if and only if Flush() isn't supported / doesn't work. + // Prior to JellyBean-MR2, flush() had several bugs (b/8125974, b/8347958) so + // we have to completely destroy and recreate the codec there. + // TODO(liberato): MediaCodecUtil implements the same function. We should + // call that one, except that it doesn't compile outside of android right now. + return sdk_int_ < 18; +} + // static const char* MediaCodecLoop::AsString(State state) { #define RETURN_STRING(x) \
diff --git a/media/base/android/media_codec_loop.h b/media/base/android/media_codec_loop.h index 8d257dea..6413698 100644 --- a/media/base/android/media_codec_loop.h +++ b/media/base/android/media_codec_loop.h
@@ -12,12 +12,13 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" +#include "base/time/tick_clock.h" #include "base/time/time.h" #include "base/timer/timer.h" #include "media/base/android/media_codec_bridge.h" -#include "media/base/audio_decoder.h" -#include "media/base/audio_decoder_config.h" +#include "media/base/decode_status.h" #include "media/base/media_export.h" +#include "media/base/subsample_entry.h" // MediaCodecLoop is based on Android's MediaCodec API. // The MediaCodec API is required to play encrypted (as in EME) content on @@ -197,9 +198,20 @@ // We will take ownership of |media_codec|. We will not destroy it until // we are destructed. |media_codec| may not be null. - MediaCodecLoop(Client* client, std::unique_ptr<MediaCodecBridge> media_codec); + // |sdk_level| is temporary. It is used only to decouple MediaCodecLoop from + // BuildInfo, until we get BuildInfo into a mockable state. + MediaCodecLoop(int sdk_level, + Client* client, + std::unique_ptr<MediaCodecBridge> media_codec, + scoped_refptr<base::SingleThreadTaskRunner> = + scoped_refptr<base::SingleThreadTaskRunner>()); ~MediaCodecLoop(); + // Optionally set the tick clock used for testing. It is our caller's + // responsibility to maintain ownership of this, since + // FakeSingleThreadTaskRunner maintains a raw ptr to it also. + void SetTestTickClock(base::TickClock* test_tick_clock); + // Does the MediaCodec processing cycle: enqueues an input buffer, then // dequeues output buffers. This should be called by the client when more // work becomes available, such as when new input data arrives. If codec @@ -271,13 +283,12 @@ // Helper method to change the state. void SetState(State new_state); + // Helper method to tell us if MediaCodecBridge::Flush() doesn't work. + bool CodecNeedsFlushWorkaround() const; + // A helper function for logging. static const char* AsString(State state); - // Used to post tasks. This class is single threaded and every method should - // run on this task runner. - scoped_refptr<base::SingleThreadTaskRunner> task_runner_; - State state_; // The client that we notify about MediaCodec events. @@ -301,6 +312,13 @@ // to us by the client. |memory| has been cleared, since the codec has it. InputData pending_input_buf_data_; + // Optional clock for use during testing. It may be null. We do not maintain + // ownership of it. + base::TickClock* test_tick_clock_ = nullptr; + + // BuildInfo::sdk_int(), eventually. + const int sdk_int_; + // NOTE: Weak pointers must be invalidated before all other member variables. base::WeakPtrFactory<MediaCodecLoop> weak_factory_;
diff --git a/media/base/android/media_codec_loop_unittest.cc b/media/base/android/media_codec_loop_unittest.cc index 2b08fe0e..fa9044e7 100644 --- a/media/base/android/media_codec_loop_unittest.cc +++ b/media/base/android/media_codec_loop_unittest.cc
@@ -6,12 +6,33 @@ #include "base/message_loop/message_loop.h" #include "media/base/android/media_codec_bridge.h" #include "media/base/android/media_codec_loop.h" +#include "media/base/android/mock_media_codec_bridge.h" +#include "media/base/fake_single_thread_task_runner.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +using ::testing::_; +using ::testing::AtLeast; +using ::testing::Eq; +using ::testing::Field; +using ::testing::InSequence; +using ::testing::Mock; +using ::testing::Return; +using ::testing::SetArgPointee; +using ::testing::StrictMock; + namespace media { -class MockMediaCodecLoopClient : public MediaCodecLoop::Client { +// These will come from mockable BuildInfo, once it exists. +enum TemporaryAndroidVersions { + kJellyBeanMR1 = 17, + kJellyBeanMR2 = 18, + kLollipop = 21, +}; + +// The client is a strict mock, since we don't want random calls into it. We +// want to be sure about the call sequence. +class MockMediaCodecLoopClient : public StrictMock<MediaCodecLoop::Client> { public: MOCK_CONST_METHOD0(IsAnyInputPending, bool()); MOCK_METHOD0(ProvideInputData, MediaCodecLoop::InputData()); @@ -24,11 +45,149 @@ class MediaCodecLoopTest : public testing::Test { public: - MediaCodecLoopTest() : client_(new MockMediaCodecLoopClient) {} + MediaCodecLoopTest() + : client_(new StrictMock<MockMediaCodecLoopClient>()), + task_runner_(new FakeSingleThreadTaskRunner(&clock_)) {} + + ~MediaCodecLoopTest() override {} + + protected: + enum IdleExpectation { + ShouldBeIdle, + ShouldNotBeIdle, + }; + + // Wait until |codec_loop_| is idle. + // Do not call this in a sequence. + void WaitUntilIdle(IdleExpectation idleExpectation = ShouldBeIdle) { + switch (idleExpectation) { + case ShouldBeIdle: + EXPECT_CALL(*client_, IsAnyInputPending()).Times(0); + EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _)).Times(0); + break; + case ShouldNotBeIdle: + // Expect at least one call to see if more work is ready. We will + // return 'no'. + EXPECT_CALL(*client_, IsAnyInputPending()) + .Times(AtLeast(1)) + .WillRepeatedly(Return(false)); + EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _)) + .Times(AtLeast(1)) + .WillRepeatedly(Return(MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER)); + break; + } + + // Either way, we expect that MCL should not attempt to dequeue input + // buffers, either because it's idle or because we said that no input + // is pending. + EXPECT_CALL(Codec(), DequeueInputBuffer(_, _)).Times(0); + + // TODO(liberato): assume that MCL doesn't retry for 30 seconds. Note + // that this doesn't actually wall-clock wait. + task_runner_->Sleep(base::TimeDelta::FromSeconds(30)); + } + + void ConstructCodecLoop(int sdk_int = kLollipop) { + std::unique_ptr<MediaCodecBridge> codec(new MockMediaCodecBridge()); + // Since we're providing a codec, we do not expect an error. + EXPECT_CALL(*client_, OnCodecLoopError()).Times(0); + codec_loop_.reset(new MediaCodecLoop(sdk_int, client_.get(), + std::move(codec), task_runner_)); + codec_loop_->SetTestTickClock(&clock_); + Mock::VerifyAndClearExpectations(client_.get()); + } + + // Set an expectation that MCL will try to get another input / output buffer, + // and not get one in DoPendingWork. + void ExpectEmptyIOLoop() { + ExpectIsAnyInputPending(false); + EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _)) + .Times(1) + .WillOnce(Return(MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER)); + } + + void ExpectIsAnyInputPending(bool pending) { + EXPECT_CALL(*client_, IsAnyInputPending()).WillOnce(Return(pending)); + } + + void ExpectDequeueInputBuffer(int input_buffer_index, + MediaCodecStatus status = MEDIA_CODEC_OK) { + EXPECT_CALL(Codec(), DequeueInputBuffer(_, _)) + .WillOnce(DoAll(SetArgPointee<1>(input_buffer_index), Return(status))); + } + + void ExpectInputDataQueued(bool success) { + EXPECT_CALL(*client_, OnInputDataQueued(success)).Times(1); + } + + // Expect a call to queue |data| into MC buffer |input_buffer_index|. + void ExpectQueueInputBuffer(int input_buffer_index, + const MediaCodecLoop::InputData& data, + MediaCodecStatus status = MEDIA_CODEC_OK) { + EXPECT_CALL(Codec(), QueueInputBuffer(input_buffer_index, data.memory, + data.length, data.presentation_time)) + .Times(1) + .WillOnce(Return(status)); + } + + void ExpectProvideInputData(const MediaCodecLoop::InputData& data) { + EXPECT_CALL(*client_, ProvideInputData()).WillOnce(Return(data)); + } + + MediaCodecLoop::InputData BigBuckBunny() { + MediaCodecLoop::InputData data; + data.memory = reinterpret_cast<const uint8_t*>("big buck bunny"); + data.length = 14; + data.presentation_time = base::TimeDelta::FromSeconds(1); + return data; + } + + struct OutputBuffer { + int index = 1; + size_t offset = 0; + size_t size = 1024; + base::TimeDelta pts = base::TimeDelta::FromSeconds(1); + bool eos = false; + bool key_frame = true; + }; + + struct EosOutputBuffer : public OutputBuffer { + EosOutputBuffer() { eos = true; } + }; + + void ExpectDequeueOutputBuffer(MediaCodecStatus status) { + EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _)) + .WillOnce(Return(status)); + } + + void ExpectDequeueOutputBuffer(const OutputBuffer& buffer) { + EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _)) + .WillOnce(DoAll( + SetArgPointee<1>(buffer.index), SetArgPointee<2>(buffer.offset), + SetArgPointee<3>(buffer.size), SetArgPointee<4>(buffer.pts), + SetArgPointee<5>(buffer.eos), SetArgPointee<6>(buffer.key_frame), + Return(MEDIA_CODEC_OK))); + } + + void ExpectOnDecodedFrame(const OutputBuffer& buf) { + EXPECT_CALL(*client_, + OnDecodedFrame( + Field(&MediaCodecLoop::OutputBuffer::index, Eq(buf.index)))) + .Times(1) + .WillOnce(Return(true)); + } + + MockMediaCodecBridge& Codec() { + return *static_cast<MockMediaCodecBridge*>(codec_loop_->GetCodec()); + } public: std::unique_ptr<MediaCodecLoop> codec_loop_; std::unique_ptr<MockMediaCodecLoopClient> client_; + // TODO: how is the lifecycle of |clock_| handled? |task_runner_| can outlive + // us, since it's a refptr. + base::SimpleTestTickClock clock_; + scoped_refptr<FakeSingleThreadTaskRunner> task_runner_; DISALLOW_COPY_AND_ASSIGN(MediaCodecLoopTest); }; @@ -36,9 +195,272 @@ TEST_F(MediaCodecLoopTest, TestConstructionWithNullCodec) { std::unique_ptr<MediaCodecBridge> codec; EXPECT_CALL(*client_, OnCodecLoopError()).Times(1); - codec_loop_.reset(new MediaCodecLoop(client_.get(), std::move(codec))); + const int sdk_int = kLollipop; + codec_loop_.reset( + new MediaCodecLoop(sdk_int, client_.get(), std::move(codec))); + // Do not WaitUntilIdle() here, since that assumes that we have a codec. ASSERT_FALSE(codec_loop_->GetCodec()); } +TEST_F(MediaCodecLoopTest, TestConstructionWithCodec) { + ConstructCodecLoop(); + ASSERT_EQ(codec_loop_->GetCodec(), &Codec()); + WaitUntilIdle(ShouldBeIdle); +} + +TEST_F(MediaCodecLoopTest, TestPendingWorkWithoutInput) { + ConstructCodecLoop(); + // MCL should try ask if there is pending input, and try to dequeue output. + ExpectIsAnyInputPending(false); + EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _)) + .Times(1) + .WillOnce(Return(MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER)); + codec_loop_->DoPendingWork(); + WaitUntilIdle(ShouldNotBeIdle); +} + +TEST_F(MediaCodecLoopTest, TestPendingWorkWithInput) { + ConstructCodecLoop(); + // MCL should try ask if there is pending input, and try to dequeue both an + // output and input buffer. + ExpectIsAnyInputPending(true); + EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _)).Times(1); + EXPECT_CALL(Codec(), DequeueInputBuffer(_, _)).Times(1); + codec_loop_->DoPendingWork(); + WaitUntilIdle(ShouldNotBeIdle); +} + +TEST_F(MediaCodecLoopTest, TestPendingWorkWithOutputBuffer) { + ConstructCodecLoop(); + { + InSequence _s; + + // MCL will first request input, then try to dequeue output. + ExpectIsAnyInputPending(false); + OutputBuffer buf; + ExpectDequeueOutputBuffer(buf); + ExpectOnDecodedFrame(buf); + + // MCL will try again for another set of buffers before DoPendingWork() + // returns. This is why we don't just leave them for WaitUntilIdle(). + ExpectEmptyIOLoop(); + } + codec_loop_->DoPendingWork(); + WaitUntilIdle(ShouldNotBeIdle); +} + +TEST_F(MediaCodecLoopTest, TestQueueEos) { + // Test sending an EOS to MCL => MCB =dequeue output=> MCL . + ConstructCodecLoop(); + { + InSequence _s; + + ExpectIsAnyInputPending(true); + int input_buffer_index = 123; + ExpectDequeueInputBuffer(input_buffer_index); + + MediaCodecLoop::InputData data; + data.is_eos = true; + ExpectProvideInputData(data); + EXPECT_CALL(Codec(), QueueEOS(input_buffer_index)); + ExpectInputDataQueued(true); + + // Now send the EOS back on the output queue. + EosOutputBuffer eos; + ExpectDequeueOutputBuffer(eos); + EXPECT_CALL(Codec(), ReleaseOutputBuffer(eos.index, false)); + EXPECT_CALL(*client_, OnDecodedEos(_)).Times(1); + + // See TestUnqueuedEos. + EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _)) + .Times(1) + .WillOnce(Return(MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER)); + } + codec_loop_->DoPendingWork(); + // Don't WaitUntilIdle() here. See TestUnqueuedEos. +} + +TEST_F(MediaCodecLoopTest, TestQueueInputData) { + // Send a buffer full of data into MCL and make sure that it gets queued with + // MediaCodecBridge correctly. + ConstructCodecLoop(); + { + InSequence _s; + + ExpectIsAnyInputPending(true); + int input_buffer_index = 123; + ExpectDequeueInputBuffer(input_buffer_index); + + MediaCodecLoop::InputData data = BigBuckBunny(); + ExpectProvideInputData(data); + + // MCL should send the buffer into MediaCodec and notify the client. + ExpectQueueInputBuffer(input_buffer_index, data); + ExpectInputDataQueued(true); + + // MCL will try to dequeue an output buffer too. + EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _)) + .Times(1) + .WillOnce(Return(MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER)); + + // DoPendingWork will try again. + ExpectEmptyIOLoop(); + } + codec_loop_->DoPendingWork(); + WaitUntilIdle(ShouldNotBeIdle); +} + +TEST_F(MediaCodecLoopTest, TestQueueInputDataFails) { + // Send a buffer full of data into MCL, but MediaCodecBridge fails to queue + // it successfully. + ConstructCodecLoop(); + { + InSequence _s; + + ExpectIsAnyInputPending(true); + int input_buffer_index = 123; + ExpectDequeueInputBuffer(input_buffer_index); + + MediaCodecLoop::InputData data = BigBuckBunny(); + ExpectProvideInputData(data); + + // MCL should send the buffer into MediaCodec and notify the client. + ExpectQueueInputBuffer(input_buffer_index, data, MEDIA_CODEC_ERROR); + ExpectInputDataQueued(false); + EXPECT_CALL(*client_, OnCodecLoopError()).Times(1); + } + codec_loop_->DoPendingWork(); + // MCL is now in the error state. +} + +TEST_F(MediaCodecLoopTest, TestQueueInputDataTryAgain) { + // Signal that there is input pending, but don't provide an input buffer. + ConstructCodecLoop(); + { + InSequence _s; + + ExpectIsAnyInputPending(true); + ExpectDequeueInputBuffer(-1, MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER); + // MCL will try for output too. + ExpectDequeueOutputBuffer(MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER); + } + codec_loop_->DoPendingWork(); + // Note that the client might not be allowed to change from "input pending" + // to "no input pending" without actually being asked for input. For now, + // MCL doesn't assume this. + WaitUntilIdle(ShouldNotBeIdle); +} + +TEST_F(MediaCodecLoopTest, TestSeveralPendingIOBuffers) { + // Provide several input and output buffers to MCL. + ConstructCodecLoop(); + int input_buffer_index = 123; + const int num_loops = 4; + + InSequence _s; + for (int i = 0; i < num_loops; i++, input_buffer_index++) { + ExpectIsAnyInputPending(true); + ExpectDequeueInputBuffer(input_buffer_index); + + MediaCodecLoop::InputData data = BigBuckBunny(); + ExpectProvideInputData(data); + + ExpectQueueInputBuffer(input_buffer_index, data); + ExpectInputDataQueued(true); + + OutputBuffer buffer; + buffer.index = i; + buffer.size += i; + buffer.pts = base::TimeDelta::FromSeconds(i + 1); + ExpectDequeueOutputBuffer(buffer); + ExpectOnDecodedFrame(buffer); + } + + ExpectEmptyIOLoop(); + + codec_loop_->DoPendingWork(); +} + +TEST_F(MediaCodecLoopTest, TestTryFlushOnJellyBeanMR2) { + // On JB MR2+ MCL should be willing to use MediaCodecBridge::Flush. + ConstructCodecLoop(kJellyBeanMR2); + EXPECT_CALL(Codec(), Flush()).Times(1).WillOnce(Return(MEDIA_CODEC_OK)); + ASSERT_TRUE(codec_loop_->TryFlush()); +} + +TEST_F(MediaCodecLoopTest, TestTryFlushAfterJellyBeanMR2Fails) { + // On JB MR2+, MCL should be willing to use MediaCodecBridge::Flush. Try + // that, but make Flush fail. + ConstructCodecLoop(kJellyBeanMR2); + EXPECT_CALL(Codec(), Flush()).Times(1).WillOnce(Return(MEDIA_CODEC_ERROR)); + EXPECT_CALL(*client_, OnCodecLoopError()).Times(1); + ASSERT_FALSE(codec_loop_->TryFlush()); +} + +TEST_F(MediaCodecLoopTest, TestTryFlushOnJellyBeanMR1) { + // In JB MR1, MCL should not be willing to use MediaCodecBridge::Flush. + ConstructCodecLoop(kJellyBeanMR1); + ASSERT_FALSE(codec_loop_->TryFlush()); +} + +TEST_F(MediaCodecLoopTest, TestOnKeyAdded) { + ConstructCodecLoop(); + + int input_buffer_index = 123; + MediaCodecLoop::InputData data = BigBuckBunny(); + + // First provide input, but have MediaCodecBridge require a key. + { + InSequence _s; + + // First DoPendingWork() + ExpectIsAnyInputPending(true); + ExpectDequeueInputBuffer(input_buffer_index); + + ExpectProvideInputData(data); + + // Notify MCL that it's missing the key. + ExpectQueueInputBuffer(input_buffer_index, data, MEDIA_CODEC_NO_KEY); + + // MCL should now try for output buffers. + ExpectDequeueOutputBuffer(MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER); + + // MCL will try again, since trying to queue the input buffer is considered + // doing work, for some reason. It would be nice to make this optional. + // Note that it should not ask us for more input, since it has not yet sent + // the buffer we just provided. + ExpectDequeueOutputBuffer(MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER); + } + codec_loop_->DoPendingWork(); + + // Try again, to be sure that MCL doesn't request more input. Note that this + // is also done in the above loop, but that one could be made optional. This + // forces MCL to try again as part of an entirely new DoPendingWork cycle. + { + InSequence _s; + // MCL should only try for output buffers, since it's still waiting for a + // key to be added. + ExpectDequeueOutputBuffer(MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER); + } + codec_loop_->DoPendingWork(); + + // When we add the key, MCL will DoPending work again. This time, it should + // succeed since the key has been added. + { + InSequence _s; + // MCL should not retain the original pointer. + data.memory = nullptr; + ExpectQueueInputBuffer(input_buffer_index, data); + ExpectInputDataQueued(true); + ExpectDequeueOutputBuffer(MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER); + + // MCL did work, so it will try again. + ExpectEmptyIOLoop(); + } + + codec_loop_->OnKeyAdded(); + WaitUntilIdle(ShouldNotBeIdle); +} + } // namespace media
diff --git a/media/base/android/media_codec_util.h b/media/base/android/media_codec_util.h index 238308b..09e5ac84d1 100644 --- a/media/base/android/media_codec_util.h +++ b/media/base/android/media_codec_util.h
@@ -12,6 +12,7 @@ #include "base/compiler_specific.h" #include "base/macros.h" +#include "media/base/android/media_codec_direction.h" #include "media/base/media_export.h" class GURL; @@ -38,12 +39,6 @@ } \ } while (0) -// Codec direction. Keep this in sync with MediaCodecUtil.java. -enum MediaCodecDirection { - MEDIA_CODEC_DECODER, - MEDIA_CODEC_ENCODER, -}; - class MEDIA_EXPORT MediaCodecUtil { public: // Returns true if MediaCodec is available on the device.
diff --git a/media/base/android/mock_media_codec_bridge.cc b/media/base/android/mock_media_codec_bridge.cc new file mode 100644 index 0000000..50ef75d8 --- /dev/null +++ b/media/base/android/mock_media_codec_bridge.cc
@@ -0,0 +1,23 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/base/android/mock_media_codec_bridge.h" + +#include "media/base/subsample_entry.h" + +using ::testing::_; +using ::testing::Return; + +namespace media { + +MockMediaCodecBridge::MockMediaCodecBridge() { + ON_CALL(*this, DequeueInputBuffer(_, _)) + .WillByDefault(Return(MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER)); + ON_CALL(*this, DequeueOutputBuffer(_, _, _, _, _, _, _)) + .WillByDefault(Return(MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER)); +} + +MockMediaCodecBridge::~MockMediaCodecBridge() {} + +} // namespace media
diff --git a/media/base/android/mock_media_codec_bridge.h b/media/base/android/mock_media_codec_bridge.h new file mode 100644 index 0000000..dfb52233 --- /dev/null +++ b/media/base/android/mock_media_codec_bridge.h
@@ -0,0 +1,65 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_BASE_ANDROID_MOCK_MEDIA_CODEC_BRIDGE_H_ +#define MEDIA_BASE_ANDROID_MOCK_MEDIA_CODEC_BRIDGE_H_ + +#include "media/base/android/media_codec_bridge.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace media { + +class MockMediaCodecBridge : public MediaCodecBridge { + public: + MockMediaCodecBridge(); + ~MockMediaCodecBridge(); + + MOCK_METHOD0(Start, bool()); + MOCK_METHOD0(Stop, void()); + MOCK_METHOD0(Flush, MediaCodecStatus()); + MOCK_METHOD1(GetOutputSize, MediaCodecStatus(gfx::Size*)); + MOCK_METHOD1(GetOutputSamplingRate, MediaCodecStatus(int*)); + MOCK_METHOD1(GetOutputChannelCount, MediaCodecStatus(int*)); + MOCK_METHOD4(QueueInputBuffer, + MediaCodecStatus(int, const uint8_t*, size_t, base::TimeDelta)); + MOCK_METHOD7(QueueSecureInputBuffer, + MediaCodecStatus(int, + const uint8_t*, + size_t, + const std::string&, + const std::string&, + const std::vector<SubsampleEntry>&, + base::TimeDelta)); + MOCK_METHOD8(QueueSecureInputBuffer, + MediaCodecStatus(int, + const uint8_t*, + size_t, + const std::vector<char>&, + const std::vector<char>&, + const SubsampleEntry*, + int, + base::TimeDelta)); + MOCK_METHOD1(QueueEOS, void(int)); + MOCK_METHOD2(DequeueInputBuffer, MediaCodecStatus(base::TimeDelta, int*)); + MOCK_METHOD7(DequeueOutputBuffer, + MediaCodecStatus(base::TimeDelta, + int*, + size_t*, + size_t*, + base::TimeDelta*, + bool*, + bool*)); + MOCK_METHOD2(ReleaseOutputBuffer, void(int, bool)); + MOCK_METHOD3(GetInputBuffer, MediaCodecStatus(int, uint8_t**, size_t*)); + MOCK_METHOD4(GetOutputBufferAddress, + MediaCodecStatus(int, size_t, const uint8_t**, size_t*)); + MOCK_METHOD4(CopyFromOutputBuffer, + MediaCodecStatus(int, size_t, void*, size_t)); + MOCK_METHOD0(GetName, std::string()); +}; + +} // namespace media + +#endif // MEDIA_BASE_ANDROID_MOCK_MEDIA_CODEC_BRIDGE_H_
diff --git a/media/base/android/ndk_media_codec_bridge.cc b/media/base/android/ndk_media_codec_bridge.cc index 2c2e745..b7d7575 100644 --- a/media/base/android/ndk_media_codec_bridge.cc +++ b/media/base/android/ndk_media_codec_bridge.cc
@@ -13,7 +13,7 @@ #include "base/logging.h" #include "base/native_library.h" #include "base/strings/string_util.h" -#include "media/base/decrypt_config.h" +#include "media/base/subsample_entry.h" namespace { const char kMediaFormatKeyCropLeft[] = "crop-left";
diff --git a/media/base/android/sdk_media_codec_bridge.cc b/media/base/android/sdk_media_codec_bridge.cc index 59a4008..a7fe13bb 100644 --- a/media/base/android/sdk_media_codec_bridge.cc +++ b/media/base/android/sdk_media_codec_bridge.cc
@@ -17,8 +17,9 @@ #include "base/numerics/safe_conversions.h" #include "base/strings/string_util.h" #include "jni/MediaCodecBridge_jni.h" +#include "media/base/android/media_codec_util.h" #include "media/base/bit_reader.h" -#include "media/base/decrypt_config.h" +#include "media/base/subsample_entry.h" using base::android::AttachCurrentThread; using base::android::ConvertJavaStringToUTF8;
diff --git a/media/base/decrypt_config.h b/media/base/decrypt_config.h index 5ce28655..e025d0f4 100644 --- a/media/base/decrypt_config.h +++ b/media/base/decrypt_config.h
@@ -13,26 +13,10 @@ #include "base/macros.h" #include "media/base/media_export.h" +#include "media/base/subsample_entry.h" namespace media { -// The Common Encryption spec provides for subsample encryption, where portions -// of a sample are set in cleartext. A SubsampleEntry specifies the number of -// clear and encrypted bytes in each subsample. For decryption, all of the -// encrypted bytes in a sample should be considered a single logical stream, -// regardless of how they are divided into subsamples, and the clear bytes -// should not be considered as part of decryption. This is logically equivalent -// to concatenating all 'cypher_bytes' portions of subsamples, decrypting that -// result, and then copying each byte from the decrypted block over the -// position of the corresponding encrypted byte. -struct SubsampleEntry { - SubsampleEntry() : clear_bytes(0), cypher_bytes(0) {} - SubsampleEntry(uint32_t clear_bytes, uint32_t cypher_bytes) - : clear_bytes(clear_bytes), cypher_bytes(cypher_bytes) {} - uint32_t clear_bytes; - uint32_t cypher_bytes; -}; - // Contains all information that a decryptor needs to decrypt a media sample. class MEDIA_EXPORT DecryptConfig { public:
diff --git a/media/base/subsample_entry.h b/media/base/subsample_entry.h new file mode 100644 index 0000000..07c5eee --- /dev/null +++ b/media/base/subsample_entry.h
@@ -0,0 +1,31 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_BASE_SUBSAMPLE_ENTRY_H_ +#define MEDIA_BASE_SUBSAMPLE_ENTRY_H_ + +#include <stdint.h> + +namespace media { + +// The Common Encryption spec provides for subsample encryption, where portions +// of a sample are set in cleartext. A SubsampleEntry specifies the number of +// clear and encrypted bytes in each subsample. For decryption, all of the +// encrypted bytes in a sample should be considered a single logical stream, +// regardless of how they are divided into subsamples, and the clear bytes +// should not be considered as part of decryption. This is logically equivalent +// to concatenating all 'cypher_bytes' portions of subsamples, decrypting that +// result, and then copying each byte from the decrypted block over the +// position of the corresponding encrypted byte. +struct SubsampleEntry { + SubsampleEntry() : clear_bytes(0), cypher_bytes(0) {} + SubsampleEntry(uint32_t clear_bytes, uint32_t cypher_bytes) + : clear_bytes(clear_bytes), cypher_bytes(cypher_bytes) {} + uint32_t clear_bytes; + uint32_t cypher_bytes; +}; + +} // namespace media + +#endif // MEDIA_BASE_SUBSAMPLE_ENTRY_H_
diff --git a/media/blink/BUILD.gn b/media/blink/BUILD.gn index ca30cd4..7de5285 100644 --- a/media/blink/BUILD.gn +++ b/media/blink/BUILD.gn
@@ -107,8 +107,6 @@ "//base/test:test_support", "//cc", "//cc/blink", - "//components/scheduler:scheduler", - "//components/scheduler:test_support", "//gin", "//media", "//media:shared_memory_support", @@ -117,6 +115,7 @@ "//testing/gmock", "//testing/gtest", "//third_party/WebKit/public:blink", + "//third_party/WebKit/public:test_support", "//ui/gfx:test_support", "//ui/gfx/geometry", "//url",
diff --git a/media/blink/media_blink.gyp b/media/blink/media_blink.gyp index a00b1f1..0d56a8e4 100644 --- a/media/blink/media_blink.gyp +++ b/media/blink/media_blink.gyp
@@ -115,13 +115,12 @@ '../../base/base.gyp:test_support_base', '../../cc/cc.gyp:cc', '../../cc/blink/cc_blink.gyp:cc_blink', - '../../components/scheduler/scheduler.gyp:scheduler', - '../../components/scheduler/scheduler.gyp:scheduler_test_support', '../../gin/gin.gyp:gin', '../../net/net.gyp:net', '../../testing/gmock.gyp:gmock', '../../testing/gtest.gyp:gtest', '../../third_party/WebKit/public/blink.gyp:blink', + '../../third_party/WebKit/public/blink.gyp:blink_test_support', '../../ui/gfx/gfx.gyp:gfx', '../../ui/gfx/gfx.gyp:gfx_geometry', '../../ui/gfx/gfx.gyp:gfx_test_support',
diff --git a/media/blink/run_all_unittests.cc b/media/blink/run_all_unittests.cc index 1694d74d..5b0b6df4 100644 --- a/media/blink/run_all_unittests.cc +++ b/media/blink/run_all_unittests.cc
@@ -9,16 +9,10 @@ #include "base/test/launcher/unit_test_launcher.h" #include "base/test/test_suite.h" #include "build/build_config.h" -#include "components/scheduler/child/scheduler_tqm_delegate_impl.h" -#include "components/scheduler/child/web_task_runner_impl.h" -#include "components/scheduler/renderer/renderer_scheduler_impl.h" -#include "components/scheduler/renderer/renderer_web_scheduler_impl.h" -#include "components/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.h" #include "media/base/media.h" #include "testing/gtest/include/gtest/gtest.h" -#include "third_party/WebKit/public/platform/WebScheduler.h" -#include "third_party/WebKit/public/platform/WebTaskRunner.h" -#include "third_party/WebKit/public/platform/WebThread.h" +#include "third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h" +#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h" #include "third_party/WebKit/public/web/WebKit.h" #if defined(OS_ANDROID) @@ -30,53 +24,27 @@ #include "gin/v8_initializer.h" #endif -class CurrentThreadMock : public blink::WebThread { +class TestBlinkPlatformSupport : public blink::Platform { public: - CurrentThreadMock() - : task_runner_delegate_( - scheduler::LazySchedulerMessageLoopDelegateForTests::Create()), - scheduler_( - new scheduler::RendererSchedulerImpl(task_runner_delegate_.get())), - web_scheduler_( - new scheduler::RendererWebSchedulerImpl(scheduler_.get())), - web_task_runner_( - new scheduler::WebTaskRunnerImpl(scheduler_->DefaultTaskRunner())) { - } - - ~CurrentThreadMock() override { - scheduler_->Shutdown(); - } - - blink::WebTaskRunner* getWebTaskRunner() override { - return web_task_runner_.get(); - } - - bool isCurrentThread() const override { return true; } - - blink::PlatformThreadId threadId() const override { return 17; } - - blink::WebScheduler* scheduler() const override { - return web_scheduler_.get(); - } - - private: - scoped_refptr<scheduler::SchedulerTqmDelegate> task_runner_delegate_; - std::unique_ptr<scheduler::RendererSchedulerImpl> scheduler_; - std::unique_ptr<blink::WebScheduler> web_scheduler_; - std::unique_ptr<blink::WebTaskRunner> web_task_runner_; -}; - -class TestBlinkPlatformSupport : NON_EXPORTED_BASE(public blink::Platform) { - public: + TestBlinkPlatformSupport() + : renderer_scheduler_( + blink::scheduler::CreateRendererSchedulerForTests()), + main_thread_(renderer_scheduler_->CreateMainThread()) {} ~TestBlinkPlatformSupport() override; - blink::WebThread* currentThread() override { return &m_currentThread; } + blink::WebThread* currentThread() override { + EXPECT_TRUE(main_thread_->isCurrentThread()); + return main_thread_.get(); + } private: - CurrentThreadMock m_currentThread; + std::unique_ptr<blink::scheduler::RendererScheduler> renderer_scheduler_; + std::unique_ptr<blink::WebThread> main_thread_; }; -TestBlinkPlatformSupport::~TestBlinkPlatformSupport() {} +TestBlinkPlatformSupport::~TestBlinkPlatformSupport() { + renderer_scheduler_->Shutdown(); +} class BlinkMediaTestSuite : public base::TestSuite { public:
diff --git a/media/capture/BUILD.gn b/media/capture/BUILD.gn index 337cd2c..989a550a 100644 --- a/media/capture/BUILD.gn +++ b/media/capture/BUILD.gn
@@ -22,10 +22,6 @@ "content/thread_safe_capture_oracle.h", "content/video_capture_oracle.cc", "content/video_capture_oracle.h", - "device_monitor_mac.h", - "device_monitor_mac.mm", - "system_message_window_win.cc", - "system_message_window_win.h", "video/fake_video_capture_device.cc", "video/fake_video_capture_device.h", "video/fake_video_capture_device_factory.cc", @@ -115,14 +111,6 @@ ] } - if (use_udev) { - deps += [ "//device/udev_linux" ] - sources += [ - "device_monitor_udev.cc", - "device_monitor_udev.h", - ] - } - if (is_win) { deps += [ "//media/base", # For media_switches. @@ -151,7 +139,6 @@ "content/capture_resolution_chooser_unittest.cc", "content/smooth_event_sampler_unittest.cc", "content/video_capture_oracle_unittest.cc", - "system_message_window_win_unittest.cc", "video/fake_video_capture_device_unittest.cc", "video/mac/video_capture_device_factory_mac_unittest.mm", "video/video_capture_device_unittest.cc",
diff --git a/media/capture/device_monitor_mac.h b/media/capture/device_monitor_mac.h deleted file mode 100644 index c6db8b9..0000000 --- a/media/capture/device_monitor_mac.h +++ /dev/null
@@ -1,53 +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. - -#ifndef MEDIA_CAPTURE_DEVICE_MONITOR_MAC_H_ -#define MEDIA_CAPTURE_DEVICE_MONITOR_MAC_H_ - -#include <memory> - -#include "base/macros.h" -#include "base/system_monitor/system_monitor.h" -#include "base/threading/thread_checker.h" -#include "media/capture/capture_export.h" - -namespace { -class DeviceMonitorMacImpl; -} - -namespace media { - -// Class to track audio/video devices removal or addition via callback to -// base::SystemMonitor ProcessDevicesChanged(). A single object of this class -// is created from the browser main process and lives as long as this one. -class CAPTURE_EXPORT DeviceMonitorMac { - public: - DeviceMonitorMac(); - ~DeviceMonitorMac(); - - // Registers the observers for the audio/video device removal, connection and - // suspension. The AVFoundation library is also loaded and initialised if the - // OS supports it. The |device_task_runner| argument represents the thread on - // which device enumeration will occur. - void StartMonitoring( - const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner); - - // Method called by the internal DeviceMonitorMacImpl object - // |device_monitor_impl_| when a device of type |type| has been added to or - // removed from the system. This code executes in the notification thread. - void NotifyDeviceChanged(base::SystemMonitor::DeviceType type); - - private: - std::unique_ptr<DeviceMonitorMacImpl> device_monitor_impl_; - - // |thread_checker_| is used to check that constructor and StartMonitoring() - // are called in the correct thread, the UI thread, that also owns the object. - base::ThreadChecker thread_checker_; - - DISALLOW_COPY_AND_ASSIGN(DeviceMonitorMac); -}; - -} // namespace content - -#endif // MEDIA_CAPTURE_DEVICE_MONITOR_MAC_H_
diff --git a/media/capture/device_monitor_mac.mm b/media/capture/device_monitor_mac.mm deleted file mode 100644 index 2ff63e0a..0000000 --- a/media/capture/device_monitor_mac.mm +++ /dev/null
@@ -1,475 +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 "media/capture/device_monitor_mac.h" - -#include <set> - -#include "base/bind_helpers.h" -#include "base/logging.h" -#include "base/mac/bind_objc_block.h" -#include "base/mac/scoped_nsobject.h" -#include "base/macros.h" -#include "base/profiler/scoped_tracker.h" -#include "base/task_runner_util.h" -#include "base/threading/thread_checker.h" -#import "media/base/mac/avfoundation_glue.h" - -namespace { - -// This class is used to keep track of system devices names and their types. -class DeviceInfo { - public: - enum DeviceType { kAudio, kVideo, kMuxed, kUnknown, kInvalid }; - - DeviceInfo(const std::string& unique_id, DeviceType type) - : unique_id_(unique_id), type_(type) {} - - // Operator== is needed here to use this class in a std::find. A given - // |unique_id_| always has the same |type_| so for comparison purposes the - // latter can be safely ignored. - bool operator==(const DeviceInfo& device) const { - return unique_id_ == device.unique_id_; - } - - const std::string& unique_id() const { return unique_id_; } - DeviceType type() const { return type_; } - - private: - std::string unique_id_; - DeviceType type_; - // Allow generated copy constructor and assignment. -}; - -// Base abstract class used by DeviceMonitorMac. -class DeviceMonitorMacImpl { - public: - explicit DeviceMonitorMacImpl(media::DeviceMonitorMac* monitor) - : monitor_(monitor), - cached_devices_(), - device_arrival_(nil), - device_removal_(nil) { - DCHECK(monitor); - // Initialise the devices_cache_ with a not-valid entry. For the case in - // which there is one single device in the system and we get notified when - // it gets removed, this will prevent the system from thinking that no - // devices were added nor removed and not notifying the |monitor_|. - cached_devices_.push_back(DeviceInfo("invalid", DeviceInfo::kInvalid)); - } - virtual ~DeviceMonitorMacImpl() {} - - virtual void OnDeviceChanged() = 0; - - // Method called by the default notification center when a device is removed - // or added to the system. It will compare the |cached_devices_| with the - // current situation, update it, and, if there's an update, signal to - // |monitor_| with the appropriate device type. - void ConsolidateDevicesListAndNotify( - const std::vector<DeviceInfo>& snapshot_devices); - - protected: - media::DeviceMonitorMac* monitor_; - std::vector<DeviceInfo> cached_devices_; - - // Handles to NSNotificationCenter block observers. - id device_arrival_; - id device_removal_; - - private: - DISALLOW_COPY_AND_ASSIGN(DeviceMonitorMacImpl); -}; - -void DeviceMonitorMacImpl::ConsolidateDevicesListAndNotify( - const std::vector<DeviceInfo>& snapshot_devices) { - bool video_device_added = false; - bool audio_device_added = false; - bool video_device_removed = false; - bool audio_device_removed = false; - - // Compare the current system devices snapshot with the ones cached to detect - // additions, present in the former but not in the latter. If we find a device - // in snapshot_devices entry also present in cached_devices, we remove it from - // the latter vector. - std::vector<DeviceInfo>::const_iterator it; - for (it = snapshot_devices.begin(); it != snapshot_devices.end(); ++it) { - std::vector<DeviceInfo>::iterator cached_devices_iterator = - std::find(cached_devices_.begin(), cached_devices_.end(), *it); - if (cached_devices_iterator == cached_devices_.end()) { - video_device_added |= ((it->type() == DeviceInfo::kVideo) || - (it->type() == DeviceInfo::kMuxed)); - audio_device_added |= ((it->type() == DeviceInfo::kAudio) || - (it->type() == DeviceInfo::kMuxed)); - DVLOG(1) << "Device has been added, id: " << it->unique_id(); - } else { - cached_devices_.erase(cached_devices_iterator); - } - } - // All the remaining entries in cached_devices are removed devices. - for (it = cached_devices_.begin(); it != cached_devices_.end(); ++it) { - video_device_removed |= ((it->type() == DeviceInfo::kVideo) || - (it->type() == DeviceInfo::kMuxed) || - (it->type() == DeviceInfo::kInvalid)); - audio_device_removed |= ((it->type() == DeviceInfo::kAudio) || - (it->type() == DeviceInfo::kMuxed) || - (it->type() == DeviceInfo::kInvalid)); - DVLOG(1) << "Device has been removed, id: " << it->unique_id(); - } - // Update the cached devices with the current system snapshot. - cached_devices_ = snapshot_devices; - - if (video_device_added || video_device_removed) - monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE); - if (audio_device_added || audio_device_removed) - monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE); -} - -// Forward declaration for use by CrAVFoundationDeviceObserver. -class SuspendObserverDelegate; - -} // namespace - -// This class is a Key-Value Observer (KVO) shim. It is needed because C++ -// classes cannot observe Key-Values directly. Created, manipulated, and -// destroyed on the UI Thread by SuspendObserverDelegate. -@interface CrAVFoundationDeviceObserver : NSObject { - @private - // Callback for device changed, has to run on Device Thread. - base::Closure onDeviceChangedCallback_; - - // Member to keep track of the devices we are already monitoring. - std::set<base::scoped_nsobject<CrAVCaptureDevice>> monitoredDevices_; - - // Pegged to the "main" thread -- usually content::BrowserThread::UI. - base::ThreadChecker mainThreadChecker_; -} - -- (id)initWithOnChangedCallback:(const base::Closure&)callback; -- (void)startObserving:(base::scoped_nsobject<CrAVCaptureDevice>)device; -- (void)stopObserving:(CrAVCaptureDevice*)device; -- (void)clearOnDeviceChangedCallback; - -@end - -namespace { - -// This class owns and manages the lifetime of a CrAVFoundationDeviceObserver. -// It is created and destroyed on AVFoundationMonitorImpl's main thread (usually -// browser's UI thread), and it operates on this thread except for the expensive -// device enumerations which are run on Device Thread. -class SuspendObserverDelegate - : public base::RefCountedThreadSafe<SuspendObserverDelegate> { - public: - explicit SuspendObserverDelegate(DeviceMonitorMacImpl* monitor); - - // Create |suspend_observer_| for all devices and register OnDeviceChanged() - // as its change callback. Schedule bottom half in DoStartObserver(). - void StartObserver( - const scoped_refptr<base::SingleThreadTaskRunner>& device_thread); - // Enumerate devices in |device_thread| and run the bottom half in - // DoOnDeviceChange(). |suspend_observer_| calls back here on suspend event, - // and our parent AVFoundationMonitorImpl calls on connect/disconnect device. - void OnDeviceChanged( - const scoped_refptr<base::SingleThreadTaskRunner>& device_thread); - // Remove the device monitor's weak reference. Remove ourselves as suspend - // notification observer from |suspend_observer_|. - void ResetDeviceMonitor(); - - private: - friend class base::RefCountedThreadSafe<SuspendObserverDelegate>; - - virtual ~SuspendObserverDelegate(); - - // Bottom half of StartObserver(), starts |suspend_observer_| for all devices. - // Assumes that |devices| has been retained prior to being called, and - // releases it internally. - void DoStartObserver(NSArray* devices); - // Bottom half of OnDeviceChanged(), starts |suspend_observer_| for current - // devices and composes a snapshot of them to send it to - // |avfoundation_monitor_impl_|. Assumes that |devices| has been retained - // prior to being called, and releases it internally. - void DoOnDeviceChanged(NSArray* devices); - - base::scoped_nsobject<CrAVFoundationDeviceObserver> suspend_observer_; - DeviceMonitorMacImpl* avfoundation_monitor_impl_; - - // Pegged to the "main" thread -- usually content::BrowserThread::UI. - base::ThreadChecker main_thread_checker_; -}; - -SuspendObserverDelegate::SuspendObserverDelegate(DeviceMonitorMacImpl* monitor) - : avfoundation_monitor_impl_(monitor) { - DCHECK(main_thread_checker_.CalledOnValidThread()); -} - -void SuspendObserverDelegate::StartObserver( - const scoped_refptr<base::SingleThreadTaskRunner>& device_thread) { - DCHECK(main_thread_checker_.CalledOnValidThread()); - - base::Closure on_device_changed_callback = base::Bind( - &SuspendObserverDelegate::OnDeviceChanged, this, device_thread); - suspend_observer_.reset([[CrAVFoundationDeviceObserver alloc] - initWithOnChangedCallback:on_device_changed_callback]); - - // Enumerate the devices in Device thread and post the observers start to be - // done on UI thread. The devices array is retained in |device_thread| and - // released in DoStartObserver(). - base::PostTaskAndReplyWithResult( - device_thread.get(), FROM_HERE, base::BindBlock(^{ - return [[AVCaptureDeviceGlue devices] retain]; - }), - base::Bind(&SuspendObserverDelegate::DoStartObserver, this)); -} - -void SuspendObserverDelegate::OnDeviceChanged( - const scoped_refptr<base::SingleThreadTaskRunner>& device_thread) { - DCHECK(main_thread_checker_.CalledOnValidThread()); - // Enumerate the devices in Device thread and post the consolidation of the - // new devices and the old ones to be done on main thread. The devices array - // is retained in |device_thread| and released in DoOnDeviceChanged(). - PostTaskAndReplyWithResult( - device_thread.get(), FROM_HERE, base::BindBlock(^{ - return [[AVCaptureDeviceGlue devices] retain]; - }), - base::Bind(&SuspendObserverDelegate::DoOnDeviceChanged, this)); -} - -void SuspendObserverDelegate::ResetDeviceMonitor() { - DCHECK(main_thread_checker_.CalledOnValidThread()); - avfoundation_monitor_impl_ = NULL; - [suspend_observer_ clearOnDeviceChangedCallback]; -} - -SuspendObserverDelegate::~SuspendObserverDelegate() { - DCHECK(main_thread_checker_.CalledOnValidThread()); -} - -void SuspendObserverDelegate::DoStartObserver(NSArray* devices) { - DCHECK(main_thread_checker_.CalledOnValidThread()); - base::scoped_nsobject<NSArray> auto_release(devices); - for (CrAVCaptureDevice* device in devices) { - base::scoped_nsobject<CrAVCaptureDevice> device_ptr([device retain]); - [suspend_observer_ startObserving:device_ptr]; - } -} - -void SuspendObserverDelegate::DoOnDeviceChanged(NSArray* devices) { - DCHECK(main_thread_checker_.CalledOnValidThread()); - base::scoped_nsobject<NSArray> auto_release(devices); - std::vector<DeviceInfo> snapshot_devices; - for (CrAVCaptureDevice* device in devices) { - base::scoped_nsobject<CrAVCaptureDevice> device_ptr([device retain]); - [suspend_observer_ startObserving:device_ptr]; - - BOOL suspended = [device respondsToSelector:@selector(isSuspended)] && - [device isSuspended]; - DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown; - if ([device hasMediaType:AVFoundationGlue::AVMediaTypeVideo()]) { - if (suspended) - continue; - device_type = DeviceInfo::kVideo; - } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeMuxed()]) { - device_type = suspended ? DeviceInfo::kAudio : DeviceInfo::kMuxed; - } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeAudio()]) { - device_type = DeviceInfo::kAudio; - } - snapshot_devices.push_back( - DeviceInfo([[device uniqueID] UTF8String], device_type)); - } - // Make sure no references are held to |devices| when - // ConsolidateDevicesListAndNotify is called since the VideoCaptureManager - // and AudioCaptureManagers also enumerates the available devices but on - // another thread. - auto_release.reset(); - // |avfoundation_monitor_impl_| might have been NULLed asynchronously before - // arriving at this line. - if (avfoundation_monitor_impl_) { - avfoundation_monitor_impl_->ConsolidateDevicesListAndNotify( - snapshot_devices); - } -} - -// AVFoundation implementation of the Mac Device Monitor, registers as a global -// device connect/disconnect observer and plugs suspend/wake up device observers -// per device. This class is created and lives on the main Application thread -// (UI for content). Owns a SuspendObserverDelegate that notifies when a device -// is suspended/resumed. -class AVFoundationMonitorImpl : public DeviceMonitorMacImpl { - public: - AVFoundationMonitorImpl( - media::DeviceMonitorMac* monitor, - const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner); - ~AVFoundationMonitorImpl() override; - - void OnDeviceChanged() override; - - private: - // {Video,AudioInput}DeviceManager's "Device" thread task runner used for - // posting tasks to |suspend_observer_delegate_|; - const scoped_refptr<base::SingleThreadTaskRunner> device_task_runner_; - - // Pegged to the "main" thread -- usually content::BrowserThread::UI. - base::ThreadChecker main_thread_checker_; - - scoped_refptr<SuspendObserverDelegate> suspend_observer_delegate_; - - DISALLOW_COPY_AND_ASSIGN(AVFoundationMonitorImpl); -}; - -AVFoundationMonitorImpl::AVFoundationMonitorImpl( - media::DeviceMonitorMac* monitor, - const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) - : DeviceMonitorMacImpl(monitor), - device_task_runner_(device_task_runner), - suspend_observer_delegate_(new SuspendObserverDelegate(this)) { - DCHECK(main_thread_checker_.CalledOnValidThread()); - NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; - device_arrival_ = - [nc addObserverForName:AVFoundationGlue:: - AVCaptureDeviceWasConnectedNotification() - object:nil - queue:nil - usingBlock:^(NSNotification* notification) { - OnDeviceChanged(); - }]; - device_removal_ = - [nc addObserverForName:AVFoundationGlue:: - AVCaptureDeviceWasDisconnectedNotification() - object:nil - queue:nil - usingBlock:^(NSNotification* notification) { - OnDeviceChanged(); - }]; - suspend_observer_delegate_->StartObserver(device_task_runner_); -} - -AVFoundationMonitorImpl::~AVFoundationMonitorImpl() { - DCHECK(main_thread_checker_.CalledOnValidThread()); - suspend_observer_delegate_->ResetDeviceMonitor(); - NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; - [nc removeObserver:device_arrival_]; - [nc removeObserver:device_removal_]; -} - -void AVFoundationMonitorImpl::OnDeviceChanged() { - DCHECK(main_thread_checker_.CalledOnValidThread()); - suspend_observer_delegate_->OnDeviceChanged(device_task_runner_); -} - -} // namespace - -@implementation CrAVFoundationDeviceObserver - -- (id)initWithOnChangedCallback:(const base::Closure&)callback { - DCHECK(mainThreadChecker_.CalledOnValidThread()); - if ((self = [super init])) { - DCHECK(!callback.is_null()); - onDeviceChangedCallback_ = callback; - } - return self; -} - -- (void)dealloc { - DCHECK(mainThreadChecker_.CalledOnValidThread()); - std::set<base::scoped_nsobject<CrAVCaptureDevice>>::iterator it = - monitoredDevices_.begin(); - while (it != monitoredDevices_.end()) - [self removeObservers:*(it++)]; - [super dealloc]; -} - -- (void)startObserving:(base::scoped_nsobject<CrAVCaptureDevice>)device { - DCHECK(mainThreadChecker_.CalledOnValidThread()); - DCHECK(device != nil); - // Skip this device if there are already observers connected to it. - if (std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device) != - monitoredDevices_.end()) { - return; - } - [device addObserver:self - forKeyPath:@"suspended" - options:0 - context:device.get()]; - [device addObserver:self - forKeyPath:@"connected" - options:0 - context:device.get()]; - monitoredDevices_.insert(device); -} - -- (void)stopObserving:(CrAVCaptureDevice*)device { - DCHECK(mainThreadChecker_.CalledOnValidThread()); - DCHECK(device != nil); - - std::set<base::scoped_nsobject<CrAVCaptureDevice>>::iterator found = - std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device); - DCHECK(found != monitoredDevices_.end()); - [self removeObservers:*found]; - monitoredDevices_.erase(found); -} - -- (void)clearOnDeviceChangedCallback { - DCHECK(mainThreadChecker_.CalledOnValidThread()); - onDeviceChangedCallback_.Reset(); -} - -- (void)removeObservers:(CrAVCaptureDevice*)device { - DCHECK(mainThreadChecker_.CalledOnValidThread()); - // Check sanity of |device| via its -observationInfo. http://crbug.com/371271. - if ([device observationInfo]) { - [device removeObserver:self - forKeyPath:@"suspended"]; - [device removeObserver:self - forKeyPath:@"connected"]; - } -} - -- (void)observeValueForKeyPath:(NSString*)keyPath - ofObject:(id)object - change:(NSDictionary*)change - context:(void*)context { - DCHECK(mainThreadChecker_.CalledOnValidThread()); - if ([keyPath isEqual:@"suspended"]) - onDeviceChangedCallback_.Run(); - if ([keyPath isEqual:@"connected"]) - [self stopObserving:static_cast<CrAVCaptureDevice*>(context)]; -} - -@end // @implementation CrAVFoundationDeviceObserver - -namespace media { - -DeviceMonitorMac::DeviceMonitorMac() { - // AVFoundation do not need to be fired up until the user - // exercises a GetUserMedia. Bringing up either library and enumerating the - // devices in the system is an operation taking in the range of hundred of ms, - // so it is triggered explicitly from MediaStreamManager::StartMonitoring(). -} - -DeviceMonitorMac::~DeviceMonitorMac() {} - -void DeviceMonitorMac::StartMonitoring( - const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) { - DCHECK(thread_checker_.CalledOnValidThread()); - - // We're on the UI thread so let's try to initialize AVFoundation. - AVFoundationGlue::InitializeAVFoundation(); - - // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/458404 - // is fixed. - tracked_objects::ScopedTracker tracking_profile( - FROM_HERE_WITH_EXPLICIT_FUNCTION( - "458404 DeviceMonitorMac::StartMonitoring::AVFoundation")); - DVLOG(1) << "Monitoring via AVFoundation"; - device_monitor_impl_.reset( - new AVFoundationMonitorImpl(this, device_task_runner)); -} - -void DeviceMonitorMac::NotifyDeviceChanged( - base::SystemMonitor::DeviceType type) { - DCHECK(thread_checker_.CalledOnValidThread()); - // TODO(xians): Remove the global variable for SystemMonitor. - base::SystemMonitor::Get()->ProcessDevicesChanged(type); -} - -} // namespace media
diff --git a/media/capture/device_monitor_udev.cc b/media/capture/device_monitor_udev.cc deleted file mode 100644 index a010427..0000000 --- a/media/capture/device_monitor_udev.cc +++ /dev/null
@@ -1,88 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// libudev is used for monitoring device changes. - -#include "media/capture/device_monitor_udev.h" - -#include <stddef.h> - -#include <string> - -#include "base/macros.h" -#include "base/system_monitor/system_monitor.h" -#include "device/udev_linux/udev.h" -#include "device/udev_linux/udev_linux.h" - -namespace { - -struct SubsystemMap { - base::SystemMonitor::DeviceType device_type; - const char* subsystem; - const char* devtype; -}; - -const char kAudioSubsystem[] = "sound"; -const char kVideoSubsystem[] = "video4linux"; - -// Add more subsystems here for monitoring. -const SubsystemMap kSubsystemMap[] = { - {base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE, kAudioSubsystem, NULL}, - {base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE, kVideoSubsystem, NULL}, -}; - -} // namespace - -namespace media { - -DeviceMonitorLinux::DeviceMonitorLinux( - const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) - : io_task_runner_(io_task_runner) { - io_task_runner_->PostTask( - FROM_HERE, - base::Bind(&DeviceMonitorLinux::Initialize, base::Unretained(this))); -} - -DeviceMonitorLinux::~DeviceMonitorLinux() {} - -void DeviceMonitorLinux::Initialize() { - DCHECK(io_task_runner_->BelongsToCurrentThread()); - - // We want to be notified of IO message loop destruction to delete |udev_|. - base::MessageLoop::current()->AddDestructionObserver(this); - - std::vector<device::UdevLinux::UdevMonitorFilter> filters; - for (const SubsystemMap& entry : kSubsystemMap) { - filters.push_back( - device::UdevLinux::UdevMonitorFilter(entry.subsystem, entry.devtype)); - } - udev_.reset(new device::UdevLinux( - filters, base::Bind(&DeviceMonitorLinux::OnDevicesChanged, - base::Unretained(this)))); -} - -void DeviceMonitorLinux::WillDestroyCurrentMessageLoop() { - DCHECK(io_task_runner_->BelongsToCurrentThread()); - udev_.reset(); -} - -void DeviceMonitorLinux::OnDevicesChanged(udev_device* device) { - DCHECK(io_task_runner_->BelongsToCurrentThread()); - DCHECK(device); - - base::SystemMonitor::DeviceType device_type = - base::SystemMonitor::DEVTYPE_UNKNOWN; - const std::string subsystem(device::udev_device_get_subsystem(device)); - for (const SubsystemMap& entry : kSubsystemMap) { - if (subsystem == entry.subsystem) { - device_type = entry.device_type; - break; - } - } - DCHECK_NE(device_type, base::SystemMonitor::DEVTYPE_UNKNOWN); - - base::SystemMonitor::Get()->ProcessDevicesChanged(device_type); -} - -} // namespace media
diff --git a/media/capture/device_monitor_udev.h b/media/capture/device_monitor_udev.h deleted file mode 100644 index a8f9d82..0000000 --- a/media/capture/device_monitor_udev.h +++ /dev/null
@@ -1,57 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This class is used to detect device change and notify base::SystemMonitor -// on Linux. - -#ifndef MEDIA_CAPTURE_DEVICE_MONITOR_UDEV_H_ -#define MEDIA_CAPTURE_DEVICE_MONITOR_UDEV_H_ - -#include <memory> - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/message_loop/message_loop.h" -#include "base/single_thread_task_runner.h" -#include "media/capture/capture_export.h" - -extern "C" { -struct udev_device; -} - -namespace device { -class UdevLinux; -} - -namespace media { - -class CAPTURE_EXPORT DeviceMonitorLinux - : public base::MessageLoop::DestructionObserver { - public: - explicit DeviceMonitorLinux( - const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner); - ~DeviceMonitorLinux() override; - - // TODO(mcasas): Consider adding a StartMonitoring() method like - // DeviceMonitorMac to reduce startup impact time. - - private: - // This object is deleted on the constructor thread after |io_task_runner_| - // has been destroyed. Need to know when the latter is being destroyed so that - // we can delete |udev_|. - void WillDestroyCurrentMessageLoop() override; - - void Initialize(); - void OnDevicesChanged(udev_device* device); - - const scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; - - std::unique_ptr<device::UdevLinux> udev_; - - DISALLOW_COPY_AND_ASSIGN(DeviceMonitorLinux); -}; - -} // namespace media - -#endif // MEDIA_CAPTURE_DEVICE_MONITOR_UDEV_H_
diff --git a/media/capture/system_message_window_win.cc b/media/capture/system_message_window_win.cc deleted file mode 100644 index 66ebb3ee..0000000 --- a/media/capture/system_message_window_win.cc +++ /dev/null
@@ -1,159 +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 "media/capture/system_message_window_win.h" - -#include <dbt.h> -#include <stddef.h> - -#include "base/logging.h" -#include "base/macros.h" -#include "base/system_monitor/system_monitor.h" -#include "base/win/wrapped_window_proc.h" -#include "media/audio/win/core_audio_util_win.h" - -namespace media { - -namespace { -const wchar_t kWindowClassName[] = L"Chrome_SystemMessageWindow"; - -// A static map from a device category guid to base::SystemMonitor::DeviceType. -struct { - const GUID device_category; - const base::SystemMonitor::DeviceType device_type; -} const kDeviceCategoryMap[] = { - {KSCATEGORY_AUDIO, base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE}, - {KSCATEGORY_VIDEO, base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE}, -}; -} // namespace - -// Manages the device notification handles for SystemMessageWindowWin. -class SystemMessageWindowWin::DeviceNotifications { - public: - explicit DeviceNotifications(HWND hwnd) : notifications_() { Register(hwnd); } - - ~DeviceNotifications() { Unregister(); } - - void Register(HWND hwnd) { - // Request to receive device notifications. All applications receive basic - // notifications via WM_DEVICECHANGE but in order to receive detailed device - // arrival and removal messages, we need to register. - DEV_BROADCAST_DEVICEINTERFACE filter = {0}; - filter.dbcc_size = sizeof(filter); - filter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; - bool core_audio_support = media::CoreAudioUtil::IsSupported(); - for (size_t i = 0; i < arraysize(kDeviceCategoryMap); ++i) { - // If CoreAudio is supported, AudioDeviceListenerWin will - // take care of monitoring audio devices. - if (core_audio_support && - KSCATEGORY_AUDIO == kDeviceCategoryMap[i].device_category) { - continue; - } - - filter.dbcc_classguid = kDeviceCategoryMap[i].device_category; - DCHECK_EQ(notifications_[i], static_cast<HDEVNOTIFY>(NULL)); - notifications_[i] = RegisterDeviceNotification( - hwnd, &filter, DEVICE_NOTIFY_WINDOW_HANDLE); - DPLOG_IF(ERROR, !notifications_[i]) - << "RegisterDeviceNotification failed"; - } - } - - void Unregister() { - for (size_t i = 0; i < arraysize(notifications_); ++i) { - if (notifications_[i]) { - UnregisterDeviceNotification(notifications_[i]); - notifications_[i] = NULL; - } - } - } - - private: - HDEVNOTIFY notifications_[arraysize(kDeviceCategoryMap)]; - - DISALLOW_IMPLICIT_CONSTRUCTORS(DeviceNotifications); -}; - -SystemMessageWindowWin::SystemMessageWindowWin() { - WNDCLASSEX window_class; - base::win::InitializeWindowClass( - kWindowClassName, - &base::win::WrappedWindowProc<SystemMessageWindowWin::WndProcThunk>, 0, 0, - 0, NULL, NULL, NULL, NULL, NULL, &window_class); - instance_ = window_class.hInstance; - ATOM clazz = RegisterClassEx(&window_class); - DCHECK(clazz); - - window_ = - CreateWindow(kWindowClassName, 0, 0, 0, 0, 0, 0, 0, 0, instance_, 0); - SetWindowLongPtr(window_, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this)); - device_notifications_.reset(new DeviceNotifications(window_)); -} - -SystemMessageWindowWin::~SystemMessageWindowWin() { - if (window_) { - DestroyWindow(window_); - UnregisterClass(kWindowClassName, instance_); - } -} - -LRESULT SystemMessageWindowWin::OnDeviceChange(UINT event_type, LPARAM data) { - base::SystemMonitor* monitor = base::SystemMonitor::Get(); - base::SystemMonitor::DeviceType device_type = - base::SystemMonitor::DEVTYPE_UNKNOWN; - switch (event_type) { - case DBT_DEVNODES_CHANGED: - // For this notification, we're happy with the default DEVTYPE_UNKNOWN. - break; - - case DBT_DEVICEREMOVECOMPLETE: - case DBT_DEVICEARRIVAL: { - // This notification has more details about the specific device that - // was added or removed. See if this is a category we're interested - // in monitoring and if so report the specific device type. If we don't - // find the category in our map, ignore the notification and do not - // notify the system monitor. - DEV_BROADCAST_DEVICEINTERFACE* device_interface = - reinterpret_cast<DEV_BROADCAST_DEVICEINTERFACE*>(data); - if (device_interface->dbcc_devicetype != DBT_DEVTYP_DEVICEINTERFACE) - return TRUE; - for (const auto& map_entry : kDeviceCategoryMap) { - if (map_entry.device_category == device_interface->dbcc_classguid) { - device_type = map_entry.device_type; - break; - } - } - - // Devices that we do not have a DEVTYPE_ for, get detected via - // DBT_DEVNODES_CHANGED, so we avoid sending additional notifications - // for those here. - if (device_type == base::SystemMonitor::DEVTYPE_UNKNOWN) - return TRUE; - break; - } - - default: - return TRUE; - } - - monitor->ProcessDevicesChanged(device_type); - - return TRUE; -} - -LRESULT CALLBACK SystemMessageWindowWin::WndProc(HWND hwnd, - UINT message, - WPARAM wparam, - LPARAM lparam) { - switch (message) { - case WM_DEVICECHANGE: - return OnDeviceChange(static_cast<UINT>(wparam), lparam); - default: - break; - } - - return ::DefWindowProc(hwnd, message, wparam, lparam); -} - -} // namespace media
diff --git a/media/capture/system_message_window_win.h b/media/capture/system_message_window_win.h deleted file mode 100644 index 6468317..0000000 --- a/media/capture/system_message_window_win.h +++ /dev/null
@@ -1,54 +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. - -#ifndef MEDIA_CAPTURE_SYSTEM_MESSAGE_WINDOW_WIN_H_ -#define MEDIA_CAPTURE_SYSTEM_MESSAGE_WINDOW_WIN_H_ - -#include <windows.h> - -#include <memory> - -#include "base/macros.h" -#include "media/capture/capture_export.h" - -namespace media { - -class CAPTURE_EXPORT SystemMessageWindowWin { - public: - SystemMessageWindowWin(); - - virtual ~SystemMessageWindowWin(); - - virtual LRESULT OnDeviceChange(UINT event_type, LPARAM data); - - private: - void Init(); - - LRESULT CALLBACK WndProc(HWND hwnd, - UINT message, - WPARAM wparam, - LPARAM lparam); - - static LRESULT CALLBACK WndProcThunk(HWND hwnd, - UINT message, - WPARAM wparam, - LPARAM lparam) { - SystemMessageWindowWin* msg_wnd = reinterpret_cast<SystemMessageWindowWin*>( - GetWindowLongPtr(hwnd, GWLP_USERDATA)); - if (msg_wnd) - return msg_wnd->WndProc(hwnd, message, wparam, lparam); - return ::DefWindowProc(hwnd, message, wparam, lparam); - } - - HMODULE instance_; - HWND window_; - class DeviceNotifications; - std::unique_ptr<DeviceNotifications> device_notifications_; - - DISALLOW_COPY_AND_ASSIGN(SystemMessageWindowWin); -}; - -} // namespace media - -#endif // MEDIA_CAPTURE_SYSTEM_MESSAGE_WINDOW_WIN_H_
diff --git a/media/capture/system_message_window_win_unittest.cc b/media/capture/system_message_window_win_unittest.cc deleted file mode 100644 index 80ff75c..0000000 --- a/media/capture/system_message_window_win_unittest.cc +++ /dev/null
@@ -1,46 +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 "media/capture/system_message_window_win.h" - -#include <dbt.h> -#include <string> -#include <vector> - -#include "base/files/file_path.h" -#include "base/message_loop/message_loop.h" -#include "base/system_monitor/system_monitor.h" -#include "base/test/mock_devices_changed_observer.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace media { - -class SystemMessageWindowWinTest : public testing::Test { - public: - ~SystemMessageWindowWinTest() override {} - - protected: - void SetUp() override { - system_monitor_.AddDevicesChangedObserver(&observer_); - } - - base::MessageLoop message_loop_; - base::SystemMonitor system_monitor_; - base::MockDevicesChangedObserver observer_; - SystemMessageWindowWin window_; -}; - -TEST_F(SystemMessageWindowWinTest, DevicesChanged) { - EXPECT_CALL(observer_, OnDevicesChanged(testing::_)).Times(1); - window_.OnDeviceChange(DBT_DEVNODES_CHANGED, NULL); - message_loop_.RunUntilIdle(); -} - -TEST_F(SystemMessageWindowWinTest, RandomMessage) { - window_.OnDeviceChange(DBT_DEVICEQUERYREMOVE, NULL); - message_loop_.RunUntilIdle(); -} - -} // namespace media
diff --git a/media/cdm/cdm_adapter_unittest.cc b/media/cdm/cdm_adapter_unittest.cc index 554ba30..bbeb5032 100644 --- a/media/cdm/cdm_adapter_unittest.cc +++ b/media/cdm/cdm_adapter_unittest.cc
@@ -44,7 +44,8 @@ const char kKeyIdAsJWK[] = "{\"kids\": [\"AQIDBAUGBwgJCgsMDQ4PEA\"]}"; const uint8_t kKeyIdAsPssh[] = { - 0x00, 0x00, 0x00, 0x00, 'p', 's', 's', 'h', // size = 0 + 0x00, 0x00, 0x00, 0x34, // size = 52 + 'p', 's', 's', 'h', // 'pssh' 0x01, // version = 1 0x00, 0x00, 0x00, // flags 0x10, 0x77, 0xEF, 0xEC, 0xC0, 0xB2, 0x4D, 0x02, // Common SystemID
diff --git a/media/cdm/cenc_utils_unittest.cc b/media/cdm/cenc_utils_unittest.cc index c124cbd..1b038ff 100644 --- a/media/cdm/cenc_utils_unittest.cc +++ b/media/cdm/cenc_utils_unittest.cc
@@ -7,6 +7,8 @@ #include <stddef.h> #include <stdint.h> +#include <limits> + #include "base/logging.h" #include "base/macros.h" #include "testing/gtest/include/gtest/gtest.h" @@ -54,6 +56,7 @@ box->reserve(size); // Add size. + DCHECK(size < std::numeric_limits<uint8_t>::max()); box->push_back(0); box->push_back(0); box->push_back(0);
diff --git a/media/device_monitors/device_monitor_mac.h b/media/device_monitors/device_monitor_mac.h new file mode 100644 index 0000000..136bb7df --- /dev/null +++ b/media/device_monitors/device_monitor_mac.h
@@ -0,0 +1,53 @@ +// 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. + +#ifndef MEDIA_DEVICE_MONITORS_DEVICE_MONITOR_MAC_H_ +#define MEDIA_DEVICE_MONITORS_DEVICE_MONITOR_MAC_H_ + +#include <memory> + +#include "base/macros.h" +#include "base/system_monitor/system_monitor.h" +#include "base/threading/thread_checker.h" +#include "media/base/media_export.h" + +namespace { +class DeviceMonitorMacImpl; +} + +namespace media { + +// Class to track audio/video devices removal or addition via callback to +// base::SystemMonitor ProcessDevicesChanged(). A single object of this class +// is created from the browser main process and lives as long as this one. +class MEDIA_EXPORT DeviceMonitorMac { + public: + DeviceMonitorMac(); + ~DeviceMonitorMac(); + + // Registers the observers for the audio/video device removal, connection and + // suspension. The AVFoundation library is also loaded and initialised if the + // OS supports it. The |device_task_runner| argument represents the thread on + // which device enumeration will occur. + void StartMonitoring( + const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner); + + // Method called by the internal DeviceMonitorMacImpl object + // |device_monitor_impl_| when a device of type |type| has been added to or + // removed from the system. This code executes in the notification thread. + void NotifyDeviceChanged(base::SystemMonitor::DeviceType type); + + private: + std::unique_ptr<DeviceMonitorMacImpl> device_monitor_impl_; + + // |thread_checker_| is used to check that constructor and StartMonitoring() + // are called in the correct thread, the UI thread, that also owns the object. + base::ThreadChecker thread_checker_; + + DISALLOW_COPY_AND_ASSIGN(DeviceMonitorMac); +}; + +} // namespace content + +#endif // MEDIA_DEVICE_MONITORS_DEVICE_MONITOR_MAC_H_
diff --git a/media/device_monitors/device_monitor_mac.mm b/media/device_monitors/device_monitor_mac.mm new file mode 100644 index 0000000..7f27bc7 --- /dev/null +++ b/media/device_monitors/device_monitor_mac.mm
@@ -0,0 +1,475 @@ +// 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 "media/device_monitors/device_monitor_mac.h" + +#include <set> + +#include "base/bind_helpers.h" +#include "base/logging.h" +#include "base/mac/bind_objc_block.h" +#include "base/mac/scoped_nsobject.h" +#include "base/macros.h" +#include "base/profiler/scoped_tracker.h" +#include "base/task_runner_util.h" +#include "base/threading/thread_checker.h" +#import "media/base/mac/avfoundation_glue.h" + +namespace { + +// This class is used to keep track of system devices names and their types. +class DeviceInfo { + public: + enum DeviceType { kAudio, kVideo, kMuxed, kUnknown, kInvalid }; + + DeviceInfo(const std::string& unique_id, DeviceType type) + : unique_id_(unique_id), type_(type) {} + + // Operator== is needed here to use this class in a std::find. A given + // |unique_id_| always has the same |type_| so for comparison purposes the + // latter can be safely ignored. + bool operator==(const DeviceInfo& device) const { + return unique_id_ == device.unique_id_; + } + + const std::string& unique_id() const { return unique_id_; } + DeviceType type() const { return type_; } + + private: + std::string unique_id_; + DeviceType type_; + // Allow generated copy constructor and assignment. +}; + +// Base abstract class used by DeviceMonitorMac. +class DeviceMonitorMacImpl { + public: + explicit DeviceMonitorMacImpl(media::DeviceMonitorMac* monitor) + : monitor_(monitor), + cached_devices_(), + device_arrival_(nil), + device_removal_(nil) { + DCHECK(monitor); + // Initialise the devices_cache_ with a not-valid entry. For the case in + // which there is one single device in the system and we get notified when + // it gets removed, this will prevent the system from thinking that no + // devices were added nor removed and not notifying the |monitor_|. + cached_devices_.push_back(DeviceInfo("invalid", DeviceInfo::kInvalid)); + } + virtual ~DeviceMonitorMacImpl() {} + + virtual void OnDeviceChanged() = 0; + + // Method called by the default notification center when a device is removed + // or added to the system. It will compare the |cached_devices_| with the + // current situation, update it, and, if there's an update, signal to + // |monitor_| with the appropriate device type. + void ConsolidateDevicesListAndNotify( + const std::vector<DeviceInfo>& snapshot_devices); + + protected: + media::DeviceMonitorMac* monitor_; + std::vector<DeviceInfo> cached_devices_; + + // Handles to NSNotificationCenter block observers. + id device_arrival_; + id device_removal_; + + private: + DISALLOW_COPY_AND_ASSIGN(DeviceMonitorMacImpl); +}; + +void DeviceMonitorMacImpl::ConsolidateDevicesListAndNotify( + const std::vector<DeviceInfo>& snapshot_devices) { + bool video_device_added = false; + bool audio_device_added = false; + bool video_device_removed = false; + bool audio_device_removed = false; + + // Compare the current system devices snapshot with the ones cached to detect + // additions, present in the former but not in the latter. If we find a device + // in snapshot_devices entry also present in cached_devices, we remove it from + // the latter vector. + std::vector<DeviceInfo>::const_iterator it; + for (it = snapshot_devices.begin(); it != snapshot_devices.end(); ++it) { + std::vector<DeviceInfo>::iterator cached_devices_iterator = + std::find(cached_devices_.begin(), cached_devices_.end(), *it); + if (cached_devices_iterator == cached_devices_.end()) { + video_device_added |= ((it->type() == DeviceInfo::kVideo) || + (it->type() == DeviceInfo::kMuxed)); + audio_device_added |= ((it->type() == DeviceInfo::kAudio) || + (it->type() == DeviceInfo::kMuxed)); + DVLOG(1) << "Device has been added, id: " << it->unique_id(); + } else { + cached_devices_.erase(cached_devices_iterator); + } + } + // All the remaining entries in cached_devices are removed devices. + for (it = cached_devices_.begin(); it != cached_devices_.end(); ++it) { + video_device_removed |= ((it->type() == DeviceInfo::kVideo) || + (it->type() == DeviceInfo::kMuxed) || + (it->type() == DeviceInfo::kInvalid)); + audio_device_removed |= ((it->type() == DeviceInfo::kAudio) || + (it->type() == DeviceInfo::kMuxed) || + (it->type() == DeviceInfo::kInvalid)); + DVLOG(1) << "Device has been removed, id: " << it->unique_id(); + } + // Update the cached devices with the current system snapshot. + cached_devices_ = snapshot_devices; + + if (video_device_added || video_device_removed) + monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE); + if (audio_device_added || audio_device_removed) + monitor_->NotifyDeviceChanged(base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE); +} + +// Forward declaration for use by CrAVFoundationDeviceObserver. +class SuspendObserverDelegate; + +} // namespace + +// This class is a Key-Value Observer (KVO) shim. It is needed because C++ +// classes cannot observe Key-Values directly. Created, manipulated, and +// destroyed on the UI Thread by SuspendObserverDelegate. +@interface CrAVFoundationDeviceObserver : NSObject { + @private + // Callback for device changed, has to run on Device Thread. + base::Closure onDeviceChangedCallback_; + + // Member to keep track of the devices we are already monitoring. + std::set<base::scoped_nsobject<CrAVCaptureDevice>> monitoredDevices_; + + // Pegged to the "main" thread -- usually content::BrowserThread::UI. + base::ThreadChecker mainThreadChecker_; +} + +- (id)initWithOnChangedCallback:(const base::Closure&)callback; +- (void)startObserving:(base::scoped_nsobject<CrAVCaptureDevice>)device; +- (void)stopObserving:(CrAVCaptureDevice*)device; +- (void)clearOnDeviceChangedCallback; + +@end + +namespace { + +// This class owns and manages the lifetime of a CrAVFoundationDeviceObserver. +// It is created and destroyed on AVFoundationMonitorImpl's main thread (usually +// browser's UI thread), and it operates on this thread except for the expensive +// device enumerations which are run on Device Thread. +class SuspendObserverDelegate + : public base::RefCountedThreadSafe<SuspendObserverDelegate> { + public: + explicit SuspendObserverDelegate(DeviceMonitorMacImpl* monitor); + + // Create |suspend_observer_| for all devices and register OnDeviceChanged() + // as its change callback. Schedule bottom half in DoStartObserver(). + void StartObserver( + const scoped_refptr<base::SingleThreadTaskRunner>& device_thread); + // Enumerate devices in |device_thread| and run the bottom half in + // DoOnDeviceChange(). |suspend_observer_| calls back here on suspend event, + // and our parent AVFoundationMonitorImpl calls on connect/disconnect device. + void OnDeviceChanged( + const scoped_refptr<base::SingleThreadTaskRunner>& device_thread); + // Remove the device monitor's weak reference. Remove ourselves as suspend + // notification observer from |suspend_observer_|. + void ResetDeviceMonitor(); + + private: + friend class base::RefCountedThreadSafe<SuspendObserverDelegate>; + + virtual ~SuspendObserverDelegate(); + + // Bottom half of StartObserver(), starts |suspend_observer_| for all devices. + // Assumes that |devices| has been retained prior to being called, and + // releases it internally. + void DoStartObserver(NSArray* devices); + // Bottom half of OnDeviceChanged(), starts |suspend_observer_| for current + // devices and composes a snapshot of them to send it to + // |avfoundation_monitor_impl_|. Assumes that |devices| has been retained + // prior to being called, and releases it internally. + void DoOnDeviceChanged(NSArray* devices); + + base::scoped_nsobject<CrAVFoundationDeviceObserver> suspend_observer_; + DeviceMonitorMacImpl* avfoundation_monitor_impl_; + + // Pegged to the "main" thread -- usually content::BrowserThread::UI. + base::ThreadChecker main_thread_checker_; +}; + +SuspendObserverDelegate::SuspendObserverDelegate(DeviceMonitorMacImpl* monitor) + : avfoundation_monitor_impl_(monitor) { + DCHECK(main_thread_checker_.CalledOnValidThread()); +} + +void SuspendObserverDelegate::StartObserver( + const scoped_refptr<base::SingleThreadTaskRunner>& device_thread) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + + base::Closure on_device_changed_callback = base::Bind( + &SuspendObserverDelegate::OnDeviceChanged, this, device_thread); + suspend_observer_.reset([[CrAVFoundationDeviceObserver alloc] + initWithOnChangedCallback:on_device_changed_callback]); + + // Enumerate the devices in Device thread and post the observers start to be + // done on UI thread. The devices array is retained in |device_thread| and + // released in DoStartObserver(). + base::PostTaskAndReplyWithResult( + device_thread.get(), FROM_HERE, base::BindBlock(^{ + return [[AVCaptureDeviceGlue devices] retain]; + }), + base::Bind(&SuspendObserverDelegate::DoStartObserver, this)); +} + +void SuspendObserverDelegate::OnDeviceChanged( + const scoped_refptr<base::SingleThreadTaskRunner>& device_thread) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + // Enumerate the devices in Device thread and post the consolidation of the + // new devices and the old ones to be done on main thread. The devices array + // is retained in |device_thread| and released in DoOnDeviceChanged(). + PostTaskAndReplyWithResult( + device_thread.get(), FROM_HERE, base::BindBlock(^{ + return [[AVCaptureDeviceGlue devices] retain]; + }), + base::Bind(&SuspendObserverDelegate::DoOnDeviceChanged, this)); +} + +void SuspendObserverDelegate::ResetDeviceMonitor() { + DCHECK(main_thread_checker_.CalledOnValidThread()); + avfoundation_monitor_impl_ = NULL; + [suspend_observer_ clearOnDeviceChangedCallback]; +} + +SuspendObserverDelegate::~SuspendObserverDelegate() { + DCHECK(main_thread_checker_.CalledOnValidThread()); +} + +void SuspendObserverDelegate::DoStartObserver(NSArray* devices) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + base::scoped_nsobject<NSArray> auto_release(devices); + for (CrAVCaptureDevice* device in devices) { + base::scoped_nsobject<CrAVCaptureDevice> device_ptr([device retain]); + [suspend_observer_ startObserving:device_ptr]; + } +} + +void SuspendObserverDelegate::DoOnDeviceChanged(NSArray* devices) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + base::scoped_nsobject<NSArray> auto_release(devices); + std::vector<DeviceInfo> snapshot_devices; + for (CrAVCaptureDevice* device in devices) { + base::scoped_nsobject<CrAVCaptureDevice> device_ptr([device retain]); + [suspend_observer_ startObserving:device_ptr]; + + BOOL suspended = [device respondsToSelector:@selector(isSuspended)] && + [device isSuspended]; + DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown; + if ([device hasMediaType:AVFoundationGlue::AVMediaTypeVideo()]) { + if (suspended) + continue; + device_type = DeviceInfo::kVideo; + } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeMuxed()]) { + device_type = suspended ? DeviceInfo::kAudio : DeviceInfo::kMuxed; + } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeAudio()]) { + device_type = DeviceInfo::kAudio; + } + snapshot_devices.push_back( + DeviceInfo([[device uniqueID] UTF8String], device_type)); + } + // Make sure no references are held to |devices| when + // ConsolidateDevicesListAndNotify is called since the VideoCaptureManager + // and AudioCaptureManagers also enumerates the available devices but on + // another thread. + auto_release.reset(); + // |avfoundation_monitor_impl_| might have been NULLed asynchronously before + // arriving at this line. + if (avfoundation_monitor_impl_) { + avfoundation_monitor_impl_->ConsolidateDevicesListAndNotify( + snapshot_devices); + } +} + +// AVFoundation implementation of the Mac Device Monitor, registers as a global +// device connect/disconnect observer and plugs suspend/wake up device observers +// per device. This class is created and lives on the main Application thread +// (UI for content). Owns a SuspendObserverDelegate that notifies when a device +// is suspended/resumed. +class AVFoundationMonitorImpl : public DeviceMonitorMacImpl { + public: + AVFoundationMonitorImpl( + media::DeviceMonitorMac* monitor, + const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner); + ~AVFoundationMonitorImpl() override; + + void OnDeviceChanged() override; + + private: + // {Video,AudioInput}DeviceManager's "Device" thread task runner used for + // posting tasks to |suspend_observer_delegate_|; + const scoped_refptr<base::SingleThreadTaskRunner> device_task_runner_; + + // Pegged to the "main" thread -- usually content::BrowserThread::UI. + base::ThreadChecker main_thread_checker_; + + scoped_refptr<SuspendObserverDelegate> suspend_observer_delegate_; + + DISALLOW_COPY_AND_ASSIGN(AVFoundationMonitorImpl); +}; + +AVFoundationMonitorImpl::AVFoundationMonitorImpl( + media::DeviceMonitorMac* monitor, + const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) + : DeviceMonitorMacImpl(monitor), + device_task_runner_(device_task_runner), + suspend_observer_delegate_(new SuspendObserverDelegate(this)) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; + device_arrival_ = + [nc addObserverForName:AVFoundationGlue:: + AVCaptureDeviceWasConnectedNotification() + object:nil + queue:nil + usingBlock:^(NSNotification* notification) { + OnDeviceChanged(); + }]; + device_removal_ = + [nc addObserverForName:AVFoundationGlue:: + AVCaptureDeviceWasDisconnectedNotification() + object:nil + queue:nil + usingBlock:^(NSNotification* notification) { + OnDeviceChanged(); + }]; + suspend_observer_delegate_->StartObserver(device_task_runner_); +} + +AVFoundationMonitorImpl::~AVFoundationMonitorImpl() { + DCHECK(main_thread_checker_.CalledOnValidThread()); + suspend_observer_delegate_->ResetDeviceMonitor(); + NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; + [nc removeObserver:device_arrival_]; + [nc removeObserver:device_removal_]; +} + +void AVFoundationMonitorImpl::OnDeviceChanged() { + DCHECK(main_thread_checker_.CalledOnValidThread()); + suspend_observer_delegate_->OnDeviceChanged(device_task_runner_); +} + +} // namespace + +@implementation CrAVFoundationDeviceObserver + +- (id)initWithOnChangedCallback:(const base::Closure&)callback { + DCHECK(mainThreadChecker_.CalledOnValidThread()); + if ((self = [super init])) { + DCHECK(!callback.is_null()); + onDeviceChangedCallback_ = callback; + } + return self; +} + +- (void)dealloc { + DCHECK(mainThreadChecker_.CalledOnValidThread()); + std::set<base::scoped_nsobject<CrAVCaptureDevice>>::iterator it = + monitoredDevices_.begin(); + while (it != monitoredDevices_.end()) + [self removeObservers:*(it++)]; + [super dealloc]; +} + +- (void)startObserving:(base::scoped_nsobject<CrAVCaptureDevice>)device { + DCHECK(mainThreadChecker_.CalledOnValidThread()); + DCHECK(device != nil); + // Skip this device if there are already observers connected to it. + if (std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device) != + monitoredDevices_.end()) { + return; + } + [device addObserver:self + forKeyPath:@"suspended" + options:0 + context:device.get()]; + [device addObserver:self + forKeyPath:@"connected" + options:0 + context:device.get()]; + monitoredDevices_.insert(device); +} + +- (void)stopObserving:(CrAVCaptureDevice*)device { + DCHECK(mainThreadChecker_.CalledOnValidThread()); + DCHECK(device != nil); + + std::set<base::scoped_nsobject<CrAVCaptureDevice>>::iterator found = + std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device); + DCHECK(found != monitoredDevices_.end()); + [self removeObservers:*found]; + monitoredDevices_.erase(found); +} + +- (void)clearOnDeviceChangedCallback { + DCHECK(mainThreadChecker_.CalledOnValidThread()); + onDeviceChangedCallback_.Reset(); +} + +- (void)removeObservers:(CrAVCaptureDevice*)device { + DCHECK(mainThreadChecker_.CalledOnValidThread()); + // Check sanity of |device| via its -observationInfo. http://crbug.com/371271. + if ([device observationInfo]) { + [device removeObserver:self + forKeyPath:@"suspended"]; + [device removeObserver:self + forKeyPath:@"connected"]; + } +} + +- (void)observeValueForKeyPath:(NSString*)keyPath + ofObject:(id)object + change:(NSDictionary*)change + context:(void*)context { + DCHECK(mainThreadChecker_.CalledOnValidThread()); + if ([keyPath isEqual:@"suspended"]) + onDeviceChangedCallback_.Run(); + if ([keyPath isEqual:@"connected"]) + [self stopObserving:static_cast<CrAVCaptureDevice*>(context)]; +} + +@end // @implementation CrAVFoundationDeviceObserver + +namespace media { + +DeviceMonitorMac::DeviceMonitorMac() { + // AVFoundation do not need to be fired up until the user + // exercises a GetUserMedia. Bringing up either library and enumerating the + // devices in the system is an operation taking in the range of hundred of ms, + // so it is triggered explicitly from MediaStreamManager::StartMonitoring(). +} + +DeviceMonitorMac::~DeviceMonitorMac() {} + +void DeviceMonitorMac::StartMonitoring( + const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) { + DCHECK(thread_checker_.CalledOnValidThread()); + + // We're on the UI thread so let's try to initialize AVFoundation. + AVFoundationGlue::InitializeAVFoundation(); + + // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/458404 + // is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "458404 DeviceMonitorMac::StartMonitoring::AVFoundation")); + DVLOG(1) << "Monitoring via AVFoundation"; + device_monitor_impl_.reset( + new AVFoundationMonitorImpl(this, device_task_runner)); +} + +void DeviceMonitorMac::NotifyDeviceChanged( + base::SystemMonitor::DeviceType type) { + DCHECK(thread_checker_.CalledOnValidThread()); + // TODO(xians): Remove the global variable for SystemMonitor. + base::SystemMonitor::Get()->ProcessDevicesChanged(type); +} + +} // namespace media
diff --git a/media/device_monitors/device_monitor_udev.cc b/media/device_monitors/device_monitor_udev.cc new file mode 100644 index 0000000..b159495 --- /dev/null +++ b/media/device_monitors/device_monitor_udev.cc
@@ -0,0 +1,88 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// libudev is used for monitoring device changes. + +#include "media/device_monitors/device_monitor_udev.h" + +#include <stddef.h> + +#include <string> + +#include "base/macros.h" +#include "base/system_monitor/system_monitor.h" +#include "device/udev_linux/udev.h" +#include "device/udev_linux/udev_linux.h" + +namespace { + +struct SubsystemMap { + base::SystemMonitor::DeviceType device_type; + const char* subsystem; + const char* devtype; +}; + +const char kAudioSubsystem[] = "sound"; +const char kVideoSubsystem[] = "video4linux"; + +// Add more subsystems here for monitoring. +const SubsystemMap kSubsystemMap[] = { + {base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE, kAudioSubsystem, NULL}, + {base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE, kVideoSubsystem, NULL}, +}; + +} // namespace + +namespace media { + +DeviceMonitorLinux::DeviceMonitorLinux( + const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) + : io_task_runner_(io_task_runner) { + io_task_runner_->PostTask( + FROM_HERE, + base::Bind(&DeviceMonitorLinux::Initialize, base::Unretained(this))); +} + +DeviceMonitorLinux::~DeviceMonitorLinux() {} + +void DeviceMonitorLinux::Initialize() { + DCHECK(io_task_runner_->BelongsToCurrentThread()); + + // We want to be notified of IO message loop destruction to delete |udev_|. + base::MessageLoop::current()->AddDestructionObserver(this); + + std::vector<device::UdevLinux::UdevMonitorFilter> filters; + for (const SubsystemMap& entry : kSubsystemMap) { + filters.push_back( + device::UdevLinux::UdevMonitorFilter(entry.subsystem, entry.devtype)); + } + udev_.reset(new device::UdevLinux( + filters, base::Bind(&DeviceMonitorLinux::OnDevicesChanged, + base::Unretained(this)))); +} + +void DeviceMonitorLinux::WillDestroyCurrentMessageLoop() { + DCHECK(io_task_runner_->BelongsToCurrentThread()); + udev_.reset(); +} + +void DeviceMonitorLinux::OnDevicesChanged(udev_device* device) { + DCHECK(io_task_runner_->BelongsToCurrentThread()); + DCHECK(device); + + base::SystemMonitor::DeviceType device_type = + base::SystemMonitor::DEVTYPE_UNKNOWN; + const std::string subsystem(device::udev_device_get_subsystem(device)); + for (const SubsystemMap& entry : kSubsystemMap) { + if (subsystem == entry.subsystem) { + device_type = entry.device_type; + break; + } + } + DCHECK_NE(device_type, base::SystemMonitor::DEVTYPE_UNKNOWN); + + base::SystemMonitor::Get()->ProcessDevicesChanged(device_type); +} + +} // namespace media
diff --git a/media/device_monitors/device_monitor_udev.h b/media/device_monitors/device_monitor_udev.h new file mode 100644 index 0000000..fe326ee --- /dev/null +++ b/media/device_monitors/device_monitor_udev.h
@@ -0,0 +1,57 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This class is used to detect device change and notify base::SystemMonitor +// on Linux. + +#ifndef MEDIA_DEVICE_MONITORS_DEVICE_MONITOR_UDEV_H_ +#define MEDIA_DEVICE_MONITORS_DEVICE_MONITOR_UDEV_H_ + +#include <memory> + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/message_loop/message_loop.h" +#include "base/single_thread_task_runner.h" +#include "media/base/media_export.h" + +extern "C" { +struct udev_device; +} + +namespace device { +class UdevLinux; +} + +namespace media { + +class MEDIA_EXPORT DeviceMonitorLinux + : public base::MessageLoop::DestructionObserver { + public: + explicit DeviceMonitorLinux( + const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner); + ~DeviceMonitorLinux() override; + + // TODO(mcasas): Consider adding a StartMonitoring() method like + // DeviceMonitorMac to reduce startup impact time. + + private: + // This object is deleted on the constructor thread after |io_task_runner_| + // has been destroyed. Need to know when the latter is being destroyed so that + // we can delete |udev_|. + void WillDestroyCurrentMessageLoop() override; + + void Initialize(); + void OnDevicesChanged(udev_device* device); + + const scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; + + std::unique_ptr<device::UdevLinux> udev_; + + DISALLOW_COPY_AND_ASSIGN(DeviceMonitorLinux); +}; + +} // namespace media + +#endif // MEDIA_DEVICE_MONITORS_DEVICE_MONITOR_UDEV_H_
diff --git a/media/device_monitors/system_message_window_win.cc b/media/device_monitors/system_message_window_win.cc new file mode 100644 index 0000000..49c1575 --- /dev/null +++ b/media/device_monitors/system_message_window_win.cc
@@ -0,0 +1,159 @@ +// 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 "media/device_monitors/system_message_window_win.h" + +#include <dbt.h> +#include <stddef.h> + +#include "base/logging.h" +#include "base/macros.h" +#include "base/system_monitor/system_monitor.h" +#include "base/win/wrapped_window_proc.h" +#include "media/audio/win/core_audio_util_win.h" + +namespace media { + +namespace { +const wchar_t kWindowClassName[] = L"Chrome_SystemMessageWindow"; + +// A static map from a device category guid to base::SystemMonitor::DeviceType. +struct { + const GUID device_category; + const base::SystemMonitor::DeviceType device_type; +} const kDeviceCategoryMap[] = { + {KSCATEGORY_AUDIO, base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE}, + {KSCATEGORY_VIDEO, base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE}, +}; +} // namespace + +// Manages the device notification handles for SystemMessageWindowWin. +class SystemMessageWindowWin::DeviceNotifications { + public: + explicit DeviceNotifications(HWND hwnd) : notifications_() { Register(hwnd); } + + ~DeviceNotifications() { Unregister(); } + + void Register(HWND hwnd) { + // Request to receive device notifications. All applications receive basic + // notifications via WM_DEVICECHANGE but in order to receive detailed device + // arrival and removal messages, we need to register. + DEV_BROADCAST_DEVICEINTERFACE filter = {0}; + filter.dbcc_size = sizeof(filter); + filter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; + bool core_audio_support = media::CoreAudioUtil::IsSupported(); + for (size_t i = 0; i < arraysize(kDeviceCategoryMap); ++i) { + // If CoreAudio is supported, AudioDeviceListenerWin will + // take care of monitoring audio devices. + if (core_audio_support && + KSCATEGORY_AUDIO == kDeviceCategoryMap[i].device_category) { + continue; + } + + filter.dbcc_classguid = kDeviceCategoryMap[i].device_category; + DCHECK_EQ(notifications_[i], static_cast<HDEVNOTIFY>(NULL)); + notifications_[i] = RegisterDeviceNotification( + hwnd, &filter, DEVICE_NOTIFY_WINDOW_HANDLE); + DPLOG_IF(ERROR, !notifications_[i]) + << "RegisterDeviceNotification failed"; + } + } + + void Unregister() { + for (size_t i = 0; i < arraysize(notifications_); ++i) { + if (notifications_[i]) { + UnregisterDeviceNotification(notifications_[i]); + notifications_[i] = NULL; + } + } + } + + private: + HDEVNOTIFY notifications_[arraysize(kDeviceCategoryMap)]; + + DISALLOW_IMPLICIT_CONSTRUCTORS(DeviceNotifications); +}; + +SystemMessageWindowWin::SystemMessageWindowWin() { + WNDCLASSEX window_class; + base::win::InitializeWindowClass( + kWindowClassName, + &base::win::WrappedWindowProc<SystemMessageWindowWin::WndProcThunk>, 0, 0, + 0, NULL, NULL, NULL, NULL, NULL, &window_class); + instance_ = window_class.hInstance; + ATOM clazz = RegisterClassEx(&window_class); + DCHECK(clazz); + + window_ = + CreateWindow(kWindowClassName, 0, 0, 0, 0, 0, 0, 0, 0, instance_, 0); + SetWindowLongPtr(window_, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this)); + device_notifications_.reset(new DeviceNotifications(window_)); +} + +SystemMessageWindowWin::~SystemMessageWindowWin() { + if (window_) { + DestroyWindow(window_); + UnregisterClass(kWindowClassName, instance_); + } +} + +LRESULT SystemMessageWindowWin::OnDeviceChange(UINT event_type, LPARAM data) { + base::SystemMonitor* monitor = base::SystemMonitor::Get(); + base::SystemMonitor::DeviceType device_type = + base::SystemMonitor::DEVTYPE_UNKNOWN; + switch (event_type) { + case DBT_DEVNODES_CHANGED: + // For this notification, we're happy with the default DEVTYPE_UNKNOWN. + break; + + case DBT_DEVICEREMOVECOMPLETE: + case DBT_DEVICEARRIVAL: { + // This notification has more details about the specific device that + // was added or removed. See if this is a category we're interested + // in monitoring and if so report the specific device type. If we don't + // find the category in our map, ignore the notification and do not + // notify the system monitor. + DEV_BROADCAST_DEVICEINTERFACE* device_interface = + reinterpret_cast<DEV_BROADCAST_DEVICEINTERFACE*>(data); + if (device_interface->dbcc_devicetype != DBT_DEVTYP_DEVICEINTERFACE) + return TRUE; + for (const auto& map_entry : kDeviceCategoryMap) { + if (map_entry.device_category == device_interface->dbcc_classguid) { + device_type = map_entry.device_type; + break; + } + } + + // Devices that we do not have a DEVTYPE_ for, get detected via + // DBT_DEVNODES_CHANGED, so we avoid sending additional notifications + // for those here. + if (device_type == base::SystemMonitor::DEVTYPE_UNKNOWN) + return TRUE; + break; + } + + default: + return TRUE; + } + + monitor->ProcessDevicesChanged(device_type); + + return TRUE; +} + +LRESULT CALLBACK SystemMessageWindowWin::WndProc(HWND hwnd, + UINT message, + WPARAM wparam, + LPARAM lparam) { + switch (message) { + case WM_DEVICECHANGE: + return OnDeviceChange(static_cast<UINT>(wparam), lparam); + default: + break; + } + + return ::DefWindowProc(hwnd, message, wparam, lparam); +} + +} // namespace media
diff --git a/media/device_monitors/system_message_window_win.h b/media/device_monitors/system_message_window_win.h new file mode 100644 index 0000000..a5223044 --- /dev/null +++ b/media/device_monitors/system_message_window_win.h
@@ -0,0 +1,54 @@ +// 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. + +#ifndef MEDIA_DEVICE_MONITORS_SYSTEM_MESSAGE_WINDOW_WIN_H_ +#define MEDIA_DEVICE_MONITORS_SYSTEM_MESSAGE_WINDOW_WIN_H_ + +#include <windows.h> + +#include <memory> + +#include "base/macros.h" +#include "media/base/media_export.h" + +namespace media { + +class MEDIA_EXPORT SystemMessageWindowWin { + public: + SystemMessageWindowWin(); + + virtual ~SystemMessageWindowWin(); + + virtual LRESULT OnDeviceChange(UINT event_type, LPARAM data); + + private: + void Init(); + + LRESULT CALLBACK WndProc(HWND hwnd, + UINT message, + WPARAM wparam, + LPARAM lparam); + + static LRESULT CALLBACK WndProcThunk(HWND hwnd, + UINT message, + WPARAM wparam, + LPARAM lparam) { + SystemMessageWindowWin* msg_wnd = reinterpret_cast<SystemMessageWindowWin*>( + GetWindowLongPtr(hwnd, GWLP_USERDATA)); + if (msg_wnd) + return msg_wnd->WndProc(hwnd, message, wparam, lparam); + return ::DefWindowProc(hwnd, message, wparam, lparam); + } + + HMODULE instance_; + HWND window_; + class DeviceNotifications; + std::unique_ptr<DeviceNotifications> device_notifications_; + + DISALLOW_COPY_AND_ASSIGN(SystemMessageWindowWin); +}; + +} // namespace media + +#endif // MEDIA_DEVICE_MONITORS_SYSTEM_MESSAGE_WINDOW_WIN_H_
diff --git a/media/device_monitors/system_message_window_win_unittest.cc b/media/device_monitors/system_message_window_win_unittest.cc new file mode 100644 index 0000000..dff7b5af --- /dev/null +++ b/media/device_monitors/system_message_window_win_unittest.cc
@@ -0,0 +1,46 @@ +// 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 "media/device_monitors/system_message_window_win.h" + +#include <dbt.h> +#include <string> +#include <vector> + +#include "base/files/file_path.h" +#include "base/message_loop/message_loop.h" +#include "base/system_monitor/system_monitor.h" +#include "base/test/mock_devices_changed_observer.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace media { + +class SystemMessageWindowWinTest : public testing::Test { + public: + ~SystemMessageWindowWinTest() override {} + + protected: + void SetUp() override { + system_monitor_.AddDevicesChangedObserver(&observer_); + } + + base::MessageLoop message_loop_; + base::SystemMonitor system_monitor_; + base::MockDevicesChangedObserver observer_; + SystemMessageWindowWin window_; +}; + +TEST_F(SystemMessageWindowWinTest, DevicesChanged) { + EXPECT_CALL(observer_, OnDevicesChanged(testing::_)).Times(1); + window_.OnDeviceChange(DBT_DEVNODES_CHANGED, NULL); + message_loop_.RunUntilIdle(); +} + +TEST_F(SystemMessageWindowWinTest, RandomMessage) { + window_.OnDeviceChange(DBT_DEVICEQUERYREMOVE, NULL); + message_loop_.RunUntilIdle(); +} + +} // namespace media
diff --git a/media/filters/android/media_codec_audio_decoder.cc b/media/filters/android/media_codec_audio_decoder.cc index 6bfeb2d..c1db1d9 100644 --- a/media/filters/android/media_codec_audio_decoder.cc +++ b/media/filters/android/media_codec_audio_decoder.cc
@@ -158,7 +158,9 @@ return false; } - codec_loop_.reset(new MediaCodecLoop(this, std::move(audio_codec_bridge))); + codec_loop_.reset( + new MediaCodecLoop(base::android::BuildInfo::GetInstance()->sdk_int(), + this, std::move(audio_codec_bridge))); return true; }
diff --git a/media/filters/default_media_permission.cc b/media/filters/default_media_permission.cc deleted file mode 100644 index 8a9223f..0000000 --- a/media/filters/default_media_permission.cc +++ /dev/null
@@ -1,49 +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 "media/filters/default_media_permission.h" - -#include "base/bind.h" -#include "base/location.h" -#include "base/logging.h" -#include "base/single_thread_task_runner.h" -#include "base/threading/thread_task_runner_handle.h" - -namespace media { - -DefaultMediaPermission::DefaultMediaPermission(bool allow) : allow_(allow) { -} - -DefaultMediaPermission::~DefaultMediaPermission() { -} - -static void FirePermissionStatusCallback( - const MediaPermission::PermissionStatusCB& permission_status_cb, - bool allow) { - LOG(WARNING) << (allow ? "Allowing" : "Denying") - << "media permission request with a default value instead of " - "real user's consent. This should NOT be used for in a real " - "user-facing product."; - // Return the callback asynchronously. - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(permission_status_cb, allow)); -} - -void DefaultMediaPermission::HasPermission( - Type type, - const GURL& /* security_origin */, - const PermissionStatusCB& permission_status_cb) { - CHECK_EQ(PROTECTED_MEDIA_IDENTIFIER, type); - FirePermissionStatusCallback(permission_status_cb, allow_); -} - -void DefaultMediaPermission::RequestPermission( - Type type, - const GURL& /* security_origin */, - const PermissionStatusCB& permission_status_cb) { - CHECK_EQ(PROTECTED_MEDIA_IDENTIFIER, type); - FirePermissionStatusCallback(permission_status_cb, allow_); -} - -} // namespace media
diff --git a/media/filters/default_media_permission.h b/media/filters/default_media_permission.h deleted file mode 100644 index 434e1f5c..0000000 --- a/media/filters/default_media_permission.h +++ /dev/null
@@ -1,40 +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 MEDIA_FILTERS_DEFAULT_MEDIA_PERMISSION_H_ -#define MEDIA_FILTERS_DEFAULT_MEDIA_PERMISSION_H_ - -#include "base/macros.h" -#include "media/base/media_export.h" -#include "media/base/media_permission.h" - -namespace media { - -// Default MediaPermission implementation that will always allow or deny the -// permission request/check based on |allow|. -// WARNING: This class allows or denies permission request/check without real -// user's consent. It should NOT be used in a real user facing product. -class MEDIA_EXPORT DefaultMediaPermission : public MediaPermission { - public: - explicit DefaultMediaPermission(bool allow); - ~DefaultMediaPermission() override; - - // media::MediaPermission implementation. - void HasPermission(Type type, - const GURL& security_origin, - const PermissionStatusCB& permission_status_cb) override; - void RequestPermission( - Type type, - const GURL& security_origin, - const PermissionStatusCB& permission_status_cb) override; - - private: - const bool allow_; - - DISALLOW_COPY_AND_ASSIGN(DefaultMediaPermission); -}; - -} // namespace media - -#endif // MEDIA_FILTERS_DEFAULT_MEDIA_PERMISSION_H_
diff --git a/media/gpu/media_foundation_video_encode_accelerator_win.cc b/media/gpu/media_foundation_video_encode_accelerator_win.cc index 9e4b194..4bc2c8b 100644 --- a/media/gpu/media_foundation_video_encode_accelerator_win.cc +++ b/media/gpu/media_foundation_video_encode_accelerator_win.cc
@@ -11,6 +11,7 @@ #include <mferror.h> #include <mftransform.h> +#include <iterator> #include <utility> #include <vector> @@ -29,10 +30,11 @@ namespace { +const int32_t kDefaultTargetBitrate = 5000000; const size_t kMaxFrameRateNumerator = 30; const size_t kMaxFrameRateDenominator = 1; -const size_t kMaxResolutionWidth = 4096; -const size_t kMaxResolutionHeight = 2160; +const size_t kMaxResolutionWidth = 1920; +const size_t kMaxResolutionHeight = 1088; const size_t kNumInputBuffers = 3; const size_t kOneSecondInMicroseconds = 1000000; const size_t kOutputSampleBufferSizeRatio = 4; @@ -96,13 +98,18 @@ DCHECK(sequence_checker_.CalledOnValidSequence()); SupportedProfiles profiles; - const bool rv = CreateHardwareEncoderMFT(); - encoder_.Release(); - if (!rv) { + + target_bitrate_ = kDefaultTargetBitrate; + frame_rate_ = kMaxFrameRateNumerator / kMaxFrameRateDenominator; + input_visible_size_ = gfx::Size(kMaxResolutionWidth, kMaxResolutionHeight); + if (!CreateHardwareEncoderMFT() || !SetEncoderModes() || + !InitializeInputOutputSamples()) { + ReleaseEncoderResources(); DVLOG(1) << "Hardware encode acceleration is not available on this platform."; return profiles; } + ReleaseEncoderResources(); SupportedProfile profile; // More profiles can be supported here, but they should be available in SW @@ -156,7 +163,6 @@ frame_rate_ = kMaxFrameRateNumerator / kMaxFrameRateDenominator; target_bitrate_ = initial_bitrate; bitstream_buffer_size_ = input_visible_size.GetArea(); - u_plane_offset_ = VideoFrame::PlaneSize(PIXEL_FORMAT_I420, VideoFrame::kYPlane, input_visible_size_) @@ -167,16 +173,21 @@ input_visible_size_) .GetArea(); - if (!InitializeInputOutputSamples()) { - DLOG(ERROR) << "Failed initializing input-output samples."; - return false; - } if (!SetEncoderModes()) { DLOG(ERROR) << "Failed setting encoder parameters."; return false; } + if (!InitializeInputOutputSamples()) { + DLOG(ERROR) << "Failed initializing input-output samples."; + return false; + } + input_sample_.Attach(mf::CreateEmptySampleWithBuffer( + VideoFrame::AllocationSize(PIXEL_FORMAT_I420, input_visible_size_), 2)); + output_sample_.Attach(mf::CreateEmptySampleWithBuffer( + bitstream_buffer_size_ * kOutputSampleBufferSizeRatio, 2)); + HRESULT hr = encoder_->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, NULL); RETURN_ON_HR_FAILURE(hr, "Couldn't set ProcessMessage", false); @@ -308,66 +319,51 @@ bool MediaFoundationVideoEncodeAccelerator::InitializeInputOutputSamples() { DCHECK(sequence_checker_.CalledOnValidSequence()); - HRESULT hr = encoder_->GetStreamLimits( - &input_stream_count_min_, &input_stream_count_max_, - &output_stream_count_min_, &output_stream_count_max_); - RETURN_ON_HR_FAILURE(hr, "Couldn't query stream limits", false); - DVLOG(3) << "Stream limits: " << input_stream_count_min_ << "," - << input_stream_count_max_ << "," << output_stream_count_min_ << "," - << output_stream_count_max_; - // Initialize output parameters. - base::win::ScopedComPtr<IMFMediaType> imf_output_media_type; - hr = MFCreateMediaType(imf_output_media_type.Receive()); + HRESULT hr = MFCreateMediaType(imf_output_media_type_.Receive()); RETURN_ON_HR_FAILURE(hr, "Couldn't create media type", false); - hr = imf_output_media_type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); + hr = imf_output_media_type_->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); RETURN_ON_HR_FAILURE(hr, "Couldn't set media type", false); - hr = imf_output_media_type->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264); + hr = imf_output_media_type_->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264); RETURN_ON_HR_FAILURE(hr, "Couldn't set video format", false); - hr = imf_output_media_type->SetUINT32(MF_MT_AVG_BITRATE, target_bitrate_); + hr = imf_output_media_type_->SetUINT32(MF_MT_AVG_BITRATE, target_bitrate_); RETURN_ON_HR_FAILURE(hr, "Couldn't set bitrate", false); - hr = MFSetAttributeRatio(imf_output_media_type.get(), MF_MT_FRAME_RATE, + hr = MFSetAttributeRatio(imf_output_media_type_.get(), MF_MT_FRAME_RATE, frame_rate_, kMaxFrameRateDenominator); RETURN_ON_HR_FAILURE(hr, "Couldn't set frame rate", false); - hr = MFSetAttributeSize(imf_output_media_type.get(), MF_MT_FRAME_SIZE, + hr = MFSetAttributeSize(imf_output_media_type_.get(), MF_MT_FRAME_SIZE, input_visible_size_.width(), input_visible_size_.height()); RETURN_ON_HR_FAILURE(hr, "Couldn't set frame size", false); - hr = imf_output_media_type->SetUINT32(MF_MT_INTERLACE_MODE, - MFVideoInterlace_Progressive); + hr = imf_output_media_type_->SetUINT32(MF_MT_INTERLACE_MODE, + MFVideoInterlace_Progressive); RETURN_ON_HR_FAILURE(hr, "Couldn't set interlace mode", false); - hr = imf_output_media_type->SetUINT32(MF_MT_MPEG2_PROFILE, - eAVEncH264VProfile_Base); + hr = imf_output_media_type_->SetUINT32(MF_MT_MPEG2_PROFILE, + eAVEncH264VProfile_Base); RETURN_ON_HR_FAILURE(hr, "Couldn't set codec profile", false); - hr = encoder_->SetOutputType(0, imf_output_media_type.get(), 0); + hr = encoder_->SetOutputType(0, imf_output_media_type_.get(), 0); RETURN_ON_HR_FAILURE(hr, "Couldn't set output media type", false); // Initialize input parameters. - base::win::ScopedComPtr<IMFMediaType> imf_input_media_type; - hr = MFCreateMediaType(imf_input_media_type.Receive()); + hr = MFCreateMediaType(imf_input_media_type_.Receive()); RETURN_ON_HR_FAILURE(hr, "Couldn't create media type", false); - hr = imf_input_media_type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); + hr = imf_input_media_type_->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); RETURN_ON_HR_FAILURE(hr, "Couldn't set media type", false); - hr = imf_input_media_type->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_YV12); + hr = imf_input_media_type_->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_YV12); RETURN_ON_HR_FAILURE(hr, "Couldn't set video format", false); - hr = MFSetAttributeRatio(imf_input_media_type.get(), MF_MT_FRAME_RATE, + hr = MFSetAttributeRatio(imf_input_media_type_.get(), MF_MT_FRAME_RATE, frame_rate_, kMaxFrameRateDenominator); RETURN_ON_HR_FAILURE(hr, "Couldn't set frame rate", false); - hr = MFSetAttributeSize(imf_input_media_type.get(), MF_MT_FRAME_SIZE, + hr = MFSetAttributeSize(imf_input_media_type_.get(), MF_MT_FRAME_SIZE, input_visible_size_.width(), input_visible_size_.height()); RETURN_ON_HR_FAILURE(hr, "Couldn't set frame size", false); - hr = imf_input_media_type->SetUINT32(MF_MT_INTERLACE_MODE, - MFVideoInterlace_Progressive); + hr = imf_input_media_type_->SetUINT32(MF_MT_INTERLACE_MODE, + MFVideoInterlace_Progressive); RETURN_ON_HR_FAILURE(hr, "Couldn't set interlace mode", false); - hr = encoder_->SetInputType(0, imf_input_media_type.get(), 0); + hr = encoder_->SetInputType(0, imf_input_media_type_.get(), 0); RETURN_ON_HR_FAILURE(hr, "Couldn't set input media type", false); - input_sample_.Attach(mf::CreateEmptySampleWithBuffer( - VideoFrame::AllocationSize(PIXEL_FORMAT_I420, input_visible_size_), 2)); - output_sample_.Attach(mf::CreateEmptySampleWithBuffer( - bitstream_buffer_size_ * kOutputSampleBufferSizeRatio, 2)); - return SUCCEEDED(hr); } @@ -560,12 +556,9 @@ HRESULT hr = codec_api_->SetValue(&CODECAPI_AVEncCommonMeanBitRate, &var); RETURN_ON_HR_FAILURE(hr, "Couldn't set bitrate", ); - base::win::ScopedComPtr<IMFMediaType> imf_output_media_type; - hr = MFCreateMediaType(imf_output_media_type.Receive()); - RETURN_ON_HR_FAILURE(hr, "Couldn't create output media type", ); - hr = imf_output_media_type->SetUINT32(MF_MT_AVG_BITRATE, target_bitrate_); + hr = imf_output_media_type_->SetUINT32(MF_MT_AVG_BITRATE, target_bitrate_); RETURN_ON_HR_FAILURE(hr, "Couldn't set bitrate", ); - hr = MFSetAttributeRatio(imf_output_media_type.get(), MF_MT_FRAME_RATE, + hr = MFSetAttributeRatio(imf_output_media_type_.get(), MF_MT_FRAME_RATE, frame_rate_, kMaxFrameRateDenominator); RETURN_ON_HR_FAILURE(hr, "Couldn't set output type params", ); } @@ -577,7 +570,16 @@ // Cancel all encoder thread callbacks. encoder_task_weak_factory_.InvalidateWeakPtrs(); + ReleaseEncoderResources(); +} + +void MediaFoundationVideoEncodeAccelerator::ReleaseEncoderResources() { encoder_.Release(); + codec_api_.Release(); + imf_input_media_type_.Release(); + imf_output_media_type_.Release(); + input_sample_.Release(); + output_sample_.Release(); } } // namespace content
diff --git a/media/gpu/media_foundation_video_encode_accelerator_win.h b/media/gpu/media_foundation_video_encode_accelerator_win.h index d820e9d..b4ce66e2 100644 --- a/media/gpu/media_foundation_video_encode_accelerator_win.h +++ b/media/gpu/media_foundation_video_encode_accelerator_win.h
@@ -97,6 +97,9 @@ // Destroys encode session on |encoder_thread_|. void DestroyTask(); + // Releases resources encoder holds. + void ReleaseEncoderResources(); + // Bitstream buffers ready to be used to return encoded output as a FIFO. std::deque<std::unique_ptr<BitstreamBufferRef>> bitstream_buffer_queue_; @@ -113,10 +116,8 @@ base::win::ScopedComPtr<IMFTransform> encoder_; base::win::ScopedComPtr<ICodecAPI> codec_api_; - DWORD input_stream_count_min_; - DWORD input_stream_count_max_; - DWORD output_stream_count_min_; - DWORD output_stream_count_max_; + base::win::ScopedComPtr<IMFMediaType> imf_input_media_type_; + base::win::ScopedComPtr<IMFMediaType> imf_output_media_type_; base::win::ScopedComPtr<IMFSample> input_sample_; base::win::ScopedComPtr<IMFSample> output_sample_;
diff --git a/media/media.gyp b/media/media.gyp index 8f65476..0648a3a8 100644 --- a/media/media.gyp +++ b/media/media.gyp
@@ -519,8 +519,6 @@ 'filters/decrypting_demuxer_stream.h', 'filters/decrypting_video_decoder.cc', 'filters/decrypting_video_decoder.h', - 'filters/default_media_permission.cc', - 'filters/default_media_permission.h', 'filters/ffmpeg_audio_decoder.cc', 'filters/ffmpeg_audio_decoder.h', 'filters/ffmpeg_bitstream_converter.h',
diff --git a/mojo/android/BUILD.gn b/mojo/android/BUILD.gn index 2b4db7a..f9bdb0a 100644 --- a/mojo/android/BUILD.gn +++ b/mojo/android/BUILD.gn
@@ -29,6 +29,7 @@ sources = [ "system/src/org/chromium/mojo/system/impl/BaseRunLoop.java", "system/src/org/chromium/mojo/system/impl/CoreImpl.java", + "system/src/org/chromium/mojo/system/impl/WatcherImpl.java", ] jni_package = "mojo" @@ -40,12 +41,15 @@ "system/base_run_loop.h", "system/core_impl.cc", "system/core_impl.h", + "system/watcher_impl.cc", + "system/watcher_impl.h", ] deps = [ ":system_java_jni_headers", "//base", - "//mojo/message_pump", + "//mojo/public/c/system", + "//mojo/public/cpp/system", ] } @@ -59,6 +63,7 @@ "system/src/org/chromium/mojo/system/impl/MessagePipeHandleImpl.java", "system/src/org/chromium/mojo/system/impl/SharedBufferHandleImpl.java", "system/src/org/chromium/mojo/system/impl/UntypedHandleImpl.java", + "system/src/org/chromium/mojo/system/impl/WatcherImpl.java", ] deps = [ @@ -90,6 +95,7 @@ "javatests/src/org/chromium/mojo/bindings/ValidationTestUtil.java", "javatests/src/org/chromium/mojo/bindings/ValidationTestUtilTest.java", "javatests/src/org/chromium/mojo/system/impl/CoreImplTest.java", + "javatests/src/org/chromium/mojo/system/impl/WatcherImplTest.java", ] deps = [ @@ -127,7 +133,6 @@ "//base/test/:test_support", "//build/config/sanitizers:deps", "//mojo/edk/system", - "//mojo/message_pump", "//mojo/public/cpp/bindings/tests:mojo_public_bindings_test_utils", "//mojo/public/cpp/test_support:test_utils", ]
diff --git a/mojo/android/javatests/init_library.cc b/mojo/android/javatests/init_library.cc index d2d9423..96752401 100644 --- a/mojo/android/javatests/init_library.cc +++ b/mojo/android/javatests/init_library.cc
@@ -10,14 +10,16 @@ #include "mojo/android/javatests/mojo_test_case.h" #include "mojo/android/javatests/validation_test_util.h" #include "mojo/android/system/core_impl.h" +#include "mojo/android/system/watcher_impl.h" #include "mojo/edk/embedder/embedder.h" namespace { base::android::RegistrationMethod kMojoRegisteredMethods[] = { - { "CoreImpl", mojo::android::RegisterCoreImpl }, - { "MojoTestCase", mojo::android::RegisterMojoTestCase }, - { "ValidationTestUtil", mojo::android::RegisterValidationTestUtil }, + {"CoreImpl", mojo::android::RegisterCoreImpl}, + {"MojoTestCase", mojo::android::RegisterMojoTestCase}, + {"ValidationTestUtil", mojo::android::RegisterValidationTestUtil}, + {"WatcherImpl", mojo::android::RegisterWatcherImpl}, }; bool RegisterJNI(JNIEnv* env) {
diff --git a/mojo/android/javatests/mojo_test_case.cc b/mojo/android/javatests/mojo_test_case.cc index d8c94f8..fc59009b 100644 --- a/mojo/android/javatests/mojo_test_case.cc +++ b/mojo/android/javatests/mojo_test_case.cc
@@ -16,14 +16,13 @@ #include "base/test/test_support_android.h" #include "base/threading/thread_task_runner_handle.h" #include "jni/MojoTestCase_jni.h" -#include "mojo/message_pump/message_pump_mojo.h" using base::android::JavaParamRef; namespace { struct TestEnvironment { - TestEnvironment() : message_loop(mojo::common::MessagePumpMojo::Create()) {} + TestEnvironment() {} base::ShadowingAtExitManager at_exit; base::MessageLoop message_loop;
diff --git a/mojo/android/javatests/src/org/chromium/mojo/bindings/ValidationTest.java b/mojo/android/javatests/src/org/chromium/mojo/bindings/ValidationTest.java index e5c4549..f4b128ff 100644 --- a/mojo/android/javatests/src/org/chromium/mojo/bindings/ValidationTest.java +++ b/mojo/android/javatests/src/org/chromium/mojo/bindings/ValidationTest.java
@@ -13,6 +13,7 @@ import org.chromium.mojo.bindings.test.mojom.mojo.IntegrationTestInterface; import org.chromium.mojo.bindings.test.mojom.mojo.IntegrationTestInterfaceTestHelper; import org.chromium.mojo.system.Handle; +import org.chromium.mojo.system.impl.CoreImpl; import java.io.File; import java.io.FileFilter; @@ -189,8 +190,10 @@ */ @SmallTest public void testConformance() throws FileNotFoundException { - runTest("conformance_", ConformanceTestInterface.MANAGER.buildStub(null, - ConformanceTestInterface.MANAGER.buildProxy(null, new SinkMessageReceiver()))); + runTest("conformance_", + ConformanceTestInterface.MANAGER.buildStub(CoreImpl.getInstance(), + ConformanceTestInterface.MANAGER.buildProxy( + CoreImpl.getInstance(), new SinkMessageReceiver()))); } /**
diff --git a/mojo/android/javatests/src/org/chromium/mojo/system/impl/CoreImplTest.java b/mojo/android/javatests/src/org/chromium/mojo/system/impl/CoreImplTest.java index 16c16f2..d7c3b81 100644 --- a/mojo/android/javatests/src/org/chromium/mojo/system/impl/CoreImplTest.java +++ b/mojo/android/javatests/src/org/chromium/mojo/system/impl/CoreImplTest.java
@@ -7,9 +7,6 @@ import android.test.suitebuilder.annotation.SmallTest; import org.chromium.mojo.MojoTestCase; -import org.chromium.mojo.system.AsyncWaiter; -import org.chromium.mojo.system.AsyncWaiter.Callback; -import org.chromium.mojo.system.AsyncWaiter.Cancellable; import org.chromium.mojo.system.Core; import org.chromium.mojo.system.Core.HandleSignals; import org.chromium.mojo.system.Core.HandleSignalsState; @@ -584,266 +581,6 @@ } } - private static class AsyncWaiterResult implements Callback { - private int mResult = Integer.MIN_VALUE; - private MojoException mException = null; - - /** - * @see Callback#onResult(int) - */ - @Override - public void onResult(int result) { - this.mResult = result; - } - - /** - * @see Callback#onError(MojoException) - */ - @Override - public void onError(MojoException exception) { - this.mException = exception; - } - - /** - * @return the result - */ - public int getResult() { - return mResult; - } - - /** - * @return the exception - */ - public MojoException getException() { - return mException; - } - } - - /** - * Testing core {@link AsyncWaiter} implementation. - */ - @SmallTest - public void testAsyncWaiterCorrectResult() { - Core core = CoreImpl.getInstance(); - - // Checking a correct result. - Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(null); - addHandlePairToClose(handles); - final AsyncWaiterResult asyncWaiterResult = new AsyncWaiterResult(); - assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); - assertEquals(null, asyncWaiterResult.getException()); - - core.getDefaultAsyncWaiter().asyncWait(handles.first, Core.HandleSignals.READABLE, - Core.DEADLINE_INFINITE, asyncWaiterResult); - assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); - assertEquals(null, asyncWaiterResult.getException()); - - handles.second.writeMessage( - ByteBuffer.allocateDirect(1), null, MessagePipeHandle.WriteFlags.NONE); - runLoopUntilIdle(); - assertNull(asyncWaiterResult.getException()); - assertEquals(MojoResult.OK, asyncWaiterResult.getResult()); - } - - /** - * Testing core {@link AsyncWaiter} implementation. - */ - @SmallTest - public void testAsyncWaiterClosingPeerHandle() { - Core core = CoreImpl.getInstance(); - - // Closing the peer handle. - Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(null); - addHandlePairToClose(handles); - - final AsyncWaiterResult asyncWaiterResult = new AsyncWaiterResult(); - assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); - assertEquals(null, asyncWaiterResult.getException()); - - core.getDefaultAsyncWaiter().asyncWait(handles.first, Core.HandleSignals.READABLE, - Core.DEADLINE_INFINITE, asyncWaiterResult); - assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); - assertEquals(null, asyncWaiterResult.getException()); - - runLoopUntilIdle(); - assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); - assertEquals(null, asyncWaiterResult.getException()); - - handles.second.close(); - runLoopUntilIdle(); - assertNull(asyncWaiterResult.getException()); - assertEquals(MojoResult.FAILED_PRECONDITION, asyncWaiterResult.getResult()); - } - - /** - * Testing core {@link AsyncWaiter} implementation. - */ - @SmallTest - public void testAsyncWaiterClosingWaitingHandle() { - Core core = CoreImpl.getInstance(); - - // Closing the peer handle. - Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(null); - addHandlePairToClose(handles); - - final AsyncWaiterResult asyncWaiterResult = new AsyncWaiterResult(); - assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); - assertEquals(null, asyncWaiterResult.getException()); - - core.getDefaultAsyncWaiter().asyncWait(handles.first, Core.HandleSignals.READABLE, - Core.DEADLINE_INFINITE, asyncWaiterResult); - assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); - assertEquals(null, asyncWaiterResult.getException()); - - runLoopUntilIdle(); - assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); - assertEquals(null, asyncWaiterResult.getException()); - - handles.first.close(); - runLoopUntilIdle(); - // TODO(qsr) Re-enable when MojoWaitMany handles it correctly. - // assertNull(asyncWaiterResult.getException()); - // assertEquals(MojoResult.CANCELLED, asyncWaiterResult.getResult()); - } - - /** - * Testing core {@link AsyncWaiter} implementation. - */ - @SmallTest - public void testAsyncWaiterWaitingOnInvalidHandle() { - Core core = CoreImpl.getInstance(); - - // Closing the peer handle. - Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(null); - addHandlePairToClose(handles); - - final AsyncWaiterResult asyncWaiterResult = new AsyncWaiterResult(); - assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); - assertEquals(null, asyncWaiterResult.getException()); - - handles.first.close(); - core.getDefaultAsyncWaiter().asyncWait(handles.first, Core.HandleSignals.READABLE, - Core.DEADLINE_INFINITE, asyncWaiterResult); - assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); - assertEquals(null, asyncWaiterResult.getException()); - - runLoopUntilIdle(); - assertNotNull(asyncWaiterResult.getException()); - assertEquals(MojoResult.INVALID_ARGUMENT, - asyncWaiterResult.getException().getMojoResult()); - assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); - } - - /** - * Testing core {@link AsyncWaiter} implementation. - */ - @SmallTest - public void testAsyncWaiterWaitingOnDefaultInvalidHandle() { - Core core = CoreImpl.getInstance(); - - final AsyncWaiterResult asyncWaiterResult = new AsyncWaiterResult(); - assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); - assertEquals(null, asyncWaiterResult.getException()); - - core.getDefaultAsyncWaiter().asyncWait(InvalidHandle.INSTANCE, Core.HandleSignals.READABLE, - Core.DEADLINE_INFINITE, asyncWaiterResult); - assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); - assertEquals(null, asyncWaiterResult.getException()); - - runLoopUntilIdle(); - assertNotNull(asyncWaiterResult.getException()); - assertEquals(MojoResult.INVALID_ARGUMENT, asyncWaiterResult.getException().getMojoResult()); - assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); - } - - /** - * Testing core {@link AsyncWaiter} implementation. - */ - @SmallTest - public void testAsyncWaiterWaitingWithTimeout() { - Core core = CoreImpl.getInstance(); - - // Closing the peer handle. - Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(null); - addHandlePairToClose(handles); - - final AsyncWaiterResult asyncWaiterResult = new AsyncWaiterResult(); - assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); - assertEquals(null, asyncWaiterResult.getException()); - - core.getDefaultAsyncWaiter().asyncWait( - handles.first, Core.HandleSignals.READABLE, RUN_LOOP_TIMEOUT_MS, asyncWaiterResult); - assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); - assertEquals(null, asyncWaiterResult.getException()); - - runLoopUntilIdle(); - assertNull(asyncWaiterResult.getException()); - assertEquals(MojoResult.DEADLINE_EXCEEDED, asyncWaiterResult.getResult()); - } - - /** - * Testing core {@link AsyncWaiter} implementation. - */ - @SmallTest - public void testAsyncWaiterCancelWaiting() { - Core core = CoreImpl.getInstance(); - - // Closing the peer handle. - Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(null); - addHandlePairToClose(handles); - - final AsyncWaiterResult asyncWaiterResult = new AsyncWaiterResult(); - assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); - assertEquals(null, asyncWaiterResult.getException()); - - Cancellable cancellable = core.getDefaultAsyncWaiter().asyncWait(handles.first, - Core.HandleSignals.READABLE, Core.DEADLINE_INFINITE, asyncWaiterResult); - assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); - assertEquals(null, asyncWaiterResult.getException()); - - runLoopUntilIdle(); - assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); - assertEquals(null, asyncWaiterResult.getException()); - - cancellable.cancel(); - runLoopUntilIdle(); - assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); - assertEquals(null, asyncWaiterResult.getException()); - - handles.second.writeMessage( - ByteBuffer.allocateDirect(1), null, MessagePipeHandle.WriteFlags.NONE); - runLoopUntilIdle(); - assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); - assertEquals(null, asyncWaiterResult.getException()); - } - - /** - * Testing core {@link AsyncWaiter} implementation. - */ - @SmallTest - public void testAsyncWaiterImmediateCancelOnInvalidHandle() { - Core core = CoreImpl.getInstance(); - - // Closing the peer handle. - Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(null); - addHandlePairToClose(handles); - - final AsyncWaiterResult asyncWaiterResult = new AsyncWaiterResult(); - handles.first.close(); - assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); - assertEquals(null, asyncWaiterResult.getException()); - - Cancellable cancellable = core.getDefaultAsyncWaiter().asyncWait(handles.first, - Core.HandleSignals.READABLE, Core.DEADLINE_INFINITE, asyncWaiterResult); - assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); - assertEquals(null, asyncWaiterResult.getException()); - cancellable.cancel(); - - runLoopUntilIdle(); - assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); - assertEquals(null, asyncWaiterResult.getException()); - } - /** * Testing the pass method on message pipes. */
diff --git a/mojo/android/javatests/src/org/chromium/mojo/system/impl/WatcherImplTest.java b/mojo/android/javatests/src/org/chromium/mojo/system/impl/WatcherImplTest.java new file mode 100644 index 0000000..862b8ca4 --- /dev/null +++ b/mojo/android/javatests/src/org/chromium/mojo/system/impl/WatcherImplTest.java
@@ -0,0 +1,239 @@ +// 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. + +package org.chromium.mojo.system.impl; + +import android.test.suitebuilder.annotation.SmallTest; + +import org.chromium.mojo.MojoTestCase; +import org.chromium.mojo.system.Core; +import org.chromium.mojo.system.Handle; +import org.chromium.mojo.system.InvalidHandle; +import org.chromium.mojo.system.MessagePipeHandle; +import org.chromium.mojo.system.MojoException; +import org.chromium.mojo.system.MojoResult; +import org.chromium.mojo.system.Pair; +import org.chromium.mojo.system.Watcher; +import org.chromium.mojo.system.Watcher.Callback; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +/** + * Testing the Watcher. + */ +public class WatcherImplTest extends MojoTestCase { + private List<Handle> mHandlesToClose = new ArrayList<Handle>(); + private Watcher mWatcher; + private Core mCore; + + /** + * @see MojoTestCase#setUp() + */ + @Override + protected void setUp() throws Exception { + super.setUp(); + mWatcher = new WatcherImpl(); + mCore = CoreImpl.getInstance(); + } + + /** + * @see MojoTestCase#tearDown() + */ + @Override + protected void tearDown() throws Exception { + mWatcher.destroy(); + MojoException toThrow = null; + for (Handle handle : mHandlesToClose) { + try { + handle.close(); + } catch (MojoException e) { + if (toThrow == null) { + toThrow = e; + } + } + } + if (toThrow != null) { + throw toThrow; + } + super.tearDown(); + } + + private void addHandlePairToClose(Pair<? extends Handle, ? extends Handle> handles) { + mHandlesToClose.add(handles.first); + mHandlesToClose.add(handles.second); + } + + private static class WatcherResult implements Callback { + private int mResult = Integer.MIN_VALUE; + + /** + * @see Callback#onResult(int) + */ + @Override + public void onResult(int result) { + this.mResult = result; + } + + /** + * @return the result + */ + public int getResult() { + return mResult; + } + } + + /** + * Testing {@link Watcher} implementation. + */ + @SmallTest + public void testCorrectResult() { + // Checking a correct result. + Pair<MessagePipeHandle, MessagePipeHandle> handles = mCore.createMessagePipe(null); + addHandlePairToClose(handles); + final WatcherResult watcherResult = new WatcherResult(); + assertEquals(Integer.MIN_VALUE, watcherResult.getResult()); + + mWatcher.start(handles.first, Core.HandleSignals.READABLE, watcherResult); + assertEquals(Integer.MIN_VALUE, watcherResult.getResult()); + + handles.second.writeMessage( + ByteBuffer.allocateDirect(1), null, MessagePipeHandle.WriteFlags.NONE); + runLoopUntilIdle(); + assertEquals(MojoResult.OK, watcherResult.getResult()); + } + + /** + * Testing {@link Watcher} implementation. + */ + @SmallTest + public void testClosingPeerHandle() { + // Closing the peer handle. + Pair<MessagePipeHandle, MessagePipeHandle> handles = mCore.createMessagePipe(null); + addHandlePairToClose(handles); + + final WatcherResult watcherResult = new WatcherResult(); + assertEquals(Integer.MIN_VALUE, watcherResult.getResult()); + + mWatcher.start(handles.first, Core.HandleSignals.READABLE, watcherResult); + assertEquals(Integer.MIN_VALUE, watcherResult.getResult()); + + runLoopUntilIdle(); + assertEquals(Integer.MIN_VALUE, watcherResult.getResult()); + + handles.second.close(); + runLoopUntilIdle(); + assertEquals(MojoResult.FAILED_PRECONDITION, watcherResult.getResult()); + } + + /** + * Testing {@link Watcher} implementation. + */ + @SmallTest + public void testClosingWatchedHandle() { + // Closing the peer handle. + Pair<MessagePipeHandle, MessagePipeHandle> handles = mCore.createMessagePipe(null); + addHandlePairToClose(handles); + + final WatcherResult watcherResult = new WatcherResult(); + assertEquals(Integer.MIN_VALUE, watcherResult.getResult()); + + mWatcher.start(handles.first, Core.HandleSignals.READABLE, watcherResult); + assertEquals(Integer.MIN_VALUE, watcherResult.getResult()); + + runLoopUntilIdle(); + assertEquals(Integer.MIN_VALUE, watcherResult.getResult()); + + handles.first.close(); + runLoopUntilIdle(); + assertEquals(MojoResult.CANCELLED, watcherResult.getResult()); + } + + /** + * Testing {@link Watcher} implementation. + */ + @SmallTest + public void testInvalidHandle() { + // Closing the peer handle. + Pair<MessagePipeHandle, MessagePipeHandle> handles = mCore.createMessagePipe(null); + addHandlePairToClose(handles); + + final WatcherResult watcherResult = new WatcherResult(); + assertEquals(Integer.MIN_VALUE, watcherResult.getResult()); + + handles.first.close(); + assertEquals(MojoResult.INVALID_ARGUMENT, + mWatcher.start(handles.first, Core.HandleSignals.READABLE, watcherResult)); + assertEquals(Integer.MIN_VALUE, watcherResult.getResult()); + + runLoopUntilIdle(); + assertEquals(Integer.MIN_VALUE, watcherResult.getResult()); + } + + /** + * Testing {@link Watcher} implementation. + */ + @SmallTest + public void testDefaultInvalidHandle() { + final WatcherResult watcherResult = new WatcherResult(); + assertEquals(Integer.MIN_VALUE, watcherResult.getResult()); + + assertEquals(MojoResult.INVALID_ARGUMENT, + mWatcher.start(InvalidHandle.INSTANCE, Core.HandleSignals.READABLE, watcherResult)); + assertEquals(Integer.MIN_VALUE, watcherResult.getResult()); + + runLoopUntilIdle(); + assertEquals(Integer.MIN_VALUE, watcherResult.getResult()); + } + + /** + * Testing {@link Watcher} implementation. + */ + @SmallTest + public void testCancel() { + // Closing the peer handle. + Pair<MessagePipeHandle, MessagePipeHandle> handles = mCore.createMessagePipe(null); + addHandlePairToClose(handles); + + final WatcherResult watcherResult = new WatcherResult(); + assertEquals(Integer.MIN_VALUE, watcherResult.getResult()); + + mWatcher.start(handles.first, Core.HandleSignals.READABLE, watcherResult); + assertEquals(Integer.MIN_VALUE, watcherResult.getResult()); + + runLoopUntilIdle(); + assertEquals(Integer.MIN_VALUE, watcherResult.getResult()); + + mWatcher.cancel(); + runLoopUntilIdle(); + assertEquals(Integer.MIN_VALUE, watcherResult.getResult()); + + handles.second.writeMessage( + ByteBuffer.allocateDirect(1), null, MessagePipeHandle.WriteFlags.NONE); + runLoopUntilIdle(); + assertEquals(Integer.MIN_VALUE, watcherResult.getResult()); + } + + /** + * Testing {@link Watcher} implementation. + */ + @SmallTest + public void testImmediateCancelOnInvalidHandle() { + // Closing the peer handle. + Pair<MessagePipeHandle, MessagePipeHandle> handles = mCore.createMessagePipe(null); + addHandlePairToClose(handles); + + final WatcherResult watcherResult = new WatcherResult(); + handles.first.close(); + assertEquals(Integer.MIN_VALUE, watcherResult.getResult()); + + mWatcher.start(handles.first, Core.HandleSignals.READABLE, watcherResult); + assertEquals(Integer.MIN_VALUE, watcherResult.getResult()); + mWatcher.cancel(); + + runLoopUntilIdle(); + assertEquals(Integer.MIN_VALUE, watcherResult.getResult()); + } +}
diff --git a/mojo/android/system/base_run_loop.cc b/mojo/android/system/base_run_loop.cc index b2276dde..5bf2a3c 100644 --- a/mojo/android/system/base_run_loop.cc +++ b/mojo/android/system/base_run_loop.cc
@@ -12,7 +12,6 @@ #include "base/bind.h" #include "base/message_loop/message_loop.h" #include "jni/BaseRunLoop_jni.h" -#include "mojo/message_pump/message_pump_mojo.h" using base::android::JavaParamRef; @@ -21,8 +20,7 @@ static jlong CreateBaseRunLoop(JNIEnv* env, const JavaParamRef<jobject>& jcaller) { - base::MessageLoop* message_loop = - new base::MessageLoop(common::MessagePumpMojo::Create()); + base::MessageLoop* message_loop = new base::MessageLoop; return reinterpret_cast<uintptr_t>(message_loop); } @@ -80,4 +78,3 @@ } // namespace android } // namespace mojo -
diff --git a/mojo/android/system/core_impl.cc b/mojo/android/system/core_impl.cc index 1d884fe..5cbd754 100644 --- a/mojo/android/system/core_impl.cc +++ b/mojo/android/system/core_impl.cc
@@ -7,59 +7,20 @@ #include <stddef.h> #include <stdint.h> -#include <memory> - #include "base/android/base_jni_registrar.h" #include "base/android/jni_android.h" #include "base/android/jni_registrar.h" #include "base/android/library_loader/library_loader_hooks.h" #include "base/android/scoped_java_ref.h" -#include "base/bind.h" -#include "base/location.h" -#include "base/single_thread_task_runner.h" -#include "base/threading/thread_task_runner_handle.h" #include "jni/CoreImpl_jni.h" -#include "mojo/message_pump/handle_watcher.h" #include "mojo/public/c/system/core.h" -using base::android::JavaParamRef; -using base::android::ScopedJavaLocalRef; - -namespace { - -using MojoAsyncWaitID = uintptr_t; -const MojoAsyncWaitID kInvalidHandleCancelID = 0; - -struct AsyncWaitCallbackData { - base::android::ScopedJavaGlobalRef<jobject> core_impl; - base::android::ScopedJavaGlobalRef<jobject> callback; - base::android::ScopedJavaGlobalRef<jobject> cancellable; - - AsyncWaitCallbackData(JNIEnv* env, jobject core_impl, jobject callback) { - this->core_impl.Reset(env, core_impl); - this->callback.Reset(env, callback); - } -}; - -void AsyncWaitCallback(mojo::common::HandleWatcher* watcher, - void* data, - MojoResult result) { - delete watcher; - std::unique_ptr<AsyncWaitCallbackData> callback_data( - static_cast<AsyncWaitCallbackData*>(data)); - mojo::android::Java_CoreImpl_onAsyncWaitResult( - base::android::AttachCurrentThread(), - callback_data->core_impl.obj(), - result, - callback_data->callback.obj(), - callback_data->cancellable.obj()); -} - -} // namespace - namespace mojo { namespace android { +using base::android::JavaParamRef; +using base::android::ScopedJavaLocalRef; + static jlong GetTimeTicksNow(JNIEnv* env, const JavaParamRef<jobject>& jcaller) { return MojoGetTimeTicksNow(); @@ -368,51 +329,6 @@ return MojoUnmapBuffer(buffer_start); } -static ScopedJavaLocalRef<jobject> AsyncWait( - JNIEnv* env, - const JavaParamRef<jobject>& jcaller, - jint mojo_handle, - jint signals, - jlong deadline, - const JavaParamRef<jobject>& callback) { - AsyncWaitCallbackData* callback_data = - new AsyncWaitCallbackData(env, jcaller, callback); - MojoAsyncWaitID cancel_id; - if (static_cast<MojoHandle>(mojo_handle) != MOJO_HANDLE_INVALID) { - common::HandleWatcher* watcher = new common::HandleWatcher(); - cancel_id = reinterpret_cast<MojoAsyncWaitID>(watcher); - watcher->Start(Handle(static_cast<MojoHandle>(mojo_handle)), signals, - deadline, - base::Bind(&AsyncWaitCallback, watcher, callback_data)); - } else { - cancel_id = kInvalidHandleCancelID; - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(&AsyncWaitCallback, nullptr, callback_data, - MOJO_RESULT_INVALID_ARGUMENT)); - } - base::android::ScopedJavaLocalRef<jobject> cancellable = - Java_CoreImpl_newAsyncWaiterCancellableImpl( - env, jcaller, cancel_id, reinterpret_cast<intptr_t>(callback_data)); - callback_data->cancellable.Reset(env, cancellable.obj()); - return cancellable; -} - -static void CancelAsyncWait(JNIEnv* env, - const JavaParamRef<jobject>& jcaller, - jlong id, - jlong data_ptr) { - if (id == 0) { - // If |id| is |kInvalidHandleCancelID|, the async wait was done on an - // invalid handle, so the AsyncWaitCallback will be called and will clear - // the data_ptr. - return; - } - std::unique_ptr<AsyncWaitCallbackData> deleter( - reinterpret_cast<AsyncWaitCallbackData*>(data_ptr)); - delete reinterpret_cast<common::HandleWatcher*>( - static_cast<MojoAsyncWaitID>(id)); -} - static jint GetNativeBufferOffset(JNIEnv* env, const JavaParamRef<jobject>& jcaller, const JavaParamRef<jobject>& buffer,
diff --git a/mojo/android/system/src/org/chromium/mojo/system/impl/CoreImpl.java b/mojo/android/system/src/org/chromium/mojo/system/impl/CoreImpl.java index a20ea0a..8330586 100644 --- a/mojo/android/system/src/org/chromium/mojo/system/impl/CoreImpl.java +++ b/mojo/android/system/src/org/chromium/mojo/system/impl/CoreImpl.java
@@ -7,7 +7,6 @@ import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.MainDex; -import org.chromium.mojo.system.AsyncWaiter; import org.chromium.mojo.system.Core; import org.chromium.mojo.system.DataPipe; import org.chromium.mojo.system.DataPipe.ConsumerHandle; @@ -23,6 +22,7 @@ import org.chromium.mojo.system.SharedBufferHandle.DuplicateOptions; import org.chromium.mojo.system.SharedBufferHandle.MapFlags; import org.chromium.mojo.system.UntypedHandle; +import org.chromium.mojo.system.Watcher; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -35,7 +35,7 @@ */ @JNINamespace("mojo::android") @MainDex -public class CoreImpl implements Core, AsyncWaiter { +public class CoreImpl implements Core { /** * Discard flag for the |MojoReadData| operation. */ @@ -216,11 +216,11 @@ } /** - * @see Core#getDefaultAsyncWaiter() + * @see Core#getWatcher() */ @Override - public AsyncWaiter getDefaultAsyncWaiter() { - return this; + public Watcher getWatcher() { + return new WatcherImpl(); } /** @@ -251,15 +251,6 @@ mCurrentRunLoop.remove(); } - /** - * @see AsyncWaiter#asyncWait(Handle, Core.HandleSignals, long, Callback) - */ - @Override - public Cancellable asyncWait( - Handle handle, HandleSignals signals, long deadline, Callback callback) { - return nativeAsyncWait(getMojoHandle(handle), signals.getFlags(), deadline, callback); - } - int closeWithResult(int mojoHandle) { return nativeClose(mojoHandle); } @@ -497,59 +488,6 @@ return buffer.order(ByteOrder.nativeOrder()); } - /** - * Implementation of {@link org.chromium.mojo.system.AsyncWaiter.Cancellable}. - */ - private class AsyncWaiterCancellableImpl implements AsyncWaiter.Cancellable { - private final long mId; - private final long mDataPtr; - private boolean mActive = true; - - private AsyncWaiterCancellableImpl(long id, long dataPtr) { - this.mId = id; - this.mDataPtr = dataPtr; - } - - /** - * @see org.chromium.mojo.system.AsyncWaiter.Cancellable#cancel() - */ - @Override - public void cancel() { - if (mActive) { - mActive = false; - nativeCancelAsyncWait(mId, mDataPtr); - } - } - - private boolean isActive() { - return mActive; - } - - private void deactivate() { - mActive = false; - } - } - - @CalledByNative - private AsyncWaiterCancellableImpl newAsyncWaiterCancellableImpl(long id, long dataPtr) { - return new AsyncWaiterCancellableImpl(id, dataPtr); - } - - @CalledByNative - private void onAsyncWaitResult( - int mojoResult, AsyncWaiter.Callback callback, AsyncWaiterCancellableImpl cancellable) { - if (!cancellable.isActive()) { - // If cancellable is not active, the user cancelled the wait. - return; - } - cancellable.deactivate(); - if (isUnrecoverableError(mojoResult)) { - callback.onError(new MojoException(mojoResult)); - return; - } - callback.onResult(mojoResult); - } - @CalledByNative private static ResultAnd<ByteBuffer> newResultAndBuffer(int mojoResult, ByteBuffer buffer) { return new ResultAnd<>(mojoResult, buffer); @@ -629,10 +567,5 @@ private native int nativeUnmap(ByteBuffer buffer); - private native AsyncWaiterCancellableImpl nativeAsyncWait( - int mojoHandle, int signals, long deadline, AsyncWaiter.Callback callback); - - private native void nativeCancelAsyncWait(long mId, long dataPtr); - private native int nativeGetNativeBufferOffset(ByteBuffer buffer, int alignment); }
diff --git a/mojo/android/system/src/org/chromium/mojo/system/impl/WatcherImpl.java b/mojo/android/system/src/org/chromium/mojo/system/impl/WatcherImpl.java new file mode 100644 index 0000000..094ad90 --- /dev/null +++ b/mojo/android/system/src/org/chromium/mojo/system/impl/WatcherImpl.java
@@ -0,0 +1,63 @@ +// 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. + +package org.chromium.mojo.system.impl; + +import org.chromium.base.annotations.CalledByNative; +import org.chromium.base.annotations.JNINamespace; +import org.chromium.mojo.system.Core; +import org.chromium.mojo.system.Handle; +import org.chromium.mojo.system.MojoResult; +import org.chromium.mojo.system.Watcher; + +@JNINamespace("mojo::android") +class WatcherImpl implements Watcher { + private long mImplPtr = nativeCreateWatcher(); + private Callback mCallback; + + @Override + public int start(Handle handle, Core.HandleSignals signals, Callback callback) { + if (mImplPtr == 0) { + return MojoResult.INVALID_ARGUMENT; + } + if (!(handle instanceof HandleBase)) { + return MojoResult.INVALID_ARGUMENT; + } + int result = + nativeStart(mImplPtr, ((HandleBase) handle).getMojoHandle(), signals.getFlags()); + if (result == MojoResult.OK) mCallback = callback; + return result; + } + + @Override + public void cancel() { + if (mImplPtr == 0) { + return; + } + mCallback = null; + nativeCancel(mImplPtr); + } + + @Override + public void destroy() { + if (mImplPtr == 0) { + return; + } + nativeDelete(mImplPtr); + mImplPtr = 0; + } + + @CalledByNative + private void onHandleReady(int result) { + mCallback.onResult(result); + } + + private native long nativeCreateWatcher(); + + private native int nativeStart(long implPtr, int mojoHandle, int flags); + + private native void nativeCancel(long implPtr); + + private native void nativeDelete(long implPtr); +}
diff --git a/mojo/android/system/watcher_impl.cc b/mojo/android/system/watcher_impl.cc new file mode 100644 index 0000000..33470fd --- /dev/null +++ b/mojo/android/system/watcher_impl.cc
@@ -0,0 +1,78 @@ +// 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 "mojo/android/system/watcher_impl.h" + +#include <stddef.h> +#include <stdint.h> + +#include "base/android/base_jni_registrar.h" +#include "base/android/jni_android.h" +#include "base/android/jni_registrar.h" +#include "base/android/library_loader/library_loader_hooks.h" +#include "base/android/scoped_java_ref.h" +#include "base/bind.h" +#include "jni/WatcherImpl_jni.h" +#include "mojo/public/cpp/system/handle.h" +#include "mojo/public/cpp/system/watcher.h" + +namespace mojo { +namespace android { + +using base::android::JavaParamRef; + +namespace { + +class JavaWatcherCallback { + public: + JavaWatcherCallback(JNIEnv* env, const JavaParamRef<jobject>& java_watcher) { + java_watcher_.Reset(env, java_watcher); + } + + void OnHandleReady(MojoResult result) { + Java_WatcherImpl_onHandleReady(base::android::AttachCurrentThread(), + java_watcher_.obj(), result); + } + + private: + base::android::ScopedJavaGlobalRef<jobject> java_watcher_; +}; + +} // namespace + +static jlong CreateWatcher(JNIEnv* env, const JavaParamRef<jobject>& jcaller) { + return reinterpret_cast<jlong>(new Watcher); +} + +static jint Start(JNIEnv* env, + const JavaParamRef<jobject>& jcaller, + jlong watcher_ptr, + jint mojo_handle, + jint signals) { + Watcher* watcher = reinterpret_cast<Watcher*>(watcher_ptr); + return watcher->Start( + mojo::Handle(static_cast<MojoHandle>(mojo_handle)), + static_cast<MojoHandleSignals>(signals), + base::Bind(&JavaWatcherCallback::OnHandleReady, + base::Owned(new JavaWatcherCallback(env, jcaller)))); +} + +static void Cancel(JNIEnv* env, + const JavaParamRef<jobject>& jcaller, + jlong watcher_ptr) { + reinterpret_cast<Watcher*>(watcher_ptr)->Cancel(); +} + +static void Delete(JNIEnv* env, + const JavaParamRef<jobject>& jcaller, + jlong watcher_ptr) { + delete reinterpret_cast<Watcher*>(watcher_ptr); +} + +bool RegisterWatcherImpl(JNIEnv* env) { + return RegisterNativesImpl(env); +} + +} // namespace android +} // namespace mojo
diff --git a/mojo/android/system/watcher_impl.h b/mojo/android/system/watcher_impl.h new file mode 100644 index 0000000..784f007 --- /dev/null +++ b/mojo/android/system/watcher_impl.h
@@ -0,0 +1,20 @@ +// 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 MOJO_ANDROID_SYSTEM_WATCHER_IMPL_H_ +#define MOJO_ANDROID_SYSTEM_WATCHER_IMPL_H_ + +#include <jni.h> + +#include "base/android/jni_android.h" + +namespace mojo { +namespace android { + +JNI_EXPORT bool RegisterWatcherImpl(JNIEnv* env); + +} // namespace android +} // namespace mojo + +#endif // MOJO_ANDROID_SYSTEM_WATCHER_IMPL_H_
diff --git a/mojo/edk/embedder/embedder.cc b/mojo/edk/embedder/embedder.cc index 8fb0735..3508ba3 100644 --- a/mojo/edk/embedder/embedder.cc +++ b/mojo/edk/embedder/embedder.cc
@@ -76,6 +76,12 @@ SetParentPipeHandle(std::move(platform_channel)); } +ScopedMessagePipeHandle ConnectToPeerProcess(ScopedPlatformHandle pipe) { + CHECK(internal::g_process_delegate); + DCHECK(pipe.is_valid()); + return internal::g_core->ConnectToPeerProcess(std::move(pipe)); +} + void Init() { MojoSystemThunks thunks = MakeSystemThunks(); size_t expected_size = MojoEmbedderSetSystemThunks(&thunks);
diff --git a/mojo/edk/embedder/embedder.h b/mojo/edk/embedder/embedder.h index e4a8420..8cb44a11 100644 --- a/mojo/edk/embedder/embedder.h +++ b/mojo/edk/embedder/embedder.h
@@ -70,6 +70,13 @@ // PlatformChannelPair for details. MOJO_SYSTEM_IMPL_EXPORT void SetParentPipeHandleFromCommandLine(); +// Called to connect to a peer process. This should be called only if there +// is no common ancestor for the processes involved within this mojo system. +// Both processes must call this function, each passing one end of a platform +// channel. This returns one end of a message pipe to each process. +MOJO_SYSTEM_IMPL_EXPORT ScopedMessagePipeHandle +ConnectToPeerProcess(ScopedPlatformHandle pipe); + // Must be called first, or just after setting configuration parameters, to // initialize the (global, singleton) system. MOJO_SYSTEM_IMPL_EXPORT void Init();
diff --git a/mojo/edk/system/core.cc b/mojo/edk/system/core.cc index 4bb07eaf3..d2a421eb 100644 --- a/mojo/edk/system/core.cc +++ b/mojo/edk/system/core.cc
@@ -187,6 +187,17 @@ GetNodeController()->CloseChildPorts(child_token); } +ScopedMessagePipeHandle Core::ConnectToPeerProcess( + ScopedPlatformHandle pipe_handle) { + RequestContext request_context; + ports::PortRef port0, port1; + GetNodeController()->node()->CreatePortPair(&port0, &port1); + MojoHandle handle = AddDispatcher(new MessagePipeDispatcher( + GetNodeController(), port0, kUnknownPipeIdForDebug, 0)); + GetNodeController()->ConnectToPeer(std::move(pipe_handle), port1); + return ScopedMessagePipeHandle(MessagePipeHandle(handle)); +} + void Core::InitChild(ScopedPlatformHandle platform_handle) { GetNodeController()->ConnectToParent(std::move(platform_handle)); }
diff --git a/mojo/edk/system/core.h b/mojo/edk/system/core.h index 9b109412..dc635a0 100644 --- a/mojo/edk/system/core.h +++ b/mojo/edk/system/core.h
@@ -62,6 +62,13 @@ // Called in the parent process when a child process fails to launch. void ChildLaunchFailed(const std::string& child_token); + // Called to connect to a peer process. This should be called only if there + // is no common ancestor for the processes involved within this mojo system. + // Both processes must call this function, each passing one end of a platform + // channel. This returns one end of a message pipe to each process. + ScopedMessagePipeHandle ConnectToPeerProcess( + ScopedPlatformHandle pipe_handle); + // Called in a child process exactly once during early initialization. void InitChild(ScopedPlatformHandle platform_handle);
diff --git a/mojo/edk/system/mach_port_relay.cc b/mojo/edk/system/mach_port_relay.cc index ddd633c..f05cf22 100644 --- a/mojo/edk/system/mach_port_relay.cc +++ b/mojo/edk/system/mach_port_relay.cc
@@ -240,7 +240,7 @@ void MachPortRelay::OnReceivedTaskPort(base::ProcessHandle process) { base::AutoLock locker(observers_lock_); - for (const auto observer : observers_) + for (auto* observer : observers_) observer->OnProcessReady(process); }
diff --git a/mojo/edk/system/multiprocess_message_pipe_unittest.cc b/mojo/edk/system/multiprocess_message_pipe_unittest.cc index 6e2c6f1..124daec 100644 --- a/mojo/edk/system/multiprocess_message_pipe_unittest.cc +++ b/mojo/edk/system/multiprocess_message_pipe_unittest.cc
@@ -68,6 +68,16 @@ }; }; +class MultiprocessMessagePipeTestWithPeerSupport + : public MultiprocessMessagePipeTest, + public testing::WithParamInterface<test::MojoTestBase::LaunchType> { + protected: + void SetUp() override { + test::MojoTestBase::SetUp(); + set_launch_type(GetParam()); + } +}; + // For each message received, sends a reply message with the same contents // repeated twice, until the other end is closed or it receives "quitquitquit" // (which it doesn't reply to). It'll return the number of messages received, @@ -116,7 +126,7 @@ return rv; } -TEST_F(MultiprocessMessagePipeTest, Basic) { +TEST_P(MultiprocessMessagePipeTestWithPeerSupport, Basic) { RUN_CHILD_ON_PIPE(EchoEcho, h) std::string hello("hello"); ASSERT_EQ(MOJO_RESULT_OK, @@ -152,7 +162,7 @@ END_CHILD_AND_EXPECT_EXIT_CODE(1 % 100); } -TEST_F(MultiprocessMessagePipeTest, QueueMessages) { +TEST_P(MultiprocessMessagePipeTestWithPeerSupport, QueueMessages) { static const size_t kNumMessages = 1001; RUN_CHILD_ON_PIPE(EchoEcho, h) for (size_t i = 0; i < kNumMessages; i++) { @@ -509,7 +519,7 @@ return 0; } -TEST_F(MultiprocessMessagePipeTest, MessagePipePassing) { +TEST_P(MultiprocessMessagePipeTestWithPeerSupport, MessagePipePassing) { RUN_CHILD_ON_PIPE(CheckMessagePipe, h) MojoCreateSharedBufferOptions options; options.struct_size = sizeof(options); @@ -551,7 +561,7 @@ END_CHILD() } -TEST_F(MultiprocessMessagePipeTest, MessagePipeTwoPassing) { +TEST_P(MultiprocessMessagePipeTestWithPeerSupport, MessagePipeTwoPassing) { RUN_CHILD_ON_PIPE(CheckMessagePipe, h) MojoHandle mp1, mp2; ASSERT_EQ(MOJO_RESULT_OK, @@ -681,7 +691,7 @@ END_CHILD(); } -TEST_F(MultiprocessMessagePipeTest, CreateMessagePipe) { +TEST_P(MultiprocessMessagePipeTestWithPeerSupport, CreateMessagePipe) { MojoHandle p0, p1; CreateMessagePipe(&p0, &p1); VerifyTransmission(p0, p1, "hey man"); @@ -693,7 +703,7 @@ CloseHandle(p1); } -TEST_F(MultiprocessMessagePipeTest, PassMessagePipeLocal) { +TEST_P(MultiprocessMessagePipeTestWithPeerSupport, PassMessagePipeLocal) { MojoHandle p0, p1; CreateMessagePipe(&p0, &p1); VerifyTransmission(p0, p1, "testing testing"); @@ -733,7 +743,7 @@ return 0; } -TEST_F(MultiprocessMessagePipeTest, MultiprocessChannelPipe) { +TEST_P(MultiprocessMessagePipeTestWithPeerSupport, MultiprocessChannelPipe) { RUN_CHILD_ON_PIPE(ChannelEchoClient, h) VerifyEcho(h, "in an interstellar burst"); VerifyEcho(h, "i am back to save the universe"); @@ -758,7 +768,8 @@ return 0; } -TEST_F(MultiprocessMessagePipeTest, PassMessagePipeCrossProcess) { +TEST_P(MultiprocessMessagePipeTestWithPeerSupport, + PassMessagePipeCrossProcess) { MojoHandle p0, p1; CreateMessagePipe(&p0, &p1); RUN_CHILD_ON_PIPE(EchoServiceClient, h) @@ -815,7 +826,8 @@ return 0; } -TEST_F(MultiprocessMessagePipeTest, PassMoarMessagePipesCrossProcess) { +TEST_P(MultiprocessMessagePipeTestWithPeerSupport, + PassMoarMessagePipesCrossProcess) { MojoHandle echo_factory_proxy, echo_factory_request; CreateMessagePipe(&echo_factory_proxy, &echo_factory_request); @@ -860,7 +872,8 @@ CloseHandle(echo_proxy_c); } -TEST_F(MultiprocessMessagePipeTest, ChannelPipesWithMultipleChildren) { +TEST_P(MultiprocessMessagePipeTestWithPeerSupport, + ChannelPipesWithMultipleChildren) { RUN_CHILD_ON_PIPE(ChannelEchoClient, a) RUN_CHILD_ON_PIPE(ChannelEchoClient, b) VerifyEcho(a, "hello child 0"); @@ -890,7 +903,7 @@ EXPECT_EQ("quit", ReadMessage(h)); } -TEST_F(MultiprocessMessagePipeTest, PingPongPipe) { +TEST_P(MultiprocessMessagePipeTestWithPeerSupport, PingPongPipe) { MojoHandle p0, p1; CreateMessagePipe(&p0, &p1); @@ -1096,11 +1109,12 @@ MojoHandle p; EXPECT_EQ("foo", ReadMessageWithHandles(h, &p, 1)); - EXPECT_EQ(MOJO_RESULT_OK, MojoWait(p, MOJO_HANDLE_SIGNAL_PEER_CLOSED, - MOJO_DEADLINE_INDEFINITE, nullptr)); + auto result = MojoWait(p, MOJO_HANDLE_SIGNAL_PEER_CLOSED, + MOJO_DEADLINE_INDEFINITE, nullptr); + EXPECT_EQ(MOJO_RESULT_OK, result); } -TEST_F(MultiprocessMessagePipeTest, SendPipeThenClosePeer) { +TEST_P(MultiprocessMessagePipeTestWithPeerSupport, SendPipeThenClosePeer) { RUN_CHILD_ON_PIPE(ReceivePipeWithClosedPeer, h) MojoHandle a, b; CreateMessagePipe(&a, &b); @@ -1176,8 +1190,7 @@ END_CHILD() } - -TEST_F(MultiprocessMessagePipeTest, SendClosePeerSend) { +TEST_P(MultiprocessMessagePipeTestWithPeerSupport, SendClosePeerSend) { MojoHandle a, b; CreateMessagePipe(&a, &b); @@ -1220,7 +1233,7 @@ EXPECT_EQ("quit", ReadMessage(h)); } -TEST_F(MultiprocessMessagePipeTest, WriteCloseSendPeer) { +TEST_P(MultiprocessMessagePipeTestWithPeerSupport, WriteCloseSendPeer) { MojoHandle pipe[2]; CreateMessagePipe(&pipe[0], &pipe[1]); @@ -1345,7 +1358,10 @@ EXPECT_NE(std::string::npos, first_process_error.find(kFirstErrorMessage)); EXPECT_NE(std::string::npos, second_process_error.find(kSecondErrorMessage)); } - +INSTANTIATE_TEST_CASE_P(, + MultiprocessMessagePipeTestWithPeerSupport, + testing::Values(test::MojoTestBase::LaunchType::CHILD, + test::MojoTestBase::LaunchType::PEER)); } // namespace } // namespace edk } // namespace mojo
diff --git a/mojo/edk/system/node_channel.cc b/mojo/edk/system/node_channel.cc index 114e286..da9e0dbf 100644 --- a/mojo/edk/system/node_channel.cc +++ b/mojo/edk/system/node_channel.cc
@@ -47,6 +47,7 @@ #if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) PORTS_MESSAGE_FROM_RELAY, #endif + ACCEPT_PEER, }; struct Header { @@ -67,6 +68,12 @@ ports::NodeName child_name; }; +struct AcceptPeerData { + ports::NodeName token; + ports::NodeName peer_name; + ports::PortName port_name; +}; + // This message may include a process handle on plaforms that require it. struct AddBrokerClientData { ports::NodeName client_name; @@ -282,6 +289,18 @@ WriteChannelMessage(std::move(message)); } +void NodeChannel::AcceptPeer(const ports::NodeName& sender_name, + const ports::NodeName& token, + const ports::PortName& port_name) { + AcceptPeerData* data; + Channel::MessagePtr message = + CreateMessage(MessageType::ACCEPT_PEER, sizeof(AcceptPeerData), 0, &data); + data->token = token; + data->peer_name = sender_name; + data->port_name = port_name; + WriteChannelMessage(std::move(message)); +} + void NodeChannel::AddBrokerClient(const ports::NodeName& client_name, base::ProcessHandle process_handle) { AddBrokerClientData* data; @@ -728,6 +747,16 @@ #endif // defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) + case MessageType::ACCEPT_PEER: { + const AcceptPeerData* data; + if (GetMessagePayload(payload, payload_size, &data)) { + delegate_->OnAcceptPeer(remote_node_name_, data->token, data->peer_name, + data->port_name); + return; + } + break; + } + default: break; }
diff --git a/mojo/edk/system/node_channel.h b/mojo/edk/system/node_channel.h index 5a5fc8a..bbac642 100644 --- a/mojo/edk/system/node_channel.h +++ b/mojo/edk/system/node_channel.h
@@ -76,7 +76,10 @@ const ports::NodeName& source_node, Channel::MessagePtr message) = 0; #endif - + virtual void OnAcceptPeer(const ports::NodeName& from_node, + const ports::NodeName& token, + const ports::NodeName& peer_name, + const ports::PortName& port_name) = 0; virtual void OnChannelError(const ports::NodeName& node, NodeChannel* channel) = 0; @@ -124,6 +127,9 @@ const ports::NodeName& token); void AcceptParent(const ports::NodeName& token, const ports::NodeName& child_name); + void AcceptPeer(const ports::NodeName& sender_name, + const ports::NodeName& token, + const ports::PortName& port_name); void AddBrokerClient(const ports::NodeName& client_name, base::ProcessHandle process_handle); void BrokerClientAdded(const ports::NodeName& client_name,
diff --git a/mojo/edk/system/node_controller.cc b/mojo/edk/system/node_controller.cc index 912ecee..78c80d13 100644 --- a/mojo/edk/system/node_controller.cc +++ b/mojo/edk/system/node_controller.cc
@@ -254,6 +254,16 @@ base::Passed(&platform_handle))); } +void NodeController::ConnectToPeer(ScopedPlatformHandle handle, + const ports::PortRef& port) { + ports::NodeName node_name; + GenerateRandomName(&node_name); + io_task_runner_->PostTask( + FROM_HERE, base::Bind(&NodeController::ConnectToPeerOnIOThread, + base::Unretained(this), base::Passed(&handle), + node_name, port)); +} + void NodeController::SetPortObserver( const ports::PortRef& port, const scoped_refptr<PortObserver>& observer) { @@ -434,6 +444,21 @@ bootstrap_parent_channel_->Start(); } +void NodeController::ConnectToPeerOnIOThread(ScopedPlatformHandle handle, + ports::NodeName token, + ports::PortRef port) { + DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); + + scoped_refptr<NodeChannel> channel = + NodeChannel::Create(this, std::move(handle), io_task_runner_, {}); + pending_peers_.insert({token, {channel, port}}); + + channel->SetRemoteNodeName(token); + channel->Start(); + + channel->AcceptPeer(name_, token, port.name()); +} + scoped_refptr<NodeChannel> NodeController::GetPeerChannel( const ports::NodeName& name) { base::AutoLock lock(peers_lock_); @@ -721,6 +746,7 @@ peers_.clear(); pending_children_.clear(); pending_peer_messages_.clear(); + pending_peers_.clear(); } for (const auto& peer : all_peers) @@ -1229,6 +1255,36 @@ } #endif +void NodeController::OnAcceptPeer(const ports::NodeName& from_node, + const ports::NodeName& token, + const ports::NodeName& peer_name, + const ports::PortName& port_name) { + DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); + + auto it = pending_peers_.find(from_node); + if (it == pending_peers_.end()) { + DLOG(ERROR) << "Received unexpected AcceptPeer message from " << from_node; + DropPeer(from_node, nullptr); + return; + } + + scoped_refptr<NodeChannel> channel = it->second.first; + ports::PortRef local_port = it->second.second; + pending_peers_.erase(it); + DCHECK(channel); + + DVLOG(1) << "Node " << name_ << " accepted peer " << peer_name; + + AddPeer(peer_name, channel, false /* start_channel */); + + // We need to choose one side to initiate the port merge. It doesn't matter + // who does it as long as they don't both try. Simple solution: pick the one + // with the "smaller" port name. + if (local_port.name() < port_name) { + node()->MergePorts(local_port, peer_name, port_name); + } +} + void NodeController::OnChannelError(const ports::NodeName& from_node, NodeChannel* channel) { if (io_task_runner_->RunsTasksOnCurrentThread()) {
diff --git a/mojo/edk/system/node_controller.h b/mojo/edk/system/node_controller.h index 2cdcd90..69185fd 100644 --- a/mojo/edk/system/node_controller.h +++ b/mojo/edk/system/node_controller.h
@@ -85,6 +85,10 @@ // handshake. void ConnectToParent(ScopedPlatformHandle platform_handle); + // Connects this node to a peer node. On success, |port| will be merged with + // the corresponding port in the peer node. + void ConnectToPeer(ScopedPlatformHandle handle, const ports::PortRef& port); + // Sets a port's observer. If |observer| is null the port's current observer // is removed. void SetPortObserver(const ports::PortRef& port, @@ -146,6 +150,10 @@ const ProcessErrorCallback& process_error_callback); void ConnectToParentOnIOThread(ScopedPlatformHandle platform_handle); + void ConnectToPeerOnIOThread(ScopedPlatformHandle handle, + ports::NodeName token, + ports::PortRef port); + scoped_refptr<NodeChannel> GetPeerChannel(const ports::NodeName& name); scoped_refptr<NodeChannel> GetParentChannel(); scoped_refptr<NodeChannel> GetBrokerChannel(); @@ -206,6 +214,10 @@ const ports::NodeName& source_node, Channel::MessagePtr message) override; #endif + void OnAcceptPeer(const ports::NodeName& from_node, + const ports::NodeName& token, + const ports::NodeName& peer_name, + const ports::PortName& port_name) override; void OnChannelError(const ports::NodeName& from_node, NodeChannel* channel) override; #if defined(OS_MACOSX) && !defined(OS_IOS) @@ -305,6 +317,11 @@ // Channels to children during handshake. NodeMap pending_children_; + using PeerNodeMap = + std::unordered_map<ports::NodeName, + std::pair<scoped_refptr<NodeChannel>, ports::PortRef>>; + PeerNodeMap pending_peers_; + // Indicates whether this object should delete itself on IO thread shutdown. // Must only be accessed from the IO thread. bool destroy_on_io_thread_shutdown_ = false;
diff --git a/mojo/edk/test/mojo_test_base.cc b/mojo/edk/test/mojo_test_base.cc index 5d77a112..cf78caa 100644 --- a/mojo/edk/test/mojo_test_base.cc +++ b/mojo/edk/test/mojo_test_base.cc
@@ -44,14 +44,15 @@ MojoTestBase::ClientController& MojoTestBase::StartClient( const std::string& client_name) { clients_.push_back(base::MakeUnique<ClientController>( - client_name, this, process_error_callback_)); + client_name, this, process_error_callback_, launch_type_)); return *clients_.back(); } MojoTestBase::ClientController::ClientController( const std::string& client_name, MojoTestBase* test, - const ProcessErrorCallback& process_error_callback) { + const ProcessErrorCallback& process_error_callback, + LaunchType launch_type) { #if !defined(OS_IOS) #if defined(OS_MACOSX) // This lock needs to be held while launching the child because the Mach port @@ -63,7 +64,7 @@ base::AutoLock lock(g_mach_broker->GetLock()); #endif helper_.set_process_error_callback(process_error_callback); - pipe_ = helper_.StartChild(client_name); + pipe_ = helper_.StartChild(client_name, launch_type); #if defined(OS_MACOSX) g_mach_broker->AddPlaceholderForPid(helper_.test_child().Handle()); #endif
diff --git a/mojo/edk/test/mojo_test_base.h b/mojo/edk/test/mojo_test_base.h index 4f5514533..cd507daa 100644 --- a/mojo/edk/test/mojo_test_base.h +++ b/mojo/edk/test/mojo_test_base.h
@@ -29,6 +29,8 @@ MojoTestBase(); ~MojoTestBase() override; + using LaunchType = MultiprocessTestHelper::LaunchType; + protected: using HandlerCallback = base::Callback<void(ScopedMessagePipeHandle)>; @@ -36,7 +38,8 @@ public: ClientController(const std::string& client_name, MojoTestBase* test, - const ProcessErrorCallback& process_error_callback_); + const ProcessErrorCallback& process_error_callback, + LaunchType launch_type); ~ClientController(); MojoHandle pipe() const { return pipe_.get().value(); } @@ -148,6 +151,8 @@ // Reads data from a data pipe. static std::string ReadData(MojoHandle consumer, size_t size); + void set_launch_type(LaunchType launch_type) { launch_type_ = launch_type; } + private: friend class ClientController; @@ -155,6 +160,8 @@ ProcessErrorCallback process_error_callback_; + LaunchType launch_type_ = LaunchType::CHILD; + DISALLOW_COPY_AND_ASSIGN(MojoTestBase); };
diff --git a/mojo/edk/test/multiprocess_test_helper.cc b/mojo/edk/test/multiprocess_test_helper.cc index 82a82c8..60a34fe3b6 100644 --- a/mojo/edk/test/multiprocess_test_helper.cc +++ b/mojo/edk/test/multiprocess_test_helper.cc
@@ -39,10 +39,11 @@ const char kMojoPrimordialPipeToken[] = "mojo-primordial-pipe-token"; -int RunClientFunction(std::function<int(MojoHandle)> handler) { - CHECK(!MultiprocessTestHelper::primordial_pipe_token.empty()); - ScopedMessagePipeHandle pipe = CreateChildMessagePipe( - MultiprocessTestHelper::primordial_pipe_token); +template <typename Func> +int RunClientFunction(Func handler) { + CHECK(MultiprocessTestHelper::primordial_pipe.is_valid()); + ScopedMessagePipeHandle pipe = + std::move(MultiprocessTestHelper::primordial_pipe); return handler(pipe.get().value()); } @@ -55,15 +56,17 @@ } ScopedMessagePipeHandle MultiprocessTestHelper::StartChild( - const std::string& test_child_name) { - return StartChildWithExtraSwitch( - test_child_name, std::string(), std::string()); + const std::string& test_child_name, + LaunchType launch_type) { + return StartChildWithExtraSwitch(test_child_name, std::string(), + std::string(), launch_type); } ScopedMessagePipeHandle MultiprocessTestHelper::StartChildWithExtraSwitch( const std::string& test_child_name, const std::string& switch_string, - const std::string& switch_value) { + const std::string& switch_value, + LaunchType launch_type) { CHECK(!test_child_name.empty()); CHECK(!test_child_.IsValid()); @@ -93,7 +96,8 @@ &handle_passing_info); std::string pipe_token = mojo::edk::GenerateRandomToken(); - command_line.AppendSwitchASCII(kMojoPrimordialPipeToken, pipe_token); + if (launch_type == LaunchType::CHILD) + command_line.AppendSwitchASCII(kMojoPrimordialPipeToken, pipe_token); if (!switch_string.empty()) { CHECK(!command_line.HasSwitch(switch_string)); @@ -116,18 +120,23 @@ #error "Not supported yet." #endif + ScopedMessagePipeHandle pipe; std::string child_token = mojo::edk::GenerateRandomToken(); - ScopedMessagePipeHandle pipe = CreateParentMessagePipe(pipe_token, - child_token); + if (launch_type == LaunchType::CHILD) + pipe = CreateParentMessagePipe(pipe_token, child_token); + else if (launch_type == LaunchType::PEER) + pipe = ConnectToPeerProcess(channel.PassServerHandle()); test_child_ = base::SpawnMultiProcessTestChild(test_child_main, command_line, options); channel.ChildProcessLaunched(); - ChildProcessLaunched(test_child_.Handle(), channel.PassServerHandle(), - child_token, process_error_callback_); - CHECK(test_child_.IsValid()); + if (launch_type == LaunchType::CHILD) { + ChildProcessLaunched(test_child_.Handle(), channel.PassServerHandle(), + child_token, process_error_callback_); + } + CHECK(test_child_.IsValid()); return pipe; } @@ -155,17 +164,21 @@ void MultiprocessTestHelper::ChildSetup() { CHECK(base::CommandLine::InitializedForCurrentProcess()); - primordial_pipe_token = base::CommandLine::ForCurrentProcess() - ->GetSwitchValueASCII(kMojoPrimordialPipeToken); - CHECK(!primordial_pipe_token.empty()); - + std::string primordial_pipe_token = + base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( + kMojoPrimordialPipeToken); + if (!primordial_pipe_token.empty()) { + primordial_pipe = CreateChildMessagePipe(primordial_pipe_token); #if defined(OS_MACOSX) && !defined(OS_IOS) - CHECK(base::MachPortBroker::ChildSendTaskPortToParent("mojo_test")); + CHECK(base::MachPortBroker::ChildSendTaskPortToParent("mojo_test")); #endif - - SetParentPipeHandle( - PlatformChannelPair::PassClientHandleFromParentProcess( - *base::CommandLine::ForCurrentProcess())); + SetParentPipeHandle(PlatformChannelPair::PassClientHandleFromParentProcess( + *base::CommandLine::ForCurrentProcess())); + } else { + primordial_pipe = ConnectToPeerProcess( + PlatformChannelPair::PassClientHandleFromParentProcess( + *base::CommandLine::ForCurrentProcess())); + } } // static @@ -187,7 +200,7 @@ } // static -std::string MultiprocessTestHelper::primordial_pipe_token; +mojo::ScopedMessagePipeHandle MultiprocessTestHelper::primordial_pipe; } // namespace test } // namespace edk
diff --git a/mojo/edk/test/multiprocess_test_helper.h b/mojo/edk/test/multiprocess_test_helper.h index 203eb117..689b0ec 100644 --- a/mojo/edk/test/multiprocess_test_helper.h +++ b/mojo/edk/test/multiprocess_test_helper.h
@@ -27,13 +27,23 @@ public: using HandlerCallback = base::Callback<void(ScopedMessagePipeHandle)>; + enum class LaunchType { + // Launch the child process as a child in the mojo system. + CHILD, + + // Launch the child process as an unrelated peer process in the mojo system. + PEER, + }; + MultiprocessTestHelper(); ~MultiprocessTestHelper(); // Start a child process and run the "main" function "named" |test_child_name| // declared using |MOJO_MULTIPROCESS_TEST_CHILD_MAIN()| or // |MOJO_MULTIPROCESS_TEST_CHILD_TEST()| (below). - ScopedMessagePipeHandle StartChild(const std::string& test_child_name); + ScopedMessagePipeHandle StartChild( + const std::string& test_child_name, + LaunchType launch_type = LaunchType::CHILD); // Like |StartChild()|, but appends an extra switch (with ASCII value) to the // command line. (The switch must not already be present in the default @@ -41,7 +51,8 @@ ScopedMessagePipeHandle StartChildWithExtraSwitch( const std::string& test_child_name, const std::string& switch_string, - const std::string& switch_value); + const std::string& switch_value, + LaunchType launch_type); void set_process_error_callback(const ProcessErrorCallback& callback) { process_error_callback_ = callback; @@ -69,7 +80,7 @@ static int RunClientTestMain(const base::Callback<void(MojoHandle)>& main); // For use (and only valid) in the child process: - static std::string primordial_pipe_token; + static mojo::ScopedMessagePipeHandle primordial_pipe; private: // Valid after |StartChild()| and before |WaitForChildShutdown()|.
diff --git a/mojo/message_pump/BUILD.gn b/mojo/message_pump/BUILD.gn deleted file mode 100644 index e1ae4af2..0000000 --- a/mojo/message_pump/BUILD.gn +++ /dev/null
@@ -1,24 +0,0 @@ -# Copyright 2015 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import("//testing/test.gni") - -component("message_pump") { - sources = [ - "handle_watcher.cc", - "handle_watcher.h", - "message_pump_mojo.cc", - "message_pump_mojo.h", - "message_pump_mojo_handler.h", - "time_helper.cc", - "time_helper.h", - ] - - defines = [ "MOJO_MESSAGE_PUMP_IMPLEMENTATION" ] - - public_deps = [ - "//base", - "//mojo/public/cpp/system", - ] -}
diff --git a/mojo/message_pump/handle_watcher.cc b/mojo/message_pump/handle_watcher.cc deleted file mode 100644 index 7f6f5616..0000000 --- a/mojo/message_pump/handle_watcher.cc +++ /dev/null
@@ -1,480 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "mojo/message_pump/handle_watcher.h" - -#include <stddef.h> -#include <stdint.h> - -#include <map> - -#include "base/atomic_sequence_num.h" -#include "base/bind.h" -#include "base/lazy_instance.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/memory/singleton.h" -#include "base/memory/weak_ptr.h" -#include "base/message_loop/message_loop.h" -#include "base/single_thread_task_runner.h" -#include "base/synchronization/lock.h" -#include "base/threading/thread.h" -#include "base/threading/thread_task_runner_handle.h" -#include "base/time/time.h" -#include "mojo/message_pump/message_pump_mojo.h" -#include "mojo/message_pump/message_pump_mojo_handler.h" -#include "mojo/message_pump/time_helper.h" -#include "mojo/public/c/system/message_pipe.h" - -namespace mojo { -namespace common { - -typedef int WatcherID; - -namespace { - -const char kWatcherThreadName[] = "handle-watcher-thread"; - -base::TimeTicks MojoDeadlineToTimeTicks(MojoDeadline deadline) { - return deadline == MOJO_DEADLINE_INDEFINITE ? base::TimeTicks() : - internal::NowTicks() + base::TimeDelta::FromMicroseconds(deadline); -} - -// Tracks the data for a single call to Start(). -struct WatchData { - WatchData() - : id(0), handle_signals(MOJO_HANDLE_SIGNAL_NONE), task_runner(NULL) {} - - WatcherID id; - Handle handle; - MojoHandleSignals handle_signals; - base::TimeTicks deadline; - base::Callback<void(MojoResult)> callback; - scoped_refptr<base::SingleThreadTaskRunner> task_runner; -}; - -// WatcherBackend -------------------------------------------------------------- - -// WatcherBackend is responsible for managing the requests and interacting with -// MessagePumpMojo. All access (outside of creation/destruction) is done on the -// thread WatcherThreadManager creates. -class WatcherBackend : public MessagePumpMojoHandler { - public: - WatcherBackend(); - ~WatcherBackend() override; - - void StartWatching(const WatchData& data); - void StopWatching(WatcherID watcher_id); - - private: - typedef std::map<Handle, WatchData> HandleToWatchDataMap; - - // Invoked when a handle needs to be removed and notified. - void RemoveAndNotify(const Handle& handle, MojoResult result); - - // Searches through |handle_to_data_| for |watcher_id|. Returns true if found - // and sets |handle| to the Handle. Returns false if not a known id. - bool GetMojoHandleByWatcherID(WatcherID watcher_id, Handle* handle) const; - - // MessagePumpMojoHandler overrides: - void OnHandleReady(const Handle& handle) override; - void OnHandleError(const Handle& handle, MojoResult result) override; - - // Maps from assigned id to WatchData. - HandleToWatchDataMap handle_to_data_; - - DISALLOW_COPY_AND_ASSIGN(WatcherBackend); -}; - -WatcherBackend::WatcherBackend() { -} - -WatcherBackend::~WatcherBackend() { -} - -void WatcherBackend::StartWatching(const WatchData& data) { - RemoveAndNotify(data.handle, MOJO_RESULT_CANCELLED); - - DCHECK_EQ(0u, handle_to_data_.count(data.handle)); - - handle_to_data_[data.handle] = data; - MessagePumpMojo::current()->AddHandler(this, data.handle, - data.handle_signals, - data.deadline); -} - -void WatcherBackend::StopWatching(WatcherID watcher_id) { - // Because of the thread hop it is entirely possible to get here and not - // have a valid handle registered for |watcher_id|. - Handle handle; - if (!GetMojoHandleByWatcherID(watcher_id, &handle)) - return; - - handle_to_data_.erase(handle); - MessagePumpMojo::current()->RemoveHandler(handle); -} - -void WatcherBackend::RemoveAndNotify(const Handle& handle, - MojoResult result) { - if (handle_to_data_.count(handle) == 0) - return; - - const WatchData data(handle_to_data_[handle]); - handle_to_data_.erase(handle); - MessagePumpMojo::current()->RemoveHandler(handle); - - data.task_runner->PostTask(FROM_HERE, base::Bind(data.callback, result)); -} - -bool WatcherBackend::GetMojoHandleByWatcherID(WatcherID watcher_id, - Handle* handle) const { - for (HandleToWatchDataMap::const_iterator i = handle_to_data_.begin(); - i != handle_to_data_.end(); ++i) { - if (i->second.id == watcher_id) { - *handle = i->second.handle; - return true; - } - } - return false; -} - -void WatcherBackend::OnHandleReady(const Handle& handle) { - RemoveAndNotify(handle, MOJO_RESULT_OK); -} - -void WatcherBackend::OnHandleError(const Handle& handle, MojoResult result) { - RemoveAndNotify(handle, result); -} - -// WatcherThreadManager -------------------------------------------------------- - -// WatcherThreadManager manages the background thread that listens for handles -// to be ready. All requests are handled by WatcherBackend. -class WatcherThreadManager { - public: - ~WatcherThreadManager(); - - // Returns the shared instance. - static WatcherThreadManager* GetInstance(); - - // Starts watching the requested handle. Returns a unique ID that is used to - // stop watching the handle. When the handle is ready |callback| is notified - // on the thread StartWatching() was invoked on. - // This may be invoked on any thread. - WatcherID StartWatching(const Handle& handle, - MojoHandleSignals handle_signals, - base::TimeTicks deadline, - const base::Callback<void(MojoResult)>& callback); - - // Stops watching a handle. - // This may be invoked on any thread. - void StopWatching(WatcherID watcher_id); - - private: - enum RequestType { - REQUEST_START, - REQUEST_STOP, - }; - - // See description of |requests_| for details. - struct RequestData { - RequestData() : type(REQUEST_START), stop_id(0) {} - - RequestType type; - WatchData start_data; - WatcherID stop_id; - }; - - typedef std::vector<RequestData> Requests; - - friend struct base::DefaultSingletonTraits<WatcherThreadManager>; - - WatcherThreadManager(); - - // Schedules a request on the background thread. See |requests_| for details. - void AddRequest(const RequestData& data); - - // Processes requests added to |requests_|. This is invoked on the backend - // thread. - void ProcessRequestsOnBackendThread(); - - base::Thread thread_; - - base::AtomicSequenceNumber watcher_id_generator_; - - WatcherBackend backend_; - - // Protects |requests_|. - base::Lock lock_; - - // Start/Stop result in adding a RequestData to |requests_| (protected by - // |lock_|). When the background thread wakes up it processes the requests. - Requests requests_; - - DISALLOW_COPY_AND_ASSIGN(WatcherThreadManager); -}; - -WatcherThreadManager::~WatcherThreadManager() { - thread_.Stop(); -} - -WatcherThreadManager* WatcherThreadManager::GetInstance() { - return base::Singleton<WatcherThreadManager>::get(); -} - -WatcherID WatcherThreadManager::StartWatching( - const Handle& handle, - MojoHandleSignals handle_signals, - base::TimeTicks deadline, - const base::Callback<void(MojoResult)>& callback) { - RequestData request_data; - request_data.type = REQUEST_START; - request_data.start_data.id = watcher_id_generator_.GetNext(); - request_data.start_data.handle = handle; - request_data.start_data.callback = callback; - request_data.start_data.handle_signals = handle_signals; - request_data.start_data.deadline = deadline; - request_data.start_data.task_runner = base::ThreadTaskRunnerHandle::Get(); - AddRequest(request_data); - return request_data.start_data.id; -} - -void WatcherThreadManager::StopWatching(WatcherID watcher_id) { - // Handle the case of StartWatching() followed by StopWatching() before - // |thread_| woke up. - { - base::AutoLock auto_lock(lock_); - for (Requests::iterator i = requests_.begin(); i != requests_.end(); ++i) { - if (i->type == REQUEST_START && i->start_data.id == watcher_id) { - // Watcher ids are not reused, so if we find it we can stop. - requests_.erase(i); - return; - } - } - } - - RequestData request_data; - request_data.type = REQUEST_STOP; - request_data.stop_id = watcher_id; - AddRequest(request_data); -} - -void WatcherThreadManager::AddRequest(const RequestData& data) { - { - base::AutoLock auto_lock(lock_); - const bool was_empty = requests_.empty(); - requests_.push_back(data); - if (!was_empty) - return; - } - - // We outlive |thread_|, so it's safe to use Unretained() here. - thread_.task_runner()->PostTask( - FROM_HERE, - base::Bind(&WatcherThreadManager::ProcessRequestsOnBackendThread, - base::Unretained(this))); -} - -void WatcherThreadManager::ProcessRequestsOnBackendThread() { - DCHECK(thread_.task_runner()->BelongsToCurrentThread()); - - Requests requests; - { - base::AutoLock auto_lock(lock_); - requests_.swap(requests); - } - for (size_t i = 0; i < requests.size(); ++i) { - if (requests[i].type == REQUEST_START) { - backend_.StartWatching(requests[i].start_data); - } else { - backend_.StopWatching(requests[i].stop_id); - } - } -} - -WatcherThreadManager::WatcherThreadManager() - : thread_(kWatcherThreadName) { - base::Thread::Options thread_options; - thread_options.message_pump_factory = base::Bind(&MessagePumpMojo::Create); - thread_.StartWithOptions(thread_options); -} - -} // namespace - -// HandleWatcher::StateBase and subclasses ------------------------------------- - -// The base class of HandleWatcher's state. Owns the user's callback and -// monitors the current thread's MessageLoop to know when to force the callback -// to run (with an error) even though the pipe hasn't been signaled yet. -class HandleWatcher::StateBase : public base::MessageLoop::DestructionObserver { - public: - StateBase(HandleWatcher* watcher, - const base::Callback<void(MojoResult)>& callback) - : watcher_(watcher), - callback_(callback), - got_ready_(false) { - base::MessageLoop::current()->AddDestructionObserver(this); - } - - ~StateBase() override { - base::MessageLoop::current()->RemoveDestructionObserver(this); - } - - protected: - void NotifyHandleReady(MojoResult result) { - got_ready_ = true; - NotifyAndDestroy(result); - } - - bool got_ready() const { return got_ready_; } - - private: - void WillDestroyCurrentMessageLoop() override { - // The current thread is exiting. Simulate a watch error. - NotifyAndDestroy(MOJO_RESULT_ABORTED); - } - - void NotifyAndDestroy(MojoResult result) { - base::Callback<void(MojoResult)> callback = callback_; - watcher_->Stop(); // Destroys |this|. - - callback.Run(result); - } - - HandleWatcher* watcher_; - base::Callback<void(MojoResult)> callback_; - - // Have we been notified that the handle is ready? - bool got_ready_; - - DISALLOW_COPY_AND_ASSIGN(StateBase); -}; - -// If the thread on which HandleWatcher is used runs MessagePumpMojo, -// SameThreadWatchingState is used to directly watch the handle on the same -// thread. -class HandleWatcher::SameThreadWatchingState : public StateBase, - public MessagePumpMojoHandler { - public: - SameThreadWatchingState(HandleWatcher* watcher, - const Handle& handle, - MojoHandleSignals handle_signals, - MojoDeadline deadline, - const base::Callback<void(MojoResult)>& callback) - : StateBase(watcher, callback), - handle_(handle) { - DCHECK(MessagePumpMojo::IsCurrent()); - - MessagePumpMojo::current()->AddHandler( - this, handle, handle_signals, MojoDeadlineToTimeTicks(deadline)); - } - - ~SameThreadWatchingState() override { - if (!got_ready()) - MessagePumpMojo::current()->RemoveHandler(handle_); - } - - private: - // MessagePumpMojoHandler overrides: - void OnHandleReady(const Handle& handle) override { - StopWatchingAndNotifyReady(handle, MOJO_RESULT_OK); - } - - void OnHandleError(const Handle& handle, MojoResult result) override { - StopWatchingAndNotifyReady(handle, result); - } - - void StopWatchingAndNotifyReady(const Handle& handle, MojoResult result) { - DCHECK_EQ(handle.value(), handle_.value()); - MessagePumpMojo::current()->RemoveHandler(handle_); - NotifyHandleReady(result); - } - - Handle handle_; - - DISALLOW_COPY_AND_ASSIGN(SameThreadWatchingState); -}; - -// If the thread on which HandleWatcher is used runs a message pump different -// from MessagePumpMojo, SecondaryThreadWatchingState is used to watch the -// handle on the handle watcher thread. -class HandleWatcher::SecondaryThreadWatchingState : public StateBase { - public: - SecondaryThreadWatchingState(HandleWatcher* watcher, - const Handle& handle, - MojoHandleSignals handle_signals, - MojoDeadline deadline, - const base::Callback<void(MojoResult)>& callback) - : StateBase(watcher, callback), - weak_factory_(this) { - watcher_id_ = WatcherThreadManager::GetInstance()->StartWatching( - handle, - handle_signals, - MojoDeadlineToTimeTicks(deadline), - base::Bind(&SecondaryThreadWatchingState::NotifyHandleReady, - weak_factory_.GetWeakPtr())); - } - - ~SecondaryThreadWatchingState() override { - // If we've been notified the handle is ready (|got_ready()| is true) then - // the watch has been implicitly removed by - // WatcherThreadManager/MessagePumpMojo and we don't have to call - // StopWatching(). To do so would needlessly entail posting a task and - // blocking until the background thread services it. - if (!got_ready()) - WatcherThreadManager::GetInstance()->StopWatching(watcher_id_); - } - - private: - WatcherID watcher_id_; - - // Used to weakly bind |this| to the WatcherThreadManager. - base::WeakPtrFactory<SecondaryThreadWatchingState> weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(SecondaryThreadWatchingState); -}; - -// HandleWatcher --------------------------------------------------------------- - -HandleWatcher::HandleWatcher() { -} - -HandleWatcher::~HandleWatcher() { -} - -void HandleWatcher::Start(const Handle& handle, - MojoHandleSignals handle_signals, - MojoDeadline deadline, - const base::Callback<void(MojoResult)>& callback) { - DCHECK(handle.is_valid()); - DCHECK_NE(MOJO_HANDLE_SIGNAL_NONE, handle_signals); - - // Need to clear the state before creating a new one. - state_.reset(); - if (MessagePumpMojo::IsCurrent()) { - state_.reset(new SameThreadWatchingState( - this, handle, handle_signals, deadline, callback)); - } else { -#if !defined(OFFICIAL_BUILD) - // Just for making debugging non-transferable message pipes easier. Since - // they can't be sent after they're read/written/listened to, - // MessagePipeDispatcher saves the callstack of when it's "bound" to a - // pipe id. Triggering a read here, instead of later in the PostTask, means - // we have a callstack that is useful to check if the pipe is erronously - // attempted to be sent. - uint32_t temp = 0; - MojoReadMessage(handle.value(), nullptr, &temp, nullptr, nullptr, - MOJO_READ_MESSAGE_FLAG_NONE); -#endif - state_.reset(new SecondaryThreadWatchingState( - this, handle, handle_signals, deadline, callback)); - } -} - -void HandleWatcher::Stop() { - state_.reset(); -} - -} // namespace common -} // namespace mojo
diff --git a/mojo/message_pump/handle_watcher.h b/mojo/message_pump/handle_watcher.h deleted file mode 100644 index 10056b14..0000000 --- a/mojo/message_pump/handle_watcher.h +++ /dev/null
@@ -1,65 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MOJO_MESSAGE_PUMP_HANDLE_WATCHER_H_ -#define MOJO_MESSAGE_PUMP_HANDLE_WATCHER_H_ - -#include <memory> - -#include "base/callback_forward.h" -#include "base/macros.h" -#include "base/run_loop.h" -#include "mojo/message_pump/mojo_message_pump_export.h" -#include "mojo/public/cpp/system/core.h" - -namespace base { -class Thread; -} - -namespace mojo { -namespace common { -namespace test { -class HandleWatcherTest; -} - -// HandleWatcher is used to asynchronously wait on a handle and notify a Closure -// when the handle is ready, or the deadline has expired. -class MOJO_MESSAGE_PUMP_EXPORT HandleWatcher { - public: - HandleWatcher(); - - ~HandleWatcher(); - - // Starts listening for |handle|. This implicitly invokes Stop(). In other - // words, Start() performs one asynchronous watch at a time. It is ok to call - // Start() multiple times, but it cancels any existing watches. |callback| is - // notified when the handle is ready, invalid or deadline has passed and is - // notified on the thread Start() was invoked on. If the current thread exits - // before the handle is ready, then |callback| is invoked with a result of - // MOJO_RESULT_ABORTED. - void Start(const Handle& handle, - MojoHandleSignals handle_signals, - MojoDeadline deadline, - const base::Callback<void(MojoResult)>& callback); - - // Stops listening. Does nothing if not in the process of listening. - void Stop(); - - bool is_watching() const { return !!state_; } - - private: - class StateBase; - class SameThreadWatchingState; - class SecondaryThreadWatchingState; - - // If non-NULL Start() has been invoked. - std::unique_ptr<StateBase> state_; - - DISALLOW_COPY_AND_ASSIGN(HandleWatcher); -}; - -} // namespace common -} // namespace mojo - -#endif // MOJO_MESSAGE_PUMP_HANDLE_WATCHER_H_
diff --git a/mojo/message_pump/handle_watcher_perftest.cc b/mojo/message_pump/handle_watcher_perftest.cc deleted file mode 100644 index 96c8495..0000000 --- a/mojo/message_pump/handle_watcher_perftest.cc +++ /dev/null
@@ -1,207 +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 <stdint.h> - -#include <string> -#include <utility> - -#include "base/auto_reset.h" -#include "base/bind.h" -#include "base/macros.h" -#include "base/memory/scoped_vector.h" -#include "base/run_loop.h" -#include "base/time/time.h" -#include "mojo/message_pump/handle_watcher.h" -#include "mojo/message_pump/message_pump_mojo.h" -#include "mojo/public/cpp/test_support/test_support.h" -#include "mojo/public/cpp/test_support/test_utils.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace mojo { -namespace common { -namespace test { - -enum MessageLoopConfig { - MESSAGE_LOOP_CONFIG_DEFAULT = 0, - MESSAGE_LOOP_CONFIG_MOJO = 1 -}; - -std::unique_ptr<base::MessageLoop> CreateMessageLoop(MessageLoopConfig config) { - std::unique_ptr<base::MessageLoop> loop; - if (config == MESSAGE_LOOP_CONFIG_DEFAULT) - loop.reset(new base::MessageLoop()); - else - loop.reset(new base::MessageLoop(MessagePumpMojo::Create())); - return loop; -} - -void OnWatcherSignaled(const base::Closure& callback, MojoResult /* result */) { - callback.Run(); -} - -class ScopedPerfTimer { - public: - ScopedPerfTimer(const std::string& test_name, - const std::string& sub_test_name, - uint64_t iterations) - : test_name_(test_name), - sub_test_name_(sub_test_name), - iterations_(iterations), - start_time_(base::TimeTicks::Now()) {} - ~ScopedPerfTimer() { - base::TimeTicks end_time = base::TimeTicks::Now(); - mojo::test::LogPerfResult( - test_name_.c_str(), sub_test_name_.c_str(), - iterations_ / (end_time - start_time_).InSecondsF(), - "iterations/second"); - } - - private: - const std::string test_name_; - const std::string sub_test_name_; - const uint64_t iterations_; - base::TimeTicks start_time_; - - DISALLOW_COPY_AND_ASSIGN(ScopedPerfTimer); -}; - -class HandleWatcherPerftest : public testing::TestWithParam<MessageLoopConfig> { - public: - HandleWatcherPerftest() : message_loop_(CreateMessageLoop(GetParam())) {} - - protected: - std::string GetMessageLoopName() const { - return (GetParam() == MESSAGE_LOOP_CONFIG_DEFAULT) ? "DefaultMessageLoop" - : "MojoMessageLoop"; - } - - private: - std::unique_ptr<base::MessageLoop> message_loop_; - - DISALLOW_COPY_AND_ASSIGN(HandleWatcherPerftest); -}; - -INSTANTIATE_TEST_CASE_P(MultipleMessageLoopConfigs, - HandleWatcherPerftest, - testing::Values(MESSAGE_LOOP_CONFIG_DEFAULT, - MESSAGE_LOOP_CONFIG_MOJO)); - -void NeverReached(MojoResult result) { - FAIL() << "Callback should never be invoked " << result; -} - -TEST_P(HandleWatcherPerftest, StartStop) { - const uint64_t kIterations = 100000; - MessagePipe pipe; - HandleWatcher watcher; - - ScopedPerfTimer timer("StartStop", GetMessageLoopName(), kIterations); - for (uint64_t i = 0; i < kIterations; i++) { - watcher.Start(pipe.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE, - MOJO_DEADLINE_INDEFINITE, base::Bind(&NeverReached)); - watcher.Stop(); - } -} - -TEST_P(HandleWatcherPerftest, StartAllThenStop_1000Handles) { - const uint64_t kIterations = 100; - const uint64_t kHandles = 1000; - - struct TestData { - MessagePipe pipe; - HandleWatcher watcher; - }; - ScopedVector<TestData> data_vector; - // Create separately from the start/stop loops to avoid affecting the - // benchmark. - for (uint64_t i = 0; i < kHandles; i++) { - std::unique_ptr<TestData> test_data(new TestData); - ASSERT_TRUE(test_data->pipe.handle0.is_valid()); - data_vector.push_back(std::move(test_data)); - } - - ScopedPerfTimer timer("StartAllThenStop_1000Handles", GetMessageLoopName(), - kIterations * kHandles); - for (uint64_t iter = 0; iter < kIterations; iter++) { - for (uint64_t i = 0; i < kHandles; i++) { - TestData* test_data = data_vector[i]; - test_data->watcher.Start( - test_data->pipe.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE, - MOJO_DEADLINE_INDEFINITE, base::Bind(&NeverReached)); - } - for (uint64_t i = 0; i < kHandles; i++) { - TestData* test_data = data_vector[i]; - test_data->watcher.Stop(); - } - } -} - -TEST_P(HandleWatcherPerftest, StartAndSignal) { - const uint64_t kIterations = 10000; - const std::string kMessage = "hello"; - MessagePipe pipe; - HandleWatcher watcher; - std::string received_message; - - ScopedPerfTimer timer("StartAndSignal", GetMessageLoopName(), kIterations); - for (uint64_t i = 0; i < kIterations; i++) { - base::RunLoop run_loop; - watcher.Start(pipe.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE, - MOJO_DEADLINE_INDEFINITE, - base::Bind(&OnWatcherSignaled, run_loop.QuitClosure())); - ASSERT_TRUE(mojo::test::WriteTextMessage(pipe.handle1.get(), kMessage)); - run_loop.Run(); - watcher.Stop(); - - ASSERT_TRUE( - mojo::test::ReadTextMessage(pipe.handle0.get(), &received_message)); - EXPECT_EQ(kMessage, received_message); - received_message.clear(); - } -} - -TEST_P(HandleWatcherPerftest, StartAndSignal_1000Waiting) { - const uint64_t kIterations = 10000; - const uint64_t kWaitingHandles = 1000; - const std::string kMessage = "hello"; - MessagePipe pipe; - HandleWatcher watcher; - std::string received_message; - - struct TestData { - MessagePipe pipe; - HandleWatcher watcher; - }; - ScopedVector<TestData> data_vector; - for (uint64_t i = 0; i < kWaitingHandles; i++) { - std::unique_ptr<TestData> test_data(new TestData); - ASSERT_TRUE(test_data->pipe.handle0.is_valid()); - test_data->watcher.Start( - test_data->pipe.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE, - MOJO_DEADLINE_INDEFINITE, base::Bind(&NeverReached)); - data_vector.push_back(std::move(test_data)); - } - - ScopedPerfTimer timer("StartAndSignal_1000Waiting", GetMessageLoopName(), - kIterations); - for (uint64_t i = 0; i < kIterations; i++) { - base::RunLoop run_loop; - watcher.Start(pipe.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE, - MOJO_DEADLINE_INDEFINITE, - base::Bind(&OnWatcherSignaled, run_loop.QuitClosure())); - ASSERT_TRUE(mojo::test::WriteTextMessage(pipe.handle1.get(), kMessage)); - run_loop.Run(); - watcher.Stop(); - - ASSERT_TRUE( - mojo::test::ReadTextMessage(pipe.handle0.get(), &received_message)); - EXPECT_EQ(kMessage, received_message); - received_message.clear(); - } -} - -} // namespace test -} // namespace common -} // namespace mojo
diff --git a/mojo/message_pump/handle_watcher_unittest.cc b/mojo/message_pump/handle_watcher_unittest.cc deleted file mode 100644 index fd1f49b..0000000 --- a/mojo/message_pump/handle_watcher_unittest.cc +++ /dev/null
@@ -1,493 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "mojo/message_pump/handle_watcher.h" - -#include <memory> -#include <string> - -#include "base/at_exit.h" -#include "base/auto_reset.h" -#include "base/bind.h" -#include "base/macros.h" -#include "base/memory/scoped_vector.h" -#include "base/run_loop.h" -#include "base/test/simple_test_tick_clock.h" -#include "base/threading/thread.h" -#include "mojo/message_pump/message_pump_mojo.h" -#include "mojo/message_pump/time_helper.h" -#include "mojo/public/cpp/system/core.h" -#include "mojo/public/cpp/test_support/test_utils.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace mojo { -namespace common { -namespace test { - -enum MessageLoopConfig { - MESSAGE_LOOP_CONFIG_DEFAULT = 0, - MESSAGE_LOOP_CONFIG_MOJO = 1 -}; - -void ObserveCallback(bool* was_signaled, - MojoResult* result_observed, - MojoResult result) { - *was_signaled = true; - *result_observed = result; -} - -void RunUntilIdle() { - base::RunLoop run_loop; - run_loop.RunUntilIdle(); -} - -void DeleteWatcherAndForwardResult( - HandleWatcher* watcher, - base::Callback<void(MojoResult)> next_callback, - MojoResult result) { - delete watcher; - next_callback.Run(result); -} - -std::unique_ptr<base::MessageLoop> CreateMessageLoop(MessageLoopConfig config) { - std::unique_ptr<base::MessageLoop> loop; - if (config == MESSAGE_LOOP_CONFIG_DEFAULT) - loop.reset(new base::MessageLoop()); - else - loop.reset(new base::MessageLoop(MessagePumpMojo::Create())); - return loop; -} - -// Helper class to manage the callback and running the message loop waiting for -// message to be received. Typical usage is something like: -// Schedule callback returned from GetCallback(). -// RunUntilGotCallback(); -// EXPECT_TRUE(got_callback()); -// clear_callback(); -class CallbackHelper { - public: - CallbackHelper() - : got_callback_(false), - run_loop_(NULL), - weak_factory_(this) {} - ~CallbackHelper() {} - - // See description above |got_callback_|. - bool got_callback() const { return got_callback_; } - void clear_callback() { got_callback_ = false; } - - // Runs the current MessageLoop until the callback returned from GetCallback() - // is notified. - void RunUntilGotCallback() { - ASSERT_TRUE(run_loop_ == NULL); - base::RunLoop run_loop; - base::AutoReset<base::RunLoop*> reseter(&run_loop_, &run_loop); - run_loop.Run(); - } - - base::Callback<void(MojoResult)> GetCallback() { - return base::Bind(&CallbackHelper::OnCallback, weak_factory_.GetWeakPtr()); - } - - void Start(HandleWatcher* watcher, const MessagePipeHandle& handle) { - StartWithCallback(watcher, handle, GetCallback()); - } - - void StartWithCallback(HandleWatcher* watcher, - const MessagePipeHandle& handle, - const base::Callback<void(MojoResult)>& callback) { - watcher->Start(handle, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_DEADLINE_INDEFINITE, callback); - } - - private: - void OnCallback(MojoResult result) { - got_callback_ = true; - if (run_loop_) - run_loop_->Quit(); - } - - // Set to true when the callback is called. - bool got_callback_; - - // If non-NULL we're in RunUntilGotCallback(). - base::RunLoop* run_loop_; - - base::WeakPtrFactory<CallbackHelper> weak_factory_; - - private: - DISALLOW_COPY_AND_ASSIGN(CallbackHelper); -}; - -class HandleWatcherTest : public testing::TestWithParam<MessageLoopConfig> { - public: - HandleWatcherTest() - : at_exit_(new base::ShadowingAtExitManager), - message_loop_(CreateMessageLoop(GetParam())) {} - virtual ~HandleWatcherTest() { - // By explicitly destroying |at_exit_| before resetting the tick clock, it - // ensures that the handle watcher thread (if there is one) is shut down, - // preventing a race with users of the tick clock in MessagePumpMojo. - at_exit_.reset(); - test::SetTickClockForTest(NULL); - } - - protected: - void TearDownMessageLoop() { - message_loop_.reset(); - } - - // This should be called at the beginning of any test that needs it, so that - // it is installed before the handle watcher thread starts. - void InstallTickClock() { - test::SetTickClockForTest(&tick_clock_); - } - - base::SimpleTestTickClock tick_clock_; - - private: - std::unique_ptr<base::ShadowingAtExitManager> at_exit_; - std::unique_ptr<base::MessageLoop> message_loop_; - - DISALLOW_COPY_AND_ASSIGN(HandleWatcherTest); -}; - -INSTANTIATE_TEST_CASE_P( - MultipleMessageLoopConfigs, HandleWatcherTest, - testing::Values(MESSAGE_LOOP_CONFIG_DEFAULT, MESSAGE_LOOP_CONFIG_MOJO)); - -// Trivial test case with a single handle to watch. -TEST_P(HandleWatcherTest, SingleHandler) { - MessagePipe test_pipe; - ASSERT_TRUE(test_pipe.handle0.is_valid()); - CallbackHelper callback_helper; - HandleWatcher watcher; - callback_helper.Start(&watcher, test_pipe.handle0.get()); - RunUntilIdle(); - EXPECT_FALSE(callback_helper.got_callback()); - EXPECT_TRUE(mojo::test::WriteTextMessage(test_pipe.handle1.get(), - std::string())); - callback_helper.RunUntilGotCallback(); - EXPECT_TRUE(callback_helper.got_callback()); -} - -// Creates three handles and notfies them in reverse order ensuring each one is -// notified appropriately. -TEST_P(HandleWatcherTest, ThreeHandles) { - MessagePipe test_pipe1; - MessagePipe test_pipe2; - MessagePipe test_pipe3; - CallbackHelper callback_helper1; - CallbackHelper callback_helper2; - CallbackHelper callback_helper3; - ASSERT_TRUE(test_pipe1.handle0.is_valid()); - ASSERT_TRUE(test_pipe2.handle0.is_valid()); - ASSERT_TRUE(test_pipe3.handle0.is_valid()); - - HandleWatcher watcher1; - callback_helper1.Start(&watcher1, test_pipe1.handle0.get()); - RunUntilIdle(); - EXPECT_FALSE(callback_helper1.got_callback()); - EXPECT_FALSE(callback_helper2.got_callback()); - EXPECT_FALSE(callback_helper3.got_callback()); - - HandleWatcher watcher2; - callback_helper2.Start(&watcher2, test_pipe2.handle0.get()); - RunUntilIdle(); - EXPECT_FALSE(callback_helper1.got_callback()); - EXPECT_FALSE(callback_helper2.got_callback()); - EXPECT_FALSE(callback_helper3.got_callback()); - - HandleWatcher watcher3; - callback_helper3.Start(&watcher3, test_pipe3.handle0.get()); - RunUntilIdle(); - EXPECT_FALSE(callback_helper1.got_callback()); - EXPECT_FALSE(callback_helper2.got_callback()); - EXPECT_FALSE(callback_helper3.got_callback()); - - // Write to 3 and make sure it's notified. - EXPECT_TRUE(mojo::test::WriteTextMessage(test_pipe3.handle1.get(), - std::string())); - callback_helper3.RunUntilGotCallback(); - EXPECT_FALSE(callback_helper1.got_callback()); - EXPECT_FALSE(callback_helper2.got_callback()); - EXPECT_TRUE(callback_helper3.got_callback()); - callback_helper3.clear_callback(); - - // Write to 1 and 3. Only 1 should be notified since 3 was is no longer - // running. - EXPECT_TRUE(mojo::test::WriteTextMessage(test_pipe1.handle1.get(), - std::string())); - EXPECT_TRUE(mojo::test::WriteTextMessage(test_pipe3.handle1.get(), - std::string())); - callback_helper1.RunUntilGotCallback(); - EXPECT_TRUE(callback_helper1.got_callback()); - EXPECT_FALSE(callback_helper2.got_callback()); - EXPECT_FALSE(callback_helper3.got_callback()); - callback_helper1.clear_callback(); - - // Write to 1 and 2. Only 2 should be notified (since 1 was already notified). - EXPECT_TRUE(mojo::test::WriteTextMessage(test_pipe1.handle1.get(), - std::string())); - EXPECT_TRUE(mojo::test::WriteTextMessage(test_pipe2.handle1.get(), - std::string())); - callback_helper2.RunUntilGotCallback(); - EXPECT_FALSE(callback_helper1.got_callback()); - EXPECT_TRUE(callback_helper2.got_callback()); - EXPECT_FALSE(callback_helper3.got_callback()); -} - -// Verifies Start() invoked a second time works. -TEST_P(HandleWatcherTest, Restart) { - MessagePipe test_pipe1; - MessagePipe test_pipe2; - CallbackHelper callback_helper1; - CallbackHelper callback_helper2; - ASSERT_TRUE(test_pipe1.handle0.is_valid()); - ASSERT_TRUE(test_pipe2.handle0.is_valid()); - - HandleWatcher watcher1; - callback_helper1.Start(&watcher1, test_pipe1.handle0.get()); - RunUntilIdle(); - EXPECT_FALSE(callback_helper1.got_callback()); - EXPECT_FALSE(callback_helper2.got_callback()); - - HandleWatcher watcher2; - callback_helper2.Start(&watcher2, test_pipe2.handle0.get()); - RunUntilIdle(); - EXPECT_FALSE(callback_helper1.got_callback()); - EXPECT_FALSE(callback_helper2.got_callback()); - - // Write to 1 and make sure it's notified. - EXPECT_TRUE(mojo::test::WriteTextMessage(test_pipe1.handle1.get(), - std::string())); - callback_helper1.RunUntilGotCallback(); - EXPECT_TRUE(callback_helper1.got_callback()); - EXPECT_FALSE(callback_helper2.got_callback()); - callback_helper1.clear_callback(); - EXPECT_TRUE(mojo::test::DiscardMessage(test_pipe1.handle0.get())); - - // Write to 2 and make sure it's notified. - EXPECT_TRUE(mojo::test::WriteTextMessage(test_pipe2.handle1.get(), - std::string())); - callback_helper2.RunUntilGotCallback(); - EXPECT_FALSE(callback_helper1.got_callback()); - EXPECT_TRUE(callback_helper2.got_callback()); - callback_helper2.clear_callback(); - - // Listen on 1 again. - callback_helper1.Start(&watcher1, test_pipe1.handle0.get()); - RunUntilIdle(); - EXPECT_FALSE(callback_helper1.got_callback()); - EXPECT_FALSE(callback_helper2.got_callback()); - - // Write to 1 and make sure it's notified. - EXPECT_TRUE(mojo::test::WriteTextMessage(test_pipe1.handle1.get(), - std::string())); - callback_helper1.RunUntilGotCallback(); - EXPECT_TRUE(callback_helper1.got_callback()); - EXPECT_FALSE(callback_helper2.got_callback()); -} - -// Verifies Start() invoked a second time on the same handle works. -TEST_P(HandleWatcherTest, RestartOnSameHandle) { - MessagePipe test_pipe; - CallbackHelper callback_helper; - ASSERT_TRUE(test_pipe.handle0.is_valid()); - - HandleWatcher watcher; - callback_helper.Start(&watcher, test_pipe.handle0.get()); - RunUntilIdle(); - EXPECT_FALSE(callback_helper.got_callback()); - - callback_helper.Start(&watcher, test_pipe.handle0.get()); - RunUntilIdle(); - EXPECT_FALSE(callback_helper.got_callback()); -} - -// Verifies deadline is honored. -TEST_P(HandleWatcherTest, Deadline) { - InstallTickClock(); - - MessagePipe test_pipe1; - MessagePipe test_pipe2; - MessagePipe test_pipe3; - CallbackHelper callback_helper1; - CallbackHelper callback_helper2; - CallbackHelper callback_helper3; - ASSERT_TRUE(test_pipe1.handle0.is_valid()); - ASSERT_TRUE(test_pipe2.handle0.is_valid()); - ASSERT_TRUE(test_pipe3.handle0.is_valid()); - - // Add a watcher with an infinite timeout. - HandleWatcher watcher1; - callback_helper1.Start(&watcher1, test_pipe1.handle0.get()); - RunUntilIdle(); - EXPECT_FALSE(callback_helper1.got_callback()); - EXPECT_FALSE(callback_helper2.got_callback()); - EXPECT_FALSE(callback_helper3.got_callback()); - - // Add another watcher wth a timeout of 500 microseconds. - HandleWatcher watcher2; - watcher2.Start(test_pipe2.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE, 500, - callback_helper2.GetCallback()); - RunUntilIdle(); - EXPECT_FALSE(callback_helper1.got_callback()); - EXPECT_FALSE(callback_helper2.got_callback()); - EXPECT_FALSE(callback_helper3.got_callback()); - - // Advance the clock passed the deadline. We also have to start another - // watcher to wake up the background thread. - tick_clock_.Advance(base::TimeDelta::FromMicroseconds(501)); - - HandleWatcher watcher3; - callback_helper3.Start(&watcher3, test_pipe3.handle0.get()); - - callback_helper2.RunUntilGotCallback(); - EXPECT_FALSE(callback_helper1.got_callback()); - EXPECT_TRUE(callback_helper2.got_callback()); - EXPECT_FALSE(callback_helper3.got_callback()); -} - -TEST_P(HandleWatcherTest, DeleteInCallback) { - MessagePipe test_pipe; - CallbackHelper callback_helper; - - HandleWatcher* watcher = new HandleWatcher(); - callback_helper.StartWithCallback(watcher, test_pipe.handle1.get(), - base::Bind(&DeleteWatcherAndForwardResult, - watcher, - callback_helper.GetCallback())); - EXPECT_TRUE(mojo::test::WriteTextMessage(test_pipe.handle0.get(), - std::string())); - callback_helper.RunUntilGotCallback(); - EXPECT_TRUE(callback_helper.got_callback()); -} - -TEST_P(HandleWatcherTest, AbortedOnMessageLoopDestruction) { - bool was_signaled = false; - MojoResult result = MOJO_RESULT_OK; - - MessagePipe pipe; - HandleWatcher watcher; - watcher.Start(pipe.handle0.get(), - MOJO_HANDLE_SIGNAL_READABLE, - MOJO_DEADLINE_INDEFINITE, - base::Bind(&ObserveCallback, &was_signaled, &result)); - - // Now, let the MessageLoop get torn down. We expect our callback to run. - TearDownMessageLoop(); - - EXPECT_TRUE(was_signaled); - EXPECT_EQ(MOJO_RESULT_ABORTED, result); -} - -void NeverReached(MojoResult result) { - FAIL() << "Callback should never be invoked " << result; -} - -// Called on the main thread when a thread is done. Decrements |active_count| -// and if |active_count| is zero quits |run_loop|. -void StressThreadDone(base::RunLoop* run_loop, int* active_count) { - (*active_count)--; - EXPECT_GE(*active_count, 0); - if (*active_count == 0) - run_loop->Quit(); -} - -// See description of StressTest. This is called on the background thread. -// |count| is the number of HandleWatchers to create. |active_count| is the -// number of outstanding threads, |task_runner| the task runner for the main -// thread and |run_loop| the run loop that should be quit when there are no more -// threads running. When done StressThreadDone() is invoked on the main thread. -// |active_count| and |run_loop| should only be used on the main thread. -void RunStressTest(int count, - scoped_refptr<base::TaskRunner> task_runner, - base::RunLoop* run_loop, - int* active_count) { - struct TestData { - MessagePipe pipe; - HandleWatcher watcher; - }; - ScopedVector<TestData> data_vector; - for (int i = 0; i < count; ++i) { - if (i % 20 == 0) { - // Every so often we wait. This results in some level of thread balancing - // as well as making sure HandleWatcher has time to actually start some - // watches. - MessagePipe test_pipe; - ASSERT_TRUE(test_pipe.handle0.is_valid()); - CallbackHelper callback_helper; - HandleWatcher watcher; - callback_helper.Start(&watcher, test_pipe.handle0.get()); - RunUntilIdle(); - EXPECT_FALSE(callback_helper.got_callback()); - EXPECT_TRUE(mojo::test::WriteTextMessage(test_pipe.handle1.get(), - std::string())); - base::MessageLoop::ScopedNestableTaskAllower scoper( - base::MessageLoop::current()); - callback_helper.RunUntilGotCallback(); - EXPECT_TRUE(callback_helper.got_callback()); - } else { - std::unique_ptr<TestData> test_data(new TestData); - ASSERT_TRUE(test_data->pipe.handle0.is_valid()); - test_data->watcher.Start(test_data->pipe.handle0.get(), - MOJO_HANDLE_SIGNAL_READABLE, - MOJO_DEADLINE_INDEFINITE, - base::Bind(&NeverReached)); - data_vector.push_back(test_data.release()); - } - if (i % 15 == 0) - data_vector.clear(); - } - task_runner->PostTask(FROM_HERE, - base::Bind(&StressThreadDone, run_loop, - active_count)); -} - -// This test is meant to stress HandleWatcher. It uses from various threads -// repeatedly starting and stopping watches. It spins up kThreadCount -// threads. Each thread creates kWatchCount watches. Every so often each thread -// writes to a pipe and waits for the response. -TEST(HandleWatcherCleanEnvironmentTest, StressTest) { -#if defined(NDEBUG) - const int kThreadCount = 15; - const int kWatchCount = 400; -#else - const int kThreadCount = 10; - const int kWatchCount = 250; -#endif - - base::ShadowingAtExitManager at_exit; - base::MessageLoop message_loop; - base::RunLoop run_loop; - ScopedVector<base::Thread> threads; - int threads_active_counter = kThreadCount; - // Starts the threads first and then post the task in hopes of having more - // threads running at once. - for (int i = 0; i < kThreadCount; ++i) { - std::unique_ptr<base::Thread> thread(new base::Thread("test thread")); - if (i % 2) { - base::Thread::Options thread_options; - thread_options.message_pump_factory = - base::Bind(&MessagePumpMojo::Create); - thread->StartWithOptions(thread_options); - } else { - thread->Start(); - } - threads.push_back(thread.release()); - } - for (int i = 0; i < kThreadCount; ++i) { - threads[i]->task_runner()->PostTask( - FROM_HERE, base::Bind(&RunStressTest, kWatchCount, - message_loop.task_runner(), - &run_loop, &threads_active_counter)); - } - run_loop.Run(); - ASSERT_EQ(0, threads_active_counter); -} - -} // namespace test -} // namespace common -} // namespace mojo
diff --git a/mojo/message_pump/message_pump_mojo.cc b/mojo/message_pump/message_pump_mojo.cc deleted file mode 100644 index b907ba3e..0000000 --- a/mojo/message_pump/message_pump_mojo.cc +++ /dev/null
@@ -1,448 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "mojo/message_pump/message_pump_mojo.h" - -#include <stdint.h> - -#include <algorithm> -#include <map> -#include <vector> - -#include "base/containers/small_map.h" -#include "base/debug/alias.h" -#include "base/lazy_instance.h" -#include "base/logging.h" -#include "base/threading/thread_local.h" -#include "base/threading/thread_restrictions.h" -#include "base/time/time.h" -#include "mojo/message_pump/message_pump_mojo_handler.h" -#include "mojo/message_pump/time_helper.h" -#include "mojo/public/c/system/wait_set.h" - -namespace mojo { -namespace common { -namespace { - -base::LazyInstance<base::ThreadLocalPointer<MessagePumpMojo> >::Leaky - g_tls_current_pump = LAZY_INSTANCE_INITIALIZER; - -MojoDeadline TimeTicksToMojoDeadline(base::TimeTicks time_ticks, - base::TimeTicks now) { - // The is_null() check matches that of HandleWatcher as well as how - // |delayed_work_time| is used. - if (time_ticks.is_null()) - return MOJO_DEADLINE_INDEFINITE; - const int64_t delta = (time_ticks - now).InMicroseconds(); - return delta < 0 ? static_cast<MojoDeadline>(0) : - static_cast<MojoDeadline>(delta); -} - -} // namespace - -struct MessagePumpMojo::RunState { - RunState() : should_quit(false) {} - - base::TimeTicks delayed_work_time; - - bool should_quit; -}; - -MessagePumpMojo::MessagePumpMojo() - : run_state_(NULL), - next_handler_id_(0), - event_(base::WaitableEvent::ResetPolicy::AUTOMATIC, - base::WaitableEvent::InitialState::NOT_SIGNALED) { - DCHECK(!current()) - << "There is already a MessagePumpMojo instance on this thread."; - g_tls_current_pump.Pointer()->Set(this); - - MojoResult result = CreateMessagePipe(nullptr, &read_handle_, &write_handle_); - CHECK_EQ(result, MOJO_RESULT_OK); - CHECK(read_handle_.is_valid()); - CHECK(write_handle_.is_valid()); - - MojoHandle handle; - result = MojoCreateWaitSet(&handle); - CHECK_EQ(result, MOJO_RESULT_OK); - wait_set_handle_.reset(Handle(handle)); - CHECK(wait_set_handle_.is_valid()); - - result = - MojoAddHandle(wait_set_handle_.get().value(), read_handle_.get().value(), - MOJO_HANDLE_SIGNAL_READABLE); - CHECK_EQ(result, MOJO_RESULT_OK); -} - -MessagePumpMojo::~MessagePumpMojo() { - DCHECK_EQ(this, current()); - g_tls_current_pump.Pointer()->Set(NULL); -} - -// static -std::unique_ptr<base::MessagePump> MessagePumpMojo::Create() { - return std::unique_ptr<MessagePump>(new MessagePumpMojo()); -} - -// static -MessagePumpMojo* MessagePumpMojo::current() { - return g_tls_current_pump.Pointer()->Get(); -} - -void MessagePumpMojo::AddHandler(MessagePumpMojoHandler* handler, - const Handle& handle, - MojoHandleSignals wait_signals, - base::TimeTicks deadline) { - CHECK(handler); - DCHECK(handle.is_valid()); - // Assume it's an error if someone tries to reregister an existing handle. - CHECK_EQ(0u, handlers_.count(handle)); - Handler handler_data; - handler_data.handler = handler; - handler_data.wait_signals = wait_signals; - handler_data.deadline = deadline; - handler_data.id = next_handler_id_++; - handlers_[handle] = handler_data; - if (!deadline.is_null()) { - bool inserted = deadline_handles_.insert(handle).second; - DCHECK(inserted); - } - - MojoResult result = MojoAddHandle(wait_set_handle_.get().value(), - handle.value(), wait_signals); - // Because stopping a HandleWatcher is now asynchronous, it's possible for the - // handle to no longer be open at this point. - CHECK(result == MOJO_RESULT_OK || result == MOJO_RESULT_INVALID_ARGUMENT); -} - -void MessagePumpMojo::RemoveHandler(const Handle& handle) { - MojoResult result = - MojoRemoveHandle(wait_set_handle_.get().value(), handle.value()); - // At this point, it's possible that the handle has been closed, which would - // cause MojoRemoveHandle() to return MOJO_RESULT_INVALID_ARGUMENT. It's also - // possible for the handle to have already been removed, so all of the - // possible error codes are valid here. - CHECK(result == MOJO_RESULT_OK || result == MOJO_RESULT_NOT_FOUND || - result == MOJO_RESULT_INVALID_ARGUMENT); - - handlers_.erase(handle); - deadline_handles_.erase(handle); -} - -void MessagePumpMojo::AddObserver(Observer* observer) { - observers_.AddObserver(observer); -} - -void MessagePumpMojo::RemoveObserver(Observer* observer) { - observers_.RemoveObserver(observer); -} - -void MessagePumpMojo::Run(Delegate* delegate) { - RunState run_state; - RunState* old_state = NULL; - { - base::AutoLock auto_lock(run_state_lock_); - old_state = run_state_; - run_state_ = &run_state; - } - DoRunLoop(&run_state, delegate); - { - base::AutoLock auto_lock(run_state_lock_); - run_state_ = old_state; - } -} - -void MessagePumpMojo::Quit() { - base::AutoLock auto_lock(run_state_lock_); - if (run_state_) - run_state_->should_quit = true; -} - -void MessagePumpMojo::ScheduleWork() { - SignalControlPipe(); -} - -void MessagePumpMojo::ScheduleDelayedWork( - const base::TimeTicks& delayed_work_time) { - base::AutoLock auto_lock(run_state_lock_); - if (!run_state_) - return; - run_state_->delayed_work_time = delayed_work_time; -} - -void MessagePumpMojo::DoRunLoop(RunState* run_state, Delegate* delegate) { - bool more_work_is_plausible = true; - for (;;) { - const bool block = !more_work_is_plausible; - if (read_handle_.is_valid()) { - more_work_is_plausible = DoInternalWork(*run_state, block); - } else { - more_work_is_plausible = DoNonMojoWork(*run_state, block); - } - - if (run_state->should_quit) - break; - - more_work_is_plausible |= delegate->DoWork(); - if (run_state->should_quit) - break; - - more_work_is_plausible |= delegate->DoDelayedWork( - &run_state->delayed_work_time); - if (run_state->should_quit) - break; - - if (more_work_is_plausible) - continue; - - more_work_is_plausible = delegate->DoIdleWork(); - if (run_state->should_quit) - break; - } -} - -bool MessagePumpMojo::DoInternalWork(const RunState& run_state, bool block) { - bool did_work = block; - if (block) { - // If the wait isn't blocking (deadline == 0), there's no point in waiting. - // Wait sets do not require a wait operation to be performed in order to - // retreive any ready handles. Performing a wait with deadline == 0 is - // unnecessary work. - did_work = WaitForReadyHandles(run_state); - } - - did_work |= ProcessReadyHandles(); - did_work |= RemoveExpiredHandles(); - - return did_work; -} - -bool MessagePumpMojo::DoNonMojoWork(const RunState& run_state, bool block) { - bool did_work = block; - if (block) { - const MojoDeadline deadline = GetDeadlineForWait(run_state); - // Stolen from base/message_loop/message_pump_default.cc - base::ThreadRestrictions::ScopedAllowWait allow_wait; - if (deadline == MOJO_DEADLINE_INDEFINITE) { - event_.Wait(); - } else { - if (deadline > 0) { - event_.TimedWait(base::TimeDelta::FromMicroseconds(deadline)); - } else { - did_work = false; - } - } - // Since event_ is auto-reset, we don't need to do anything special here - // other than service each delegate method. - } - - did_work |= RemoveExpiredHandles(); - - return did_work; -} - -bool MessagePumpMojo::WaitForReadyHandles(const RunState& run_state) const { - const MojoDeadline deadline = GetDeadlineForWait(run_state); - const MojoResult wait_result = Wait( - wait_set_handle_.get(), MOJO_HANDLE_SIGNAL_READABLE, deadline, nullptr); - if (wait_result == MOJO_RESULT_OK) { - // Handles may be ready. Or not since wake-ups can be spurious in certain - // circumstances. - return true; - } else if (wait_result == MOJO_RESULT_DEADLINE_EXCEEDED) { - return false; - } - - base::debug::Alias(&wait_result); - // Unexpected result is likely fatal, crash so we can determine cause. - CHECK(false); - return false; -} - -bool MessagePumpMojo::ProcessReadyHandles() { - // Maximum number of handles to retrieve and process. Experimentally, the 95th - // percentile is 1 handle, and the long-term average is 1.1. However, this has - // been seen to reach >10 under heavy load. 8 is a hand-wavy compromise. - const uint32_t kMaxServiced = 8; - uint32_t num_ready_handles = kMaxServiced; - MojoHandle handles[kMaxServiced]; - MojoResult handle_results[kMaxServiced]; - - const MojoResult get_result = - MojoGetReadyHandles(wait_set_handle_.get().value(), &num_ready_handles, - handles, handle_results, nullptr); - CHECK(get_result == MOJO_RESULT_OK || get_result == MOJO_RESULT_SHOULD_WAIT); - if (get_result != MOJO_RESULT_OK) - return false; - - DCHECK(num_ready_handles); - DCHECK_LE(num_ready_handles, kMaxServiced); - // Do this in two steps, because notifying a handler may remove/add other - // handles that may have also been woken up. - // First, enumerate the IDs of the ready handles. Then, iterate over the - // handles and only take action if the ID hasn't changed. - // Since the size of this map is bounded by |kMaxServiced|, use a SmallMap to - // avoid the per-element allocation. - base::SmallMap<std::map<Handle, int>, kMaxServiced> ready_handles; - for (uint32_t i = 0; i < num_ready_handles; i++) { - const Handle handle = Handle(handles[i]); - // Skip the control handle. It's special. - if (handle.value() == read_handle_.get().value()) - continue; - DCHECK(handle.is_valid()); - const auto it = handlers_.find(handle); - // Skip handles that have been removed. This is possible because - // RemoveHandler() can be called with a handle that has been closed. Because - // the handle is closed, the MojoRemoveHandle() call in RemoveHandler() - // would have failed, but the handle is still in the wait set. Once the - // handle is retrieved using MojoGetReadyHandles(), it is implicitly removed - // from the set. The result is either the pending result that existed when - // the handle was closed, or |MOJO_RESULT_CANCELLED| to indicate that the - // handle was closed. - if (it == handlers_.end()) - continue; - ready_handles[handle] = it->second.id; - } - - for (uint32_t i = 0; i < num_ready_handles; i++) { - const Handle handle = Handle(handles[i]); - - // If the handle has been removed, or it's ID has changed, skip over it. - // If the handle's ID has changed, and it still satisfies its signals, - // then it'll be caught in the next message pump iteration. - const auto it = handlers_.find(handle); - if ((handle.value() != read_handle_.get().value()) && - (it == handlers_.end() || it->second.id != ready_handles[handle])) { - continue; - } - - switch (handle_results[i]) { - case MOJO_RESULT_CANCELLED: - case MOJO_RESULT_FAILED_PRECONDITION: - DVLOG(1) << "Error: " << handle_results[i] - << " handle: " << handle.value(); - if (handle.value() == read_handle_.get().value()) { - // The Mojo EDK is shutting down. We can't just quit the message pump - // because that may cause the thread to quit, which causes the - // thread's MessageLoop to be destroyed, which races with any use of - // |Thread::task_runner()|. So instead, we enter a "dumb" mode which - // bypasses Mojo and just acts like a trivial message pump. That way, - // we can wait for the usual thread exiting mechanism to happen. - // The dumb mode is indicated by releasing the control pipe's read - // handle. - read_handle_.reset(); - } else { - SignalHandleError(handle, handle_results[i]); - } - break; - case MOJO_RESULT_OK: - if (handle.value() == read_handle_.get().value()) { - DVLOG(1) << "Signaled control pipe"; - // Control pipe was written to. - ReadMessageRaw(read_handle_.get(), nullptr, nullptr, nullptr, nullptr, - MOJO_READ_MESSAGE_FLAG_MAY_DISCARD); - } else { - DVLOG(1) << "Handle ready: " << handle.value(); - SignalHandleReady(handle); - } - break; - default: - base::debug::Alias(&i); - base::debug::Alias(&handle_results[i]); - // Unexpected result is likely fatal, crash so we can determine cause. - CHECK(false); - } - } - return true; -} - -bool MessagePumpMojo::RemoveExpiredHandles() { - bool removed = false; - // Notify and remove any handlers whose time has expired. First, iterate over - // the set of handles that have a deadline, and add the expired handles to a - // map of <Handle, id>. Then, iterate over those expired handles and remove - // them. The two-step process is because a handler can add/remove new - // handlers. - std::map<Handle, int> expired_handles; - const base::TimeTicks now(internal::NowTicks()); - for (const Handle handle : deadline_handles_) { - const auto it = handlers_.find(handle); - // Expect any handle in |deadline_handles_| to also be in |handlers_| since - // the two are modified in lock-step. - DCHECK(it != handlers_.end()); - if (!it->second.deadline.is_null() && it->second.deadline < now) - expired_handles[handle] = it->second.id; - } - for (const auto& pair : expired_handles) { - auto it = handlers_.find(pair.first); - // Don't need to check deadline again since it can't change if id hasn't - // changed. - if (it != handlers_.end() && it->second.id == pair.second) { - SignalHandleError(pair.first, MOJO_RESULT_DEADLINE_EXCEEDED); - removed = true; - } - } - return removed; -} - -void MessagePumpMojo::SignalControlPipe() { - const MojoResult result = - WriteMessageRaw(write_handle_.get(), NULL, 0, NULL, 0, - MOJO_WRITE_MESSAGE_FLAG_NONE); - if (result == MOJO_RESULT_FAILED_PRECONDITION) { - // Mojo EDK is shutting down. - event_.Signal(); - return; - } - - // If we can't write we likely won't wake up the thread and there is a strong - // chance we'll deadlock. - CHECK_EQ(MOJO_RESULT_OK, result); -} - -MojoDeadline MessagePumpMojo::GetDeadlineForWait( - const RunState& run_state) const { - const base::TimeTicks now(internal::NowTicks()); - MojoDeadline deadline = TimeTicksToMojoDeadline(run_state.delayed_work_time, - now); - for (const Handle handle : deadline_handles_) { - auto it = handlers_.find(handle); - DCHECK(it != handlers_.end()); - deadline = std::min( - TimeTicksToMojoDeadline(it->second.deadline, now), deadline); - } - return deadline; -} - -void MessagePumpMojo::SignalHandleReady(Handle handle) { - auto it = handlers_.find(handle); - DCHECK(it != handlers_.end()); - MessagePumpMojoHandler* handler = it->second.handler; - - WillSignalHandler(); - handler->OnHandleReady(handle); - DidSignalHandler(); -} - -void MessagePumpMojo::SignalHandleError(Handle handle, MojoResult result) { - auto it = handlers_.find(handle); - DCHECK(it != handlers_.end()); - MessagePumpMojoHandler* handler = it->second.handler; - - RemoveHandler(handle); - WillSignalHandler(); - handler->OnHandleError(handle, result); - DidSignalHandler(); -} - -void MessagePumpMojo::WillSignalHandler() { - FOR_EACH_OBSERVER(Observer, observers_, WillSignalHandler()); -} - -void MessagePumpMojo::DidSignalHandler() { - FOR_EACH_OBSERVER(Observer, observers_, DidSignalHandler()); -} - -} // namespace common -} // namespace mojo
diff --git a/mojo/message_pump/message_pump_mojo.h b/mojo/message_pump/message_pump_mojo.h deleted file mode 100644 index ef2f55a7f..0000000 --- a/mojo/message_pump/message_pump_mojo.h +++ /dev/null
@@ -1,178 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MOJO_MESSAGE_PUMP_MESSAGE_PUMP_MOJO_H_ -#define MOJO_MESSAGE_PUMP_MESSAGE_PUMP_MOJO_H_ - -#include <stdint.h> - -#include <functional> -#include <memory> -#include <set> -#include <unordered_map> - -#include "base/macros.h" -#include "base/message_loop/message_pump.h" -#include "base/observer_list.h" -#include "base/synchronization/lock.h" -#include "base/synchronization/waitable_event.h" -#include "base/time/time.h" -#include "mojo/message_pump/mojo_message_pump_export.h" -#include "mojo/public/cpp/system/core.h" - -namespace mojo { -namespace common { - -class MessagePumpMojoHandler; - -// Mojo implementation of MessagePump. -class MOJO_MESSAGE_PUMP_EXPORT MessagePumpMojo : public base::MessagePump { - public: - class MOJO_MESSAGE_PUMP_EXPORT Observer { - public: - Observer() {} - - virtual void WillSignalHandler() = 0; - virtual void DidSignalHandler() = 0; - - protected: - virtual ~Observer() {} - }; - - MessagePumpMojo(); - ~MessagePumpMojo() override; - - // Static factory function (for using with |base::Thread::Options|, wrapped - // using |base::Bind()|). - static std::unique_ptr<base::MessagePump> Create(); - - // Returns the MessagePumpMojo instance of the current thread, if it exists. - static MessagePumpMojo* current(); - - static bool IsCurrent() { return !!current(); } - - // Registers a MessagePumpMojoHandler for the specified handle. Only one - // handler can be registered for a specified handle. - // NOTE: a value of 0 for |deadline| indicates an indefinite timeout. - void AddHandler(MessagePumpMojoHandler* handler, - const Handle& handle, - MojoHandleSignals wait_signals, - base::TimeTicks deadline); - - void RemoveHandler(const Handle& handle); - - void AddObserver(Observer*); - void RemoveObserver(Observer*); - - // MessagePump: - void Run(Delegate* delegate) override; - void Quit() override; - void ScheduleWork() override; - void ScheduleDelayedWork(const base::TimeTicks& delayed_work_time) override; - - private: - struct RunState; - - // Contains the data needed to track a request to AddHandler(). - struct Handler { - Handler() : handler(NULL), wait_signals(MOJO_HANDLE_SIGNAL_NONE), id(0) {} - - MessagePumpMojoHandler* handler; - MojoHandleSignals wait_signals; - base::TimeTicks deadline; - // See description of |MessagePumpMojo::next_handler_id_| for details. - int id; - }; - - struct HandleHasher { - size_t operator()(const Handle& handle) const { - return std::hash<uint32_t>()(static_cast<uint32_t>(handle.value())); - } - }; - - using HandleToHandler = std::unordered_map<Handle, Handler, HandleHasher>; - - // Implementation of Run(). - void DoRunLoop(RunState* run_state, Delegate* delegate); - - // Services the set of handles ready. If |block| is true this waits for a - // handle to become ready, otherwise this does not block. Returns |true| if a - // handle has become ready, |false| otherwise. - bool DoInternalWork(const RunState& run_state, bool block); - - bool DoNonMojoWork(const RunState& run_state, bool block); - - // Waits for handles in the wait set to become ready. Returns |true| if ready - // handles may be available, or |false| if the wait's deadline was exceeded. - // Note, ready handles may be unavailable, even though |true| was returned. - bool WaitForReadyHandles(const RunState& run_state) const; - - // Retrieves any 'ready' handles from the wait set, and runs the handler's - // OnHandleReady() or OnHandleError() functions as necessary. Returns |true| - // if any handles were ready and processed. - bool ProcessReadyHandles(); - - // Removes any handles that have expired their deadline. Runs the handler's - // OnHandleError() function with |MOJO_RESULT_DEADLINE_EXCEEDED| as the - // result. Returns |true| if any handles were removed. - bool RemoveExpiredHandles(); - - void SignalControlPipe(); - - // Returns the deadline for the call to MojoWait(). - MojoDeadline GetDeadlineForWait(const RunState& run_state) const; - - // Run |OnHandleReady()| for the handler registered with |handle|. |handle| - // must be registered. - void SignalHandleReady(Handle handle); - - // Run |OnHandleError()| for the handler registered with |handle| and the - // error code |result|. |handle| must be registered, and will be removed - // before calling |OnHandleError()|. - void SignalHandleError(Handle handle, MojoResult result); - - void WillSignalHandler(); - void DidSignalHandler(); - - // If non-NULL we're running (inside Run()). Member is reference to value on - // stack. - RunState* run_state_; - - // Lock for accessing |run_state_|. In general the only method that we have to - // worry about is ScheduleWork(). All other methods are invoked on the same - // thread. - base::Lock run_state_lock_; - - HandleToHandler handlers_; - // Set of handles that have a deadline set. Avoids iterating over all elements - // in |handles_| in the common case (no deadline set). - // TODO(amistry): Make this better and avoid special-casing deadlines. - std::set<Handle> deadline_handles_; - - // An ever increasing value assigned to each Handler::id. Used to detect - // uniqueness while notifying. That is, while notifying expired timers we copy - // |handlers_| and only notify handlers whose id match. If the id does not - // match it means the handler was removed then added so that we shouldn't - // notify it. - int next_handler_id_; - - base::ObserverList<Observer> observers_; - - // Mojo handle for the wait set. - ScopedHandle wait_set_handle_; - // Used to wake up run loop from |SignalControlPipe()|. - ScopedMessagePipeHandle read_handle_; - ScopedMessagePipeHandle write_handle_; - - // Used to sleep until there is more work to do, when the Mojo EDK is shutting - // down. - base::WaitableEvent event_; - - DISALLOW_COPY_AND_ASSIGN(MessagePumpMojo); -}; - -} // namespace common -} // namespace mojo - -#endif // MOJO_MESSAGE_PUMP_MESSAGE_PUMP_MOJO_H_
diff --git a/mojo/message_pump/message_pump_mojo_handler.h b/mojo/message_pump/message_pump_mojo_handler.h deleted file mode 100644 index 8beb9baa..0000000 --- a/mojo/message_pump/message_pump_mojo_handler.h +++ /dev/null
@@ -1,29 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MOJO_MESSAGE_PUMP_MESSAGE_PUMP_MOJO_HANDLER_H_ -#define MOJO_MESSAGE_PUMP_MESSAGE_PUMP_MOJO_HANDLER_H_ - -#include "mojo/message_pump/mojo_message_pump_export.h" -#include "mojo/public/cpp/system/core.h" - -namespace mojo { -namespace common { - -// Used by MessagePumpMojo to notify when a handle is either ready or has become -// invalid. In case of error, the handler will be removed. -class MOJO_MESSAGE_PUMP_EXPORT MessagePumpMojoHandler { - public: - virtual void OnHandleReady(const Handle& handle) = 0; - - virtual void OnHandleError(const Handle& handle, MojoResult result) = 0; - - protected: - virtual ~MessagePumpMojoHandler() {} -}; - -} // namespace common -} // namespace mojo - -#endif // MOJO_MESSAGE_PUMP_MESSAGE_PUMP_MOJO_HANDLER_H_
diff --git a/mojo/message_pump/message_pump_mojo_unittest.cc b/mojo/message_pump/message_pump_mojo_unittest.cc deleted file mode 100644 index 1abb27c..0000000 --- a/mojo/message_pump/message_pump_mojo_unittest.cc +++ /dev/null
@@ -1,193 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "mojo/message_pump/message_pump_mojo.h" - -#include "base/macros.h" -#include "base/message_loop/message_loop_test.h" -#include "base/run_loop.h" -#include "mojo/message_pump/message_pump_mojo_handler.h" -#include "mojo/public/cpp/system/core.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace mojo { -namespace common { -namespace test { - -std::unique_ptr<base::MessagePump> CreateMojoMessagePump() { - return std::unique_ptr<base::MessagePump>(new MessagePumpMojo()); -} - -RUN_MESSAGE_LOOP_TESTS(Mojo, &CreateMojoMessagePump); - -class CountingMojoHandler : public MessagePumpMojoHandler { - public: - CountingMojoHandler() : success_count_(0), error_count_(0) {} - - void OnHandleReady(const Handle& handle) override { - ReadMessageRaw(static_cast<const MessagePipeHandle&>(handle), - NULL, - NULL, - NULL, - NULL, - MOJO_READ_MESSAGE_FLAG_NONE); - ++success_count_; - if (success_count_ == success_callback_count_ && - !success_callback_.is_null()) { - success_callback_.Run(); - success_callback_.Reset(); - } - } - - void set_success_callback(const base::Closure& callback, - int success_count) { - success_callback_ = callback; - success_callback_count_ = success_count; - } - - void OnHandleError(const Handle& handle, MojoResult result) override { - ++error_count_; - if (!error_callback_.is_null()) { - error_callback_.Run(); - error_callback_.Reset(); - } - } - - void set_error_callback(const base::Closure& callback) { - error_callback_ = callback; - } - - int success_count() { return success_count_; } - int error_count() { return error_count_; } - - private: - int success_count_; - int error_count_; - - base::Closure error_callback_; - int success_callback_count_; - - base::Closure success_callback_; - - DISALLOW_COPY_AND_ASSIGN(CountingMojoHandler); -}; - -class CountingObserver : public MessagePumpMojo::Observer { - public: - void WillSignalHandler() override { will_signal_handler_count++; } - void DidSignalHandler() override { did_signal_handler_count++; } - - int will_signal_handler_count = 0; - int did_signal_handler_count = 0; -}; - -TEST(MessagePumpMojo, RunUntilIdle) { - base::MessageLoop message_loop(MessagePumpMojo::Create()); - CountingMojoHandler handler; - base::RunLoop run_loop; - handler.set_success_callback(run_loop.QuitClosure(), 2); - MessagePipe handles; - MessagePumpMojo::current()->AddHandler(&handler, - handles.handle0.get(), - MOJO_HANDLE_SIGNAL_READABLE, - base::TimeTicks()); - WriteMessageRaw( - handles.handle1.get(), NULL, 0, NULL, 0, MOJO_WRITE_MESSAGE_FLAG_NONE); - WriteMessageRaw( - handles.handle1.get(), NULL, 0, NULL, 0, MOJO_WRITE_MESSAGE_FLAG_NONE); - MojoHandleSignalsState hss; - ASSERT_EQ(MOJO_RESULT_OK, - MojoWait(handles.handle0.get().value(), MOJO_HANDLE_SIGNAL_READABLE, - MOJO_DEADLINE_INDEFINITE, &hss)); - run_loop.Run(); - EXPECT_EQ(2, handler.success_count()); -} - -TEST(MessagePumpMojo, Observer) { - base::MessageLoop message_loop(MessagePumpMojo::Create()); - - CountingObserver observer; - MessagePumpMojo::current()->AddObserver(&observer); - - CountingMojoHandler handler; - base::RunLoop run_loop; - handler.set_success_callback(run_loop.QuitClosure(), 1); - MessagePipe handles; - MessagePumpMojo::current()->AddHandler(&handler, - handles.handle0.get(), - MOJO_HANDLE_SIGNAL_READABLE, - base::TimeTicks()); - WriteMessageRaw( - handles.handle1.get(), NULL, 0, NULL, 0, MOJO_WRITE_MESSAGE_FLAG_NONE); - - MojoHandleSignalsState hss; - ASSERT_EQ(MOJO_RESULT_OK, - MojoWait(handles.handle0.get().value(), MOJO_HANDLE_SIGNAL_READABLE, - MOJO_DEADLINE_INDEFINITE, &hss)); - run_loop.Run(); - EXPECT_EQ(1, handler.success_count()); - EXPECT_EQ(1, observer.will_signal_handler_count); - EXPECT_EQ(1, observer.did_signal_handler_count); - MessagePumpMojo::current()->RemoveObserver(&observer); - - base::RunLoop run_loop2; - handler.set_success_callback(run_loop2.QuitClosure(), 2); - WriteMessageRaw( - handles.handle1.get(), NULL, 0, NULL, 0, MOJO_WRITE_MESSAGE_FLAG_NONE); - ASSERT_EQ(MOJO_RESULT_OK, - MojoWait(handles.handle0.get().value(), MOJO_HANDLE_SIGNAL_READABLE, - MOJO_DEADLINE_INDEFINITE, &hss)); - run_loop2.Run(); - EXPECT_EQ(2, handler.success_count()); - EXPECT_EQ(1, observer.will_signal_handler_count); - EXPECT_EQ(1, observer.did_signal_handler_count); -} - -TEST(MessagePumpMojo, UnregisterAfterDeadline) { - base::MessageLoop message_loop(MessagePumpMojo::Create()); - CountingMojoHandler handler; - base::RunLoop run_loop; - handler.set_error_callback(run_loop.QuitClosure()); - MessagePipe handles; - MessagePumpMojo::current()->AddHandler( - &handler, - handles.handle0.get(), - MOJO_HANDLE_SIGNAL_READABLE, - base::TimeTicks::Now() - base::TimeDelta::FromSeconds(1)); - run_loop.Run(); - EXPECT_EQ(1, handler.error_count()); -} - -TEST(MessagePumpMojo, AddClosedHandle) { - base::MessageLoop message_loop(MessagePumpMojo::Create()); - CountingMojoHandler handler; - MessagePipe handles; - Handle closed_handle = handles.handle0.get(); - handles.handle0.reset(); - MessagePumpMojo::current()->AddHandler( - &handler, closed_handle, MOJO_HANDLE_SIGNAL_READABLE, base::TimeTicks()); - base::RunLoop run_loop; - run_loop.RunUntilIdle(); - MessagePumpMojo::current()->RemoveHandler(closed_handle); - EXPECT_EQ(0, handler.error_count()); - EXPECT_EQ(0, handler.success_count()); -} - -TEST(MessagePumpMojo, CloseAfterAdding) { - base::MessageLoop message_loop(MessagePumpMojo::Create()); - CountingMojoHandler handler; - MessagePipe handles; - MessagePumpMojo::current()->AddHandler(&handler, handles.handle0.get(), - MOJO_HANDLE_SIGNAL_READABLE, - base::TimeTicks()); - handles.handle0.reset(); - base::RunLoop run_loop; - run_loop.RunUntilIdle(); - EXPECT_EQ(1, handler.error_count()); - EXPECT_EQ(0, handler.success_count()); -} - -} // namespace test -} // namespace common -} // namespace mojo
diff --git a/mojo/message_pump/mojo_message_pump_export.h b/mojo/message_pump/mojo_message_pump_export.h deleted file mode 100644 index f8c1864..0000000 --- a/mojo/message_pump/mojo_message_pump_export.h +++ /dev/null
@@ -1,32 +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 MOJO_MESSAGE_PUMP_MOJO_MESSAGE_PUMP_EXPORT_H_ -#define MOJO_MESSAGE_PUMP_MOJO_MESSAGE_PUMP_EXPORT_H_ - -#if defined(COMPONENT_BUILD) - -#if defined(WIN32) - -#if defined(MOJO_MESSAGE_PUMP_IMPLEMENTATION) -#define MOJO_MESSAGE_PUMP_EXPORT __declspec(dllexport) -#else -#define MOJO_MESSAGE_PUMP_EXPORT __declspec(dllimport) -#endif - -#else // !defined(WIN32) - -#if defined(MOJO_MESSAGE_PUMP_IMPLEMENTATION) -#define MOJO_MESSAGE_PUMP_EXPORT __attribute__((visibility("default"))) -#else -#define MOJO_MESSAGE_PUMP_EXPORT -#endif - -#endif // defined(WIN32) - -#else // !defined(COMPONENT_BUILD) -#define MOJO_MESSAGE_PUMP_EXPORT -#endif - -#endif // MOJO_MESSAGE_PUMP_MOJO_MESSAGE_PUMP_EXPORT_H_
diff --git a/mojo/message_pump/time_helper.cc b/mojo/message_pump/time_helper.cc deleted file mode 100644 index ffd667e..0000000 --- a/mojo/message_pump/time_helper.cc +++ /dev/null
@@ -1,33 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "mojo/message_pump/time_helper.h" - -#include "base/time/tick_clock.h" - -namespace mojo { -namespace common { - -namespace { - -base::TickClock* tick_clock = NULL; - -} // namespace - -namespace test { - -void SetTickClockForTest(base::TickClock* clock) { - tick_clock = clock; -} -} // namespace test - -namespace internal { - -base::TimeTicks NowTicks() { - return tick_clock ? tick_clock->NowTicks() : base::TimeTicks::Now(); -} - -} // namespace internal -} // namespace common -} // namespace mojo
diff --git a/mojo/message_pump/time_helper.h b/mojo/message_pump/time_helper.h deleted file mode 100644 index 60790004..0000000 --- a/mojo/message_pump/time_helper.h +++ /dev/null
@@ -1,34 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MOJO_MESSAGE_PUMP_TIME_HELPER_H_ -#define MOJO_MESSAGE_PUMP_TIME_HELPER_H_ - -#include "base/time/time.h" -#include "mojo/message_pump/mojo_message_pump_export.h" - -namespace base { -class TickClock; -} - -namespace mojo { -namespace common { -namespace test { - -// Sets the TickClock used for getting TimeTicks::Now(). This is currently used -// by both HandleWatcher and MessagePumpMojo. -MOJO_MESSAGE_PUMP_EXPORT void SetTickClockForTest(base::TickClock* clock); - -} // namespace test - -namespace internal { - -// Returns now. Used internally; generally not useful. -MOJO_MESSAGE_PUMP_EXPORT base::TimeTicks NowTicks(); - -} // namespace internal -} // namespace common -} // namespace mojo - -#endif // MOJO_MESSAGE_PUMP_TIME_HELPER_H_
diff --git a/mojo/public/cpp/bindings/array_traits_stl.h b/mojo/public/cpp/bindings/array_traits_stl.h index 9054a92..55efd32d 100644 --- a/mojo/public/cpp/bindings/array_traits_stl.h +++ b/mojo/public/cpp/bindings/array_traits_stl.h
@@ -57,6 +57,30 @@ } }; +// This ArrayTraits specialization is used only for serialization. +template <typename T> +struct ArrayTraits<std::set<T>> { + using Element = T; + using ConstIterator = typename std::set<T>::const_iterator; + + static bool IsNull(const std::set<T>& input) { + // std::set<> is always converted to non-null mojom array. + return false; + } + + static size_t GetSize(const std::set<T>& input) { return input.size(); } + + static ConstIterator GetBegin(const std::set<T>& input) { + return input.begin(); + } + static void AdvanceIterator(ConstIterator& iterator) { + ++iterator; + } + static const T& GetValue(ConstIterator& iterator) { + return *iterator; + } +}; + } // namespace mojo #endif // MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_STL_H_
diff --git a/mojo/public/cpp/bindings/tests/struct_traits_unittest.cc b/mojo/public/cpp/bindings/tests/struct_traits_unittest.cc index 221dc93..f281981 100644 --- a/mojo/public/cpp/bindings/tests/struct_traits_unittest.cc +++ b/mojo/public/cpp/bindings/tests/struct_traits_unittest.cc
@@ -274,6 +274,8 @@ input.set_uint64(42); input.set_string("hello world!"); input.get_mutable_string_array().assign({"hello", "world!"}); + input.get_mutable_string_set().insert("hello"); + input.get_mutable_string_set().insert("world!"); input.get_mutable_struct().value = 42; input.get_mutable_struct_array().resize(2); input.get_mutable_struct_array()[0].value = 1; @@ -408,7 +410,9 @@ input.set_uint32(7); input.set_uint64(42); input.set_string("hello world!"); - input.get_mutable_string_array().assign({"hello", "world!"}); + input.get_mutable_string_array().assign({ "hello", "world!" }); + input.get_mutable_string_set().insert("hello"); + input.get_mutable_string_set().insert("world!"); input.get_mutable_struct().value = 42; input.get_mutable_struct_array().resize(2); input.get_mutable_struct_array()[0].value = 1; @@ -426,6 +430,7 @@ EXPECT_EQ(input.get_uint64(), output.get_uint64()); EXPECT_EQ(input.get_string(), output.get_string()); EXPECT_EQ(input.get_string_array(), output.get_string_array()); + EXPECT_EQ(input.get_string_set(), output.get_string_set()); EXPECT_EQ(input.get_struct(), output.get_struct()); EXPECT_EQ(input.get_struct_array(), output.get_struct_array()); EXPECT_EQ(input.get_struct_map(), output.get_struct_map());
diff --git a/mojo/public/cpp/bindings/tests/struct_with_traits_impl.h b/mojo/public/cpp/bindings/tests/struct_with_traits_impl.h index 87d4591..7b007cc08 100644 --- a/mojo/public/cpp/bindings/tests/struct_with_traits_impl.h +++ b/mojo/public/cpp/bindings/tests/struct_with_traits_impl.h
@@ -8,6 +8,7 @@ #include <stdint.h> #include <map> +#include <set> #include <string> #include <vector> @@ -61,6 +62,11 @@ } std::vector<std::string>& get_mutable_string_array() { return string_array_; } + const std::set<std::string>& get_string_set() const { + return string_set_; + } + std::set<std::string>& get_mutable_string_set() { return string_set_; } + const NestedStructWithTraitsImpl& get_struct() const { return struct_; } NestedStructWithTraitsImpl& get_mutable_struct() { return struct_; } @@ -86,6 +92,7 @@ uint64_t uint64_ = 0; std::string string_; std::vector<std::string> string_array_; + std::set<std::string> string_set_; NestedStructWithTraitsImpl struct_; std::vector<NestedStructWithTraitsImpl> struct_array_; std::map<std::string, NestedStructWithTraitsImpl> struct_map_;
diff --git a/mojo/public/cpp/bindings/tests/struct_with_traits_impl_traits.cc b/mojo/public/cpp/bindings/tests/struct_with_traits_impl_traits.cc index 017d3703..ad9d119 100644 --- a/mojo/public/cpp/bindings/tests/struct_with_traits_impl_traits.cc +++ b/mojo/public/cpp/bindings/tests/struct_with_traits_impl_traits.cc
@@ -103,6 +103,16 @@ if (!data.ReadFStringArray(&out->get_mutable_string_array())) return false; + // We can't deserialize as a std::set, so we have to manually copy from the + // data view. + ArrayDataView<StringDataView> string_set_data_view; + data.GetFStringSetDataView(&string_set_data_view); + for (size_t i = 0; i < string_set_data_view.size(); ++i) { + std::string value; + string_set_data_view.Read(i, &value); + out->get_mutable_string_set().insert(value); + } + if (!data.ReadFStruct(&out->get_mutable_struct())) return false;
diff --git a/mojo/public/cpp/bindings/tests/struct_with_traits_impl_traits.h b/mojo/public/cpp/bindings/tests/struct_with_traits_impl_traits.h index 3f3aa77..6e7efb7 100644 --- a/mojo/public/cpp/bindings/tests/struct_with_traits_impl_traits.h +++ b/mojo/public/cpp/bindings/tests/struct_with_traits_impl_traits.h
@@ -76,6 +76,11 @@ return value.get_string_array(); } + static const std::set<std::string>& f_string_set( + const test::StructWithTraitsImpl& value) { + return value.get_string_set(); + } + static const test::NestedStructWithTraitsImpl& f_struct( const test::StructWithTraitsImpl& value) { return value.get_struct();
diff --git a/mojo/public/interfaces/bindings/tests/struct_with_traits.mojom b/mojo/public/interfaces/bindings/tests/struct_with_traits.mojom index ac41df7c..b50409e 100644 --- a/mojo/public/interfaces/bindings/tests/struct_with_traits.mojom +++ b/mojo/public/interfaces/bindings/tests/struct_with_traits.mojom
@@ -23,6 +23,7 @@ string f_string; string f_string2; array<string> f_string_array; + array<string> f_string_set; NestedStructWithTraits f_struct; array<NestedStructWithTraits> f_struct_array; map<string, NestedStructWithTraits> f_struct_map;
diff --git a/mojo/public/java/BUILD.gn b/mojo/public/java/BUILD.gn index e33faaa9..8762db3 100644 --- a/mojo/public/java/BUILD.gn +++ b/mojo/public/java/BUILD.gn
@@ -6,7 +6,6 @@ android_library("system") { java_files = [ - "system/src/org/chromium/mojo/system/AsyncWaiter.java", "system/src/org/chromium/mojo/system/Core.java", "system/src/org/chromium/mojo/system/DataPipe.java", "system/src/org/chromium/mojo/system/Flags.java", @@ -20,6 +19,7 @@ "system/src/org/chromium/mojo/system/SharedBufferHandle.java", "system/src/org/chromium/mojo/system/UntypedHandle.java", "system/src/org/chromium/mojo/system/RunLoop.java", + "system/src/org/chromium/mojo/system/Watcher.java", ] }
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/BindingsHelper.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/BindingsHelper.java index 6146316..f77399d1 100644 --- a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/BindingsHelper.java +++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/BindingsHelper.java
@@ -4,8 +4,8 @@ package org.chromium.mojo.bindings; -import org.chromium.mojo.system.AsyncWaiter; import org.chromium.mojo.system.Handle; +import org.chromium.mojo.system.Watcher; /** * Helper functions. @@ -189,9 +189,9 @@ /** * Returns an {@link AsyncWaiter} to use with the given handle, or |null| if none if available. */ - static AsyncWaiter getDefaultAsyncWaiterForHandle(Handle handle) { + static Watcher getWatcherForHandle(Handle handle) { if (handle.getCore() != null) { - return handle.getCore().getDefaultAsyncWaiter(); + return handle.getCore().getWatcher(); } else { return null; }
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Connector.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Connector.java index 3686bcfa..2aa5ea69 100644 --- a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Connector.java +++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Connector.java
@@ -4,13 +4,13 @@ package org.chromium.mojo.bindings; -import org.chromium.mojo.system.AsyncWaiter; import org.chromium.mojo.system.Core; import org.chromium.mojo.system.MessagePipeHandle; import org.chromium.mojo.system.MessagePipeHandle.ReadMessageResult; import org.chromium.mojo.system.MojoException; import org.chromium.mojo.system.MojoResult; import org.chromium.mojo.system.ResultAnd; +import org.chromium.mojo.system.Watcher; import java.nio.ByteBuffer; @@ -27,7 +27,7 @@ /** * The callback that is notified when the state of the owned handle changes. */ - private final AsyncWaiterCallback mAsyncWaiterCallback = new AsyncWaiterCallback(); + private final WatcherCallback mWatcherCallback = new WatcherCallback(); /** * The owned message pipe. @@ -35,9 +35,9 @@ private final MessagePipeHandle mMessagePipeHandle; /** - * A waiter which is notified when a new message is available on the owned message pipe. + * A watcher which is notified when a new message is available on the owned message pipe. */ - private final AsyncWaiter mAsyncWaiter; + private final Watcher mWatcher; /** * The {@link MessageReceiver} to which received messages are sent. @@ -45,11 +45,6 @@ private MessageReceiver mIncomingMessageReceiver; /** - * The Cancellable for the current wait. Is |null| when not currently waiting for new messages. - */ - private AsyncWaiter.Cancellable mCancellable; - - /** * The error handler to notify of errors. */ private ConnectionErrorHandler mErrorHandler; @@ -59,17 +54,16 @@ * {@link AsyncWaiter} from the {@link Core} implementation of |messagePipeHandle|. */ public Connector(MessagePipeHandle messagePipeHandle) { - this(messagePipeHandle, BindingsHelper.getDefaultAsyncWaiterForHandle(messagePipeHandle)); + this(messagePipeHandle, BindingsHelper.getWatcherForHandle(messagePipeHandle)); } /** * Create a new connector over a |messagePipeHandle| using the given {@link AsyncWaiter} to get * notified of changes on the handle. */ - public Connector(MessagePipeHandle messagePipeHandle, AsyncWaiter asyncWaiter) { - mCancellable = null; + public Connector(MessagePipeHandle messagePipeHandle, Watcher watcher) { mMessagePipeHandle = messagePipeHandle; - mAsyncWaiter = asyncWaiter; + mWatcher = watcher; } /** @@ -91,8 +85,7 @@ * Start listening for incoming messages. */ public void start() { - assert mCancellable == null; - registerAsyncWaiterForRead(); + mWatcher.start(mMessagePipeHandle, Core.HandleSignals.READABLE, mWatcherCallback); } /** @@ -140,32 +133,21 @@ } } - private class AsyncWaiterCallback implements AsyncWaiter.Callback { - + private class WatcherCallback implements Watcher.Callback { /** - * @see org.chromium.mojo.system.AsyncWaiter.Callback#onResult(int) + * @see org.chromium.mojo.system.Watcher.Callback#onResult(int) */ @Override public void onResult(int result) { - Connector.this.onAsyncWaiterResult(result); - } - - /** - * @see org.chromium.mojo.system.AsyncWaiter.Callback#onError(MojoException) - */ - @Override - public void onError(MojoException exception) { - mCancellable = null; - Connector.this.onError(exception); + Connector.this.onWatcherResult(result); } } /** - * @see org.chromium.mojo.system.AsyncWaiter.Callback#onResult(int) + * @see org.chromium.mojo.system.Watcher.Callback#onResult(int) */ - private void onAsyncWaiterResult(int result) { - mCancellable = null; + private void onWatcherResult(int result) { if (result == MojoResult.OK) { readOutstandingMessages(); } else { @@ -175,26 +157,12 @@ private void onError(MojoException exception) { close(); - assert mCancellable == null; if (mErrorHandler != null) { mErrorHandler.onConnectionError(exception); } } /** - * Register to be called back when a new message is available on the owned message pipe. - */ - private void registerAsyncWaiterForRead() { - assert mCancellable == null; - if (mAsyncWaiter != null) { - mCancellable = mAsyncWaiter.asyncWait(mMessagePipeHandle, Core.HandleSignals.READABLE, - Core.DEADLINE_INFINITE, mAsyncWaiterCallback); - } else { - onError(new MojoException(MojoResult.INVALID_ARGUMENT)); - } - } - - /** * Read all available messages on the owned message pipe. */ private void readOutstandingMessages() { @@ -207,18 +175,14 @@ return; } } while (result.getValue()); - if (result.getMojoResult() == MojoResult.SHOULD_WAIT) { - registerAsyncWaiterForRead(); - } else { + if (result.getMojoResult() != MojoResult.SHOULD_WAIT) { onError(new MojoException(result.getMojoResult())); } } private void cancelIfActive() { - if (mCancellable != null) { - mCancellable.cancel(); - mCancellable = null; - } + mWatcher.cancel(); + mWatcher.destroy(); } /**
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/ExecutorFactory.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/ExecutorFactory.java index c621d9b0..bb49cbc4 100644 --- a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/ExecutorFactory.java +++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/ExecutorFactory.java
@@ -4,8 +4,6 @@ package org.chromium.mojo.bindings; -import org.chromium.mojo.system.AsyncWaiter; -import org.chromium.mojo.system.AsyncWaiter.Callback; import org.chromium.mojo.system.Core; import org.chromium.mojo.system.MessagePipeHandle; import org.chromium.mojo.system.MessagePipeHandle.ReadMessageResult; @@ -13,6 +11,8 @@ import org.chromium.mojo.system.MojoResult; import org.chromium.mojo.system.Pair; import org.chromium.mojo.system.ResultAnd; +import org.chromium.mojo.system.Watcher; +import org.chromium.mojo.system.Watcher.Callback; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -58,32 +58,23 @@ */ private final Object mLock; /** - * The {@link AsyncWaiter} to get notified of new message availability on |mReadHandle|. + * The {@link Watcher} to get notified of new message availability on |mReadHandle|. */ - private final AsyncWaiter mWaiter; + private final Watcher mWatcher; /** * Constructor. */ public PipedExecutor(Core core) { - mWaiter = core.getDefaultAsyncWaiter(); - assert mWaiter != null; + mWatcher = core.getWatcher(); + assert mWatcher != null; mLock = new Object(); Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe( new MessagePipeHandle.CreateOptions()); mReadHandle = handles.first; mWriteHandle = handles.second; mPendingActions = new ArrayList<Runnable>(); - asyncWait(); - } - - /** - * Asynchronously wait for the next command to arrive. This should only be called on the - * executor thread. - */ - private void asyncWait() { - mWaiter.asyncWait(mReadHandle, Core.HandleSignals.READABLE, Core.DEADLINE_INFINITE, - this); + mWatcher.start(mReadHandle, Core.HandleSignals.READABLE, this); } /** @@ -99,14 +90,6 @@ } /** - * @see Callback#onError(MojoException) - */ - @Override - public void onError(MojoException exception) { - close(); - } - - /** * Close the handles. Should only be called on the executor thread. */ private void close() { @@ -114,6 +97,8 @@ mWriteHandle.close(); mPendingActions.clear(); } + mWatcher.cancel(); + mWatcher.destroy(); mReadHandle.close(); } @@ -126,7 +111,6 @@ ResultAnd<ReadMessageResult> readMessageResult = mReadHandle.readMessage(NOTIFY_BUFFER, 0, MessagePipeHandle.ReadFlags.NONE); if (readMessageResult.getMojoResult() == MojoResult.OK) { - asyncWait(); return true; } } catch (MojoException e) {
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/RouterImpl.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/RouterImpl.java index 4e7b6b3..856ae60 100644 --- a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/RouterImpl.java +++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/RouterImpl.java
@@ -6,9 +6,9 @@ import android.annotation.SuppressLint; -import org.chromium.mojo.system.AsyncWaiter; import org.chromium.mojo.system.Core; import org.chromium.mojo.system.MessagePipeHandle; +import org.chromium.mojo.system.Watcher; import java.util.HashMap; import java.util.Map; @@ -109,23 +109,23 @@ private final Executor mExecutor; /** - * Constructor that will use the default {@link AsyncWaiter}. + * Constructor that will use the default {@link Watcher}. * * @param messagePipeHandle The {@link MessagePipeHandle} to route message for. */ public RouterImpl(MessagePipeHandle messagePipeHandle) { - this(messagePipeHandle, BindingsHelper.getDefaultAsyncWaiterForHandle(messagePipeHandle)); + this(messagePipeHandle, BindingsHelper.getWatcherForHandle(messagePipeHandle)); } /** * Constructor. * * @param messagePipeHandle The {@link MessagePipeHandle} to route message for. - * @param asyncWaiter the {@link AsyncWaiter} to use to get notification of new messages on the + * @param watcher the {@link Watcher} to use to get notification of new messages on the * handle. */ - public RouterImpl(MessagePipeHandle messagePipeHandle, AsyncWaiter asyncWaiter) { - mConnector = new Connector(messagePipeHandle, asyncWaiter); + public RouterImpl(MessagePipeHandle messagePipeHandle, Watcher watcher) { + mConnector = new Connector(messagePipeHandle, watcher); mConnector.setIncomingMessageReceiver(new HandleIncomingMessageThunk()); Core core = messagePipeHandle.getCore(); if (core != null) {
diff --git a/mojo/public/java/system/src/org/chromium/mojo/system/AsyncWaiter.java b/mojo/public/java/system/src/org/chromium/mojo/system/AsyncWaiter.java deleted file mode 100644 index 474de4b..0000000 --- a/mojo/public/java/system/src/org/chromium/mojo/system/AsyncWaiter.java +++ /dev/null
@@ -1,53 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.mojo.system; - -import org.chromium.mojo.system.Core.HandleSignals; - -/** - * A class which implements the {@link AsyncWaiter} allows asynchronously waiting on a background - * thread. - */ -public interface AsyncWaiter { - - /** - * Allows cancellation of an asyncWait operation. - */ - interface Cancellable { - /** - * Cancels an asyncWait operation. Has no effect if the operation has already been canceled - * or the callback has already been called. - * <p> - * Must be called from the same thread as {@link AsyncWaiter#asyncWait} was called from. - */ - void cancel(); - } - - /** - * Callback passed to {@link AsyncWaiter#asyncWait}. - */ - public interface Callback { - /** - * Called when the handle is ready. - */ - public void onResult(int result); - - /** - * Called when an error occurred while waiting. - */ - public void onError(MojoException exception); - } - - /** - * Asynchronously call wait on a background thread. The given {@link Callback} will be notified - * of the result of the wait on the same thread as asyncWait was called. - * - * @return a {@link Cancellable} object that can be used to cancel waiting. The cancellable - * should only be used on the current thread, and becomes invalid once the callback has - * been notified. - */ - Cancellable asyncWait(Handle handle, HandleSignals signals, long deadline, Callback callback); - -}
diff --git a/mojo/public/java/system/src/org/chromium/mojo/system/Core.java b/mojo/public/java/system/src/org/chromium/mojo/system/Core.java index ba0e5c6f..e5c6d08 100644 --- a/mojo/public/java/system/src/org/chromium/mojo/system/Core.java +++ b/mojo/public/java/system/src/org/chromium/mojo/system/Core.java
@@ -305,9 +305,9 @@ public UntypedHandle acquireNativeHandle(int handle); /** - * Returns a default implementation of {@link AsyncWaiter}. + * Returns an implementation of {@link Watcher}. */ - public AsyncWaiter getDefaultAsyncWaiter(); + public Watcher getWatcher(); /** * Returns a new run loop.
diff --git a/mojo/public/java/system/src/org/chromium/mojo/system/Watcher.java b/mojo/public/java/system/src/org/chromium/mojo/system/Watcher.java new file mode 100644 index 0000000..9c70161 --- /dev/null +++ b/mojo/public/java/system/src/org/chromium/mojo/system/Watcher.java
@@ -0,0 +1,38 @@ +// 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. + +package org.chromium.mojo.system; + +import org.chromium.mojo.system.Core.HandleSignals; + +/** + * Watches a handle for signals being satisfied. + */ +public interface Watcher { + /** + * Callback passed to {@link Watcher#start}. + */ + public interface Callback { + /** + * Called when the handle is ready. + */ + public void onResult(int result); + } + + /** + * Starts watching a handle. + */ + int start(Handle handle, HandleSignals signals, Callback callback); + + /** + * Cancels an already-started watch. + */ + void cancel(); + + /** + * Destroys the underlying implementation. Other methods will fail after destroy has been + * called. + */ + void destroy(); +}
diff --git a/mojo/public/tools/bindings/blink_bindings_configuration.gni b/mojo/public/tools/bindings/blink_bindings_configuration.gni index 5083f6b..18c4eeb 100644 --- a/mojo/public/tools/bindings/blink_bindings_configuration.gni +++ b/mojo/public/tools/bindings/blink_bindings_configuration.gni
@@ -14,6 +14,9 @@ _typemaps = [] foreach(typemap_import, _typemap_imports) { + # Avoid reassignment error by assigning to empty scope first. + _imported = { + } _imported = read_file(typemap_import, "scope") _typemaps += _imported.typemaps }
diff --git a/mojo/public/tools/bindings/chromium_bindings_configuration.gni b/mojo/public/tools/bindings/chromium_bindings_configuration.gni index 3ab0bd73..032b0c17 100644 --- a/mojo/public/tools/bindings/chromium_bindings_configuration.gni +++ b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
@@ -23,6 +23,9 @@ _typemaps = [] foreach(typemap_import, _typemap_imports) { + # Avoid reassignment error by assigning to empty scope first. + _imported = { + } _imported = read_file(typemap_import, "scope") _typemaps += _imported.typemaps }
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_data_view_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_data_view_declaration.tmpl index 4a4948c..550258f2 100644 --- a/mojo/public/tools/bindings/generators/cpp_templates/struct_data_view_declaration.tmpl +++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_data_view_declaration.tmpl
@@ -20,7 +20,8 @@ inline void Get{{name|under_to_camel}}DataView( {{kind|cpp_data_view_type}}* output); - bool Read{{name|under_to_camel}}({{kind|cpp_wrapper_type}}* output) { + template <typename UserType> + bool Read{{name|under_to_camel}}(UserType* output) { {%- if pf.min_version != 0 %} auto pointer = data_->header_.version >= {{pf.min_version}} ? &data_->{{name}} : nullptr; @@ -29,7 +30,7 @@ {%- endif %} return mojo::internal::Deserialize<{{kind|unmapped_type_for_serializer}}>( pointer, output, context_); -} + } {%- elif kind|is_object_kind %} inline void Get{{name|under_to_camel}}DataView(
diff --git a/net/data/ftp/dir-listing-ls-20.expected b/net/data/ftp/dir-listing-ls-20.expected index 9c636b9..d2c76955 100644 --- a/net/data/ftp/dir-listing-ls-20.expected +++ b/net/data/ftp/dir-listing-ls-20.expected
@@ -35,7 +35,7 @@ 24 d -Áåç_ëèöà_-_Face_Off-(1997)-[1080p]_[BD] +Без_лица_-_Face_Off-(1997)-[1080p]_[BD] -1 1994 11 @@ -44,7 +44,7 @@ 27 d -Ââåðõ_-_Up-(2009)-[1080p]_[BD] +Вверх_-_Up-(2009)-[1080p]_[BD] -1 2010 1 @@ -53,7 +53,7 @@ 0 d -Âñïîìíèòü_âñå_-_Total_Recall-(1990)-[1080p]_[BD] +Вспомнить_все_-_Total_Recall-(1990)-[1080p]_[BD] -1 1994 5 @@ -62,7 +62,7 @@ 12 d -Çàêîíîïîñëóøíûé_ãðàæäàíèí_[Ðàñøèðåííàÿ_âåðñèÿ]_-_Law_Abiding_Citizen_[Unrated_Edition]-(2009)-[1080p]_[BD_Remux] +Законопослушный_гражданин_[Расширенная_версия]_-_Law_Abiding_Citizen_[Unrated_Edition]-(2009)-[1080p]_[BD_Remux] -1 1994 5 @@ -71,7 +71,7 @@ 28 d -Ìîíñòðî_-_Cloverfield-(2008)-[1080p]_[BD] +Монстро_-_Cloverfield-(2008)-[1080p]_[BD] -1 2010 1 @@ -80,7 +80,7 @@ 0 d -Ïàíäîðóì_-_Pandorum-(2009)-[1080p]_[BD] +Пандорум_-_Pandorum-(2009)-[1080p]_[BD] -1 1994 5 @@ -89,7 +89,7 @@ 43 d -Ïîñëåäíèé_ñàìóðàé_-_The_Last_Samurai-(2003)-[1080p]_[BD] +Последний_самурай_-_The_Last_Samurai-(2003)-[1080p]_[BD] -1 1994 5 @@ -98,7 +98,7 @@ 18 d -Ðàéîí_9_-_District_9-(2009)-[1080p]_[BD] +Район_9_-_District_9-(2009)-[1080p]_[BD] -1 2010 1 @@ -107,7 +107,7 @@ 0 d -Ðîêêè_Àíòîëîãèÿ_-_Rocky_The_Undisputed_Collection-(1976_1979_1982_1985_1990)-[1080p]_[BD] +Рокки_Антология_-_Rocky_The_Undisputed_Collection-(1976_1979_1982_1985_1990)-[1080p]_[BD] -1 2010 1 @@ -116,7 +116,7 @@ 0 d -Ñóððîãàòû_-_Surrogates-(2009)-[1080p]_[BD] +Суррогаты_-_Surrogates-(2009)-[1080p]_[BD] -1 1994 5 @@ -125,7 +125,7 @@ 57 d -Òðîéíîé_Ôîðñàæ-Òîêèéñêèé_Äðèôò_-_The_Fast_and_the_Furious-Tokyo_Drift-(2006)-[1080p]_[BD] +Тройной_Форсаж-Токийский_Дрифт_-_The_Fast_and_the_Furious-Tokyo_Drift-(2006)-[1080p]_[BD] -1 2010 1 @@ -134,7 +134,7 @@ 0 d -Ôîðñàæ_-_The_Fast_and_the_Furious-(2001)-[1080p]_[BD] +Форсаж_-_The_Fast_and_the_Furious-(2001)-[1080p]_[BD] -1 2010 1 @@ -143,7 +143,7 @@ 0 d -Ôîðñàæ_2_-_2_Fast_2_Furious-(2003)-[1080p]_[BD] +Форсаж_2_-_2_Fast_2_Furious-(2003)-[1080p]_[BD] -1 2010 1 @@ -152,7 +152,7 @@ 0 d -Ôîðñàæ_4_-_Fast_&_Furious-(2009)-[1080p]_[BD] +Форсаж_4_-_Fast_&_Furious-(2009)-[1080p]_[BD] -1 1994 6
diff --git a/net/data/ftp/dir-listing-ls-21.expected b/net/data/ftp/dir-listing-ls-21.expected index 0111be1..fd701d7 100644 --- a/net/data/ftp/dir-listing-ls-21.expected +++ b/net/data/ftp/dir-listing-ls-21.expected
@@ -26,7 +26,7 @@ 24 d -Àâàëîí_-_Avalon-(2001)-[1080p]_[BD_Remux] +Авалон_-_Avalon-(2001)-[1080p]_[BD_Remux] -1 2009 4 @@ -35,7 +35,7 @@ 0 d -Áðþñ_âñåìîãóùèé_-_Bruce_Almighty-(2003)-[1080p]_[BD] +Брюс_всемогущий_-_Bruce_Almighty-(2003)-[1080p]_[BD] -1 2009 6 @@ -44,7 +44,7 @@ 0 d -ÂÀËË-È_-_WALL-E-(2008)-[1080p]_[BD] +ВАЛЛ-И_-_WALL-E-(2008)-[1080p]_[BD] -1 2009 4 @@ -53,7 +53,7 @@ 0 d -Äæåéìñ_Áîíä_007-Êâàíò_ìèëîñåðäèÿ_-_James_Bond_007-Quantum_of_Solace-(2008)-[1080p]_[BD] +Джеймс_Бонд_007-Квант_милосердия_-_James_Bond_007-Quantum_of_Solace-(2008)-[1080p]_[BD] -1 2009 4 @@ -62,7 +62,7 @@ 0 d -Êîñìîñ-Òåððèòîðèÿ_cìåðòè_-_Dead_Space-Downfall-(2008)-[1080p]_[BD] +Космос-Территория_cмерти_-_Dead_Space-Downfall-(2008)-[1080p]_[BD] -1 2009 4 @@ -71,7 +71,7 @@ 0 d -Ìàäàãàñêàð_1_-_Madagascar_1-(2005)-[1080p]_[BD] +Мадагаскар_1_-_Madagascar_1-(2005)-[1080p]_[BD] -1 2009 7 @@ -80,7 +80,7 @@ 0 d -Ìàäàãàñêàð_2_-_Madagascar-Escape_2_Africa-(2008)-[1080p]_[BD] +Мадагаскар_2_-_Madagascar-Escape_2_Africa-(2008)-[1080p]_[BD] -1 2009 7 @@ -89,7 +89,7 @@ 0 d -Ìàòðèöà-Ïåðåçàãðóçêà_-_The_Matrix-Reloaded-(2003)-[1080p]_[BD] +Матрица-Перезагрузка_-_The_Matrix-Reloaded-(2003)-[1080p]_[BD] -1 2009 6 @@ -98,7 +98,7 @@ 0 d -Ìàòðèöà-Ðåâîëþöèÿ_-_The_Matrix-Revolutions-(2003)-[1080p]_[BD] +Матрица-Революция_-_The_Matrix-Revolutions-(2003)-[1080p]_[BD] -1 2009 6 @@ -107,7 +107,7 @@ 0 d -Ìàòðèöà_-_The_Matrix-(1999)-[1080p]_[BD] +Матрица_-_The_Matrix-(1999)-[1080p]_[BD] -1 2009 6 @@ -116,7 +116,7 @@ 0 d -Îáèòåëü_çëà_3_-_Resident_Evil-Extinction-(2007)-[1080p]_[BD] +Обитель_зла_3_-_Resident_Evil-Extinction-(2007)-[1080p]_[BD] -1 2009 7 @@ -125,7 +125,7 @@ 0 d -Îñòðîâ_-_The_Island-(2005)-[1080p]_[BD] +Остров_-_The_Island-(2005)-[1080p]_[BD] -1 2009 5 @@ -134,7 +134,7 @@ 0 d -Ïåðåâîç÷èê_3_-_Transporter_3-(2008)-[1080p]_[BD] +Перевозчик_3_-_Transporter_3-(2008)-[1080p]_[BD] -1 2009 7 @@ -143,7 +143,7 @@ 0 d -Ïèðàòû_Êàðèáñêîãî_ìîðÿ-Íà_êðàþ_Ñâåòà_-_Pirates_of_the_Caribbean-At_World's_End-(2007)-[1080p]_[BD] +Пираты_Карибского_моря-На_краю_Света_-_Pirates_of_the_Caribbean-At_World's_End-(2007)-[1080p]_[BD] -1 2009 5 @@ -152,7 +152,7 @@ 0 d -Ïèðàòû_Êàðèáñêîãî_ìîðÿ-Ïðîêëÿòèå_×åðíîé_Æåì÷óæèíû_-_Pirates_of_the_Caribbean-The_Curse_of_the_Black_Pearl-(2003)-[1080p]_[BD] +Пираты_Карибского_моря-Проклятие_Черной_Жемчужины_-_Pirates_of_the_Caribbean-The_Curse_of_the_Black_Pearl-(2003)-[1080p]_[BD] -1 2009 5 @@ -161,7 +161,7 @@ 0 d -Ïèðàòû_Êàðèáñêîãî_ìîðÿ-Ñóíäóê_ìåðòâåöà_-_Pirates_of_the_Caribbean-Dead_Man's_Chest-(2006)-[1080p]_[BD] +Пираты_Карибского_моря-Сундук_мертвеца_-_Pirates_of_the_Caribbean-Dead_Man's_Chest-(2006)-[1080p]_[BD] -1 2009 5 @@ -170,7 +170,7 @@ 0 d -Ïðèçðà÷íûé_ãîíùèê_-_Ghost_Rider-(2007)-[1080p]_[BD] +Призрачный_гонщик_-_Ghost_Rider-(2007)-[1080p]_[BD] -1 2009 5 @@ -179,7 +179,7 @@ 0 d -Ïðèíöåññà-íåâåñòà_-_The_Princess_Bride-(1987)-[1080p]_[BD] +Принцесса-невеста_-_The_Princess_Bride-(1987)-[1080p]_[BD] -1 2009 4 @@ -188,7 +188,7 @@ 0 d -Ñåêñ_è_101_ñìåðòü_-_Sex_and_Death_101-(2007)-[1080p]_[BD] +Секс_и_101_смерть_-_Sex_and_Death_101-(2007)-[1080p]_[BD] -1 2009 6 @@ -197,7 +197,7 @@ 0 d -Òðàíñôîðìåðû-Áîíóñ_äèñê_-_Transformers-Bonus_Disk-(2007)-[1080p]_[BD] +Трансформеры-Бонус_диск_-_Transformers-Bonus_Disk-(2007)-[1080p]_[BD] -1 2009 5 @@ -206,7 +206,7 @@ 0 d -Òðàíñôîðìåðû_-_Transformers-(2007)-[1080p]_[BD] +Трансформеры_-_Transformers-(2007)-[1080p]_[BD] -1 2009 4 @@ -215,7 +215,7 @@ 0 d -Òðèíàäöàòûé_ýòàæ_-_The_Thirteenth_Floor-(1999)-[1080p]_[BD] +Тринадцатый_этаж_-_The_Thirteenth_Floor-(1999)-[1080p]_[BD] -1 2009 6 @@ -224,7 +224,7 @@ 0 d -Óëè÷íûé_áîåö_-_Street_Fighter-(1994)-[1080p]_[BD_Remux] +Уличный_боец_-_Street_Fighter-(1994)-[1080p]_[BD_Remux] -1 2009 5 @@ -233,7 +233,7 @@ 0 d -×åãî_õîòÿò_æåíùèíû_-_What_Woman_Want-(2000)-[1080p]_[BD] +Чего_хотят_женщины_-_What_Woman_Want-(2000)-[1080p]_[BD] -1 2009 3
diff --git a/net/data/ftp/dir-listing-ls-22.expected b/net/data/ftp/dir-listing-ls-22.expected index c5a02b7..9578268 100644 --- a/net/data/ftp/dir-listing-ls-22.expected +++ b/net/data/ftp/dir-listing-ls-22.expected
@@ -26,7 +26,7 @@ 23 d -Àâàòàð_-_Avatar-(2009)-[1080p]_[BD] +Аватар_-_Avatar-(2009)-[1080p]_[BD] -1 1994 5 @@ -35,8 +35,8 @@ 26 - -Àìåðèêàíñêèé_ïèðîã_1_[Ðàñøèðåííàÿ_âåðñèÿ]_-_American_Pie_1_[Unrated_Edition]-(1999)-[1080p]_[BD_remux].ts -17577705968 +Американский_пирог_1_[Расширенная_версия]_-_American_Pie_1_[Unrated_Edition]-(1999)-[1080p]_[BD_remux].ts +17577705968 2009 3 8 @@ -44,8 +44,8 @@ 0 - -Áîëüøîé_êóø_-_Snatch-(2000)-[1080i]_[HDTV].ts -15512934868 +Большой_куш_-_Snatch-(2000)-[1080i]_[HDTV].ts +15512934868 2009 3 16 @@ -53,7 +53,7 @@ 0 d -Áîëüøîé_êóø_-_Snatch-(2000)-[1080p]_[BD_Remux] +Большой_куш_-_Snatch-(2000)-[1080p]_[BD_Remux] -1 1994 6 @@ -62,8 +62,8 @@ 7 - -Âîéíà_ìèðîâ_-_War_of_the_Worlds-(2005)-[720p]_[HDTV].mkv -8900589105 +Война_миров_-_War_of_the_Worlds-(2005)-[720p]_[HDTV].mkv +8900589105 2009 3 24 @@ -71,8 +71,8 @@ 0 - -Ãàíãñòåð_-_American_Gangster-(2007)-[1080p]_[BD_remux].mkv -27728321654 +Гангстер_-_American_Gangster-(2007)-[1080p]_[BD_remux].mkv +27728321654 2009 3 9 @@ -80,8 +80,8 @@ 0 - -Ãàíãñòåð_[Ðàñøèðåííàÿ_âåðñèÿ]_-_American_Gangster_[Unrated_Edition]-(2007)-[1080p]_[BD_remux].mkv -31731782861 +Гангстер_[Расширенная_версия]_-_American_Gangster_[Unrated_Edition]-(2007)-[1080p]_[BD_remux].mkv +31731782861 2009 3 9 @@ -89,8 +89,8 @@ 0 - -Äîðîæíîå_ïðèêëþ÷åíèå_-_Road_Trip-(2000)-[720p]_[HDTV_Rip].mkv -5009104014 +Дорожное_приключение_-_Road_Trip-(2000)-[720p]_[HDTV_Rip].mkv +5009104014 2009 3 24 @@ -98,8 +98,8 @@ 0 - -Çâ¸çäíûå_âîéíû-Ýïèçîä_2-Àòàêà_êëîíîâ_-_Star_Wars-Episode_2-Attack_of_the_Clones-(2002)-[1080i]_[HDTV].ts -21410583980 +Звёздные_войны-Эпизод_2-Атака_клонов_-_Star_Wars-Episode_2-Attack_of_the_Clones-(2002)-[1080i]_[HDTV].ts +21410583980 2009 3 11 @@ -107,8 +107,8 @@ 0 - -Çâ¸çäíûå_âîéíû-Ýïèçîä_3-Ìåñòü_Ñèòõîâ_-_Star_Wars-Episode_3-Revenge_of_the_Sith-(2005)-[1080i]_[HDTV].ts -19858181688 +Звёздные_войны-Эпизод_3-Месть_Ситхов_-_Star_Wars-Episode_3-Revenge_of_the_Sith-(2005)-[1080i]_[HDTV].ts +19858181688 2009 3 11 @@ -116,8 +116,8 @@ 0 - -Çâ¸çäíûé_äåñàíò_-_Starship_Troopers-(1997)-[1080p]_[BD_remux].mkv -29026065728 +Звёздный_десант_-_Starship_Troopers-(1997)-[1080p]_[BD_remux].mkv +29026065728 2009 3 16 @@ -125,8 +125,8 @@ 0 - -Çåðêàëà_[Ðàñøèðåííàÿ_âåðñèÿ]_-_Mirrors_[Unrated_Edition]-(2008)-[1080p]_[BD_remux].mkv -22169179449 +Зеркала_[Расширенная_версия]_-_Mirrors_[Unrated_Edition]-(2008)-[1080p]_[BD_remux].mkv +22169179449 2009 3 16 @@ -134,7 +134,7 @@ 0 d -Íèíäçÿ-óáèéöà_-_Ninja_Assassin-(2009)-[1080p]_[BD] +Ниндзя-убийца_-_Ninja_Assassin-(2009)-[1080p]_[BD] -1 1994 6 @@ -143,8 +143,8 @@ 56 - -Îáèòåëü_çëà_3_-_Resident_Evil-Extinction-(2007)-[1080p]_[BD_remux].mkv -19717173247 +Обитель_зла_3_-_Resident_Evil-Extinction-(2007)-[1080p]_[BD_remux].mkv +19717173247 2009 3 11 @@ -152,8 +152,8 @@ 0 - -Ïàòîëîãèÿ_-_Pathology-(2008)-[1080p]_[BD_remux].mkv -18660904388 +Патология_-_Pathology-(2008)-[1080p]_[BD_remux].mkv +18660904388 2009 3 11 @@ -161,8 +161,8 @@ 0 - -Ïèëà_1_[Ðåæèññ¸ðñêàÿ_âåðñèÿ]_-_Saw_I_[Director's_Cut]-(2004)-[1080p]_[HDDVD_remux].mkv -16476154520 +Пила_1_[Режиссёрская_версия]_-_Saw_I_[Director's_Cut]-(2004)-[1080p]_[HDDVD_remux].mkv +16476154520 2009 3 5 @@ -170,8 +170,8 @@ 0 - -Ïèëà_2_[Ðåæèññ¸ðñêàÿ_âåðñèÿ]_-_Saw_II_[Director's_Cut]-(2005)-[1080p]_[BD_remux].mkv -19917510515 +Пила_2_[Режиссёрская_версия]_-_Saw_II_[Director's_Cut]-(2005)-[1080p]_[BD_remux].mkv +19917510515 2009 3 5 @@ -179,8 +179,8 @@ 0 - -Ïèëà_3_[Ðåæèññ¸ðñêàÿ_âåðñèÿ]_-_Saw_III_[Director's_Cut]-(2006)-[1080p]_[BD_remux].mkv -18085592265 +Пила_3_[Режиссёрская_версия]_-_Saw_III_[Director's_Cut]-(2006)-[1080p]_[BD_remux].mkv +18085592265 2009 3 5 @@ -188,8 +188,8 @@ 0 - -Ïèëà_4_[Ðåæèññ¸ðñêàÿ_âåðñèÿ]_-_Saw_IV_[Director's_Cut]-(2007)-[1080p]_[BD_remux].flac -3473582701 +Пила_4_[Режиссёрская_версия]_-_Saw_IV_[Director's_Cut]-(2007)-[1080p]_[BD_remux].flac +3473582701 2009 3 5 @@ -197,8 +197,8 @@ 0 - -Ïèëà_4_[Ðåæèññ¸ðñêàÿ_âåðñèÿ]_-_Saw_IV_[Director's_Cut]-(2007)-[1080p]_[BD_remux].mkv -15263958421 +Пила_4_[Режиссёрская_версия]_-_Saw_IV_[Director's_Cut]-(2007)-[1080p]_[BD_remux].mkv +15263958421 2009 3 5 @@ -206,8 +206,8 @@ 0 - -Ïèëà_5_[Ðåæèññ¸ðñêàÿ_âåðñèÿ]_-_Saw_V_[Director's_Cut]-(2008)-[1080p]_[BD_remux].mkv -19944605507 +Пила_5_[Режиссёрская_версия]_-_Saw_V_[Director's_Cut]-(2008)-[1080p]_[BD_remux].mkv +19944605507 2009 3 16 @@ -215,8 +215,8 @@ 0 - -Ïèíãâèíû_èç_Ìàäàãàñêàðà-Îïåðàöèÿ_Ñ_Íîâûì_Ãîäîì!_-_The_Madagascar_Penguins_in_A_Christmas_Caper-(2005)-[1080p]_[BD_remux].ts -3024333064 +Пингвины_из_Мадагаскара-Операция_С_Новым_Годом!_-_The_Madagascar_Penguins_in_A_Christmas_Caper-(2005)-[1080p]_[BD_remux].ts +3024333064 2009 3 24 @@ -224,8 +224,8 @@ 0 - -Ïëîõîé_Ñàíòà_[Ðàñøèðåííàÿ_âåðñèÿ]_-_Bad_Santa_[Unrated_Edition]-(2003)-[1080p]_[BD_remux].srt -125961 +Плохой_Санта_[Расширенная_версия]_-_Bad_Santa_[Unrated_Edition]-(2003)-[1080p]_[BD_remux].srt +125961 2009 3 5 @@ -233,8 +233,8 @@ 0 - -Ïëîõîé_Ñàíòà_[Ðàñøèðåííàÿ_âåðñèÿ]_-_Bad_Santa_[Unrated_Edition]-(2003)-[1080p]_[BD_remux].ts -19908695408 +Плохой_Санта_[Расширенная_версия]_-_Bad_Santa_[Unrated_Edition]-(2003)-[1080p]_[BD_remux].ts +19908695408 2009 3 5 @@ -242,8 +242,8 @@ 0 - -Ïîáåã_èç_Øîóøåíêà_-_The_Shawshank_Redemption-(1994)-[1080p]_[BD_remux].mkv -23185439267 +Побег_из_Шоушенка_-_The_Shawshank_Redemption-(1994)-[1080p]_[BD_remux].mkv +23185439267 2009 3 11 @@ -251,8 +251,8 @@ 0 - -Òóïîé_è_åùå_òóïåå_[Ðàñøèðåííàÿ_âåðñèÿ]_-_Dumb_and_Dumber_[Unrated_Edition]-(1994)-[1080p]_[BD_remux].mkv -19567287274 +Тупой_и_еще_тупее_[Расширенная_версия]_-_Dumb_and_Dumber_[Unrated_Edition]-(1994)-[1080p]_[BD_remux].mkv +19567287274 2009 3 16 @@ -260,8 +260,8 @@ 0 - -Óðàãàí_-_The_Hurricane-(1999)-[1080p]_[HDDVD_Rip].mkv -14773061093 +Ураган_-_The_Hurricane-(1999)-[1080p]_[HDDVD_Rip].mkv +14773061093 2009 3 16 @@ -269,8 +269,8 @@ 0 - -Õîñòåë_2_[Ðåæèññ¸ðñêàÿ_âåðñèÿ]_-_Hostel_2_[Director's_Cut]-(2007)-[1080p]_[BD_remux].ts -22411268500 +Хостел_2_[Режиссёрская_версия]_-_Hostel_2_[Director's_Cut]-(2007)-[1080p]_[BD_remux].ts +22411268500 2009 3 11 @@ -278,8 +278,8 @@ 0 - -×óæîé_ïðîòèâ_Õèùíèêà_[Ðàñøèðåííàÿ_âåðñèÿ]_-_Alien_vs_Predator_[Unrated_Edition]-(2004)-[1080p]_[BD_remux].mkv -23712519861 +Чужой_против_Хищника_[Расширенная_версия]_-_Alien_vs_Predator_[Unrated_Edition]-(2004)-[1080p]_[BD_remux].mkv +23712519861 2009 3 11
diff --git a/net/ftp/ftp_directory_listing_parser.cc b/net/ftp/ftp_directory_listing_parser.cc index a1aabf3f..73e831f6 100644 --- a/net/ftp/ftp_directory_listing_parser.cc +++ b/net/ftp/ftp_directory_listing_parser.cc
@@ -6,7 +6,7 @@ #include "base/bind.h" #include "base/callback.h" -#include "base/i18n/icu_encoding_detection.h" +#include "base/i18n/encoding_detection.h" #include "base/i18n/icu_string_conversions.h" #include "base/stl_util.h" #include "base/strings/string_util.h" @@ -84,29 +84,23 @@ const base::Time& current_time, std::vector<FtpDirectoryListingEntry>* entries, FtpServerType* server_type) { - const char* const kNewlineSeparators[] = { "\n", "\r\n" }; - - std::vector<std::string> encodings; - if (!base::DetectAllEncodings(text, &encodings)) + std::string encoding; + if (!base::DetectEncoding(text, &encoding)) return ERR_ENCODING_DETECTION_FAILED; + const char* encoding_name = encoding.c_str(); - // Use first encoding that can be used to decode the text. - for (size_t i = 0; i < encodings.size(); i++) { - base::string16 converted_text; - if (base::CodepageToUTF16(text, - encodings[i].c_str(), - base::OnStringConversionError::FAIL, - &converted_text)) { - for (size_t j = 0; j < arraysize(kNewlineSeparators); j++) { - int rv = ParseListing(converted_text, - base::ASCIIToUTF16(kNewlineSeparators[j]), - encodings[i], - current_time, - entries, - server_type); - if (rv == OK) - return rv; - } + base::string16 converted_text; + if (base::CodepageToUTF16(text, encoding_name, + base::OnStringConversionError::FAIL, + &converted_text)) { + const char* const kNewlineSeparators[] = {"\n", "\r\n"}; + + for (size_t j = 0; j < arraysize(kNewlineSeparators); j++) { + int rv = ParseListing(converted_text, + base::ASCIIToUTF16(kNewlineSeparators[j]), + encoding_name, current_time, entries, server_type); + if (rv == OK) + return rv; } }
diff --git a/net/http/bidirectional_stream.cc b/net/http/bidirectional_stream.cc index a3f74d2..bbac8c0 100644 --- a/net/http/bidirectional_stream.cc +++ b/net/http/bidirectional_stream.cc
@@ -126,7 +126,6 @@ } BidirectionalStream::~BidirectionalStream() { - Cancel(); if (net_log_.IsCapturing()) { net_log_.EndEvent(NetLog::TYPE_BIDIRECTIONAL_STREAM_ALIVE); } @@ -193,14 +192,6 @@ } } -void BidirectionalStream::Cancel() { - stream_request_.reset(); - if (stream_impl_) { - stream_impl_->Cancel(); - stream_impl_.reset(); - } -} - NextProto BidirectionalStream::GetProtocol() const { if (!stream_impl_) return kProtoUnknown;
diff --git a/net/http/bidirectional_stream.h b/net/http/bidirectional_stream.h index 635cf5b79..0b86870 100644 --- a/net/http/bidirectional_stream.h +++ b/net/http/bidirectional_stream.h
@@ -154,11 +154,6 @@ const std::vector<int>& lengths, bool end_stream); - // If |stream_request_| is non-NULL, cancel it. If |stream_impl_| is - // established, cancel it. No delegate method will be called after Cancel(). - // Any pending operations may or may not succeed. - void Cancel(); - // Returns the protocol used by this stream. If stream has not been // established, return kProtoUnknown. NextProto GetProtocol() const;
diff --git a/net/http/bidirectional_stream_impl.h b/net/http/bidirectional_stream_impl.h index 52a7c7771..dd173ec0 100644 --- a/net/http/bidirectional_stream_impl.h +++ b/net/http/bidirectional_stream_impl.h
@@ -135,10 +135,6 @@ const std::vector<int>& lengths, bool end_stream) = 0; - // Cancels the stream. No Delegate method will be called. Any pending - // operations may or may not succeed. - virtual void Cancel() = 0; - // Returns the protocol used by this stream. If stream has not been // established, return kProtoUnknown. virtual NextProto GetProtocol() const = 0;
diff --git a/net/http/bidirectional_stream_unittest.cc b/net/http/bidirectional_stream_unittest.cc index 3d0db380..b7e8666e 100644 --- a/net/http/bidirectional_stream_unittest.cc +++ b/net/http/bidirectional_stream_unittest.cc
@@ -59,6 +59,8 @@ read_buf_len_(read_buf_len), timer_(std::move(timer)), loop_(nullptr), + received_bytes_(0), + sent_bytes_(0), error_(OK), on_data_read_count_(0), on_data_sent_count_(0), @@ -82,6 +84,7 @@ CHECK(!not_expect_callback_); response_headers_ = response_headers.Clone(); + if (!do_not_start_read_) StartOrContinueReading(); } @@ -175,19 +178,31 @@ return rv; } - // Cancels |stream_|. - void CancelStream() { stream_->Cancel(); } - // Deletes |stream_|. - void DeleteStream() { stream_.reset(); } - - NextProto GetProtocol() const { return stream_->GetProtocol(); } - - int64_t GetTotalReceivedBytes() const { - return stream_->GetTotalReceivedBytes(); + void DeleteStream() { + next_proto_ = stream_->GetProtocol(); + received_bytes_ = stream_->GetTotalReceivedBytes(); + sent_bytes_ = stream_->GetTotalSentBytes(); + stream_.reset(); } - int64_t GetTotalSentBytes() const { return stream_->GetTotalSentBytes(); } + NextProto GetProtocol() const { + if (stream_) + return stream_->GetProtocol(); + return next_proto_; + } + + int64_t GetTotalReceivedBytes() const { + if (stream_) + return stream_->GetTotalReceivedBytes(); + return received_bytes_; + } + + int64_t GetTotalSentBytes() const { + if (stream_) + return stream_->GetTotalSentBytes(); + return sent_bytes_; + } // Const getters for internal states. const std::string& data_received() const { return data_received_; } @@ -220,6 +235,9 @@ std::unique_ptr<base::RunLoop> loop_; SpdyHeaderBlock response_headers_; SpdyHeaderBlock trailers_; + NextProto next_proto_; + int64_t received_bytes_; + int64_t sent_bytes_; int error_; int on_data_read_count_; int on_data_sent_count_; @@ -234,7 +252,7 @@ }; // A delegate that deletes the stream in a particular callback. -class CancelOrDeleteStreamDelegate : public TestDelegateBase { +class DeleteStreamDelegate : public TestDelegateBase { public: // Specifies in which callback the stream can be deleted. enum Phase { @@ -244,17 +262,14 @@ ON_FAILED, }; - CancelOrDeleteStreamDelegate(IOBuffer* buf, - int buf_len, - Phase phase, - bool do_cancel) - : TestDelegateBase(buf, buf_len), phase_(phase), do_cancel_(do_cancel) {} - ~CancelOrDeleteStreamDelegate() override {} + DeleteStreamDelegate(IOBuffer* buf, int buf_len, Phase phase) + : TestDelegateBase(buf, buf_len), phase_(phase) {} + ~DeleteStreamDelegate() override {} void OnHeadersReceived(const SpdyHeaderBlock& response_headers) override { TestDelegateBase::OnHeadersReceived(response_headers); if (phase_ == ON_HEADERS_RECEIVED) { - CancelOrDelete(); + DeleteStream(); QuitLoop(); } } @@ -268,7 +283,7 @@ } TestDelegateBase::OnDataRead(bytes_read); if (phase_ == ON_DATA_READ) { - CancelOrDelete(); + DeleteStream(); QuitLoop(); } } @@ -280,7 +295,7 @@ } TestDelegateBase::OnTrailersReceived(trailers); if (phase_ == ON_TRAILERS_RECEIVED) { - CancelOrDelete(); + DeleteStream(); QuitLoop(); } } @@ -291,26 +306,16 @@ return; } TestDelegateBase::OnFailed(error); - CancelOrDelete(); + DeleteStream(); QuitLoop(); } private: - void CancelOrDelete() { - if (do_cancel_) { - CancelStream(); - } else { - DeleteStream(); - } - } - // Indicates in which callback the delegate should cancel or delete the // stream. Phase phase_; - // Indicates whether to cancel or delete the stream. - bool do_cancel_; - DISALLOW_COPY_AND_ASSIGN(CancelOrDeleteStreamDelegate); + DISALLOW_COPY_AND_ASSIGN(DeleteStreamDelegate); }; // A Timer that does not start a delayed task unless the timer is fired. @@ -1064,7 +1069,7 @@ delegate->GetTotalReceivedBytes()); } -TEST_F(BidirectionalStreamTest, CancelStreamAfterSendData) { +TEST_F(BidirectionalStreamTest, DeleteStreamAfterSendData) { SpdySerializedFrame req(spdy_util_.ConstructSpdyPost( kDefaultUrl, 1, kBodyDataSize * 3, LOWEST, nullptr, 0)); SpdySerializedFrame data_frame(spdy_util_.ConstructSpdyDataFrame( @@ -1113,22 +1118,23 @@ delegate->SendData(buf, buf->size(), false); sequenced_data_->Resume(); base::RunLoop().RunUntilIdle(); - // Cancel the stream. - delegate->CancelStream(); + + delegate->DeleteStream(); sequenced_data_->Resume(); base::RunLoop().RunUntilIdle(); EXPECT_EQ("200", delegate->response_headers().find(":status")->second); EXPECT_EQ(0, delegate->on_data_read_count()); - // EXPECT_EQ(1, delegate->on_data_send_count()); // OnDataSent may or may not have been invoked. - // Calling after stream is canceled gives kProtoUnknown. - EXPECT_EQ(kProtoUnknown, delegate->GetProtocol()); - EXPECT_EQ(0, delegate->GetTotalSentBytes()); - EXPECT_EQ(0, delegate->GetTotalReceivedBytes()); + EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol()); + // Bytes sent excludes the RST frame. + EXPECT_EQ(CountWriteBytes(writes, arraysize(writes) - 1), + delegate->GetTotalSentBytes()); + EXPECT_EQ(CountReadBytes(reads, arraysize(reads)), + delegate->GetTotalReceivedBytes()); } -TEST_F(BidirectionalStreamTest, CancelStreamDuringReadData) { +TEST_F(BidirectionalStreamTest, DeleteStreamDuringReadData) { SpdySerializedFrame req(spdy_util_.ConstructSpdyPost( kDefaultUrl, 1, kBodyDataSize * 3, LOWEST, nullptr, 0)); SpdySerializedFrame rst( @@ -1167,20 +1173,24 @@ base::RunLoop().RunUntilIdle(); EXPECT_EQ("200", delegate->response_headers().find(":status")->second); - // Cancel the stream after ReadData returns ERR_IO_PENDING. + // Delete the stream after ReadData returns ERR_IO_PENDING. int rv = delegate->ReadData(); EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); - delegate->CancelStream(); + delegate->DeleteStream(); sequenced_data_->Resume(); base::RunLoop().RunUntilIdle(); EXPECT_EQ(0, delegate->on_data_read_count()); EXPECT_EQ(0, delegate->on_data_sent_count()); - // Calling after stream is canceled gives kProtoUnknown. - EXPECT_EQ(kProtoUnknown, delegate->GetProtocol()); - EXPECT_EQ(0, delegate->GetTotalSentBytes()); - EXPECT_EQ(0, delegate->GetTotalReceivedBytes()); + EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol()); + // Bytes sent excludes the RST frame. + EXPECT_EQ(CountWriteBytes(writes, arraysize(writes) - 1), + delegate->GetTotalSentBytes()); + // Response body frame isn't read becase stream is deleted once read returns + // ERR_IO_PENDING. + EXPECT_EQ(CountReadBytes(reads, arraysize(reads) - 2), + delegate->GetTotalReceivedBytes()); } // Receiving a header with uppercase ASCII will result in a protocol error, @@ -1251,11 +1261,7 @@ EXPECT_THAT(net_error, IsError(ERR_SPDY_PROTOCOL_ERROR)); } -INSTANTIATE_TEST_CASE_P(CancelOrDeleteTests, - BidirectionalStreamTest, - ::testing::Values(true, false)); - -TEST_P(BidirectionalStreamTest, CancelOrDeleteStreamDuringOnHeadersReceived) { +TEST_F(BidirectionalStreamTest, DeleteStreamDuringOnHeadersReceived) { SpdySerializedFrame req(spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST)); SpdySerializedFrame rst( @@ -1283,11 +1289,9 @@ request_info->end_stream_on_headers = true; scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize)); - std::unique_ptr<CancelOrDeleteStreamDelegate> delegate( - new CancelOrDeleteStreamDelegate( - read_buffer.get(), kReadBufferSize, - CancelOrDeleteStreamDelegate::Phase::ON_HEADERS_RECEIVED, - GetParam())); + std::unique_ptr<DeleteStreamDelegate> delegate(new DeleteStreamDelegate( + read_buffer.get(), kReadBufferSize, + DeleteStreamDelegate::Phase::ON_HEADERS_RECEIVED)); delegate->SetRunUntilCompletion(true); delegate->Start(std::move(request_info), http_session_.get()); // Makes sure delegate does not get called. @@ -1299,15 +1303,15 @@ EXPECT_EQ(0, delegate->on_data_sent_count()); EXPECT_EQ(0, delegate->on_data_read_count()); - // If stream is destroyed, do not call into stream. - if (!GetParam()) - return; - EXPECT_EQ(0, delegate->GetTotalSentBytes()); - EXPECT_EQ(0, delegate->GetTotalReceivedBytes()); - EXPECT_EQ(kProtoUnknown, delegate->GetProtocol()); + EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol()); + // Bytes sent excludes the RST frame. + EXPECT_EQ(CountWriteBytes(writes, arraysize(writes) - 1), + delegate->GetTotalSentBytes()); + EXPECT_EQ(CountReadBytes(reads, arraysize(reads)), + delegate->GetTotalReceivedBytes()); } -TEST_P(BidirectionalStreamTest, CancelOrDeleteStreamDuringOnDataRead) { +TEST_F(BidirectionalStreamTest, DeleteStreamDuringOnDataRead) { SpdySerializedFrame req(spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST)); SpdySerializedFrame rst( @@ -1339,10 +1343,9 @@ request_info->end_stream_on_headers = true; scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize)); - std::unique_ptr<CancelOrDeleteStreamDelegate> delegate( - new CancelOrDeleteStreamDelegate( - read_buffer.get(), kReadBufferSize, - CancelOrDeleteStreamDelegate::Phase::ON_DATA_READ, GetParam())); + std::unique_ptr<DeleteStreamDelegate> delegate( + new DeleteStreamDelegate(read_buffer.get(), kReadBufferSize, + DeleteStreamDelegate::Phase::ON_DATA_READ)); delegate->SetRunUntilCompletion(true); delegate->Start(std::move(request_info), http_session_.get()); // Makes sure delegate does not get called. @@ -1354,15 +1357,15 @@ static_cast<int>(delegate->data_received().size())); EXPECT_EQ(0, delegate->on_data_sent_count()); - // If stream is destroyed, do not call into stream. - if (!GetParam()) - return; - EXPECT_EQ(0, delegate->GetTotalSentBytes()); - EXPECT_EQ(0, delegate->GetTotalReceivedBytes()); - EXPECT_EQ(kProtoUnknown, delegate->GetProtocol()); + EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol()); + // Bytes sent excludes the RST frame. + EXPECT_EQ(CountWriteBytes(writes, arraysize(writes) - 1), + delegate->GetTotalSentBytes()); + EXPECT_EQ(CountReadBytes(reads, arraysize(reads)), + delegate->GetTotalReceivedBytes()); } -TEST_P(BidirectionalStreamTest, CancelOrDeleteStreamDuringOnTrailersReceived) { +TEST_F(BidirectionalStreamTest, DeleteStreamDuringOnTrailersReceived) { SpdySerializedFrame req(spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST)); SpdySerializedFrame rst( @@ -1399,11 +1402,9 @@ request_info->end_stream_on_headers = true; scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize)); - std::unique_ptr<CancelOrDeleteStreamDelegate> delegate( - new CancelOrDeleteStreamDelegate( - read_buffer.get(), kReadBufferSize, - CancelOrDeleteStreamDelegate::Phase::ON_TRAILERS_RECEIVED, - GetParam())); + std::unique_ptr<DeleteStreamDelegate> delegate(new DeleteStreamDelegate( + read_buffer.get(), kReadBufferSize, + DeleteStreamDelegate::Phase::ON_TRAILERS_RECEIVED)); delegate->SetRunUntilCompletion(true); delegate->Start(std::move(request_info), http_session_.get()); // Makes sure delegate does not get called. @@ -1414,17 +1415,16 @@ EXPECT_EQ("bar", delegate->trailers().find("foo")->second); EXPECT_EQ(0, delegate->on_data_sent_count()); // OnDataRead may or may not have been fired before the stream is - // canceled/deleted. - - // If stream is destroyed, do not call into stream. - if (!GetParam()) - return; - EXPECT_EQ(0, delegate->GetTotalSentBytes()); - EXPECT_EQ(0, delegate->GetTotalReceivedBytes()); - EXPECT_EQ(kProtoUnknown, delegate->GetProtocol()); + // deleted. + EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol()); + // Bytes sent excludes the RST frame. + EXPECT_EQ(CountWriteBytes(writes, arraysize(writes) - 1), + delegate->GetTotalSentBytes()); + EXPECT_EQ(CountReadBytes(reads, arraysize(reads)), + delegate->GetTotalReceivedBytes()); } -TEST_P(BidirectionalStreamTest, CancelOrDeleteStreamDuringOnFailed) { +TEST_F(BidirectionalStreamTest, DeleteStreamDuringOnFailed) { SpdySerializedFrame req(spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST)); SpdySerializedFrame rst( @@ -1452,10 +1452,9 @@ request_info->end_stream_on_headers = true; scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize)); - std::unique_ptr<CancelOrDeleteStreamDelegate> delegate( - new CancelOrDeleteStreamDelegate( - read_buffer.get(), kReadBufferSize, - CancelOrDeleteStreamDelegate::Phase::ON_FAILED, GetParam())); + std::unique_ptr<DeleteStreamDelegate> delegate( + new DeleteStreamDelegate(read_buffer.get(), kReadBufferSize, + DeleteStreamDelegate::Phase::ON_FAILED)); delegate->SetRunUntilCompletion(true); delegate->Start(std::move(request_info), http_session_.get()); // Makes sure delegate does not get called. @@ -1466,12 +1465,12 @@ EXPECT_EQ(0, delegate->on_data_read_count()); EXPECT_THAT(delegate->error(), IsError(ERR_SPDY_PROTOCOL_ERROR)); - // If stream is destroyed, do not call into stream. - if (!GetParam()) - return; - EXPECT_EQ(0, delegate->GetTotalSentBytes()); - EXPECT_EQ(0, delegate->GetTotalReceivedBytes()); - EXPECT_EQ(kProtoUnknown, delegate->GetProtocol()); + EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol()); + // Bytes sent excludes the RST frame. + EXPECT_EQ(CountWriteBytes(writes, arraysize(writes) - 1), + delegate->GetTotalSentBytes()); + EXPECT_EQ(CountReadBytes(reads, arraysize(reads)), + delegate->GetTotalReceivedBytes()); } TEST_F(BidirectionalStreamTest, TestHonorAlternativeServiceHeader) {
diff --git a/net/http/disk_cache_based_quic_server_info.h b/net/http/disk_cache_based_quic_server_info.h index 7420f32..6e15fc3 100644 --- a/net/http/disk_cache_based_quic_server_info.h +++ b/net/http/disk_cache_based_quic_server_info.h
@@ -61,36 +61,6 @@ NONE, }; - // Enum to track number of times data read/parse/write API calls of - // QuicServerInfo to and from disk cache is called. - enum QuicServerInfoAPICall { - QUIC_SERVER_INFO_START = 0, - QUIC_SERVER_INFO_WAIT_FOR_DATA_READY = 1, - QUIC_SERVER_INFO_PARSE = 2, - QUIC_SERVER_INFO_WAIT_FOR_DATA_READY_CANCEL = 3, - QUIC_SERVER_INFO_READY_TO_PERSIST = 4, - QUIC_SERVER_INFO_PERSIST = 5, - QUIC_SERVER_INFO_EXTERNAL_CACHE_HIT = 6, - QUIC_SERVER_INFO_NUM_OF_API_CALLS = 7, - }; - - // Enum to track failure reasons to read/load/write of QuicServerInfo to - // and from disk cache. - enum FailureReason { - WAIT_FOR_DATA_READY_INVALID_ARGUMENT_FAILURE = 0, - GET_BACKEND_FAILURE = 1, - OPEN_FAILURE = 2, - CREATE_OR_OPEN_FAILURE = 3, - PARSE_NO_DATA_FAILURE = 4, - PARSE_FAILURE = 5, - READ_FAILURE = 6, - READY_TO_PERSIST_FAILURE = 7, - PERSIST_NO_BACKEND_FAILURE = 8, - WRITE_FAILURE = 9, - NO_FAILURE = 10, - NUM_OF_FAILURES = 11, - }; - ~DiskCacheBasedQuicServerInfo() override; // Persists |pending_write_data_| if it is not empty, otherwise serializes the
diff --git a/net/nqe/cached_network_quality.cc b/net/nqe/cached_network_quality.cc index d4e454d..8b65c34 100644 --- a/net/nqe/cached_network_quality.cc +++ b/net/nqe/cached_network_quality.cc
@@ -10,25 +10,24 @@ namespace internal { -CachedNetworkQuality::CachedNetworkQuality() {} +CachedNetworkQuality::CachedNetworkQuality() + : effective_connection_type_(EFFECTIVE_CONNECTION_TYPE_UNKNOWN) {} CachedNetworkQuality::CachedNetworkQuality( base::TimeTicks last_update_time, - const NetworkQuality& network_quality) - : last_update_time_(last_update_time), network_quality_(network_quality) {} + const NetworkQuality& network_quality, + EffectiveConnectionType effective_connection_type) + : last_update_time_(last_update_time), + network_quality_(network_quality), + effective_connection_type_(effective_connection_type) {} -CachedNetworkQuality::CachedNetworkQuality(const CachedNetworkQuality& other) - : last_update_time_(other.last_update_time_), - network_quality_(other.network_quality_) {} +CachedNetworkQuality::CachedNetworkQuality(const CachedNetworkQuality& other) = + default; CachedNetworkQuality::~CachedNetworkQuality() {} CachedNetworkQuality& CachedNetworkQuality::operator=( - const CachedNetworkQuality& other) { - last_update_time_ = other.last_update_time_; - network_quality_ = other.network_quality_; - return *this; -} + const CachedNetworkQuality& other) = default; bool CachedNetworkQuality::OlderThan( const CachedNetworkQuality& cached_network_quality) const {
diff --git a/net/nqe/cached_network_quality.h b/net/nqe/cached_network_quality.h index a8fae2f7..4aeebd7 100644 --- a/net/nqe/cached_network_quality.h +++ b/net/nqe/cached_network_quality.h
@@ -5,9 +5,9 @@ #ifndef NET_NQE_CACHED_NETWORK_QUALITY_H_ #define NET_NQE_CACHED_NETWORK_QUALITY_H_ -#include "base/macros.h" #include "base/time/time.h" #include "net/base/net_export.h" +#include "net/nqe/effective_connection_type.h" #include "net/nqe/network_quality.h" namespace net { @@ -23,7 +23,8 @@ // |last_update_time| is the time when the |network_quality| was computed. CachedNetworkQuality(base::TimeTicks last_update_time, - const NetworkQuality& network_quality); + const NetworkQuality& network_quality, + EffectiveConnectionType effective_connection_type); CachedNetworkQuality(const CachedNetworkQuality& other); ~CachedNetworkQuality(); @@ -40,12 +41,19 @@ const NetworkQuality& network_quality() { return network_quality_; } + EffectiveConnectionType effective_connection_type() const { + return effective_connection_type_; + } + private: // Time when this cache entry was last updated. base::TimeTicks last_update_time_; // Quality of this cached network. NetworkQuality network_quality_; + + // Effective connection type of the cached network. + EffectiveConnectionType effective_connection_type_; }; } // namespace internal
diff --git a/net/nqe/network_quality_estimator.cc b/net/nqe/network_quality_estimator.cc index 96c0f3c9..c31f9a4 100644 --- a/net/nqe/network_quality_estimator.cc +++ b/net/nqe/network_quality_estimator.cc
@@ -962,10 +962,11 @@ RecordMetricsOnConnectionTypeChanged(); // Write the estimates of the previous network to the cache. - network_quality_store_.Add(current_network_id_, - nqe::internal::CachedNetworkQuality( - last_effective_connection_type_computation_, - estimated_quality_at_last_main_frame_)); + network_quality_store_.Add( + current_network_id_, + nqe::internal::CachedNetworkQuality( + last_effective_connection_type_computation_, + estimated_quality_at_last_main_frame_, effective_connection_type_)); // Clear the local state. last_connection_change_ = tick_clock_->NowTicks(); @@ -983,6 +984,10 @@ #endif // OS_ANDROID min_signal_strength_since_connection_change_ = INT32_MAX; max_signal_strength_since_connection_change_ = INT32_MIN; + estimated_quality_at_last_main_frame_ = nqe::internal::NetworkQuality(); + effective_connection_type_ = EFFECTIVE_CONNECTION_TYPE_UNKNOWN; + effective_connection_type_at_last_main_frame_ = + EFFECTIVE_CONNECTION_TYPE_UNKNOWN; // Update the local state as part of preparation for the new connection. current_network_id_ = GetCurrentNetworkID(); @@ -1462,6 +1467,16 @@ const base::TimeTicks now = tick_clock_->NowTicks(); + if (effective_connection_type_ == EFFECTIVE_CONNECTION_TYPE_UNKNOWN) { + // Read the effective connection type from the cached estimate. + last_effective_connection_type_computation_ = now; + effective_connection_type_ = + cached_network_quality.effective_connection_type(); + + if (effective_connection_type_ != EFFECTIVE_CONNECTION_TYPE_UNKNOWN) + NotifyObserversOfEffectiveConnectionTypeChanged(); + } + if (cached_network_quality.network_quality().downstream_throughput_kbps() != nqe::internal::kInvalidThroughput) { ThroughputObservation througphput_observation( @@ -1647,10 +1662,14 @@ // last computed or a connection change event was observed since the last // computation. Strict inequalities are used to ensure that effective // connection type is recomputed on connection change events even if the clock - // has not updated. + // has not updated. Recompute the effective connection type if the effective + // connection type was previously unavailable. This is because the RTT + // observations are voluminous, so it may now be possible to compute the + // effective connection type. if (now - last_effective_connection_type_computation_ < effective_connection_type_recomputation_interval_ && - last_connection_change_ < last_effective_connection_type_computation_) { + last_connection_change_ < last_effective_connection_type_computation_ && + effective_connection_type_ != EFFECTIVE_CONNECTION_TYPE_UNKNOWN) { return; } @@ -1670,6 +1689,15 @@ FOR_EACH_OBSERVER( EffectiveConnectionTypeObserver, effective_connection_type_observer_list_, OnEffectiveConnectionTypeChanged(effective_connection_type_)); + + // Add the estimates of the current network to the cache store. + if (effective_connection_type_ != EFFECTIVE_CONNECTION_TYPE_UNKNOWN) { + network_quality_store_.Add( + current_network_id_, + nqe::internal::CachedNetworkQuality( + tick_clock_->NowTicks(), estimated_quality_at_last_main_frame_, + effective_connection_type_)); + } } } // namespace net
diff --git a/net/nqe/network_quality_estimator_unittest.cc b/net/nqe/network_quality_estimator_unittest.cc index 0280fbc..d6917fc 100644 --- a/net/nqe/network_quality_estimator_unittest.cc +++ b/net/nqe/network_quality_estimator_unittest.cc
@@ -490,6 +490,73 @@ 1); } +// Tests that the network quality estimator writes and reads network quality +// from the cache store correctly. +TEST(NetworkQualityEstimatorTest, Caching) { + base::HistogramTester histogram_tester; + std::map<std::string, std::string> variation_params; + TestNetworkQualityEstimator estimator(variation_params); + + estimator.SimulateNetworkChangeTo( + NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test"); + histogram_tester.ExpectUniqueSample("NQE.CachedNetworkQualityAvailable", + false, 1); + + base::TimeDelta rtt; + int32_t kbps; + EXPECT_FALSE(estimator.GetHttpRTTEstimate(&rtt)); + EXPECT_FALSE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); + + TestDelegate test_delegate; + TestURLRequestContext context(true); + context.set_network_quality_estimator(&estimator); + context.Init(); + + // Start two requests so that the network quality is added to cache store at + // the beginning of the second request from the network traffic observed from + // the first request. + for (size_t i = 0; i < 2; ++i) { + std::unique_ptr<URLRequest> request(context.CreateRequest( + estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate)); + request->SetLoadFlags(request->load_flags() | LOAD_MAIN_FRAME); + request->Start(); + base::RunLoop().Run(); + } + + base::RunLoop().RunUntilIdle(); + + // Both RTT and downstream throughput should be updated. + EXPECT_TRUE(estimator.GetHttpRTTEstimate(&rtt)); + EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); + EXPECT_NE(EFFECTIVE_CONNECTION_TYPE_UNKNOWN, + estimator.GetEffectiveConnectionType()); + EXPECT_FALSE(estimator.GetTransportRTTEstimate(&rtt)); + + histogram_tester.ExpectBucketCount("NQE.CachedNetworkQualityAvailable", false, + 1); + + // Add the observers before changing the network type. + TestEffectiveConnectionTypeObserver observer; + estimator.AddEffectiveConnectionTypeObserver(&observer); + TestRTTObserver rtt_observer; + estimator.AddRTTObserver(&rtt_observer); + TestThroughputObserver throughput_observer; + estimator.AddThroughputObserver(&throughput_observer); + + estimator.SimulateNetworkChangeTo( + NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test"); + histogram_tester.ExpectBucketCount("NQE.CachedNetworkQualityAvailable", true, + 1); + histogram_tester.ExpectTotalCount("NQE.CachedNetworkQualityAvailable", 2); + base::RunLoop().RunUntilIdle(); + + // Verify that the cached network quality was read, and observers were + // notified. + EXPECT_EQ(1U, observer.effective_connection_types().size()); + EXPECT_EQ(1U, rtt_observer.observations().size()); + EXPECT_EQ(1U, throughput_observer.observations().size()); +} + TEST(NetworkQualityEstimatorTest, StoreObservations) { std::map<std::string, std::string> variation_params; TestNetworkQualityEstimator estimator(variation_params);
diff --git a/net/nqe/network_quality_store_unittest.cc b/net/nqe/network_quality_store_unittest.cc index d880720..5a17e63 100644 --- a/net/nqe/network_quality_store_unittest.cc +++ b/net/nqe/network_quality_store_unittest.cc
@@ -9,6 +9,7 @@ #include "base/time/time.h" #include "net/base/network_change_notifier.h" #include "net/nqe/cached_network_quality.h" +#include "net/nqe/effective_connection_type.h" #include "net/nqe/network_id.h" #include "testing/gtest/include/gtest/gtest.h" @@ -24,16 +25,14 @@ const nqe::internal::CachedNetworkQuality cached_network_quality_2g_test1( tick_clock.NowTicks(), nqe::internal::NetworkQuality(base::TimeDelta::FromSeconds(1), - base::TimeDelta::FromSeconds(1), 1)); + base::TimeDelta::FromSeconds(1), 1), + EFFECTIVE_CONNECTION_TYPE_2G); { // Entry will be added for (2G, "test1"). nqe::internal::NetworkID network_id(NetworkChangeNotifier::CONNECTION_2G, "test1"); - nqe::internal::CachedNetworkQuality read_network_quality( - tick_clock.NowTicks(), - nqe::internal::NetworkQuality(base::TimeDelta::FromSeconds(0), - base::TimeDelta::FromSeconds(0), 0)); + nqe::internal::CachedNetworkQuality read_network_quality; network_quality_store.Add(network_id, cached_network_quality_2g_test1); EXPECT_TRUE( network_quality_store.GetById(network_id, &read_network_quality)); @@ -45,14 +44,12 @@ // Entry will be added for (2G, "test2"). nqe::internal::NetworkID network_id(NetworkChangeNotifier::CONNECTION_2G, "test2"); - nqe::internal::CachedNetworkQuality read_network_quality( - tick_clock.NowTicks(), - nqe::internal::NetworkQuality(base::TimeDelta::FromSeconds(0), - base::TimeDelta::FromSeconds(0), 0)); + nqe::internal::CachedNetworkQuality read_network_quality; nqe::internal::CachedNetworkQuality cached_network_quality( tick_clock.NowTicks(), nqe::internal::NetworkQuality(base::TimeDelta::FromSeconds(2), - base::TimeDelta::FromSeconds(2), 2)); + base::TimeDelta::FromSeconds(2), 2), + EFFECTIVE_CONNECTION_TYPE_2G); network_quality_store.Add(network_id, cached_network_quality); EXPECT_TRUE( network_quality_store.GetById(network_id, &read_network_quality)); @@ -64,14 +61,12 @@ // Entry will be added for (3G, "test3"). nqe::internal::NetworkID network_id(NetworkChangeNotifier::CONNECTION_3G, "test3"); - nqe::internal::CachedNetworkQuality read_network_quality( - tick_clock.NowTicks(), - nqe::internal::NetworkQuality(base::TimeDelta::FromSeconds(0), - base::TimeDelta::FromSeconds(0), 0)); + nqe::internal::CachedNetworkQuality read_network_quality; nqe::internal::CachedNetworkQuality cached_network_quality( tick_clock.NowTicks(), nqe::internal::NetworkQuality(base::TimeDelta::FromSeconds(3), - base::TimeDelta::FromSeconds(3), 3)); + base::TimeDelta::FromSeconds(3), 3), + EFFECTIVE_CONNECTION_TYPE_3G); network_quality_store.Add(network_id, cached_network_quality); EXPECT_TRUE( network_quality_store.GetById(network_id, &read_network_quality)); @@ -83,14 +78,12 @@ // Entry will not be added for (Unknown, ""). nqe::internal::NetworkID network_id( NetworkChangeNotifier::CONNECTION_UNKNOWN, ""); - nqe::internal::CachedNetworkQuality read_network_quality( - tick_clock.NowTicks(), - nqe::internal::NetworkQuality(base::TimeDelta::FromSeconds(0), - base::TimeDelta::FromSeconds(0), 0)); + nqe::internal::CachedNetworkQuality read_network_quality; nqe::internal::CachedNetworkQuality set_network_quality( tick_clock.NowTicks(), nqe::internal::NetworkQuality(base::TimeDelta::FromSeconds(4), - base::TimeDelta::FromSeconds(4), 4)); + base::TimeDelta::FromSeconds(4), 4), + EFFECTIVE_CONNECTION_TYPE_4G); network_quality_store.Add(network_id, set_network_quality); EXPECT_FALSE( network_quality_store.GetById(network_id, &read_network_quality)); @@ -100,10 +93,7 @@ // Existing entry will be read for (2G, "test1"). nqe::internal::NetworkID network_id(NetworkChangeNotifier::CONNECTION_2G, "test1"); - nqe::internal::CachedNetworkQuality read_network_quality( - tick_clock.NowTicks(), - nqe::internal::NetworkQuality(base::TimeDelta::FromSeconds(0), - base::TimeDelta::FromSeconds(0), 0)); + nqe::internal::CachedNetworkQuality read_network_quality; EXPECT_TRUE( network_quality_store.GetById(network_id, &read_network_quality)); EXPECT_EQ(cached_network_quality_2g_test1.network_quality(), @@ -114,14 +104,12 @@ // Existing entry will be overwritten for (2G, "test1"). nqe::internal::NetworkID network_id(NetworkChangeNotifier::CONNECTION_2G, "test1"); - nqe::internal::CachedNetworkQuality read_network_quality( - tick_clock.NowTicks(), - nqe::internal::NetworkQuality(base::TimeDelta::FromSeconds(0), - base::TimeDelta::FromSeconds(0), 0)); + nqe::internal::CachedNetworkQuality read_network_quality; const nqe::internal::CachedNetworkQuality cached_network_quality( tick_clock.NowTicks(), nqe::internal::NetworkQuality(base::TimeDelta::FromSeconds(5), - base::TimeDelta::FromSeconds(5), 5)); + base::TimeDelta::FromSeconds(5), 5), + EFFECTIVE_CONNECTION_TYPE_4G); network_quality_store.Add(network_id, cached_network_quality); EXPECT_TRUE( network_quality_store.GetById(network_id, &read_network_quality)); @@ -133,10 +121,7 @@ // No entry should exist for (2G, "test4"). nqe::internal::NetworkID network_id(NetworkChangeNotifier::CONNECTION_2G, "test4"); - nqe::internal::CachedNetworkQuality read_network_quality( - tick_clock.NowTicks(), - nqe::internal::NetworkQuality(base::TimeDelta::FromSeconds(0), - base::TimeDelta::FromSeconds(0), 0)); + nqe::internal::CachedNetworkQuality read_network_quality; EXPECT_FALSE( network_quality_store.GetById(network_id, &read_network_quality)); } @@ -154,7 +139,8 @@ nqe::internal::CachedNetworkQuality read_network_quality( tick_clock.NowTicks(), nqe::internal::NetworkQuality(base::TimeDelta::FromSeconds(0), - base::TimeDelta::FromSeconds(0), 0)); + base::TimeDelta::FromSeconds(0), 0), + EFFECTIVE_CONNECTION_TYPE_2G); for (size_t i = 0; i < network_count; ++i) { nqe::internal::NetworkID network_id(NetworkChangeNotifier::CONNECTION_2G, @@ -163,7 +149,8 @@ const nqe::internal::CachedNetworkQuality network_quality( tick_clock.NowTicks(), nqe::internal::NetworkQuality(base::TimeDelta::FromSeconds(1), - base::TimeDelta::FromSeconds(1), 1)); + base::TimeDelta::FromSeconds(1), 1), + EFFECTIVE_CONNECTION_TYPE_2G); network_quality_store.Add(network_id, network_quality); tick_clock.Advance(base::TimeDelta::FromSeconds(1)); } @@ -177,7 +164,8 @@ nqe::internal::CachedNetworkQuality read_network_quality( tick_clock.NowTicks(), nqe::internal::NetworkQuality(base::TimeDelta::FromSeconds(0), - base::TimeDelta::FromSeconds(0), 0)); + base::TimeDelta::FromSeconds(0), 0), + EFFECTIVE_CONNECTION_TYPE_2G); if (network_quality_store.GetById(network_id, &read_network_quality)) { cache_match_count++; earliest_last_update_time = std::min(
diff --git a/net/quic/chromium/bidirectional_stream_quic_impl.cc b/net/quic/chromium/bidirectional_stream_quic_impl.cc index 3f25286e..d115e40 100644 --- a/net/quic/chromium/bidirectional_stream_quic_impl.cc +++ b/net/quic/chromium/bidirectional_stream_quic_impl.cc
@@ -42,7 +42,11 @@ } BidirectionalStreamQuicImpl::~BidirectionalStreamQuicImpl() { - Cancel(); + if (stream_) { + delegate_ = nullptr; + stream_->Reset(QUIC_STREAM_CANCELLED); + } + if (session_) session_->RemoveObserver(this); } @@ -195,18 +199,6 @@ } } -void BidirectionalStreamQuicImpl::Cancel() { - if (delegate_) { - delegate_ = nullptr; - // Cancel any pending callbacks. - weak_factory_.InvalidateWeakPtrs(); - } - if (stream_) { - stream_->Reset(QUIC_STREAM_CANCELLED); - ResetStream(); - } -} - NextProto BidirectionalStreamQuicImpl::GetProtocol() const { return negotiated_protocol_; }
diff --git a/net/quic/chromium/bidirectional_stream_quic_impl.h b/net/quic/chromium/bidirectional_stream_quic_impl.h index cb8e24b..25e2bac 100644 --- a/net/quic/chromium/bidirectional_stream_quic_impl.h +++ b/net/quic/chromium/bidirectional_stream_quic_impl.h
@@ -51,7 +51,6 @@ void SendvData(const std::vector<scoped_refptr<IOBuffer>>& buffers, const std::vector<int>& lengths, bool end_stream) override; - void Cancel() override; NextProto GetProtocol() const override; int64_t GetTotalReceivedBytes() const override; int64_t GetTotalSentBytes() const override;
diff --git a/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc b/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc index 27e43081..754bf4a 100644 --- a/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc +++ b/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc
@@ -69,6 +69,9 @@ read_buf_len_(read_buf_len), timer_(std::move(timer)), loop_(nullptr), + next_proto_(kProtoUnknown), + received_bytes_(0), + sent_bytes_(0), error_(OK), on_data_read_count_(0), on_data_sent_count_(0), @@ -180,21 +183,36 @@ return rv; } - // Cancels |stream_|. - void CancelStream() { stream_->Cancel(); } - - NextProto GetProtocol() const { return stream_->GetProtocol(); } - - int64_t GetTotalReceivedBytes() const { - return stream_->GetTotalReceivedBytes(); + NextProto GetProtocol() const { + if (stream_) + return stream_->GetProtocol(); + return next_proto_; } - int64_t GetTotalSentBytes() const { return stream_->GetTotalSentBytes(); } + int64_t GetTotalReceivedBytes() const { + if (stream_) + return stream_->GetTotalReceivedBytes(); + return received_bytes_; + } + + int64_t GetTotalSentBytes() const { + if (stream_) + return stream_->GetTotalSentBytes(); + return sent_bytes_; + } void DoNotSendRequestHeadersAutomatically() { send_request_headers_automatically_ = false; } + // Deletes |stream_|. + void DeleteStream() { + next_proto_ = stream_->GetProtocol(); + received_bytes_ = stream_->GetTotalReceivedBytes(); + sent_bytes_ = stream_->GetTotalSentBytes(); + stream_.reset(); + } + // Const getters for internal states. const std::string& data_received() const { return data_received_; } int error() const { return error_; } @@ -209,9 +227,6 @@ // Quits |loop_|. void QuitLoop() { loop_->Quit(); } - // Deletes |stream_|. - void DeleteStream() { stream_.reset(); } - private: std::unique_ptr<BidirectionalStreamQuicImpl> stream_; scoped_refptr<IOBuffer> read_buf_; @@ -221,6 +236,9 @@ std::unique_ptr<base::RunLoop> loop_; SpdyHeaderBlock response_headers_; SpdyHeaderBlock trailers_; + NextProto next_proto_; + int64_t received_bytes_; + int64_t sent_bytes_; int error_; int on_data_read_count_; int on_data_sent_count_; @@ -1343,68 +1361,6 @@ delegate->GetTotalReceivedBytes()); } -TEST_P(BidirectionalStreamQuicImplTest, CancelStreamAfterSendData) { - SetRequest("POST", "/", DEFAULT_PRIORITY); - size_t spdy_request_headers_frame_length; - AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY, - &spdy_request_headers_frame_length)); - AddWrite(ConstructAckAndDataPacket(2, !kIncludeVersion, 2, 1, !kFin, 0, - kUploadData, &client_maker_)); - AddWrite(ConstructRstStreamCancelledPacket(3, strlen(kUploadData), - &client_maker_)); - - Initialize(); - - BidirectionalStreamRequestInfo request; - request.method = "POST"; - request.url = GURL("http://www.google.com/"); - request.end_stream_on_headers = false; - request.priority = DEFAULT_PRIORITY; - - scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize)); - std::unique_ptr<TestDelegateBase> delegate( - new TestDelegateBase(read_buffer.get(), kReadBufferSize)); - delegate->Start(&request, net_log().bound(), session()->GetWeakPtr()); - ConfirmHandshake(); - delegate->WaitUntilNextCallback(); // OnStreamReady - - // Server acks the request. - ProcessPacket(ConstructServerAckPacket(1, 0, 0)); - - // Server sends the response headers. - SpdyHeaderBlock response_headers = ConstructResponseHeaders("200"); - size_t spdy_response_headers_frame_length; - ProcessPacket( - ConstructResponseHeadersPacket(2, !kFin, std::move(response_headers), - &spdy_response_headers_frame_length, 0)); - - delegate->WaitUntilNextCallback(); // OnHeadersReceived - EXPECT_EQ("200", delegate->response_headers().find(":status")->second); - - // Send a DATA frame. - scoped_refptr<StringIOBuffer> buf(new StringIOBuffer(kUploadData)); - - delegate->SendData(buf, buf->size(), false); - delegate->WaitUntilNextCallback(); // OnDataSent - - delegate->CancelStream(); - base::RunLoop().RunUntilIdle(); - - // Try to send data after Cancel(), should not get called back. - delegate->SendData(buf, buf->size(), false); - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(delegate->on_failed_called()); - - EXPECT_EQ(0, delegate->on_data_read_count()); - EXPECT_EQ(1, delegate->on_data_sent_count()); - EXPECT_EQ(kProtoQUIC1SPDY3, delegate->GetProtocol()); - EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length + - strlen(kUploadData)), - delegate->GetTotalSentBytes()); - EXPECT_EQ(static_cast<int64_t>(spdy_response_headers_frame_length), - delegate->GetTotalReceivedBytes()); -} - TEST_P(BidirectionalStreamQuicImplTest, SessionClosedBeforeReadData) { SetRequest("POST", "/", DEFAULT_PRIORITY); size_t spdy_request_headers_frame_length; @@ -1462,7 +1418,7 @@ delegate->GetTotalReceivedBytes()); } -TEST_P(BidirectionalStreamQuicImplTest, CancelStreamAfterReadData) { +TEST_P(BidirectionalStreamQuicImplTest, DeleteStreamAfterReadData) { SetRequest("POST", "/", DEFAULT_PRIORITY); size_t spdy_request_headers_frame_length; AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY, @@ -1500,7 +1456,7 @@ // Cancel the stream after ReadData returns ERR_IO_PENDING. TestCompletionCallback cb; EXPECT_THAT(delegate->ReadData(cb.callback()), IsError(ERR_IO_PENDING)); - delegate->CancelStream(); + delegate->DeleteStream(); base::RunLoop().RunUntilIdle();
diff --git a/net/quic/chromium/quic_chromium_packet_writer.cc b/net/quic/chromium/quic_chromium_packet_writer.cc index 7a69415..0494d44 100644 --- a/net/quic/chromium/quic_chromium_packet_writer.cc +++ b/net/quic/chromium/quic_chromium_packet_writer.cc
@@ -99,6 +99,8 @@ void QuicChromiumPacketWriter::OnWriteComplete(int rv) { DCHECK_NE(rv, ERR_IO_PENDING); + DCHECK(connection_) << "Uninitialized connection."; + DCHECK(observer_) << "Uninitialized observer."; write_blocked_ = false; if (rv < 0) { // If write error, then call into the observer's OnWriteError,
diff --git a/net/quic/chromium/quic_stream_factory.cc b/net/quic/chromium/quic_stream_factory.cc index a805a87a..5cd80d1 100644 --- a/net/quic/chromium/quic_stream_factory.cc +++ b/net/quic/chromium/quic_stream_factory.cc
@@ -1626,10 +1626,10 @@ DatagramSocket::DEFAULT_BIND, RandIntCallback(), session->net_log().net_log(), session->net_log().source())); if (ConfigureSocket(socket.get(), peer_address, network) != OK) { - session->CloseSessionOnError(ERR_NETWORK_CHANGED, QUIC_INTERNAL_ERROR); HistogramAndLogMigrationFailure( bound_net_log, MIGRATION_STATUS_INTERNAL_ERROR, session->connection_id(), "Socket configuration failed"); + session->CloseSessionOnError(ERR_NETWORK_CHANGED, QUIC_INTERNAL_ERROR); return; } std::unique_ptr<QuicChromiumPacketReader> new_reader( @@ -1638,6 +1638,7 @@ session->net_log())); std::unique_ptr<QuicChromiumPacketWriter> new_writer( new QuicChromiumPacketWriter(socket.get())); + new_writer->Initialize(session, session->connection()); if (!session->MigrateToSocket(std::move(socket), std::move(new_reader), std::move(new_writer), packet)) { @@ -1987,7 +1988,7 @@ // touches quic_server_info_map. const QuicServerInfoMap& quic_server_info_map = http_server_properties_->quic_server_info_map(); - std::vector<QuicServerId> server_list(quic_server_info_map.size()); + std::vector<QuicServerId> server_list; for (const auto& key_value : quic_server_info_map) server_list.push_back(key_value.first); for (auto it = server_list.rbegin(); it != server_list.rend(); ++it) {
diff --git a/net/quic/chromium/quic_stream_factory_test.cc b/net/quic/chromium/quic_stream_factory_test.cc index 165bb0e..d8abc7f2 100644 --- a/net/quic/chromium/quic_stream_factory_test.cc +++ b/net/quic/chromium/quic_stream_factory_test.cc
@@ -2257,6 +2257,138 @@ EXPECT_TRUE(socket_data2.AllWriteDataConsumed()); } +TEST_P(QuicStreamFactoryTest, MigrateSessionEarlyWithAsyncWrites) { + // Nearly identical to MigrateSessionEarly except that the write to + // the second socket is asynchronous. Ensures that the callback + // infrastructure for asynchronous writes is set up correctly for + // the old connection on the migrated socket. + InitializeConnectionMigrationTest( + {kDefaultNetworkForTests, kNewNetworkForTests}); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + + MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; + std::unique_ptr<QuicEncryptedPacket> request_packet( + ConstructGetRequestPacket(1, kClientDataStreamId1, true, true)); + MockWrite writes[] = {MockWrite(SYNCHRONOUS, request_packet->data(), + request_packet->length(), 1)}; + SequencedSocketData socket_data(reads, arraysize(reads), writes, + arraysize(writes)); + socket_factory_.AddSocketDataProvider(&socket_data); + + // Create request and QuicHttpStream. + QuicStreamRequest request(factory_.get()); + EXPECT_EQ(ERR_IO_PENDING, + request.Request(host_port_pair_, privacy_mode_, + /*cert_verify_flags=*/0, url_, "GET", net_log_, + callback_.callback())); + EXPECT_THAT(callback_.WaitForResult(), IsOk()); + std::unique_ptr<QuicHttpStream> stream = request.CreateStream(); + EXPECT_TRUE(stream.get()); + + // Cause QUIC stream to be created. + HttpRequestInfo request_info; + request_info.method = "GET"; + request_info.url = url_; + EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + net_log_, CompletionCallback())); + + // Ensure that session is alive and active. + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); + EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); + EXPECT_TRUE(HasActiveSession(host_port_pair_)); + + // Send GET request on stream. + HttpResponseInfo response; + HttpRequestHeaders request_headers; + EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, + callback_.callback())); + + // Set up second socket data provider that is used after migration. + // The response to the earlier request is read on this new socket. + std::unique_ptr<QuicEncryptedPacket> ping( + client_maker_.MakePingPacket(2, /*include_version=*/true)); + std::unique_ptr<QuicEncryptedPacket> client_rst( + client_maker_.MakeAckAndRstPacket(3, false, kClientDataStreamId1, + QUIC_STREAM_CANCELLED, 1, 1, 1, true)); + MockWrite writes1[] = { + MockWrite(ASYNC, ping->data(), ping->length(), 0), + MockWrite(SYNCHRONOUS, client_rst->data(), client_rst->length(), 3)}; + std::unique_ptr<QuicEncryptedPacket> response_headers_packet( + ConstructOkResponsePacket(1, kClientDataStreamId1, false, false)); + MockRead reads1[] = {MockRead(ASYNC, response_headers_packet->data(), + response_headers_packet->length(), 1), + MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2)}; + SequencedSocketData socket_data1(reads1, arraysize(reads1), writes1, + arraysize(writes1)); + socket_factory_.AddSocketDataProvider(&socket_data1); + + // Trigger early connection migration. This should cause a PING frame + // to be emitted. + session->OnPathDegrading(); + + // Run the message loop so that data queued in the new socket is read by the + // packet reader. + base::RunLoop().RunUntilIdle(); + + // The session should now be marked as going away. Ensure that + // while it is still alive, it is no longer active. + EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); + EXPECT_FALSE(HasActiveSession(host_port_pair_)); + EXPECT_EQ(1u, session->GetNumActiveStreams()); + + // Verify that response headers on the migrated socket were delivered to the + // stream. + EXPECT_THAT(stream->ReadResponseHeaders(callback_.callback()), IsOk()); + EXPECT_EQ(200, response.headers->response_code()); + + // Create a new request for the same destination and verify that a + // new session is created. + MockRead reads2[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; + SequencedSocketData socket_data2(reads2, arraysize(reads2), nullptr, 0); + socket_factory_.AddSocketDataProvider(&socket_data2); + + QuicStreamRequest request2(factory_.get()); + EXPECT_EQ(ERR_IO_PENDING, + request2.Request(host_port_pair_, privacy_mode_, + /*cert_verify_flags=*/0, url_, "GET", net_log_, + callback_.callback())); + EXPECT_THAT(callback_.WaitForResult(), IsOk()); + std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream(); + EXPECT_TRUE(stream2.get()); + + EXPECT_TRUE(HasActiveSession(host_port_pair_)); + QuicChromiumClientSession* new_session = GetActiveSession(host_port_pair_); + EXPECT_NE(session, new_session); + + // On a SOON_TO_DISCONNECT notification, nothing happens to the + // migrated session, but the new session is closed since it has no + // open streams. + scoped_mock_network_change_notifier_->mock_network_change_notifier() + ->NotifyNetworkSoonToDisconnect(kDefaultNetworkForTests); + EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); + EXPECT_EQ(1u, session->GetNumActiveStreams()); + EXPECT_FALSE( + QuicStreamFactoryPeer::IsLiveSession(factory_.get(), new_session)); + + // On a DISCONNECTED notification, nothing happens to the migrated session. + scoped_mock_network_change_notifier_->mock_network_change_notifier() + ->NotifyNetworkDisconnected(kDefaultNetworkForTests); + EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); + EXPECT_EQ(1u, session->GetNumActiveStreams()); + + stream.reset(); + stream2.reset(); + + EXPECT_TRUE(socket_data.AllReadDataConsumed()); + EXPECT_TRUE(socket_data.AllWriteDataConsumed()); + EXPECT_TRUE(socket_data1.AllReadDataConsumed()); + EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); + EXPECT_TRUE(socket_data2.AllReadDataConsumed()); + EXPECT_TRUE(socket_data2.AllWriteDataConsumed()); +} + TEST_P(QuicStreamFactoryTest, MigrateSessionEarlyNoNewNetwork) { InitializeConnectionMigrationTest({kDefaultNetworkForTests}); ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); @@ -2667,6 +2799,70 @@ EXPECT_TRUE(socket_data.AllWriteDataConsumed()); } +TEST_P(QuicStreamFactoryTest, MigrateSessionEarlyToBadSocket) { + // This simulates the case where we attempt to migrate to a new + // socket but the socket is unusable, such as an ipv4/ipv6 mismatch. + InitializeConnectionMigrationTest( + {kDefaultNetworkForTests, kNewNetworkForTests}); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + + MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; + std::unique_ptr<QuicEncryptedPacket> request_packet( + ConstructGetRequestPacket(1, kClientDataStreamId1, true, true)); + MockWrite writes[] = {MockWrite(SYNCHRONOUS, request_packet->data(), + request_packet->length(), 1)}; + SequencedSocketData socket_data(reads, arraysize(reads), writes, + arraysize(writes)); + socket_factory_.AddSocketDataProvider(&socket_data); + + // Create request and QuicHttpStream. + QuicStreamRequest request(factory_.get()); + EXPECT_EQ(ERR_IO_PENDING, + request.Request(host_port_pair_, privacy_mode_, + /*cert_verify_flags=*/0, url_, "GET", net_log_, + callback_.callback())); + EXPECT_THAT(callback_.WaitForResult(), IsOk()); + std::unique_ptr<QuicHttpStream> stream = request.CreateStream(); + EXPECT_TRUE(stream.get()); + + // Cause QUIC stream to be created. + HttpRequestInfo request_info; + request_info.method = "GET"; + request_info.url = url_; + EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY, + net_log_, CompletionCallback())); + + // Ensure that session is alive and active. + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); + EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); + EXPECT_TRUE(HasActiveSession(host_port_pair_)); + + // Send GET request on stream. + HttpResponseInfo response; + HttpRequestHeaders request_headers; + EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, + callback_.callback())); + + // Set up second socket that will immediately return disconnected. + // The stream factory will attempt to migrate to the new socket and + // immediately fail. + MockConnect connect_result = + MockConnect(SYNCHRONOUS, ERR_INTERNET_DISCONNECTED); + SequencedSocketData socket_data1(connect_result, nullptr, 0, nullptr, 0); + socket_factory_.AddSocketDataProvider(&socket_data1); + + // Trigger early connection migration. + session->OnPathDegrading(); + + // Migration fails, and the session is marked as going away. + EXPECT_FALSE(HasActiveSession(host_port_pair_)); + + EXPECT_TRUE(socket_data.AllReadDataConsumed()); + EXPECT_TRUE(socket_data.AllWriteDataConsumed()); +} + TEST_P(QuicStreamFactoryTest, ServerMigration) { allow_server_migration_ = true; Initialize();
diff --git a/net/quic/core/crypto/properties_based_quic_server_info.cc b/net/quic/core/crypto/properties_based_quic_server_info.cc index 6fd9b241..0ab4f6ce 100644 --- a/net/quic/core/crypto/properties_based_quic_server_info.cc +++ b/net/quic/core/crypto/properties_based_quic_server_info.cc
@@ -5,11 +5,29 @@ #include "net/quic/core/crypto/properties_based_quic_server_info.h" #include "base/base64.h" +#include "base/metrics/histogram_macros.h" #include "net/base/net_errors.h" #include "net/http/http_server_properties.h" using std::string; +namespace { + +void RecordQuicServerInfoStatus( + net::QuicServerInfo::QuicServerInfoAPICall call) { + UMA_HISTOGRAM_ENUMERATION( + "Net.QuicDiskCache.APICall.PropertiesBasedCache", call, + net::QuicServerInfo::QUIC_SERVER_INFO_NUM_OF_API_CALLS); +} + +void RecordQuicServerInfoFailure(net::QuicServerInfo::FailureReason failure) { + UMA_HISTOGRAM_ENUMERATION( + "Net.QuicDiskCache.FailureReason.PropertiesBasedCache", failure, + net::QuicServerInfo::NUM_OF_FAILURES); +} + +} // namespace + namespace net { PropertiesBasedQuicServerInfo::PropertiesBasedQuicServerInfo( @@ -22,37 +40,58 @@ PropertiesBasedQuicServerInfo::~PropertiesBasedQuicServerInfo() {} -void PropertiesBasedQuicServerInfo::Start() {} +void PropertiesBasedQuicServerInfo::Start() { + RecordQuicServerInfoStatus(QUIC_SERVER_INFO_START); +} int PropertiesBasedQuicServerInfo::WaitForDataReady( const CompletionCallback& callback) { + RecordQuicServerInfoStatus(QUIC_SERVER_INFO_WAIT_FOR_DATA_READY); const string* data = http_server_properties_->GetQuicServerInfo(server_id_); string decoded; - if (!data || !base::Base64Decode(*data, &decoded) || !Parse(decoded)) { + if (!data) { + RecordQuicServerInfoFailure(PARSE_NO_DATA_FAILURE); + return ERR_FAILED; + } + if (!base::Base64Decode(*data, &decoded)) { + RecordQuicServerInfoFailure(PARSE_DATA_DECODE_FAILURE); + return ERR_FAILED; + } + RecordQuicServerInfoStatus(QUIC_SERVER_INFO_PARSE); + if (!Parse(decoded)) { + RecordQuicServerInfoFailure(PARSE_FAILURE); return ERR_FAILED; } return OK; } -void PropertiesBasedQuicServerInfo::ResetWaitForDataReadyCallback() {} +void PropertiesBasedQuicServerInfo::ResetWaitForDataReadyCallback() { + RecordQuicServerInfoStatus(QUIC_SERVER_INFO_RESET_WAIT_FOR_DATA_READY); +} -void PropertiesBasedQuicServerInfo::CancelWaitForDataReadyCallback() {} +void PropertiesBasedQuicServerInfo::CancelWaitForDataReadyCallback() { + RecordQuicServerInfoStatus(QUIC_SERVER_INFO_WAIT_FOR_DATA_READY_CANCEL); +} bool PropertiesBasedQuicServerInfo::IsDataReady() { return true; } bool PropertiesBasedQuicServerInfo::IsReadyToPersist() { + RecordQuicServerInfoStatus(QUIC_SERVER_INFO_READY_TO_PERSIST); return true; } void PropertiesBasedQuicServerInfo::Persist() { + RecordQuicServerInfoStatus(QUIC_SERVER_INFO_PERSIST); string encoded; base::Base64Encode(Serialize(), &encoded); http_server_properties_->SetQuicServerInfo(server_id_, encoded); } -void PropertiesBasedQuicServerInfo::OnExternalCacheHit() {} +void PropertiesBasedQuicServerInfo::OnExternalCacheHit() { + RecordQuicServerInfoStatus(QUIC_SERVER_INFO_EXTERNAL_CACHE_HIT); +} PropertiesBasedQuicServerInfoFactory::PropertiesBasedQuicServerInfoFactory( HttpServerProperties* http_server_properties)
diff --git a/net/quic/core/crypto/quic_server_info.h b/net/quic/core/crypto/quic_server_info.h index a6091f8..12c807ee 100644 --- a/net/quic/core/crypto/quic_server_info.h +++ b/net/quic/core/crypto/quic_server_info.h
@@ -26,6 +26,38 @@ // crypto config. class NET_EXPORT_PRIVATE QuicServerInfo { public: + // Enum to track number of times data read/parse/write API calls of + // QuicServerInfo to and from disk cache is called. + enum QuicServerInfoAPICall { + QUIC_SERVER_INFO_START = 0, + QUIC_SERVER_INFO_WAIT_FOR_DATA_READY = 1, + QUIC_SERVER_INFO_PARSE = 2, + QUIC_SERVER_INFO_WAIT_FOR_DATA_READY_CANCEL = 3, + QUIC_SERVER_INFO_READY_TO_PERSIST = 4, + QUIC_SERVER_INFO_PERSIST = 5, + QUIC_SERVER_INFO_EXTERNAL_CACHE_HIT = 6, + QUIC_SERVER_INFO_RESET_WAIT_FOR_DATA_READY = 7, + QUIC_SERVER_INFO_NUM_OF_API_CALLS = 8, + }; + + // Enum to track failure reasons to read/load/write of QuicServerInfo to + // and from disk cache. + enum FailureReason { + WAIT_FOR_DATA_READY_INVALID_ARGUMENT_FAILURE = 0, + GET_BACKEND_FAILURE = 1, + OPEN_FAILURE = 2, + CREATE_OR_OPEN_FAILURE = 3, + PARSE_NO_DATA_FAILURE = 4, + PARSE_FAILURE = 5, + READ_FAILURE = 6, + READY_TO_PERSIST_FAILURE = 7, + PERSIST_NO_BACKEND_FAILURE = 8, + WRITE_FAILURE = 9, + NO_FAILURE = 10, + PARSE_DATA_DECODE_FAILURE = 11, + NUM_OF_FAILURES = 12, + }; + explicit QuicServerInfo(const QuicServerId& server_id); virtual ~QuicServerInfo();
diff --git a/net/quic/core/spdy_utils.cc b/net/quic/core/spdy_utils.cc index 6ca66684..c6d6666 100644 --- a/net/quic/core/spdy_utils.cc +++ b/net/quic/core/spdy_utils.cc
@@ -121,6 +121,12 @@ return false; } + if (std::any_of(name.begin(), name.end(), base::IsAsciiUpper<char>)) { + DVLOG(1) << "Malformed header: Header name " << name + << " contains upper-case characters."; + return false; + } + if (FLAGS_chromium_http2_flag_use_new_spdy_header_block_header_joining) { headers->AppendValueOrAddHeader(name, p.second); } else {
diff --git a/net/quic/core/spdy_utils_test.cc b/net/quic/core/spdy_utils_test.cc index 3d626089..64fd745 100644 --- a/net/quic/core/spdy_utils_test.cc +++ b/net/quic/core/spdy_utils_test.cc
@@ -198,6 +198,15 @@ SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block)); } +TEST(SpdyUtilsTest, CopyAndValidateHeadersUpperCaseName) { + auto headers = + FromList({{"foo", "foovalue"}, {"bar", "barvalue"}, {"bAz", ""}}); + int64_t content_length = -1; + SpdyHeaderBlock block; + ASSERT_FALSE( + SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block)); +} + TEST(SpdyUtilsTest, CopyAndValidateHeadersMultipleContentLengths) { auto headers = FromList({{"content-length", "9"}, {"foo", "foovalue"},
diff --git a/net/quic/test_tools/quic_test_packet_maker.cc b/net/quic/test_tools/quic_test_packet_maker.cc index ee32f1b..b12a99f8 100644 --- a/net/quic/test_tools/quic_test_packet_maker.cc +++ b/net/quic/test_tools/quic_test_packet_maker.cc
@@ -629,7 +629,7 @@ const std::string& alt_svc) { SpdyHeaderBlock headers; headers[":status"] = status; - headers["Alt-Svc"] = alt_svc; + headers["alt-svc"] = alt_svc; headers["content-type"] = "text/plain"; return headers; }
diff --git a/net/spdy/bidirectional_stream_spdy_impl.cc b/net/spdy/bidirectional_stream_spdy_impl.cc index 4f11cdf..66050fe 100644 --- a/net/spdy/bidirectional_stream_spdy_impl.cc +++ b/net/spdy/bidirectional_stream_spdy_impl.cc
@@ -41,7 +41,8 @@ weak_factory_(this) {} BidirectionalStreamSpdyImpl::~BidirectionalStreamSpdyImpl() { - Cancel(); + // Sends a RST to the remote if the stream is destroyed before it completes. + ResetStream(); } void BidirectionalStreamSpdyImpl::Start( @@ -151,15 +152,6 @@ end_stream ? NO_MORE_DATA_TO_SEND : MORE_DATA_TO_SEND); } -void BidirectionalStreamSpdyImpl::Cancel() { - if (delegate_) { - delegate_ = nullptr; - // Cancel any pending callback. - weak_factory_.InvalidateWeakPtrs(); - } - ResetStream(); -} - NextProto BidirectionalStreamSpdyImpl::GetProtocol() const { return negotiated_protocol_; }
diff --git a/net/spdy/bidirectional_stream_spdy_impl.h b/net/spdy/bidirectional_stream_spdy_impl.h index b40c1ff..e9e1a05 100644 --- a/net/spdy/bidirectional_stream_spdy_impl.h +++ b/net/spdy/bidirectional_stream_spdy_impl.h
@@ -53,7 +53,6 @@ void SendvData(const std::vector<scoped_refptr<IOBuffer>>& buffers, const std::vector<int>& lengths, bool end_stream) override; - void Cancel() override; NextProto GetProtocol() const override; int64_t GetTotalReceivedBytes() const override; int64_t GetTotalSentBytes() const override;
diff --git a/net/spdy/bidirectional_stream_spdy_impl_unittest.cc b/net/spdy/bidirectional_stream_spdy_impl_unittest.cc index 975ef39d..574ad3d 100644 --- a/net/spdy/bidirectional_stream_spdy_impl_unittest.cc +++ b/net/spdy/bidirectional_stream_spdy_impl_unittest.cc
@@ -50,6 +50,8 @@ read_buf_(read_buf), read_buf_len_(read_buf_len), loop_(nullptr), + received_bytes_(0), + sent_bytes_(0), error_(OK), bytes_read_(0), on_data_read_count_(0), @@ -159,10 +161,16 @@ NextProto GetProtocol() const { return stream_->GetProtocol(); } int64_t GetTotalReceivedBytes() const { - return stream_->GetTotalReceivedBytes(); + if (stream_) + return stream_->GetTotalReceivedBytes(); + return received_bytes_; } - int64_t GetTotalSentBytes() const { return stream_->GetTotalSentBytes(); } + int64_t GetTotalSentBytes() const { + if (stream_) + return stream_->GetTotalSentBytes(); + return sent_bytes_; + } // Const getters for internal states. const std::string& data_received() const { return data_received_; } @@ -179,8 +187,7 @@ do_not_start_read_ = do_not_start_read; } - // Cancels |stream_|. - void CancelStream() { stream_->Cancel(); } + void DeleteStream() { stream_.reset(); } private: std::unique_ptr<BidirectionalStreamSpdyImpl> stream_; @@ -190,6 +197,8 @@ std::unique_ptr<base::RunLoop> loop_; SpdyHeaderBlock response_headers_; SpdyHeaderBlock trailers_; + int64_t received_bytes_; + int64_t sent_bytes_; int error_; int bytes_read_; int on_data_read_count_; @@ -304,70 +313,4 @@ delegate->GetTotalReceivedBytes()); } -TEST_F(BidirectionalStreamSpdyImplTest, SendDataAfterCancelStream) { - SpdySerializedFrame req(spdy_util_.ConstructSpdyPost( - kDefaultUrl, 1, kBodyDataSize * 3, LOWEST, nullptr, 0)); - SpdySerializedFrame data_frame( - spdy_util_.ConstructSpdyDataFrame(1, kBodyData, kBodyDataSize, - /*fin=*/false)); - SpdySerializedFrame rst( - spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL)); - - MockWrite writes[] = { - CreateMockWrite(req, 0), CreateMockWrite(data_frame, 3), - CreateMockWrite(rst, 5), - }; - - SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); - SpdySerializedFrame response_body_frame( - spdy_util_.ConstructSpdyDataFrame(1, false)); - - MockRead reads[] = { - CreateMockRead(resp, 1), - MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause. - MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause. - MockRead(ASYNC, 0, 6), - }; - - InitSession(reads, arraysize(reads), writes, arraysize(writes)); - - BidirectionalStreamRequestInfo request_info; - request_info.method = "POST"; - request_info.url = default_url_; - request_info.priority = LOWEST; - request_info.extra_headers.SetHeader(net::HttpRequestHeaders::kContentLength, - base::SizeTToString(kBodyDataSize * 3)); - - scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize)); - std::unique_ptr<TestDelegateBase> delegate( - new TestDelegateBase(session_, read_buffer.get(), kReadBufferSize)); - delegate->set_do_not_start_read(true); - delegate->Start(&request_info, net_log_.bound()); - // Send the request and receive response headers. - sequenced_data_->RunUntilPaused(); - EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol()); - - // Send a DATA frame. - scoped_refptr<StringIOBuffer> buf( - new StringIOBuffer(std::string(kBodyData, kBodyDataSize))); - delegate->SendData(buf.get(), buf->size(), false); - sequenced_data_->Resume(); - base::RunLoop().RunUntilIdle(); - // Cancel the stream. - delegate->CancelStream(); - sequenced_data_->Resume(); - base::RunLoop().RunUntilIdle(); - - // Try to send data after Cancel(), should not get called back. - delegate->SendData(buf.get(), buf->size(), false); - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(delegate->on_failed_called()); - - EXPECT_EQ("200", delegate->response_headers().find(":status")->second); - EXPECT_EQ(0, delegate->on_data_read_count()); - EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol()); - EXPECT_EQ(0, delegate->GetTotalSentBytes()); - EXPECT_EQ(0, delegate->GetTotalReceivedBytes()); -} - } // namespace net
diff --git a/net/spdy/hpack/hpack_encoder.cc b/net/spdy/hpack/hpack_encoder.cc index 85610ef5..d642c3f0 100644 --- a/net/spdy/hpack/hpack_encoder.cc +++ b/net/spdy/hpack/hpack_encoder.cc
@@ -18,18 +18,78 @@ using base::StringPiece; using std::string; +class HpackEncoder::RepresentationIterator { + public: + // |pseudo_headers| and |regular_headers| must outlive the iterator. + RepresentationIterator(const Representations& pseudo_headers, + const Representations& regular_headers) + : pseudo_begin_(pseudo_headers.begin()), + pseudo_end_(pseudo_headers.end()), + regular_begin_(regular_headers.begin()), + regular_end_(regular_headers.end()) {} + + // |headers| must outlive the iterator. + explicit RepresentationIterator(const Representations& headers) + : pseudo_begin_(headers.begin()), + pseudo_end_(headers.end()), + regular_begin_(headers.end()), + regular_end_(headers.end()) {} + + bool HasNext() { + return pseudo_begin_ != pseudo_end_ || regular_begin_ != regular_end_; + } + + const Representation Next() { + if (pseudo_begin_ != pseudo_end_) { + return *pseudo_begin_++; + } else { + return *regular_begin_++; + } + } + + private: + Representations::const_iterator pseudo_begin_; + Representations::const_iterator pseudo_end_; + Representations::const_iterator regular_begin_; + Representations::const_iterator regular_end_; +}; + +namespace { + +// The default HPACK indexing policy. +bool DefaultPolicy(StringPiece name, StringPiece /* value */) { + if (name.empty()) { + return false; + } + // :authority is always present and rarely changes, and has moderate + // length, therefore it makes a lot of sense to index (insert in the + // dynamic table). + if (name[0] == kPseudoHeaderPrefix) { + return name == ":authority"; + } + return true; +} + +} // namespace + HpackEncoder::HpackEncoder(const HpackHuffmanTable& table) : output_stream_(), huffman_table_(table), min_table_size_setting_received_(std::numeric_limits<size_t>::max()), + should_index_(DefaultPolicy), allow_huffman_compression_(true), should_emit_table_size_(false) {} HpackEncoder::~HpackEncoder() {} +void HpackEncoder::EncodeHeaderSet(const Representations& representations, + string* output) { + RepresentationIterator iter(representations); + EncodeRepresentations(&iter, output); +} + bool HpackEncoder::EncodeHeaderSet(const SpdyHeaderBlock& header_set, string* output) { - MaybeEmitTableSize(); // Separate header set into pseudo-headers and regular headers. Representations pseudo_headers; Representations regular_headers; @@ -48,42 +108,10 @@ } } - // Encode pseudo-headers. - bool found_authority = false; - for (const auto& header : pseudo_headers) { - const HpackEntry* entry = - header_table_.GetByNameAndValue(header.first, header.second); - if (entry != NULL) { - EmitIndex(entry); - } else { - // :authority is always present and rarely changes, and has moderate - // length, therefore it makes a lot of sense to index (insert in the - // header table). - if (!found_authority && header.first == ":authority") { - // Note that there can only be one ":authority" header, because - // |header_set| is a map. - found_authority = true; - EmitIndexedLiteral(header); - } else { - // Most common pseudo-header fields are represented in the static table, - // while uncommon ones are small, so do not index them. - EmitNonIndexedLiteral(header); - } - } + { + RepresentationIterator iter(pseudo_headers, regular_headers); + EncodeRepresentations(&iter, output); } - - // Encode regular headers. - for (const auto& header : regular_headers) { - const HpackEntry* entry = - header_table_.GetByNameAndValue(header.first, header.second); - if (entry != NULL) { - EmitIndex(entry); - } else { - EmitIndexedLiteral(header); - } - } - - output_stream_.TakeString(output); return true; } @@ -113,6 +141,25 @@ should_emit_table_size_ = true; } +void HpackEncoder::EncodeRepresentations(RepresentationIterator* iter, + string* output) { + MaybeEmitTableSize(); + while (iter->HasNext()) { + const auto header = iter->Next(); + const HpackEntry* entry = + header_table_.GetByNameAndValue(header.first, header.second); + if (entry != nullptr) { + EmitIndex(entry); + } else if (should_index_(header.first, header.second)) { + EmitIndexedLiteral(header); + } else { + EmitNonIndexedLiteral(header); + } + } + + output_stream_.TakeString(output); +} + void HpackEncoder::EmitIndex(const HpackEntry* entry) { output_stream_.AppendPrefix(kIndexedOpcode); output_stream_.AppendUint32(header_table_.IndexOf(entry)); @@ -133,7 +180,7 @@ void HpackEncoder::EmitLiteral(const Representation& representation) { const HpackEntry* name_entry = header_table_.GetByName(representation.first); - if (name_entry != NULL) { + if (name_entry != nullptr) { output_stream_.AppendUint32(header_table_.IndexOf(name_entry)); } else { output_stream_.AppendUint32(0);
diff --git a/net/spdy/hpack/hpack_encoder.h b/net/spdy/hpack/hpack_encoder.h index cfa6e08..ce5c9df 100644 --- a/net/spdy/hpack/hpack_encoder.h +++ b/net/spdy/hpack/hpack_encoder.h
@@ -2,12 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef NET_SPDY_HPACK_ENCODER_H_ -#define NET_SPDY_HPACK_ENCODER_H_ +#ifndef NET_SPDY_HPACK_HPACK_ENCODER_H_ +#define NET_SPDY_HPACK_HPACK_ENCODER_H_ #include <stddef.h> #include <map> +#include <memory> #include <string> #include <utility> #include <vector> @@ -32,13 +33,23 @@ class NET_EXPORT_PRIVATE HpackEncoder { public: - friend class test::HpackEncoderPeer; + using Representation = std::pair<base::StringPiece, base::StringPiece>; + using Representations = std::vector<Representation>; + + // An indexing policy should return true if the provided header name-value + // pair should be inserted into the HPACK dynamic table. + using IndexingPolicy = + std::function<bool(base::StringPiece, base::StringPiece)>; // |table| is an initialized HPACK Huffman table, having an // externally-managed lifetime which spans beyond HpackEncoder. explicit HpackEncoder(const HpackHuffmanTable& table); ~HpackEncoder(); + // Encodes a sequence of Representations into the given string. + void EncodeHeaderSet(const Representations& representations, + std::string* output); + // Encodes the given header set into the given string. Returns // whether or not the encoding was successful. bool EncodeHeaderSet(const SpdyHeaderBlock& header_set, std::string* output); @@ -58,14 +69,22 @@ return header_table_.settings_size_bound(); } + // This HpackEncoder will use |policy| to determine whether to insert header + // name-value pairs into the dynamic table. + void SetIndexingPolicy(IndexingPolicy policy) { should_index_ = policy; } + void SetHeaderTableDebugVisitor( std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor) { header_table_.set_debug_visitor(std::move(visitor)); } private: - typedef std::pair<base::StringPiece, base::StringPiece> Representation; - typedef std::vector<Representation> Representations; + friend class test::HpackEncoderPeer; + + class RepresentationIterator; + + // Encodes a sequence of header name-value pairs as a single header block. + void EncodeRepresentations(RepresentationIterator* iter, std::string* output); // Emits a static/dynamic indexed representation (Section 7.1). void EmitIndex(const HpackEntry* entry); @@ -95,6 +114,7 @@ const HpackHuffmanTable& huffman_table_; size_t min_table_size_setting_received_; + IndexingPolicy should_index_; bool allow_huffman_compression_; bool should_emit_table_size_; @@ -103,4 +123,4 @@ } // namespace net -#endif // NET_SPDY_HPACK_ENCODER_H_ +#endif // NET_SPDY_HPACK_HPACK_ENCODER_H_
diff --git a/net/url_request/url_request_context.h b/net/url_request/url_request_context.h index 40b2486e..e483178 100644 --- a/net/url_request/url_request_context.h +++ b/net/url_request/url_request_context.h
@@ -3,9 +3,7 @@ // found in the LICENSE file. // This class represents contextual information (cookies, cache, etc.) -// that's useful when processing resource requests. -// The class is reference-counted so that it can be cleaned up after any -// requests that are using it have been completed. +// that's necessary when processing resource requests. #ifndef NET_URL_REQUEST_URL_REQUEST_CONTEXT_H_ #define NET_URL_REQUEST_URL_REQUEST_CONTEXT_H_ @@ -47,9 +45,11 @@ class URLRequestThrottlerManager; // Subclass to provide application-specific context for URLRequest -// instances. Note that URLRequestContext typically does not provide storage for -// these member variables, since they may be shared. For the ones that aren't -// shared, URLRequestContextStorage can be helpful in defining their storage. +// instances. URLRequestContext does not own these member variables, since they +// may be shared with other contexts. URLRequestContextStorage can be used for +// automatic lifetime management. Most callers should use an existing +// URLRequestContext rather than creating a new one, as guaranteeing that the +// URLRequestContext is destroyed before its members can be difficult. class NET_EXPORT URLRequestContext : NON_EXPORTED_BASE(public base::NonThreadSafe) { public:
diff --git a/net/url_request/url_request_context_storage.h b/net/url_request/url_request_context_storage.h index a38fd13..d74d754 100644 --- a/net/url_request/url_request_context_storage.h +++ b/net/url_request/url_request_context_storage.h
@@ -90,9 +90,7 @@ } private: - // We use a raw pointer to prevent reference cycles, since - // URLRequestContextStorage can often be contained within a URLRequestContext - // subclass. + // Not owned. URLRequestContext* const context_; // Owned members. @@ -103,7 +101,7 @@ std::unique_ptr<ChannelIDService> channel_id_service_; std::unique_ptr<HttpAuthHandlerFactory> http_auth_handler_factory_; std::unique_ptr<ProxyService> proxy_service_; - // TODO(willchan): Remove refcounting on these members. + // TODO(willchan): Remove refcounting on this member. scoped_refptr<SSLConfigService> ssl_config_service_; std::unique_ptr<NetworkDelegate> network_delegate_; std::unique_ptr<ProxyDelegate> proxy_delegate_;
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc index b197e5d..29f9a7ac 100644 --- a/pdf/pdfium/pdfium_engine.cc +++ b/pdf/pdfium/pdfium_engine.cc
@@ -11,7 +11,7 @@ #include <memory> #include <set> -#include "base/i18n/icu_encoding_detection.h" +#include "base/i18n/encoding_detection.h" #include "base/i18n/icu_string_conversions.h" #include "base/lazy_instance.h" #include "base/logging.h"
diff --git a/printing/backend/cups_ipp_util.cc b/printing/backend/cups_ipp_util.cc index eb5976d..88ae495 100644 --- a/printing/backend/cups_ipp_util.cc +++ b/printing/backend/cups_ipp_util.cc
@@ -69,7 +69,7 @@ base::StringPiece value) { std::vector<base::StringPiece> values = printer.GetSupportedOptionValueStrings(name); - return ContainsValue(values, value); + return base::ContainsValue(values, value); } DuplexMode PrinterDefaultDuplex(const CupsOptionProvider& printer) {
diff --git a/remoting/android/BUILD.gn b/remoting/android/BUILD.gn index af463b4..a1fb981c 100644 --- a/remoting/android/BUILD.gn +++ b/remoting/android/BUILD.gn
@@ -60,6 +60,7 @@ "//remoting/client/jni/remoting_jni_registrar.h", ] libs = [ + "android", "OpenSLES", "EGL", ]
diff --git a/remoting/android/java/src/org/chromium/chromoting/GlDesktopView.java b/remoting/android/java/src/org/chromium/chromoting/GlDesktopView.java index 524db4e..22c959e 100644 --- a/remoting/android/java/src/org/chromium/chromoting/GlDesktopView.java +++ b/remoting/android/java/src/org/chromium/chromoting/GlDesktopView.java
@@ -20,11 +20,20 @@ private Object mOnHostSizeChangedListenerKey; private Object mOnCanvasRenderedListenerKey; + private Event.ParameterRunnable<Void> mProcessAnimationRunnable; + public GlDesktopView(GlDisplay display, Desktop desktop, Client client) { super(desktop, client); Preconditions.notNull(display); mDisplay = display; + mProcessAnimationRunnable = new Event.ParameterRunnable<Void>() { + @Override + public void run(Void p) { + mInputHandler.processAnimation(); + } + }; + getHolder().addCallback(this); } @@ -62,7 +71,14 @@ @Override public void setAnimationEnabled(boolean enabled) { - mDisplay.setRenderEventEnabled(enabled); + if (enabled && mOnCanvasRenderedListenerKey == null) { + mOnCanvasRenderedListenerKey = mDisplay.onCanvasRendered() + .add(mProcessAnimationRunnable); + mInputHandler.processAnimation(); + } else if (!enabled && mOnCanvasRenderedListenerKey != null) { + mDisplay.onCanvasRendered().remove(mOnCanvasRenderedListenerKey); + mOnCanvasRenderedListenerKey = null; + } } @Override @@ -81,19 +97,6 @@ } }); - mOnCanvasRenderedListenerKey = mDisplay - .onCanvasRendered().add(new Event.ParameterRunnable<Void>() { - @Override - public void run(Void p) { - getHandler().post(new Runnable() { - @Override - public void run() { - mInputHandler.processAnimation(); - } - }); - } - }); - mDisplay.surfaceCreated(holder.getSurface()); } @@ -111,8 +114,12 @@ // GlDisplay's life time spans to the whole session while GlDesktopView may be created and // destroyed for multiple times (say when the phone is rotated). It is important to remove // the listeners when the surface is about to be destroyed. - mDisplay.onHostSizeChanged().remove(mOnHostSizeChangedListenerKey); - mDisplay.onCanvasRendered().remove(mOnCanvasRenderedListenerKey); + if (mOnHostSizeChangedListenerKey != null) { + mDisplay.onHostSizeChanged().remove(mOnHostSizeChangedListenerKey); + } + if (mOnCanvasRenderedListenerKey != null) { + mDisplay.onCanvasRendered().remove(mOnCanvasRenderedListenerKey); + } mDisplay.surfaceDestroyed(); } }
diff --git a/remoting/android/java/src/org/chromium/chromoting/jni/GlDisplay.java b/remoting/android/java/src/org/chromium/chromoting/jni/GlDisplay.java index 066f5e4..bede3da 100644 --- a/remoting/android/java/src/org/chromium/chromoting/jni/GlDisplay.java +++ b/remoting/android/java/src/org/chromium/chromoting/jni/GlDisplay.java
@@ -85,9 +85,7 @@ } } - /** - * Moves the cursor to the corresponding location on the desktop. - */ + /** Moves the cursor to the corresponding location on the desktop. */ public void cursorPixelPositionChanged(int x, int y) { if (mNativeJniGlDisplay != 0) { nativeOnCursorPixelPositionChanged(mNativeJniGlDisplay, x, y); @@ -139,17 +137,6 @@ } /** - * Enables or disables render event callback. {@link GlDisplay#onCanvasRendered()} will only be - * triggered if this is set to true. - * @param enabled true to enable and false to disable - */ - public void setRenderEventEnabled(boolean enabled) { - if (mNativeJniGlDisplay != 0) { - nativeSetRenderEventEnabled(mNativeJniGlDisplay, enabled); - } - } - - /** * Shows the cursor input feedback animation with the given diameter at the given desktop * location. */ @@ -186,6 +173,4 @@ int x, int y, float diameter); private native void nativeOnCursorVisibilityChanged(long nativeJniGlDisplayHandler, boolean visible); - private native void nativeSetRenderEventEnabled(long nativeJniGlDisplayHandler, - boolean enabled); }
diff --git a/remoting/client/BUILD.gn b/remoting/client/BUILD.gn index 5bae90e..389da69 100644 --- a/remoting/client/BUILD.gn +++ b/remoting/client/BUILD.gn
@@ -41,20 +41,30 @@ } } -if (is_android || is_ios) { - source_set("opengl_renderer") { - sources = - rebase_path(remoting_srcs_gypi_values.remoting_opengl_renderer_sources, - ".", - "//remoting") +source_set("opengl_renderer") { + sources = + rebase_path(remoting_srcs_gypi_values.remoting_opengl_renderer_sources, + ".", + "//remoting") - deps = [ - "//remoting/proto", - "//third_party/libyuv", - "//third_party/webrtc", - ] + deps = [ + "//remoting/proto", + "//third_party/libyuv", + "//third_party/webrtc", + ] - configs += [ "//third_party/khronos:khronos_headers" ] + configs += [ "//third_party/khronos:khronos_headers" ] + + if (is_linux) { + libs = [ "GL" ] + } + + if (is_mac) { + libs = [ "OpenGL.framework" ] + } + + if (is_win) { + deps += [ "//third_party/angle:libGLESv2" ] } } @@ -87,10 +97,12 @@ "client_telemetry_logger_unittest.cc", "dual_buffer_frame_consumer_unittest.cc", "empty_cursor_filter_unittest.cc", + "gl_renderer_unittest.cc", "key_event_mapper_unittest.cc", "normalizing_input_filter_cros_unittest.cc", "normalizing_input_filter_mac_unittest.cc", "normalizing_input_filter_win_unittest.cc", + "queued_task_poster_unittest.cc", "server_log_entry_client_unittest.cc", "software_video_renderer_unittest.cc", "touch_input_scaler_unittest.cc", @@ -104,6 +116,7 @@ deps = [ ":client", + ":opengl_renderer", ":test_support", "//remoting/proto", "//testing/gmock",
diff --git a/remoting/client/dual_buffer_frame_consumer.cc b/remoting/client/dual_buffer_frame_consumer.cc index 709f1be..1339a0b 100644 --- a/remoting/client/dual_buffer_frame_consumer.cc +++ b/remoting/client/dual_buffer_frame_consumer.cc
@@ -10,8 +10,6 @@ #include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/threading/thread_task_runner_handle.h" -#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" -#include "third_party/webrtc/modules/desktop_capture/shared_desktop_frame.h" namespace remoting {
diff --git a/remoting/client/dual_buffer_frame_consumer.h b/remoting/client/dual_buffer_frame_consumer.h index a1f609f..1932d8a 100644 --- a/remoting/client/dual_buffer_frame_consumer.h +++ b/remoting/client/dual_buffer_frame_consumer.h
@@ -13,10 +13,7 @@ #include "base/threading/thread_checker.h" #include "remoting/protocol/frame_consumer.h" #include "third_party/webrtc/modules/desktop_capture/desktop_region.h" - -namespace webrtc { -class SharedDesktopFrame; -} // namespace webrtc +#include "third_party/webrtc/modules/desktop_capture/shared_desktop_frame.h" namespace remoting {
diff --git a/remoting/client/gl_canvas.cc b/remoting/client/gl_canvas.cc index 8bcfa11..0a49f13 100644 --- a/remoting/client/gl_canvas.cc +++ b/remoting/client/gl_canvas.cc
@@ -66,6 +66,8 @@ namespace remoting { GlCanvas::GlCanvas(int gl_version) : gl_version_(gl_version) { + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size_); + vertex_shader_ = CompileShader(GL_VERTEX_SHADER, kTexCoordToViewVert); fragment_shader_ = CompileShader(GL_FRAGMENT_SHADER, kDrawTexFrag); program_ = CreateProgram(vertex_shader_, fragment_shader_); @@ -139,4 +141,8 @@ return gl_version_; } +int GlCanvas::GetMaxTextureSize() const { + return max_texture_size_; +} + } // namespace remoting
diff --git a/remoting/client/gl_canvas.h b/remoting/client/gl_canvas.h index df1994b6..4df0a4b8 100644 --- a/remoting/client/gl_canvas.h +++ b/remoting/client/gl_canvas.h
@@ -60,9 +60,14 @@ // Returns the version number of current OpenGL ES context. Either 2 or 3. int GetGlVersion() const; + // Returns the maximum texture resolution limitation. Neither the width nor + // the height of the texture can exceed this limitation. + int GetMaxTextureSize() const; + private: int gl_version_; + int max_texture_size_ = 0; bool transformation_set_ = false; bool view_size_set_ = false;
diff --git a/remoting/client/gl_cursor.cc b/remoting/client/gl_cursor.cc index 9e10e2bc..ceab13e 100644 --- a/remoting/client/gl_cursor.cc +++ b/remoting/client/gl_cursor.cc
@@ -8,17 +8,14 @@ #include "remoting/client/gl_canvas.h" #include "remoting/client/gl_math.h" #include "remoting/client/gl_render_layer.h" +#include "remoting/client/gl_texture_ids.h" #include "remoting/proto/control.pb.h" #include "third_party/libyuv/include/libyuv/convert_argb.h" namespace remoting { namespace { - -// TODO(yuweih): Create separate header file for texture IDs to avoid conflicts. -const int kTextureId = 1; const int kDefaultCursorDataSize = 32 * 32 * GlRenderLayer::kBytesPerPixel; - } // namespace GlCursor::GlCursor() {} @@ -76,7 +73,7 @@ layer_.reset(); return; } - layer_.reset(new GlRenderLayer(kTextureId, canvas)); + layer_.reset(new GlRenderLayer(kGlCursorTextureId, canvas)); if (current_cursor_data_) { SetCurrentCursorShape(true); } @@ -93,7 +90,7 @@ if (layer_) { if (size_changed) { layer_->SetTexture(current_cursor_data_.get(), current_cursor_width_, - current_cursor_height_); + current_cursor_height_, 0); } else { layer_->UpdateTexture(current_cursor_data_.get(), 0, 0, current_cursor_width_, current_cursor_width_, 0);
diff --git a/remoting/client/gl_cursor.h b/remoting/client/gl_cursor.h index 7e1ee4f..c0250462 100644 --- a/remoting/client/gl_cursor.h +++ b/remoting/client/gl_cursor.h
@@ -6,6 +6,7 @@ #define REMOTING_CLIENT_OPENGL_GL_CURSOR_H_ #include <array> +#include <cstdint> #include <memory> #include "base/macros.h"
diff --git a/remoting/client/gl_cursor_feedback.cc b/remoting/client/gl_cursor_feedback.cc index fcadf59..4befc88c 100644 --- a/remoting/client/gl_cursor_feedback.cc +++ b/remoting/client/gl_cursor_feedback.cc
@@ -12,12 +12,10 @@ #include "remoting/client/gl_cursor_feedback_texture.h" #include "remoting/client/gl_math.h" #include "remoting/client/gl_render_layer.h" +#include "remoting/client/gl_texture_ids.h" namespace { - -const int kTextureId = 2; const float kAnimationDurationMs = 220.f; - } // namespace namespace remoting { @@ -31,11 +29,11 @@ layer_.reset(); return; } - layer_.reset(new GlRenderLayer(kTextureId, canvas)); + layer_.reset(new GlRenderLayer(kGlCursorFeedbackTextureId, canvas)); GlCursorFeedbackTexture* texture = GlCursorFeedbackTexture::GetInstance(); layer_->SetTexture(texture->GetTexture().data(), GlCursorFeedbackTexture::kTextureWidth, - GlCursorFeedbackTexture::kTextureWidth); + GlCursorFeedbackTexture::kTextureWidth, 0); } void GlCursorFeedback::StartAnimation(int x, int y, float diameter) {
diff --git a/remoting/client/gl_cursor_feedback_texture.cc b/remoting/client/gl_cursor_feedback_texture.cc index 5a572750..7a82b32 100644 --- a/remoting/client/gl_cursor_feedback_texture.cc +++ b/remoting/client/gl_cursor_feedback_texture.cc
@@ -34,7 +34,7 @@ if (ring_index < 0) { NOTREACHED(); - return -1; + return 0; } if (ring_index == kColorRingsCount - 1) {
diff --git a/remoting/client/gl_desktop.cc b/remoting/client/gl_desktop.cc index 124318c..8efba818 100644 --- a/remoting/client/gl_desktop.cc +++ b/remoting/client/gl_desktop.cc
@@ -5,59 +5,122 @@ #include "remoting/client/gl_desktop.h" #include "base/logging.h" +#include "base/memory/ptr_util.h" #include "remoting/client/gl_canvas.h" #include "remoting/client/gl_math.h" #include "remoting/client/gl_render_layer.h" +#include "remoting/client/gl_texture_ids.h" #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" +#include "third_party/webrtc/modules/desktop_capture/desktop_region.h" + +namespace remoting { namespace { -const int kTextureId = 0; +void UpdateDesktopRegion(const webrtc::DesktopFrame& frame, + const webrtc::DesktopRegion& region, + const webrtc::DesktopRect& texture_rect, + GlRenderLayer* layer) { + for (webrtc::DesktopRegion::Iterator i(region); !i.IsAtEnd(); i.Advance()) { + const uint8_t* rect_start = frame.GetFrameDataAtPos(i.rect().top_left()); + webrtc::DesktopVector update_pos = + i.rect().top_left().subtract(texture_rect.top_left()); + layer->UpdateTexture(rect_start, update_pos.x(), update_pos.y(), + i.rect().width(), i.rect().height(), frame.stride()); + } +} + +void SetFrameForTexture(const webrtc::DesktopFrame& frame, + GlRenderLayer* layer, + const webrtc::DesktopRect& rect) { + if (!layer->is_texture_set()) { + // First frame received. + layer->SetTexture(frame.GetFrameDataAtPos(rect.top_left()), rect.width(), + rect.height(), frame.stride()); + return; + } + // Incremental update. + if (frame.size().equals(rect.size())) { + // Single texture. No intersection is needed. + UpdateDesktopRegion(frame, frame.updated_region(), rect, layer); + } else { + webrtc::DesktopRegion intersected_region = frame.updated_region(); + intersected_region.IntersectWith(rect); + UpdateDesktopRegion(frame, intersected_region, rect, layer); + } +} } // namespace -namespace remoting { +struct GlDesktop::GlDesktopTextureContainer { + std::unique_ptr<GlRenderLayer> layer; + webrtc::DesktopRect rect; +}; GlDesktop::GlDesktop() {} GlDesktop::~GlDesktop() {} void GlDesktop::SetCanvas(GlCanvas* canvas) { - if (!canvas) { - layer_.reset(); - return; - } - layer_.reset(new GlRenderLayer(kTextureId, canvas)); last_desktop_size_.set(0, 0); + textures_.clear(); + canvas_ = canvas; + if (canvas) { + max_texture_size_ = canvas->GetMaxTextureSize(); + } } -void GlDesktop::SetVideoFrame(std::unique_ptr<webrtc::DesktopFrame> frame) { - if (!layer_) { +void GlDesktop::SetVideoFrame(const webrtc::DesktopFrame& frame) { + if (!canvas_) { return; } - if (!frame->size().equals(last_desktop_size_)) { - layer_->SetTexture(frame->data(), frame->size().width(), - frame->size().height()); - std::array<float, 8> positions; - FillRectangleVertexPositions(0, 0, frame->size().width(), - frame->size().height(), &positions); - layer_->SetVertexPositions(positions); - last_desktop_size_.set(frame->size().width(), frame->size().height()); - } else { - for (webrtc::DesktopRegion::Iterator i(frame->updated_region()); - !i.IsAtEnd(); i.Advance()) { - const uint8_t* rect_start = - frame->GetFrameDataAtPos(i.rect().top_left()); - layer_->UpdateTexture( - rect_start, i.rect().left(), i.rect().top(), i.rect().width(), - i.rect().height(), frame->stride()); - } + if (!frame.size().equals(last_desktop_size_)) { + last_desktop_size_.set(frame.size().width(), frame.size().height()); + ReallocateTextures(last_desktop_size_); + } + for (std::unique_ptr<GlDesktopTextureContainer>& texture : textures_) { + SetFrameForTexture(frame, texture->layer.get(), texture->rect); } } void GlDesktop::Draw() { - if (layer_ && !last_desktop_size_.is_empty()) { - layer_->Draw(1.f); + if (!textures_.empty() && !last_desktop_size_.is_empty()) { + for (std::unique_ptr<GlDesktopTextureContainer>& texture : textures_) { + texture->layer->Draw(1.0f); + } + } +} + +void GlDesktop::ReallocateTextures(const webrtc::DesktopSize& size) { + DCHECK(max_texture_size_); + DCHECK(canvas_); + textures_.clear(); + + int textures_per_row = + (size.width() + max_texture_size_ - 1) / max_texture_size_; + + int textures_per_column = + (size.height() + max_texture_size_ - 1) / max_texture_size_; + + webrtc::DesktopRect desktop_rect = webrtc::DesktopRect::MakeSize(size); + + int texture_id = kGlDesktopFirstTextureId; + std::array<float, 8> positions; + for (int x = 0; x < textures_per_row; x++) { + for (int y = 0; y < textures_per_column; y++) { + webrtc::DesktopRect rect = webrtc::DesktopRect::MakeXYWH( + x * max_texture_size_, y * max_texture_size_, max_texture_size_, + max_texture_size_); + rect.IntersectWith(desktop_rect); + std::unique_ptr<GlDesktopTextureContainer> container = + base::WrapUnique(new GlDesktopTextureContainer{ + base::WrapUnique(new GlRenderLayer(texture_id, canvas_)), rect}); + FillRectangleVertexPositions(rect.left(), rect.top(), rect.width(), + rect.height(), &positions); + container->layer->SetVertexPositions(positions); + textures_.push_back(std::move(container)); + texture_id++; + } } }
diff --git a/remoting/client/gl_desktop.h b/remoting/client/gl_desktop.h index ca7a5ee..2c98cd42 100644 --- a/remoting/client/gl_desktop.h +++ b/remoting/client/gl_desktop.h
@@ -6,6 +6,7 @@ #define REMOTING_CLIENT_OPENGL_GL_DESKTOP_H_ #include <memory> +#include <vector> #include "base/macros.h" #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h" @@ -26,7 +27,7 @@ virtual ~GlDesktop(); // |frame| can be either a full frame or updated regions only frame. - void SetVideoFrame(std::unique_ptr<webrtc::DesktopFrame> frame); + void SetVideoFrame(const webrtc::DesktopFrame& frame); // Sets the canvas on which the desktop will be drawn. Caller must feed a // full desktop frame after calling this function. @@ -37,8 +38,15 @@ void Draw(); private: - std::unique_ptr<GlRenderLayer> layer_; + struct GlDesktopTextureContainer; + + void ReallocateTextures(const webrtc::DesktopSize& size); + + std::vector<std::unique_ptr<GlDesktopTextureContainer>> textures_; + webrtc::DesktopSize last_desktop_size_; + int max_texture_size_ = 0; + GlCanvas* canvas_ = nullptr; DISALLOW_COPY_AND_ASSIGN(GlDesktop); };
diff --git a/remoting/client/gl_render_layer.cc b/remoting/client/gl_render_layer.cc index 0fcdbe4..7d3e06ce 100644 --- a/remoting/client/gl_render_layer.cc +++ b/remoting/client/gl_render_layer.cc
@@ -52,15 +52,27 @@ glDeleteTextures(1, &texture_handle_); } -void GlRenderLayer::SetTexture(const uint8_t* texture, int width, int height) { +void GlRenderLayer::SetTexture(const uint8_t* texture, + int width, + int height, + int stride) { DCHECK(thread_checker_.CalledOnValidThread()); CHECK(width > 0 && height > 0); texture_set_ = true; glActiveTexture(GL_TEXTURE0 + texture_id_); glBindTexture(GL_TEXTURE_2D, texture_handle_); + bool should_reset_row_length; + const void* buffer_to_update = PrepareTextureBuffer( + texture, width, height, stride, &should_reset_row_length); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, - GL_UNSIGNED_BYTE, texture); + GL_UNSIGNED_BYTE, buffer_to_update); + + if (should_reset_row_length) { + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -81,40 +93,17 @@ glActiveTexture(GL_TEXTURE0 + texture_id_); glBindTexture(GL_TEXTURE_2D, texture_handle_); - bool stride_multiple_of_bytes_per_pixel = stride % kBytesPerPixel == 0; - bool loosely_packed = - !stride_multiple_of_bytes_per_pixel || - (stride > 0 && stride != kBytesPerPixel * width); - - const void* buffer_to_update = subtexture; - - if (loosely_packed) { - if (stride_multiple_of_bytes_per_pixel && canvas_->GetGlVersion() >= 3) { - glPixelStorei(GL_UNPACK_ROW_LENGTH, stride / kBytesPerPixel); - } else { - // Doesn't support GL_UNPACK_ROW_LENGTH or stride not multiple of - // kBytesPerPixel. Manually pack the data. - int required_size = width * height * kBytesPerPixel; - if (update_buffer_size_ < required_size) { - if (required_size < kDefaultUpdateBufferCapacity) { - update_buffer_size_ = kDefaultUpdateBufferCapacity; - } else { - update_buffer_size_ = required_size; - } - update_buffer_.reset(new uint8_t[update_buffer_size_]); - } - PackDirtyRegion(update_buffer_.get(), subtexture, width, height, stride); - buffer_to_update = update_buffer_.get(); - } - } + bool should_reset_row_length; + const void* buffer_to_update = PrepareTextureBuffer( + subtexture, width, height, stride, &should_reset_row_length); glTexSubImage2D(GL_TEXTURE_2D, 0, offset_x, offset_y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer_to_update); - if (loosely_packed && stride_multiple_of_bytes_per_pixel && - canvas_->GetGlVersion() >= 3) { + if (should_reset_row_length) { glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); } + glBindTexture(GL_TEXTURE_2D, 0); } @@ -142,4 +131,41 @@ alpha_multiplier); } +const uint8_t* GlRenderLayer::PrepareTextureBuffer( + const uint8_t* data, + int width, + int height, + int stride, + bool* should_reset_row_length) { + *should_reset_row_length = false; + + bool stride_multiple_of_bytes_per_pixel = stride % kBytesPerPixel == 0; + bool loosely_packed = !stride_multiple_of_bytes_per_pixel || + (stride > 0 && stride != kBytesPerPixel * width); + + if (!loosely_packed) { + return data; + } + + if (stride_multiple_of_bytes_per_pixel && canvas_->GetGlVersion() >= 3) { + glPixelStorei(GL_UNPACK_ROW_LENGTH, stride / kBytesPerPixel); + *should_reset_row_length = true; + return data; + } + + // Doesn't support GL_UNPACK_ROW_LENGTH or stride not multiple of + // kBytesPerPixel. Manually pack the data. + int required_size = width * height * kBytesPerPixel; + if (update_buffer_size_ < required_size) { + if (required_size < kDefaultUpdateBufferCapacity) { + update_buffer_size_ = kDefaultUpdateBufferCapacity; + } else { + update_buffer_size_ = required_size; + } + update_buffer_.reset(new uint8_t[update_buffer_size_]); + } + PackDirtyRegion(update_buffer_.get(), data, width, height, stride); + return update_buffer_.get(); +} + } // namespace remoting
diff --git a/remoting/client/gl_render_layer.h b/remoting/client/gl_render_layer.h index 7190f16..5306e84 100644 --- a/remoting/client/gl_render_layer.h +++ b/remoting/client/gl_render_layer.h
@@ -5,6 +5,9 @@ #ifndef REMOTING_CLIENT_OPENGL_GL_RENDER_LAYER_H_ #define REMOTING_CLIENT_OPENGL_GL_RENDER_LAYER_H_ +#include <array> +#include <memory> + #include "base/macros.h" #include "base/threading/thread_checker.h" #include "remoting/client/sys_opengl.h" @@ -25,12 +28,14 @@ // Sets the texture (RGBA 8888) to be drawn. Please use UpdateTexture() if the // texture size isn't changed. - void SetTexture(const uint8_t* texture, int width, int height); - - // Updates a subregion (RGBA 8888) of the texture. // stride: byte distance between two rows in |subtexture|. // If |stride| is 0 or |stride| == |width|*kBytesPerPixel, |subtexture| will // be treated as tightly packed. + void SetTexture(const uint8_t* texture, int width, int height, int stride); + + // Updates a subregion (RGBA 8888) of the texture. Can only be called after + // SetTexture() has been called. + // stride: See SetTexture(). void UpdateTexture(const uint8_t* subtexture, int offset_x, int offset_y, @@ -54,14 +59,30 @@ // Draws the texture on the canvas. Texture must be set before calling Draw(). void Draw(float alpha_multiplier); + // true if the texture is already set by calling SetTexture(). + bool is_texture_set() { return texture_set_; } + private: + // Returns pointer to the texture buffer that can be used by glTexImage2d or + // glTexSubImage2d. The returned value will be |data| if the texture can be + // used without manual packing, otherwise the data will be manually packed and + // the pointer to |update_buffer_| will be returned. + // should_reset_row_length: Pointer to a bool that will be set by the + // function. If this is true, the user need to call + // glPixelStorei(GL_UNPACK_ROW_LENGTH, 0) after + // updating the texture to reset the stride. + const uint8_t* PrepareTextureBuffer(const uint8_t* data, + int width, + int height, + int stride, + bool* should_reset_row_length); + int texture_id_; GlCanvas* canvas_; GLuint texture_handle_; GLuint buffer_handle_; - // true IFF the texture is already set by calling SetTexture(). bool texture_set_ = false; bool vertex_position_set_ = false;
diff --git a/remoting/client/gl_renderer.cc b/remoting/client/gl_renderer.cc index 719bde10..683fda5 100644 --- a/remoting/client/gl_renderer.cc +++ b/remoting/client/gl_renderer.cc
@@ -74,7 +74,7 @@ canvas_height_ = frame->size().height(); } - desktop_.SetVideoFrame(std::move(frame)); + desktop_.SetVideoFrame(*frame); pending_done_callbacks_.push(done); RequestRender(); } @@ -114,6 +114,7 @@ } void GlRenderer::RequestRender() { + DCHECK(thread_checker_.CalledOnValidThread()); if (render_scheduled_) { return; } @@ -129,11 +130,13 @@ return; } - glClear(GL_COLOR_BUFFER_BIT); - desktop_.Draw(); - cursor_.Draw(); - if (cursor_feedback_.Draw()) { - RequestRender(); + if (canvas_) { + glClear(GL_COLOR_BUFFER_BIT); + desktop_.Draw(); + cursor_.Draw(); + if (cursor_feedback_.Draw()) { + RequestRender(); + } } delegate_->OnFrameRendered();
diff --git a/remoting/client/gl_renderer.h b/remoting/client/gl_renderer.h index b364903..627407b 100644 --- a/remoting/client/gl_renderer.h +++ b/remoting/client/gl_renderer.h
@@ -28,6 +28,7 @@ class GlCanvas; class GlRendererDelegate; +class GlRendererTest; // Renders desktop and cursor on the OpenGL surface. Can be created on any // thread but thereafter must be used and deleted on the same thread (usually @@ -94,6 +95,8 @@ base::WeakPtr<GlRenderer> GetWeakPtr(); private: + friend class GlRendererTest; + // Post a rendering task to the task runner of current thread. // Do nothing if render_callback_ is not set yet or an existing rendering task // in the queue will cover changes before this function is called.
diff --git a/remoting/client/gl_renderer_unittest.cc b/remoting/client/gl_renderer_unittest.cc new file mode 100644 index 0000000..182a2dc --- /dev/null +++ b/remoting/client/gl_renderer_unittest.cc
@@ -0,0 +1,220 @@ +// 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 "remoting/client/gl_renderer.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/memory/ptr_util.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "base/threading/thread_task_runner_handle.h" +#include "remoting/client/gl_renderer_delegate.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" + +namespace remoting { + +class FakeGlRendererDelegate : public GlRendererDelegate { + public: + FakeGlRendererDelegate() : weak_factory_(this) {} + + bool CanRenderFrame() override { + can_render_frame_call_count_++; + return can_render_frame_; + } + + void OnFrameRendered() override { + on_frame_rendered_call_count_++; + if (on_frame_rendered_callback_) { + on_frame_rendered_callback_.Run(); + } + } + + void OnSizeChanged(int width, int height) override { + canvas_width_ = width; + canvas_height_ = height; + on_size_changed_call_count_++; + } + + void SetOnFrameRenderedCallback(const base::Closure& callback) { + on_frame_rendered_callback_ = callback; + } + + int canvas_width() { + return canvas_width_; + } + + int canvas_height() { + return canvas_height_; + } + + base::WeakPtr<FakeGlRendererDelegate> GetWeakPtr() { + return weak_factory_.GetWeakPtr(); + } + + int can_render_frame_call_count() { + return can_render_frame_call_count_; + } + + int on_frame_rendered_call_count() { + return on_frame_rendered_call_count_; + } + + int on_size_changed_call_count() { + return on_size_changed_call_count_; + } + + bool can_render_frame_ = false; + + private: + int can_render_frame_call_count_ = 0; + int on_frame_rendered_call_count_ = 0; + int on_size_changed_call_count_ = 0; + + int canvas_width_ = 0; + int canvas_height_ = 0; + + base::Closure on_frame_rendered_callback_; + + base::WeakPtrFactory<FakeGlRendererDelegate> weak_factory_; +}; + +class GlRendererTest : public testing::Test { + public: + void SetUp() override; + void SetDesktopFrameWithSize(const webrtc::DesktopSize& size); + void PostSetDesktopFrameTasks(const webrtc::DesktopSize& size, int count); + + protected: + void RequestRender(); + void OnDesktopFrameProcessed(); + void RunTasksInCurrentQueue(); + void RunUntilRendered(); + int on_desktop_frame_processed_call_count() { + return on_desktop_frame_processed_call_count_; + } + + base::MessageLoop message_loop_; + std::unique_ptr<GlRenderer> renderer_; + FakeGlRendererDelegate delegate_; + + private: + int on_desktop_frame_processed_call_count_ = 0; +}; + +void GlRendererTest::SetUp() { + renderer_.reset(new GlRenderer()); + renderer_->SetDelegate(delegate_.GetWeakPtr()); +} + +void GlRendererTest::RequestRender() { + renderer_->RequestRender(); +} + +void GlRendererTest::SetDesktopFrameWithSize(const webrtc::DesktopSize& size) { + renderer_->OnFrameReceived( + base::WrapUnique( + new webrtc::BasicDesktopFrame(size)), + base::Bind(&GlRendererTest::OnDesktopFrameProcessed, + base::Unretained(this))); +} + +void GlRendererTest::PostSetDesktopFrameTasks( + const webrtc::DesktopSize& size, int count) { + for (int i = 0; i < count; i++) { + message_loop_.task_runner()->PostTask( + FROM_HERE, base::Bind(&GlRendererTest::SetDesktopFrameWithSize, + base::Unretained(this), size)); + } +} + +void GlRendererTest::OnDesktopFrameProcessed() { + on_desktop_frame_processed_call_count_++; +} + +void GlRendererTest::RunTasksInCurrentQueue() { + base::RunLoop run_loop; + message_loop_.task_runner()->PostTask(FROM_HERE, run_loop.QuitClosure()); + run_loop.Run(); +} + +void GlRendererTest::RunUntilRendered() { + base::RunLoop run_loop; + delegate_.SetOnFrameRenderedCallback(run_loop.QuitClosure()); + run_loop.Run(); +} + + +TEST_F(GlRendererTest, TestDelegateCanRenderFrame) { + delegate_.can_render_frame_ = true; + RequestRender(); + RunTasksInCurrentQueue(); + EXPECT_EQ(1, delegate_.can_render_frame_call_count()); + EXPECT_EQ(1, delegate_.on_frame_rendered_call_count()); + + delegate_.can_render_frame_ = false; + RequestRender(); + RunTasksInCurrentQueue(); + EXPECT_EQ(2, delegate_.can_render_frame_call_count()); + EXPECT_EQ(1, delegate_.on_frame_rendered_call_count()); +} + +TEST_F(GlRendererTest, TestRequestRenderOnlyScheduleOnce) { + delegate_.can_render_frame_ = true; + + RequestRender(); + RequestRender(); + RequestRender(); + RunTasksInCurrentQueue(); + EXPECT_EQ(1, delegate_.can_render_frame_call_count()); + EXPECT_EQ(1, delegate_.on_frame_rendered_call_count()); + + RequestRender(); + RunTasksInCurrentQueue(); + EXPECT_EQ(2, delegate_.can_render_frame_call_count()); + EXPECT_EQ(2, delegate_.on_frame_rendered_call_count()); +} + +TEST_F(GlRendererTest, TestDelegateOnSizeChanged) { + SetDesktopFrameWithSize(webrtc::DesktopSize(16, 16)); + EXPECT_EQ(1, delegate_.on_size_changed_call_count()); + EXPECT_EQ(16, delegate_.canvas_width()); + EXPECT_EQ(16, delegate_.canvas_height()); + + SetDesktopFrameWithSize(webrtc::DesktopSize(16, 16)); + EXPECT_EQ(1, delegate_.on_size_changed_call_count()); + EXPECT_EQ(16, delegate_.canvas_width()); + EXPECT_EQ(16, delegate_.canvas_height()); + + SetDesktopFrameWithSize(webrtc::DesktopSize(32, 32)); + EXPECT_EQ(2, delegate_.on_size_changed_call_count()); + EXPECT_EQ(32, delegate_.canvas_width()); + EXPECT_EQ(32, delegate_.canvas_height()); + + renderer_->RequestCanvasSize(); + EXPECT_EQ(3, delegate_.on_size_changed_call_count()); + EXPECT_EQ(32, delegate_.canvas_width()); + EXPECT_EQ(32, delegate_.canvas_height()); +} + +TEST_F(GlRendererTest, TestOnFrameReceivedDoneCallbacks) { + delegate_.can_render_frame_ = true; + + // Implicitly calls RequestRender(). + + PostSetDesktopFrameTasks(webrtc::DesktopSize(16, 16), 1); + RunUntilRendered(); + EXPECT_EQ(1, delegate_.on_frame_rendered_call_count()); + EXPECT_EQ(1, on_desktop_frame_processed_call_count()); + + PostSetDesktopFrameTasks(webrtc::DesktopSize(16, 16), 20); + RunUntilRendered(); + EXPECT_EQ(2, delegate_.on_frame_rendered_call_count()); + EXPECT_EQ(21, on_desktop_frame_processed_call_count()); +} + +// TODO(yuweih): Add tests to validate the rendered output. + +} // namespace remoting
diff --git a/remoting/client/gl_texture_ids.h b/remoting/client/gl_texture_ids.h new file mode 100644 index 0000000..a4fb91e --- /dev/null +++ b/remoting/client/gl_texture_ids.h
@@ -0,0 +1,22 @@ +// 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 REMOTING_CLIENT_GL_TEXTURE_IDS_H_ +#define REMOTING_CLIENT_GL_TEXTURE_IDS_H_ + +#include "base/macros.h" + +namespace remoting { + +const int kGlCursorTextureId = 0; +const int kGlCursorFeedbackTextureId = 1; + +// GlDesktop may occupy more than one texture unit. This should be the last +// texture ID so that GlDesktop can use any id >= kGlDesktopFirstTextureId +// without conflict. +const int kGlDesktopFirstTextureId = 2; + +} // namespace remoting + +#endif // REMOTING_CLIENT_GL_TEXTURE_IDS_H_
diff --git a/remoting/client/jni/chromoting_jni_runtime.cc b/remoting/client/jni/chromoting_jni_runtime.cc index fe11386..eb54996 100644 --- a/remoting/client/jni/chromoting_jni_runtime.cc +++ b/remoting/client/jni/chromoting_jni_runtime.cc
@@ -21,6 +21,7 @@ using base::android::ConvertJavaStringToUTF8; using base::android::ConvertUTF8ToJavaString; +using base::android::JavaParamRef; using base::android::ToJavaByteArray; namespace {
diff --git a/remoting/client/jni/jni_client.cc b/remoting/client/jni/jni_client.cc index b3c7114a..78aea2a 100644 --- a/remoting/client/jni/jni_client.cc +++ b/remoting/client/jni/jni_client.cc
@@ -19,6 +19,8 @@ using base::android::ConvertJavaStringToUTF8; using base::android::ConvertUTF8ToJavaString; +using base::android::JavaParamRef; +using base::android::ScopedJavaLocalRef; namespace remoting {
diff --git a/remoting/client/jni/jni_gl_display_handler.cc b/remoting/client/jni/jni_gl_display_handler.cc index 4e86735f..13d09d84 100644 --- a/remoting/client/jni/jni_gl_display_handler.cc +++ b/remoting/client/jni/jni_gl_display_handler.cc
@@ -4,23 +4,38 @@ #include "remoting/client/jni/jni_gl_display_handler.h" +#include <android/native_window_jni.h> +#include <array> + +#include "base/android/jni_android.h" +#include "base/bind.h" #include "base/logging.h" +#include "base/memory/ptr_util.h" #include "jni/GlDisplay_jni.h" +#include "remoting/client/cursor_shape_stub_proxy.h" +#include "remoting/client/dual_buffer_frame_consumer.h" #include "remoting/client/jni/chromoting_jni_runtime.h" -#include "remoting/protocol/video_renderer.h" +#include "remoting/client/jni/egl_thread_context.h" +#include "remoting/client/queued_task_poster.h" +#include "remoting/client/software_video_renderer.h" +#include "remoting/protocol/frame_consumer.h" namespace remoting { -JniGlDisplayHandler::JniGlDisplayHandler(ChromotingJniRuntime* runtime) : - runtime_(runtime) { +JniGlDisplayHandler::JniGlDisplayHandler(ChromotingJniRuntime* runtime) + : runtime_(runtime), weak_factory_(this) { + weak_ptr_ = weak_factory_.GetWeakPtr(); java_display_.Reset(Java_GlDisplay_createJavaDisplayObject( base::android::AttachCurrentThread(), reinterpret_cast<intptr_t>(this))); + renderer_.SetDelegate(weak_ptr_); + ui_task_poster_.reset(new QueuedTaskPoster(runtime->display_task_runner())); } JniGlDisplayHandler::~JniGlDisplayHandler() { DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread()); Java_GlDisplay_invalidate(base::android::AttachCurrentThread(), java_display_.obj()); + runtime_->ui_task_runner()->DeleteSoon(FROM_HERE, ui_task_poster_.release()); } void JniGlDisplayHandler::InitializeClient( @@ -32,14 +47,21 @@ std::unique_ptr<protocol::CursorShapeStub> JniGlDisplayHandler::CreateCursorShapeStub() { - NOTIMPLEMENTED(); - return std::unique_ptr<protocol::CursorShapeStub>(); + return base::WrapUnique( + new CursorShapeStubProxy(weak_ptr_, runtime_->display_task_runner())); } std::unique_ptr<protocol::VideoRenderer> JniGlDisplayHandler::CreateVideoRenderer() { - NOTIMPLEMENTED(); - return std::unique_ptr<protocol::VideoRenderer>(); + DCHECK(runtime_->ui_task_runner()->BelongsToCurrentThread()); + DCHECK(!frame_consumer_); + std::unique_ptr<DualBufferFrameConsumer> consumer = + base::WrapUnique(new DualBufferFrameConsumer( + base::Bind(&GlRenderer::OnFrameReceived, renderer_.GetWeakPtr()), + runtime_->display_task_runner(), + protocol::FrameConsumer::PixelFormat::FORMAT_RGBA)); + frame_consumer_ = consumer->GetWeakPtr(); + return base::WrapUnique(new SoftwareVideoRenderer(std::move(consumer))); } // static @@ -52,7 +74,10 @@ const base::android::JavaParamRef<jobject>& caller, const base::android::JavaParamRef<jobject>& surface) { DCHECK(runtime_->ui_task_runner()->BelongsToCurrentThread()); - NOTIMPLEMENTED(); + runtime_->display_task_runner()->PostTask( + FROM_HERE, + base::Bind(&JniGlDisplayHandler::SurfaceCreatedOnDisplayThread, weak_ptr_, + base::android::ScopedJavaGlobalRef<jobject>(env, surface))); } void JniGlDisplayHandler::OnSurfaceChanged( @@ -61,14 +86,19 @@ int width, int height) { DCHECK(runtime_->ui_task_runner()->BelongsToCurrentThread()); - NOTIMPLEMENTED(); + runtime_->display_task_runner()->PostTask( + FROM_HERE, base::Bind(&GlRenderer::OnSurfaceChanged, + renderer_.GetWeakPtr(), width, height)); } void JniGlDisplayHandler::OnSurfaceDestroyed( JNIEnv* env, const base::android::JavaParamRef<jobject>& caller) { DCHECK(runtime_->ui_task_runner()->BelongsToCurrentThread()); - NOTIMPLEMENTED(); + runtime_->display_task_runner()->PostTask( + FROM_HERE, + base::Bind(&JniGlDisplayHandler::SurfaceDestroyedOnDisplayThread, + weak_ptr_)); } void JniGlDisplayHandler::OnPixelTransformationChanged( @@ -76,7 +106,11 @@ const base::android::JavaParamRef<jobject>& caller, const base::android::JavaParamRef<jfloatArray>& jmatrix) { DCHECK(runtime_->ui_task_runner()->BelongsToCurrentThread()); - NOTIMPLEMENTED(); + DCHECK(env->GetArrayLength(jmatrix.obj()) == 9); + std::array<float, 9> matrix; + env->GetFloatArrayRegion(jmatrix.obj(), 0, 9, matrix.data()); + ui_task_poster_->AddTask(base::Bind(&GlRenderer::OnPixelTransformationChanged, + renderer_.GetWeakPtr(), matrix)); } void JniGlDisplayHandler::OnCursorPixelPositionChanged( @@ -85,7 +119,8 @@ int x, int y) { DCHECK(runtime_->ui_task_runner()->BelongsToCurrentThread()); - NOTIMPLEMENTED(); + ui_task_poster_->AddTask(base::Bind(&GlRenderer::OnCursorMoved, + renderer_.GetWeakPtr(), x, y)); } void JniGlDisplayHandler::OnCursorVisibilityChanged( @@ -93,7 +128,8 @@ const base::android::JavaParamRef<jobject>& caller, bool visible) { DCHECK(runtime_->ui_task_runner()->BelongsToCurrentThread()); - NOTIMPLEMENTED(); + ui_task_poster_->AddTask(base::Bind(&GlRenderer::OnCursorVisibilityChanged, + renderer_.GetWeakPtr(), visible)); } void JniGlDisplayHandler::OnCursorInputFeedback( @@ -103,31 +139,71 @@ int y, float diameter) { DCHECK(runtime_->ui_task_runner()->BelongsToCurrentThread()); - NOTIMPLEMENTED(); + ui_task_poster_->AddTask(base::Bind(&GlRenderer::OnCursorInputFeedback, + renderer_.GetWeakPtr(), x, y, diameter)); } -void JniGlDisplayHandler::SetRenderEventEnabled( - JNIEnv* env, - const base::android::JavaParamRef<jobject>& caller, - jboolean enabled) { - DCHECK(runtime_->ui_task_runner()->BelongsToCurrentThread()); - NOTIMPLEMENTED(); +bool JniGlDisplayHandler::CanRenderFrame() { + DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread()); + return egl_context_ && egl_context_->IsWindowBound(); +} + +void JniGlDisplayHandler::OnFrameRendered() { + DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread()); + egl_context_->SwapBuffers(); + runtime_->ui_task_runner()->PostTask( + FROM_HERE, base::Bind(&JniGlDisplayHandler::NotifyRenderDoneOnUiThread, + java_display_)); +} + +void JniGlDisplayHandler::OnSizeChanged(int width, int height) { + DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread()); + runtime_->ui_task_runner()->PostTask( + FROM_HERE, base::Bind(&JniGlDisplayHandler::ChangeCanvasSizeOnUiThread, + java_display_, width, height)); +} + +void JniGlDisplayHandler::SetCursorShape( + const protocol::CursorShapeInfo& cursor_shape) { + DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread()); + renderer_.OnCursorShapeChanged(cursor_shape); } // static -void JniGlDisplayHandler::NotifyRenderEventOnUiThread( - base::android::ScopedJavaGlobalRef<jobject> java_client) { +void JniGlDisplayHandler::NotifyRenderDoneOnUiThread( + base::android::ScopedJavaGlobalRef<jobject> java_display) { Java_GlDisplay_canvasRendered(base::android::AttachCurrentThread(), - java_client.obj()); + java_display.obj()); +} + +void JniGlDisplayHandler::SurfaceCreatedOnDisplayThread( + base::android::ScopedJavaGlobalRef<jobject> surface) { + DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread()); + renderer_.RequestCanvasSize(); + ANativeWindow* window = ANativeWindow_fromSurface( + base::android::AttachCurrentThread(), surface.obj()); + egl_context_.reset(new EglThreadContext()); + egl_context_->BindToWindow(window); + ANativeWindow_release(window); + renderer_.OnSurfaceCreated(static_cast<int>(egl_context_->client_version())); + runtime_->network_task_runner()->PostTask( + FROM_HERE, base::Bind(&DualBufferFrameConsumer::RequestFullDesktopFrame, + frame_consumer_)); +} + +void JniGlDisplayHandler::SurfaceDestroyedOnDisplayThread() { + DCHECK(runtime_->display_task_runner()->BelongsToCurrentThread()); + renderer_.OnSurfaceDestroyed(); + egl_context_.reset(); } // static void JniGlDisplayHandler::ChangeCanvasSizeOnUiThread( - base::android::ScopedJavaGlobalRef<jobject> java_client, + base::android::ScopedJavaGlobalRef<jobject> java_display, int width, int height) { JNIEnv* env = base::android::AttachCurrentThread(); - Java_GlDisplay_changeCanvasSize(env, java_client.obj(), width, height); + Java_GlDisplay_changeCanvasSize(env, java_display.obj(), width, height); } } // namespace remoting
diff --git a/remoting/client/jni/jni_gl_display_handler.h b/remoting/client/jni/jni_gl_display_handler.h index 7ddfaaa..69ea765 100644 --- a/remoting/client/jni/jni_gl_display_handler.h +++ b/remoting/client/jni/jni_gl_display_handler.h
@@ -5,23 +5,32 @@ #ifndef REMOTING_CLIENT_JNI_JNI_GL_DISPLAY_HANDLER_H_ #define REMOTING_CLIENT_JNI_JNI_GL_DISPLAY_HANDLER_H_ +#include <EGL/egl.h> #include <jni.h> #include "base/android/scoped_java_ref.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" +#include "remoting/client/gl_renderer.h" +#include "remoting/client/gl_renderer_delegate.h" #include "remoting/client/jni/display_updater_factory.h" +#include "remoting/protocol/cursor_shape_stub.h" namespace remoting { class ChromotingJniRuntime; +class DualBufferFrameConsumer; +class EglThreadContext; +class QueuedTaskPoster; // Handles OpenGL display operations. Draws desktop and cursor on the OpenGL // surface. // JNI functions should all be called on the UI thread. The display handler // itself should be deleted on the display thread. // Please see GlDisplay.java for documentations. -class JniGlDisplayHandler : public DisplayUpdaterFactory { +class JniGlDisplayHandler : public DisplayUpdaterFactory, + public protocol::CursorShapeStub, + public GlRendererDelegate { public: JniGlDisplayHandler(ChromotingJniRuntime* runtime); ~JniGlDisplayHandler() override; @@ -29,7 +38,8 @@ // Sets the DesktopViewFactory for the Java client. void InitializeClient( const base::android::JavaRef<jobject>& java_client); - // DisplayUpdaterFactory overrides. + + // DisplayUpdaterFactory interface. std::unique_ptr<protocol::CursorShapeStub> CreateCursorShapeStub() override; std::unique_ptr<protocol::VideoRenderer> CreateVideoRenderer() override; @@ -73,16 +83,25 @@ int y, float diameter); - void SetRenderEventEnabled(JNIEnv* env, - const base::android::JavaParamRef<jobject>& caller, - jboolean enabled); - private: - static void NotifyRenderEventOnUiThread( - base::android::ScopedJavaGlobalRef<jobject> java_client); + // GlRendererDelegate interface. + bool CanRenderFrame() override; + void OnFrameRendered() override; + void OnSizeChanged(int width, int height) override; + + // CursorShapeStub interface. + void SetCursorShape(const protocol::CursorShapeInfo& cursor_shape) override; + + static void NotifyRenderDoneOnUiThread( + base::android::ScopedJavaGlobalRef<jobject> java_display); + + void SurfaceCreatedOnDisplayThread( + base::android::ScopedJavaGlobalRef<jobject> surface); + + void SurfaceDestroyedOnDisplayThread(); static void ChangeCanvasSizeOnUiThread( - base::android::ScopedJavaGlobalRef<jobject> java_client, + base::android::ScopedJavaGlobalRef<jobject> java_display, int width, int height); @@ -90,6 +109,18 @@ base::android::ScopedJavaGlobalRef<jobject> java_display_; + std::unique_ptr<EglThreadContext> egl_context_; + + base::WeakPtr<DualBufferFrameConsumer> frame_consumer_; + + // |renderer_| must be deleted earlier than |egl_context_|. + GlRenderer renderer_; + + std::unique_ptr<QueuedTaskPoster> ui_task_poster_; + + // Used on display thread. + base::WeakPtr<JniGlDisplayHandler> weak_ptr_; + base::WeakPtrFactory<JniGlDisplayHandler> weak_factory_; DISALLOW_COPY_AND_ASSIGN(JniGlDisplayHandler); };
diff --git a/remoting/client/jni/remoting_jni_registrar.cc b/remoting/client/jni/remoting_jni_registrar.cc index 8da2ea7b..6613a55 100644 --- a/remoting/client/jni/remoting_jni_registrar.cc +++ b/remoting/client/jni/remoting_jni_registrar.cc
@@ -11,6 +11,7 @@ #include "remoting/client/jni/chromoting_jni_runtime.h" #include "remoting/client/jni/jni_client.h" #include "remoting/client/jni/jni_display_handler.h" +#include "remoting/client/jni/jni_gl_display_handler.h" namespace remoting { @@ -18,7 +19,8 @@ const base::android::RegistrationMethod kRemotingRegisteredMethods[] = { {"JniClient", JniClient::RegisterJni}, {"ChromotingJniRuntime", RegisterChromotingJniRuntime}, - {"JniDisplayHandler", JniDisplayHandler::RegisterJni} + {"JniDisplayHandler", JniDisplayHandler::RegisterJni}, + {"JniGlDisplay", JniGlDisplayHandler::RegisterJni}, }; } // namespace
diff --git a/remoting/client/queued_task_poster.cc b/remoting/client/queued_task_poster.cc new file mode 100644 index 0000000..adab1d6d --- /dev/null +++ b/remoting/client/queued_task_poster.cc
@@ -0,0 +1,52 @@ +// 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 "remoting/client/queued_task_poster.h" + +#include "base/bind.h" +#include "base/location.h" +#include "base/logging.h" +#include "base/threading/thread_task_runner_handle.h" + +namespace remoting { + +QueuedTaskPoster::QueuedTaskPoster( + scoped_refptr<base::SingleThreadTaskRunner> target_task_runner) + : target_task_runner_(target_task_runner), + weak_factory_(this) {} + +QueuedTaskPoster::~QueuedTaskPoster() {} + +void QueuedTaskPoster::AddTask(const base::Closure& closure) { + if (!source_task_runner_) { + source_task_runner_ = base::ThreadTaskRunnerHandle::Get(); + } + DCHECK(source_task_runner_->BelongsToCurrentThread()); + task_queue_.push(closure); + if (!transfer_task_scheduled_) { + source_task_runner_->PostTask( + FROM_HERE, base::Bind(&QueuedTaskPoster::TransferTaskQueue, + weak_factory_.GetWeakPtr())); + transfer_task_scheduled_ = true; + } +} + +static void ConsumeTaskQueue(std::queue<base::Closure>* queue) { + while (!queue->empty()) { + queue->front().Run(); + queue->pop(); + } +} + +void QueuedTaskPoster::TransferTaskQueue() { + DCHECK(transfer_task_scheduled_); + transfer_task_scheduled_ = false; + std::queue<base::Closure>* queue_to_transfer = + new std::queue<base::Closure>(); + queue_to_transfer->swap(task_queue_); + target_task_runner_->PostTask( + FROM_HERE, base::Bind(&ConsumeTaskQueue, base::Owned(queue_to_transfer))); +} + +} // namespace remoting
diff --git a/remoting/client/queued_task_poster.h b/remoting/client/queued_task_poster.h new file mode 100644 index 0000000..44c537c --- /dev/null +++ b/remoting/client/queued_task_poster.h
@@ -0,0 +1,48 @@ +// 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 REMOTING_CLIENT_QUEUED_TASK_POSTER_H_ +#define REMOTING_CLIENT_QUEUED_TASK_POSTER_H_ + +#include <memory> +#include <queue> + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" + +namespace remoting { + +// This is a helper class ensuring tasks posted to |target_task_runner| inside +// the same task slot will be queued up and executed together after current +// task is done on |source_task_runner|. This can prevent unrelated tasks to +// be scheduled on |target_task_runner| in between the task sequence. +// This class can be created on any thread but must be used and deleted on the +// thread of |source_task_runner|. +class QueuedTaskPoster { + public: + QueuedTaskPoster( + scoped_refptr<base::SingleThreadTaskRunner> target_task_runner); + ~QueuedTaskPoster(); + + void AddTask(const base::Closure& closure); + + private: + void TransferTaskQueue(); + + scoped_refptr<base::SingleThreadTaskRunner> source_task_runner_; + scoped_refptr<base::SingleThreadTaskRunner> target_task_runner_; + + std::queue<base::Closure> task_queue_; + + bool transfer_task_scheduled_ = false; + + base::WeakPtrFactory<QueuedTaskPoster> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(QueuedTaskPoster); +}; + +} // namespace remoting + +#endif // REMOTING_CLIENT_QUEUED_TASK_POSTER_H_
diff --git a/remoting/client/queued_task_poster_unittest.cc b/remoting/client/queued_task_poster_unittest.cc new file mode 100644 index 0000000..ed36528 --- /dev/null +++ b/remoting/client/queued_task_poster_unittest.cc
@@ -0,0 +1,145 @@ +// 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 "remoting/client/queued_task_poster.h" + +#include <memory> + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "base/threading/thread.h" +#include "base/threading/thread_task_runner_handle.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace remoting { + +class QueuedTaskPosterTest : public testing::Test { + public: + QueuedTaskPosterTest(); + void SetUp() override; + void TearDown() override; + + protected: + base::Closure SetSequenceStartedClosure(bool started); + base::Closure AssertExecutionOrderClosure(int order); + base::Closure AssertSequenceNotStartedClosure(); + + void RunUntilPosterDone(); + + scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; + scoped_refptr<base::SingleThreadTaskRunner> target_task_runner_; + std::unique_ptr<QueuedTaskPoster> poster_; + int current_execution_order_ = 0; + + private: + void SetSequenceStarted(bool started); + void AssertExecutionOrder(int order); + void AssertSequenceNotStarted(); + + base::Thread target_thread_; + base::MessageLoop main_message_loop_; + bool sequence_started_ = false; +}; + +QueuedTaskPosterTest::QueuedTaskPosterTest() + : target_thread_("Target Thread") {} + +void QueuedTaskPosterTest::SetUp() { + target_thread_.StartAndWaitForTesting(); + main_task_runner_ = base::ThreadTaskRunnerHandle::Get(); + target_task_runner_ = target_thread_.task_runner(); + poster_.reset(new QueuedTaskPoster(target_task_runner_)); +} + +void QueuedTaskPosterTest::TearDown() { + target_thread_.Stop(); +} + +base::Closure QueuedTaskPosterTest::SetSequenceStartedClosure(bool started) { + return base::Bind(&QueuedTaskPosterTest::SetSequenceStarted, + base::Unretained(this), started); +} + +base::Closure QueuedTaskPosterTest::AssertExecutionOrderClosure(int order) { + return base::Bind(&QueuedTaskPosterTest::AssertExecutionOrder, + base::Unretained(this), order); +} + +base::Closure QueuedTaskPosterTest::AssertSequenceNotStartedClosure() { + return base::Bind(&QueuedTaskPosterTest::AssertSequenceNotStarted, + base::Unretained(this)); +} + +void QueuedTaskPosterTest::RunUntilPosterDone() { + base::RunLoop run_loop; + poster_->AddTask( + base::Bind(base::IgnoreResult(&base::SingleThreadTaskRunner::PostTask), + main_task_runner_, FROM_HERE, run_loop.QuitClosure())); + run_loop.Run(); +} + +void QueuedTaskPosterTest::SetSequenceStarted(bool started) { + sequence_started_ = started; +} + +void QueuedTaskPosterTest::AssertExecutionOrder(int order) { + ASSERT_EQ(current_execution_order_ + 1, order); + current_execution_order_++; +} + +void QueuedTaskPosterTest::AssertSequenceNotStarted() { + ASSERT_FALSE(sequence_started_); +} + +TEST_F(QueuedTaskPosterTest, TestTaskOrder) { + poster_->AddTask(AssertExecutionOrderClosure(1)); + poster_->AddTask(AssertExecutionOrderClosure(2)); + poster_->AddTask(AssertExecutionOrderClosure(3)); + poster_->AddTask(AssertExecutionOrderClosure(4)); + poster_->AddTask(AssertExecutionOrderClosure(5)); + + RunUntilPosterDone(); + EXPECT_EQ(5, current_execution_order_); +} + +TEST_F(QueuedTaskPosterTest, TestTaskSequenceNotInterfered) { + target_task_runner_->PostTask(FROM_HERE, AssertSequenceNotStartedClosure()); + poster_->AddTask(SetSequenceStartedClosure(true)); + target_task_runner_->PostTask(FROM_HERE, AssertSequenceNotStartedClosure()); + poster_->AddTask(AssertExecutionOrderClosure(1)); + target_task_runner_->PostTask(FROM_HERE, AssertSequenceNotStartedClosure()); + poster_->AddTask(AssertExecutionOrderClosure(2)); + target_task_runner_->PostTask(FROM_HERE, AssertSequenceNotStartedClosure()); + poster_->AddTask(AssertExecutionOrderClosure(3)); + target_task_runner_->PostTask(FROM_HERE, AssertSequenceNotStartedClosure()); + poster_->AddTask(AssertExecutionOrderClosure(4)); + target_task_runner_->PostTask(FROM_HERE, AssertSequenceNotStartedClosure()); + poster_->AddTask(AssertExecutionOrderClosure(5)); + target_task_runner_->PostTask(FROM_HERE, AssertSequenceNotStartedClosure()); + poster_->AddTask(SetSequenceStartedClosure(false)); + target_task_runner_->PostTask(FROM_HERE, AssertSequenceNotStartedClosure()); + + RunUntilPosterDone(); + EXPECT_EQ(5, current_execution_order_); +} + +TEST_F(QueuedTaskPosterTest, TestUsingPosterInMultipleTasks) { + poster_->AddTask(AssertExecutionOrderClosure(1)); + poster_->AddTask(AssertExecutionOrderClosure(2)); + poster_->AddTask(AssertExecutionOrderClosure(3)); + + RunUntilPosterDone(); + EXPECT_EQ(3, current_execution_order_); + + poster_->AddTask(AssertExecutionOrderClosure(4)); + poster_->AddTask(AssertExecutionOrderClosure(5)); + poster_->AddTask(AssertExecutionOrderClosure(6)); + + RunUntilPosterDone(); + EXPECT_EQ(6, current_execution_order_); +} + +} // namespace remoting
diff --git a/remoting/client/sys_opengl.h b/remoting/client/sys_opengl.h index 142f5d4..8a1c907d 100644 --- a/remoting/client/sys_opengl.h +++ b/remoting/client/sys_opengl.h
@@ -9,10 +9,16 @@ #if defined(OS_IOS) #include <OpenGLES/ES3/gl.h> -#elif defined(OS_ANDROID) -#include <GLES3/gl3.h> +#elif defined(OS_LINUX) +#define GL_GLEXT_PROTOTYPES +#include <GL/gl.h> +#include <GL/glext.h> +#elif defined(OS_MACOSX) +#define GL_GLEXT_PROTOTYPES +#include <OpenGL/gl.h> +#include <OpenGL/glext.h> #else -#error OpenGL renderer not supported on this platform. -#endif +#include <GLES3/gl3.h> +#endif // defined(OS_IOS) #endif // REMOTING_CLIENT_SYS_OPENGL_H_
diff --git a/remoting/host/BUILD.gn b/remoting/host/BUILD.gn index beaa529..c3ade737 100644 --- a/remoting/host/BUILD.gn +++ b/remoting/host/BUILD.gn
@@ -366,6 +366,8 @@ } if (is_win) { sources += [ + "win/elevated_native_messaging_host.cc", + "win/elevated_native_messaging_host.h", "win/launch_native_messaging_host_process.cc", "win/launch_native_messaging_host_process.h", ] @@ -597,6 +599,8 @@ "win/chromoting_module.h", "win/core.cc", "win/core_resource.h", + "win/elevated_native_messaging_host.cc", + "win/elevated_native_messaging_host.h", "win/host_service.cc", "win/host_service.h", "win/launch_native_messaging_host_process.cc", @@ -1298,7 +1302,24 @@ ] _generated_files = rebase_path(inputs, root_build_dir) - _extra_files = [] + _generated_files += [ rebase_path("//remoting/resources/chromoting.ico") ] + + # _generated_dst_files must contain the same files in the same order as + # _generated_files, otherwise the Windows MSI will not be built correctly. + _generated_dst_files = [ + "files/remote_assistance_host.exe", + "files/remote_security_key.exe", + "files/remoting_core.dll", + "files/remoting_desktop.exe", + "files/remoting_host.exe", + "files/remoting_native_messaging_host.exe", + "files/remoting_start_host.exe", + "files/CREDITS.txt", + "files/com.google.chrome.remote_assistance.json", + "files/com.google.chrome.remote_desktop.json", + "files/icudtl.dat", + "files/chromoting.ico", + ] args = [ @@ -1314,24 +1335,11 @@ "--generated-files", ] + _generated_files + [ - rebase_path("//remoting/resources/chromoting.ico"), - # Position of files in zip file "--generated-files-dst", - "files/remote_assistance_host.exe", - "files/remote_security_key.exe", - "files/remoting_core.dll", - "files/remoting_desktop.exe", - "files/remoting_host.exe", - "files/remoting_native_messaging_host.exe", - "files/remoting_start_host.exe", - "files/CREDITS.txt", - "files/com.google.chrome.remote_assistance.json", - "files/com.google.chrome.remote_desktop.json", - "files/chromoting.ico", - "files/icudtl.dat", - ] + _extra_files + # Defs + ] + _generated_dst_files + [ + # Defs "--defs", "BRANDING=$_branding", "DAEMON_CONTROLLER_CLSID={$daemon_controller_clsid}",
diff --git a/remoting/host/android/jni_host.cc b/remoting/host/android/jni_host.cc index 11b3bcc..a2fe272 100644 --- a/remoting/host/android/jni_host.cc +++ b/remoting/host/android/jni_host.cc
@@ -19,6 +19,7 @@ using base::android::ConvertJavaStringToUTF8; using base::android::ConvertUTF8ToJavaString; +using base::android::JavaParamRef; namespace remoting {
diff --git a/remoting/host/client_session.cc b/remoting/host/client_session.cc index 262343c..2bcc11f 100644 --- a/remoting/host/client_session.cc +++ b/remoting/host/client_session.cc
@@ -120,12 +120,23 @@ if (!screen_controls_) return; - ScreenResolution client_resolution( - webrtc::DesktopSize(resolution.dips_width(), resolution.dips_height()), - webrtc::DesktopVector(kDefaultDpi, kDefaultDpi)); + webrtc::DesktopSize client_size(resolution.dips_width(), + resolution.dips_height()); + if (connection_->session()->config().protocol() == + protocol::SessionConfig::Protocol::WEBRTC) { + // When using WebRTC round down the dimensions to multiple of 2. Otherwise + // the dimensions will be rounded on the receiver, which will cause blurring + // due to scaling. The resulting size is still close to the client size and + // will fit on the client's screen without scaling. + // TODO(sergeyu): Make WebRTC handle odd dimensions properly. + // crbug.com/636071 + client_size.set(client_size.width() & (~1), client_size.height() & (~1)); + } // Try to match the client's resolution. - screen_controls_->SetScreenResolution(client_resolution); + // TODO(sergeyu): Pass clients DPI to the resizer. + screen_controls_->SetScreenResolution(ScreenResolution( + client_size, webrtc::DesktopVector(kDefaultDpi, kDefaultDpi))); } void ClientSession::ControlVideo(const protocol::VideoControl& video_control) {
diff --git a/remoting/host/native_messaging/native_messaging_reader.cc b/remoting/host/native_messaging/native_messaging_reader.cc index 23f6eb2f..6aad692 100644 --- a/remoting/host/native_messaging/native_messaging_reader.cc +++ b/remoting/host/native_messaging/native_messaging_reader.cc
@@ -4,8 +4,7 @@ #include "remoting/host/native_messaging/native_messaging_reader.h" -#include <stdint.h> - +#include <cstdint> #include <string> #include <utility> @@ -17,9 +16,17 @@ #include "base/sequenced_task_runner.h" #include "base/single_thread_task_runner.h" #include "base/stl_util.h" -#include "base/threading/sequenced_worker_pool.h" +#include "base/threading/thread.h" #include "base/threading/thread_task_runner_handle.h" #include "base/values.h" +#include "build/build_config.h" + +#if defined(OS_WIN) +#include <windows.h> + +#include "base/threading/platform_thread.h" +#include "base/win/scoped_handle.h" +#endif // defined(OS_WIN) namespace { @@ -137,7 +144,9 @@ NativeMessagingReader::NativeMessagingReader(base::File file) : reader_thread_("Reader"), weak_factory_(this) { - reader_thread_.Start(); + reader_thread_.StartWithOptions( + base::Thread::Options(base::MessageLoop::TYPE_IO, /*size=*/0)); + read_task_runner_ = reader_thread_.task_runner(); core_.reset(new Core(std::move(file), base::ThreadTaskRunnerHandle::Get(), read_task_runner_, weak_factory_.GetWeakPtr())); @@ -145,6 +154,29 @@ NativeMessagingReader::~NativeMessagingReader() { read_task_runner_->DeleteSoon(FROM_HERE, core_.release()); + +#if defined(OS_WIN) + // The ReadMessage() method uses a blocking read (on all platforms) which + // cause a deadlock if the owning thread attempts to destroy this object + // while there is a read operation pending. + // On POSIX platforms, closing the write end of the pipe causes the Chrome + // process to close the read end so that this class can be cleaned up. + // On Windows, closing the write end of the pipe does nothing as the parent + // process is cmd.exe which doesn't care. Thus, the read end of the pipe + // remains open, the read operation is blocked, and we hang in the d'tor. + // Canceling the pending I/O here prevents the hang on Windows and isn't + // needed for POSIX since it works correctly. + base::PlatformThreadId thread_id = reader_thread_.GetThreadId(); + base::win::ScopedHandle thread_handle( + OpenThread(THREAD_TERMINATE, /*bInheritHandle=*/false, thread_id)); + if (!CancelSynchronousIo(thread_handle.Get())) { + // ERROR_NOT_FOUND means there were no pending IO requests so don't treat + // that result as an error. + if (GetLastError() != ERROR_NOT_FOUND) { + PLOG(ERROR) << "CancelSynchronousIo() failed"; + } + } +#endif // defined(OS_WIN) } void NativeMessagingReader::Start(MessageCallback message_callback,
diff --git a/remoting/host/native_messaging/native_messaging_reader_unittest.cc b/remoting/host/native_messaging/native_messaging_reader_unittest.cc index e5e033c..733ace1 100644 --- a/remoting/host/native_messaging/native_messaging_reader_unittest.cc +++ b/remoting/host/native_messaging/native_messaging_reader_unittest.cc
@@ -4,8 +4,7 @@ #include "remoting/host/native_messaging/native_messaging_reader.h" -#include <stdint.h> - +#include <cstdint> #include <memory> #include <utility> @@ -25,13 +24,16 @@ void SetUp() override; - // Starts the reader and runs the MessageLoop to completion. - void Run(); + // Runs the MessageLoop to completion. + void RunAndWaitForOperationComplete(); // MessageCallback passed to the Reader. Stores |message| so it can be // verified by tests. void OnMessage(std::unique_ptr<base::Value> message); + // Closure passed to the Reader, called back when the reader detects an error. + void OnError(); + // Writes a message (header+body) to the write-end of the pipe. void WriteMessage(const std::string& message); @@ -42,38 +44,46 @@ std::unique_ptr<NativeMessagingReader> reader_; base::File read_file_; base::File write_file_; + bool on_error_signaled_ = false; std::unique_ptr<base::Value> message_; private: // MessageLoop declared here, since the NativeMessageReader ctor requires a // MessageLoop to have been created. base::MessageLoopForIO message_loop_; - base::RunLoop run_loop_; + std::unique_ptr<base::RunLoop> run_loop_; }; NativeMessagingReaderTest::NativeMessagingReaderTest() {} + NativeMessagingReaderTest::~NativeMessagingReaderTest() {} void NativeMessagingReaderTest::SetUp() { ASSERT_TRUE(MakePipe(&read_file_, &write_file_)); reader_.reset(new NativeMessagingReader(std::move(read_file_))); -} - -void NativeMessagingReaderTest::Run() { - // Close the write-end, so the reader doesn't block waiting for more data. - write_file_.Close(); + run_loop_.reset(new base::RunLoop()); // base::Unretained is safe since no further tasks can run after // RunLoop::Run() returns. reader_->Start( base::Bind(&NativeMessagingReaderTest::OnMessage, base::Unretained(this)), - run_loop_.QuitClosure()); - run_loop_.Run(); + base::Bind(&NativeMessagingReaderTest::OnError, base::Unretained(this))); +} + +void NativeMessagingReaderTest::RunAndWaitForOperationComplete() { + run_loop_->Run(); + run_loop_.reset(new base::RunLoop()); } void NativeMessagingReaderTest::OnMessage( std::unique_ptr<base::Value> message) { message_ = std::move(message); + run_loop_->Quit(); +} + +void NativeMessagingReaderTest::OnError() { + on_error_signaled_ = true; + run_loop_->Quit(); } void NativeMessagingReaderTest::WriteMessage(const std::string& message) { @@ -87,41 +97,108 @@ ASSERT_EQ(length, written); } -TEST_F(NativeMessagingReaderTest, GoodMessage) { +TEST_F(NativeMessagingReaderTest, ReaderDestroyedByClosingPipe) { WriteMessage("{\"foo\": 42}"); - Run(); - EXPECT_TRUE(message_); + RunAndWaitForOperationComplete(); + ASSERT_FALSE(on_error_signaled_); + + // Close the write end of the pipe while the reader is waiting for more data. + write_file_.Close(); + RunAndWaitForOperationComplete(); + ASSERT_TRUE(on_error_signaled_); +} + +#if defined(OS_WIN) +// This scenario is only a problem on Windows as closing the write pipe there +// does not trigger the parent process to close the read pipe. +TEST_F(NativeMessagingReaderTest, ReaderDestroyedByOwner) { + WriteMessage("{\"foo\": 42}"); + RunAndWaitForOperationComplete(); + ASSERT_FALSE(on_error_signaled_); + + // Destroy the reader while it is waiting for more data. + reader_.reset(); + ASSERT_FALSE(on_error_signaled_); +} +#endif // defined(OS_WIN) + +TEST_F(NativeMessagingReaderTest, SingleGoodMessage) { + WriteMessage("{\"foo\": 42}"); + RunAndWaitForOperationComplete(); + ASSERT_FALSE(on_error_signaled_); + ASSERT_TRUE(message_); base::DictionaryValue* message_dict; - EXPECT_TRUE(message_->GetAsDictionary(&message_dict)); + ASSERT_TRUE(message_->GetAsDictionary(&message_dict)); int result; - EXPECT_TRUE(message_dict->GetInteger("foo", &result)); - EXPECT_EQ(42, result); + ASSERT_TRUE(message_dict->GetInteger("foo", &result)); + ASSERT_EQ(42, result); +} + +TEST_F(NativeMessagingReaderTest, MultipleGoodMessages) { + WriteMessage("{}"); + RunAndWaitForOperationComplete(); + ASSERT_FALSE(on_error_signaled_); + ASSERT_TRUE(message_); + base::DictionaryValue* message_dict; + ASSERT_TRUE(message_->GetAsDictionary(&message_dict)); + + int result; + WriteMessage("{\"foo\": 42}"); + RunAndWaitForOperationComplete(); + ASSERT_FALSE(on_error_signaled_); + ASSERT_TRUE(message_); + ASSERT_TRUE(message_->GetAsDictionary(&message_dict)); + ASSERT_TRUE(message_dict->GetInteger("foo", &result)); + ASSERT_EQ(42, result); + + WriteMessage("{\"bar\": 43}"); + RunAndWaitForOperationComplete(); + ASSERT_FALSE(on_error_signaled_); + ASSERT_TRUE(message_); + ASSERT_TRUE(message_->GetAsDictionary(&message_dict)); + ASSERT_TRUE(message_dict->GetInteger("bar", &result)); + ASSERT_EQ(43, result); + + WriteMessage("{\"baz\": 44}"); + RunAndWaitForOperationComplete(); + ASSERT_FALSE(on_error_signaled_); + ASSERT_TRUE(message_); + ASSERT_TRUE(message_->GetAsDictionary(&message_dict)); + ASSERT_TRUE(message_dict->GetInteger("baz", &result)); + ASSERT_EQ(44, result); } TEST_F(NativeMessagingReaderTest, InvalidLength) { uint32_t length = 0xffffffff; WriteData(reinterpret_cast<char*>(&length), 4); - Run(); - EXPECT_FALSE(message_); + RunAndWaitForOperationComplete(); + ASSERT_FALSE(message_); + ASSERT_TRUE(on_error_signaled_); } TEST_F(NativeMessagingReaderTest, EmptyFile) { - Run(); - EXPECT_FALSE(message_); + write_file_.Close(); + RunAndWaitForOperationComplete(); + ASSERT_FALSE(message_); + ASSERT_TRUE(on_error_signaled_); } TEST_F(NativeMessagingReaderTest, ShortHeader) { // Write only 3 bytes - the message length header is supposed to be 4 bytes. WriteData("xxx", 3); - Run(); - EXPECT_FALSE(message_); + write_file_.Close(); + RunAndWaitForOperationComplete(); + ASSERT_FALSE(message_); + ASSERT_TRUE(on_error_signaled_); } TEST_F(NativeMessagingReaderTest, EmptyBody) { uint32_t length = 1; WriteData(reinterpret_cast<char*>(&length), 4); - Run(); - EXPECT_FALSE(message_); + write_file_.Close(); + RunAndWaitForOperationComplete(); + ASSERT_FALSE(message_); + ASSERT_TRUE(on_error_signaled_); } TEST_F(NativeMessagingReaderTest, ShortBody) { @@ -130,27 +207,19 @@ // Only write 1 byte, where the header indicates there should be 2 bytes. WriteData("x", 1); - Run(); - EXPECT_FALSE(message_); + write_file_.Close(); + RunAndWaitForOperationComplete(); + ASSERT_FALSE(message_); + ASSERT_TRUE(on_error_signaled_); } TEST_F(NativeMessagingReaderTest, InvalidJSON) { std::string text = "{"; WriteMessage(text); - Run(); - EXPECT_FALSE(message_); -} - -TEST_F(NativeMessagingReaderTest, SecondMessage) { - WriteMessage("{}"); - WriteMessage("{\"foo\": 42}"); - Run(); - EXPECT_TRUE(message_); - base::DictionaryValue* message_dict; - EXPECT_TRUE(message_->GetAsDictionary(&message_dict)); - int result; - EXPECT_TRUE(message_dict->GetInteger("foo", &result)); - EXPECT_EQ(42, result); + write_file_.Close(); + RunAndWaitForOperationComplete(); + ASSERT_FALSE(message_); + ASSERT_TRUE(on_error_signaled_); } } // namespace remoting
diff --git a/remoting/host/resizing_host_observer.cc b/remoting/host/resizing_host_observer.cc index f9d879a..8654ea44 100644 --- a/remoting/host/resizing_host_observer.cc +++ b/remoting/host/resizing_host_observer.cc
@@ -122,7 +122,7 @@ bool restore) : desktop_resizer_(std::move(desktop_resizer)), restore_(restore), - now_function_(base::Bind(base::Time::Now)), + now_function_(base::Bind(base::TimeTicks::Now)), weak_factory_(this) {} ResizingHostObserver::~ResizingHostObserver() { @@ -134,22 +134,20 @@ const ScreenResolution& resolution) { // Get the current time. This function is called exactly once for each call // to SetScreenResolution to simplify the implementation of unit-tests. - base::Time now = now_function_.Run(); + base::TimeTicks now = now_function_.Run(); if (resolution.IsEmpty()) return; // Resizing the desktop too often is probably not a good idea, so apply a // simple rate-limiting scheme. - base::TimeDelta minimum_resize_interval = + base::TimeTicks next_allowed_resize = + previous_resize_time_ + base::TimeDelta::FromMilliseconds(kMinimumResizeIntervalMs); - base::Time next_allowed_resize = - previous_resize_time_ + minimum_resize_interval; if (now < next_allowed_resize) { deferred_resize_timer_.Start( - FROM_HERE, - next_allowed_resize - now, + FROM_HERE, next_allowed_resize - now, base::Bind(&ResizingHostObserver::SetScreenResolution, weak_factory_.GetWeakPtr(), resolution)); return; @@ -183,7 +181,7 @@ } void ResizingHostObserver::SetNowFunctionForTesting( - const base::Callback<base::Time(void)>& now_function) { + const base::Callback<base::TimeTicks(void)>& now_function) { now_function_ = now_function; }
diff --git a/remoting/host/resizing_host_observer.h b/remoting/host/resizing_host_observer.h index c393290..9e46af0 100644 --- a/remoting/host/resizing_host_observer.h +++ b/remoting/host/resizing_host_observer.h
@@ -38,11 +38,11 @@ // ScreenControls interface. void SetScreenResolution(const ScreenResolution& resolution) override; - // Provide a replacement for base::Time::Now so that this class can be + // Provide a replacement for base::TimeTicks::Now so that this class can be // unit-tested in a timely manner. This function will be called exactly // once for each call to SetScreenResolution. void SetNowFunctionForTesting( - const base::Callback<base::Time(void)>& now_function); + const base::Callback<base::TimeTicks(void)>& now_function); private: std::unique_ptr<DesktopResizer> desktop_resizer_; @@ -51,8 +51,8 @@ // State to manage rate-limiting of desktop resizes. base::OneShotTimer deferred_resize_timer_; - base::Time previous_resize_time_; - base::Callback<base::Time(void)> now_function_; + base::TimeTicks previous_resize_time_; + base::Callback<base::TimeTicks(void)> now_function_; base::WeakPtrFactory<ResizingHostObserver> weak_factory_;
diff --git a/remoting/host/resizing_host_observer_unittest.cc b/remoting/host/resizing_host_observer_unittest.cc index 833eef88..b9a61616c 100644 --- a/remoting/host/resizing_host_observer_unittest.cc +++ b/remoting/host/resizing_host_observer_unittest.cc
@@ -99,12 +99,12 @@ class ResizingHostObserverTest : public testing::Test { public: ResizingHostObserverTest() - : now_(base::Time::Now()) { + : now_(base::TimeTicks::Now()) { } // This needs to be public because the derived test-case class needs to // pass it to Bind, which fails if it's protected. - base::Time GetTime() { + base::TimeTicks GetTime() { return now_; } @@ -144,8 +144,8 @@ } } - base::Time GetTimeAndIncrement() { - base::Time result = now_; + base::TimeTicks GetTimeAndIncrement() { + base::TimeTicks result = now_; now_ += base::TimeDelta::FromSeconds(1); return result; } @@ -153,7 +153,7 @@ ScreenResolution current_resolution_; FakeDesktopResizer::CallCounts call_counts_; std::unique_ptr<ResizingHostObserver> resizing_host_observer_; - base::Time now_; + base::TimeTicks now_; }; // Check that the resolution isn't restored if it wasn't changed by this class.
diff --git a/remoting/host/setup/me2me_native_messaging_host.cc b/remoting/host/setup/me2me_native_messaging_host.cc index 975b913..1b054f22 100644 --- a/remoting/host/setup/me2me_native_messaging_host.cc +++ b/remoting/host/setup/me2me_native_messaging_host.cc
@@ -18,6 +18,7 @@ #include "base/macros.h" #include "base/single_thread_task_runner.h" #include "base/strings/stringize_macros.h" +#include "base/time/time.h" #include "base/values.h" #include "build/build_config.h" #include "google_apis/gaia/gaia_oauth_client.h" @@ -27,16 +28,12 @@ #include "remoting/base/rsa_key_pair.h" #include "remoting/host/chromoting_host_context.h" #include "remoting/host/native_messaging/log_message_handler.h" -#include "remoting/host/native_messaging/pipe_messaging_channel.h" #include "remoting/host/pin_hash.h" #include "remoting/host/setup/oauth_client.h" -#include "remoting/host/switches.h" #include "remoting/protocol/pairing_registry.h" #if defined(OS_WIN) -#include "base/win/scoped_handle.h" -#include "base/win/win_util.h" -#include "remoting/host/win/launch_native_messaging_host_process.h" +#include "remoting/host/win/elevated_native_messaging_host.h" #endif // defined(OS_WIN) namespace { @@ -193,8 +190,9 @@ DCHECK(task_runner()->BelongsToCurrentThread()); if (needs_elevation_) { - if (!DelegateToElevatedHost(std::move(message))) + if (!DelegateToElevatedHost(std::move(message))) { SendBooleanResult(std::move(response), false); + } return; } @@ -213,8 +211,9 @@ DCHECK(task_runner()->BelongsToCurrentThread()); if (needs_elevation_) { - if (!DelegateToElevatedHost(std::move(message))) + if (!DelegateToElevatedHost(std::move(message))) { SendBooleanResult(std::move(response), false); + } return; } @@ -284,8 +283,9 @@ DCHECK(task_runner()->BelongsToCurrentThread()); if (needs_elevation_) { - if (!DelegateToElevatedHost(std::move(message))) + if (!DelegateToElevatedHost(std::move(message))) { SendAsyncResult(std::move(response), DaemonController::RESULT_FAILED); + } return; } @@ -344,8 +344,9 @@ DCHECK(task_runner()->BelongsToCurrentThread()); if (needs_elevation_) { - if (!DelegateToElevatedHost(std::move(message))) + if (!DelegateToElevatedHost(std::move(message))) { SendAsyncResult(std::move(response), DaemonController::RESULT_FAILED); + } return; } @@ -374,8 +375,9 @@ DCHECK(task_runner()->BelongsToCurrentThread()); if (needs_elevation_) { - if (!DelegateToElevatedHost(std::move(message))) + if (!DelegateToElevatedHost(std::move(message))) { SendAsyncResult(std::move(response), DaemonController::RESULT_FAILED); + } return; } @@ -541,78 +543,27 @@ } #if defined(OS_WIN) -Me2MeNativeMessagingHost::ElevatedChannelEventHandler:: - ElevatedChannelEventHandler(extensions::NativeMessageHost::Client* client) - : client_(client) {} - -void Me2MeNativeMessagingHost::ElevatedChannelEventHandler::OnMessage( - std::unique_ptr<base::Value> message) { - DCHECK(thread_checker_.CalledOnValidThread()); - - // Simply pass along the response from the elevated host to the client. - std::string message_json; - base::JSONWriter::Write(*message, &message_json); - client_->PostMessageFromNativeHost(message_json); -} - -void Me2MeNativeMessagingHost::ElevatedChannelEventHandler::OnDisconnect() { - DCHECK(thread_checker_.CalledOnValidThread()); - client_->CloseChannel(std::string()); -} bool Me2MeNativeMessagingHost::DelegateToElevatedHost( std::unique_ptr<base::DictionaryValue> message) { DCHECK(task_runner()->BelongsToCurrentThread()); - - EnsureElevatedHostCreated(); - - // elevated_channel_ will be null if user rejects the UAC request. - if (elevated_channel_) - elevated_channel_->SendMessage(std::move(message)); - - return elevated_channel_ != nullptr; -} - -void Me2MeNativeMessagingHost::EnsureElevatedHostCreated() { - DCHECK(task_runner()->BelongsToCurrentThread()); DCHECK(needs_elevation_); - if (elevated_channel_) - return; - - base::win::ScopedHandle read_handle; - base::win::ScopedHandle write_handle; - // Get the name of the binary to launch. - base::FilePath binary = base::CommandLine::ForCurrentProcess()->GetProgram(); - ProcessLaunchResult result = LaunchNativeMessagingHostProcess( - binary, parent_window_handle_, - /*elevate_process=*/true, &read_handle, &write_handle); - if (result != PROCESS_LAUNCH_RESULT_SUCCESS) { - if (result != PROCESS_LAUNCH_RESULT_CANCELLED) { - OnError(std::string()); - } - return; + if (!elevated_host_) { + elevated_host_.reset(new ElevatedNativeMessagingHost( + base::CommandLine::ForCurrentProcess()->GetProgram(), + parent_window_handle_, + /*elevate_process=*/true, + base::TimeDelta::FromSeconds(kElevatedHostTimeoutSeconds), + client_)); } - // Set up the native messaging channel to talk to the elevated host. - // Note that input for the elevated channel is output for the elevated host. - elevated_channel_.reset(new PipeMessagingChannel( - base::File(read_handle.Take()), base::File(write_handle.Take()))); + if (elevated_host_->EnsureElevatedHostCreated()) { + elevated_host_->SendMessage(std::move(message)); + return true; + } - elevated_channel_event_handler_.reset( - new Me2MeNativeMessagingHost::ElevatedChannelEventHandler(client_)); - elevated_channel_->Start(elevated_channel_event_handler_.get()); - - elevated_host_timer_.Start( - FROM_HERE, base::TimeDelta::FromSeconds(kElevatedHostTimeoutSeconds), - this, &Me2MeNativeMessagingHost::DisconnectElevatedHost); -} - -void Me2MeNativeMessagingHost::DisconnectElevatedHost() { - DCHECK(task_runner()->BelongsToCurrentThread()); - - // This will send an EOF to the elevated host, triggering its shutdown. - elevated_channel_.reset(); + return false; } #else // defined(OS_WIN)
diff --git a/remoting/host/setup/me2me_native_messaging_host.h b/remoting/host/setup/me2me_native_messaging_host.h index abc137f..181dae5 100644 --- a/remoting/host/setup/me2me_native_messaging_host.h +++ b/remoting/host/setup/me2me_native_messaging_host.h
@@ -13,10 +13,8 @@ #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/threading/thread_checker.h" -#include "base/timer/timer.h" #include "build/build_config.h" #include "extensions/browser/api/messaging/native_message_host.h" -#include "extensions/browser/api/messaging/native_messaging_channel.h" #include "remoting/host/setup/daemon_controller.h" #include "remoting/host/setup/oauth_client.h" @@ -24,6 +22,7 @@ class DictionaryValue; class ListValue; class SingleThreadTaskRunner; +class Value; } // namespace base namespace gaia { @@ -37,6 +36,7 @@ } // namespace protocol class ChromotingHostContext; +class ElevatedNativeMessagingHost; class LogMessageHandler; // Implementation of the me2me native messaging host. @@ -120,48 +120,15 @@ void OnError(const std::string& error_message); - // Returns true if the request was successfully delegated to the elevated - // host and false otherwise. + // Returns whether the request was successfully sent to the elevated host. bool DelegateToElevatedHost(std::unique_ptr<base::DictionaryValue> message); -#if defined(OS_WIN) - class ElevatedChannelEventHandler - : public extensions::NativeMessagingChannel::EventHandler { - public: - ElevatedChannelEventHandler(extensions::NativeMessageHost::Client* client); - - // extensions::NativeMessagingChannel::EventHandler implementation. - void OnMessage(std::unique_ptr<base::Value> message) override; - void OnDisconnect() override; - - private: - extensions::NativeMessageHost::Client* client_; - - base::ThreadChecker thread_checker_; - }; - - // Create and connect to an elevated host process if necessary. - // |elevated_channel_| will contain the native messaging channel to the - // elevated host if the function succeeds. - void EnsureElevatedHostCreated(); - - // Disconnect and shut down the elevated host. - void DisconnectElevatedHost(); - - // Native messaging channel used to communicate with the elevated host. - std::unique_ptr<extensions::NativeMessagingChannel> elevated_channel_; - - // Native messaging event handler used to process responses from the elevated - // host. - std::unique_ptr<ElevatedChannelEventHandler> elevated_channel_event_handler_; - - // Timer to control the lifetime of the elevated host. - base::OneShotTimer elevated_host_timer_; -#endif // defined(OS_WIN) - bool needs_elevation_; #if defined(OS_WIN) + // Controls the lifetime of the elevated native messaging host process. + std::unique_ptr<ElevatedNativeMessagingHost> elevated_host_; + // Handle of the parent window. intptr_t parent_window_handle_; #endif // defined(OS_WIN)
diff --git a/remoting/host/win/elevated_native_messaging_host.cc b/remoting/host/win/elevated_native_messaging_host.cc new file mode 100644 index 0000000..0e2dcddb --- /dev/null +++ b/remoting/host/win/elevated_native_messaging_host.cc
@@ -0,0 +1,96 @@ +// 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 "remoting/host/win/elevated_native_messaging_host.h" + +#include <memory> +#include <string> +#include <utility> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/json/json_writer.h" +#include "base/logging.h" +#include "base/macros.h" +#include "base/values.h" +#include "base/win/scoped_handle.h" +#include "remoting/host/native_messaging/pipe_messaging_channel.h" +#include "remoting/host/win/launch_native_messaging_host_process.h" + +namespace remoting { + +ElevatedNativeMessagingHost::ElevatedNativeMessagingHost( + const base::FilePath& binary_path, + intptr_t parent_window_handle, + bool elevate_process, + base::TimeDelta host_timeout, + extensions::NativeMessageHost::Client* client) + : host_binary_path_(binary_path), + parent_window_handle_(parent_window_handle), + elevate_host_process_(elevate_process), + host_process_timeout_(host_timeout), + client_(client) {} + +ElevatedNativeMessagingHost::~ElevatedNativeMessagingHost() {} + +void ElevatedNativeMessagingHost::OnMessage( + std::unique_ptr<base::Value> message) { + DCHECK(thread_checker_.CalledOnValidThread()); + + // Simply pass along the response from the elevated host to the client. + std::string message_json; + base::JSONWriter::Write(*message, &message_json); + client_->PostMessageFromNativeHost(message_json); +} + +void ElevatedNativeMessagingHost::OnDisconnect() { + DCHECK(thread_checker_.CalledOnValidThread()); + client_->CloseChannel(std::string()); +} + +bool ElevatedNativeMessagingHost::EnsureElevatedHostCreated() { + DCHECK(thread_checker_.CalledOnValidThread()); + + if (elevated_channel_) { + return true; + } + + base::win::ScopedHandle read_handle; + base::win::ScopedHandle write_handle; + ProcessLaunchResult result = LaunchNativeMessagingHostProcess( + host_binary_path_, parent_window_handle_, elevate_host_process_, + &read_handle, &write_handle); + if (result != PROCESS_LAUNCH_RESULT_SUCCESS) { + return false; + } + + // Set up the native messaging channel to talk to the elevated host. + // Note that input for the elevated channel is output for the elevated host. + elevated_channel_.reset(new PipeMessagingChannel( + base::File(read_handle.Take()), base::File(write_handle.Take()))); + elevated_channel_->Start(this); + + if (!host_process_timeout_.is_zero()) { + elevated_host_timer_.Start( + FROM_HERE, host_process_timeout_, + this, &ElevatedNativeMessagingHost::DisconnectHost); + } + + return true; +} + +void ElevatedNativeMessagingHost::SendMessage( + std::unique_ptr<base::Value> message) { + DCHECK(thread_checker_.CalledOnValidThread()); + elevated_channel_->SendMessage(std::move(message)); +} + +void ElevatedNativeMessagingHost::DisconnectHost() { + DCHECK(thread_checker_.CalledOnValidThread()); + + // This will send an EOF to the elevated host, triggering its shutdown. + elevated_channel_.reset(); +} + +} // namespace remoting
diff --git a/remoting/host/win/elevated_native_messaging_host.h b/remoting/host/win/elevated_native_messaging_host.h new file mode 100644 index 0000000..e00e671 --- /dev/null +++ b/remoting/host/win/elevated_native_messaging_host.h
@@ -0,0 +1,84 @@ +// 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 REMOTING_HOST_WIN_ELEVATED_NATIVE_MESSAGING_HOST_H_ +#define REMOTING_HOST_WIN_ELEVATED_NATIVE_MESSAGING_HOST_H_ + +#include <cstdint> +#include <memory> + +#include "base/files/file_path.h" +#include "base/macros.h" +#include "base/threading/thread_checker.h" +#include "base/time/time.h" +#include "base/timer/timer.h" +#include "extensions/browser/api/messaging/native_message_host.h" +#include "extensions/browser/api/messaging/native_messaging_channel.h" + +namespace base { +class Value; +} // namespace base + +namespace remoting { + +// Helper class which manages the creation and lifetime of an elevated native +// messaging host process. +class ElevatedNativeMessagingHost + : public extensions::NativeMessagingChannel::EventHandler { + public: + ElevatedNativeMessagingHost(const base::FilePath& binary_path, + intptr_t parent_window_handle, + bool elevate_process, + base::TimeDelta host_timeout, + extensions::NativeMessageHost::Client* client); + ~ElevatedNativeMessagingHost() override; + + // extensions::NativeMessagingChannel::EventHandle implementation. + void OnMessage(std::unique_ptr<base::Value> message) override; + void OnDisconnect() override; + + // Create and connect to an elevated host process if necessary. + // |elevated_channel_| will contain the native messaging channel to the + // elevated host if the function succeeds. + bool EnsureElevatedHostCreated(); + + // Send |message| to the elevated host. + void SendMessage(std::unique_ptr<base::Value> message); + + private: + // Disconnect and shut down the elevated host. + void DisconnectHost(); + + // Path to the binary to use for the elevated host process. + base::FilePath host_binary_path_; + + // Handle of the parent window. + intptr_t parent_window_handle_; + + // Indicates whether the launched process should be elevated when lauinched. + // Note: Binaries with uiaccess run at a higher UIPI level than the launching + // process so they still need to be launched and controlled by this class but + // do not require traditional elevation to function. + bool elevate_host_process_; + + // Specifies the amount of time to allow the elevated host to run. + base::TimeDelta host_process_timeout_; + + // EventHandler of the parent process. + extensions::NativeMessageHost::Client* client_; + + // Native messaging channel used to communicate with the elevated host. + std::unique_ptr<extensions::NativeMessagingChannel> elevated_channel_; + + // Timer to control the lifetime of the elevated host. + base::OneShotTimer elevated_host_timer_; + + base::ThreadChecker thread_checker_; + + DISALLOW_COPY_AND_ASSIGN(ElevatedNativeMessagingHost); +}; + +} // namespace remoting + +#endif // REMOTING_HOST_WIN_ELEVATED_NATIVE_MESSAGING_HOST_H_
diff --git a/remoting/protocol/connection_unittest.cc b/remoting/protocol/connection_unittest.cc index 4f7b362..380bba3 100644 --- a/remoting/protocol/connection_unittest.cc +++ b/remoting/protocol/connection_unittest.cc
@@ -223,15 +223,38 @@ 1U); EXPECT_EQ( client_video_renderer_.GetVideoStub()->received_packets().size(), 0U); + client_video_renderer_.GetFrameConsumer()->set_on_frame_callback( + base::Closure()); } else { EXPECT_EQ( client_video_renderer_.GetFrameConsumer()->received_frames().size(), 0U); EXPECT_EQ( client_video_renderer_.GetVideoStub()->received_packets().size(), 1U); + client_video_renderer_.GetVideoStub()->set_on_frame_callback( + base::Closure()); } } + void WaitFirstFrameStats() { + if (!client_video_renderer_.GetFrameStatsConsumer() + ->received_stats() + .empty()) { + return; + } + + base::RunLoop run_loop; + client_video_renderer_.GetFrameStatsConsumer()->set_on_stats_callback( + base::Bind(&base::RunLoop::Quit, base::Unretained(&run_loop))); + run_loop.Run(); + client_video_renderer_.GetFrameStatsConsumer()->set_on_stats_callback( + base::Closure()); + + EXPECT_FALSE(client_video_renderer_.GetFrameStatsConsumer() + ->received_stats() + .empty()); + } + base::MessageLoopForIO message_loop_; std::unique_ptr<base::RunLoop> run_loop_; @@ -369,5 +392,58 @@ run_loop.Run(); } +TEST_P(ConnectionTest, VideoStats) { + // Currently this test only works for WebRTC because for ICE connections stats + // are reported by SoftwareVideoRenderer which is not used in this test. + // TODO(sergeyu): Fix this. + if (!is_using_webrtc()) + return; + + Connect(); + + base::TimeTicks start_time = base::TimeTicks::Now(); + + std::unique_ptr<VideoStream> video_stream = + host_connection_->StartVideoStream( + base::WrapUnique(new TestScreenCapturer())); + + // Simulate an input invent injected at the start. + video_stream->OnInputEventReceived(start_time.ToInternalValue()); + + WaitFirstVideoFrame(); + + base::TimeTicks finish_time = base::TimeTicks::Now(); + + WaitFirstFrameStats(); + + const FrameStats& stats = + client_video_renderer_.GetFrameStatsConsumer()->received_stats().front(); + + EXPECT_TRUE(stats.host_stats.frame_size > 0); + + EXPECT_TRUE(stats.host_stats.latest_event_timestamp == start_time); + EXPECT_TRUE(stats.host_stats.capture_delay != base::TimeDelta::Max()); + EXPECT_TRUE(stats.host_stats.capture_overhead_delay != + base::TimeDelta::Max()); + EXPECT_TRUE(stats.host_stats.encode_delay != base::TimeDelta::Max()); + EXPECT_TRUE(stats.host_stats.send_pending_delay != base::TimeDelta::Max()); + + EXPECT_FALSE(stats.client_stats.time_received.is_null()); + EXPECT_FALSE(stats.client_stats.time_decoded.is_null()); + EXPECT_FALSE(stats.client_stats.time_rendered.is_null()); + + EXPECT_TRUE(start_time + stats.host_stats.capture_pending_delay + + stats.host_stats.capture_delay + + stats.host_stats.capture_overhead_delay + + stats.host_stats.encode_delay + + stats.host_stats.send_pending_delay <= + stats.client_stats.time_received); + EXPECT_TRUE(stats.client_stats.time_received <= + stats.client_stats.time_decoded); + EXPECT_TRUE(stats.client_stats.time_decoded <= + stats.client_stats.time_rendered); + EXPECT_TRUE(stats.client_stats.time_rendered <= finish_time); +} + } // namespace protocol } // namespace remoting
diff --git a/remoting/protocol/webrtc_connection_to_host.cc b/remoting/protocol/webrtc_connection_to_host.cc index eda4347..3ef3d44 100644 --- a/remoting/protocol/webrtc_connection_to_host.cc +++ b/remoting/protocol/webrtc_connection_to_host.cc
@@ -6,7 +6,9 @@ #include <utility> +#include "base/strings/string_util.h" #include "jingle/glue/thread_wrapper.h" +#include "remoting/base/constants.h" #include "remoting/protocol/client_control_dispatcher.h" #include "remoting/protocol/client_event_dispatcher.h" #include "remoting/protocol/client_stub.h" @@ -121,21 +123,26 @@ std::unique_ptr<MessagePipe> pipe) { if (!control_dispatcher_) control_dispatcher_.reset(new ClientControlDispatcher()); + if (name == control_dispatcher_->channel_name() && !control_dispatcher_->is_connected()) { control_dispatcher_->set_client_stub(client_stub_); control_dispatcher_->set_clipboard_stub(clipboard_stub_); control_dispatcher_->Init(std::move(pipe), this); + } else if (base::StartsWith(name, kVideoStatsChannelNamePrefix, + base::CompareCase::SENSITIVE)) { + std::string video_stream_label = + name.substr(strlen(kVideoStatsChannelNamePrefix)); + GetOrCreateVideoAdapter(video_stream_label) + ->SetVideoStatsChannel(std::move(pipe)); + } else { + LOG(WARNING) << "Received unknown incoming data channel " << name; } } void WebrtcConnectionToHost::OnWebrtcTransportMediaStreamAdded( scoped_refptr<webrtc::MediaStreamInterface> stream) { - if (video_adapter_) { - LOG(WARNING) - << "Received multiple media streams. Ignoring all except the last one."; - } - video_adapter_.reset(new WebrtcVideoRendererAdapter(stream, video_renderer_)); + GetOrCreateVideoAdapter(stream->label())->SetMediaStream(stream); } void WebrtcConnectionToHost::OnWebrtcTransportMediaStreamRemoved( @@ -172,6 +179,19 @@ SetState(CONNECTED, OK); } +WebrtcVideoRendererAdapter* WebrtcConnectionToHost::GetOrCreateVideoAdapter( + const std::string& label) { + if (!video_adapter_ || video_adapter_->label() != label) { + if (video_adapter_) { + LOG(WARNING) << "Received multiple media streams. Ignoring all except " + "the last one."; + } + video_adapter_.reset( + new WebrtcVideoRendererAdapter(label, video_renderer_)); + } + return video_adapter_.get(); +} + void WebrtcConnectionToHost::CloseChannels() { clipboard_forwarder_.set_clipboard_stub(nullptr); control_dispatcher_.reset();
diff --git a/remoting/protocol/webrtc_connection_to_host.h b/remoting/protocol/webrtc_connection_to_host.h index 75e0397d..8a497329 100644 --- a/remoting/protocol/webrtc_connection_to_host.h +++ b/remoting/protocol/webrtc_connection_to_host.h
@@ -69,8 +69,14 @@ void NotifyIfChannelsReady(); + WebrtcVideoRendererAdapter* GetOrCreateVideoAdapter(const std::string& label); + void CloseChannels(); + void OnFrameRendered(uint32_t frame_id, + base::TimeTicks event_timestamp, + base::TimeTicks frame_rendered_time); + void SetState(State state, ErrorCode error); HostEventCallback* event_callback_ = nullptr;
diff --git a/remoting/protocol/webrtc_video_encoder_factory.cc b/remoting/protocol/webrtc_video_encoder_factory.cc index 95a2e349..b2d6fa17 100644 --- a/remoting/protocol/webrtc_video_encoder_factory.cc +++ b/remoting/protocol/webrtc_video_encoder_factory.cc
@@ -90,14 +90,17 @@ return WEBRTC_VIDEO_CODEC_OK; } -int WebrtcVideoEncoder::SendEncodedFrame(std::unique_ptr<VideoPacket> frame) { +webrtc::EncodedImageCallback::Result WebrtcVideoEncoder::SendEncodedFrame( + std::unique_ptr<VideoPacket> frame, + base::TimeTicks capture_time) { uint8_t* buffer = reinterpret_cast<uint8_t*>(const_cast<char*>(frame->data().data())); size_t buffer_size = frame->data().size(); base::AutoLock lock(lock_); if (state_ == kUninitialized) { LOG(ERROR) << "encoder interface uninitialized"; - return -1; + return webrtc::EncodedImageCallback::Result( + webrtc::EncodedImageCallback::Result::ERROR_SEND_FAILED); } webrtc::EncodedImage encoded_image(buffer, buffer_size, buffer_size); @@ -106,9 +109,9 @@ encoded_image._completeFrame = true; encoded_image._frameType = frame->key_frame() ? webrtc::kVideoFrameKey : webrtc::kVideoFrameDelta; - encoded_image.capture_time_ms_ = frame->capture_time_ms(); - encoded_image._timeStamp = - static_cast<uint32_t>(frame->capture_time_ms() * 90); + int64_t capture_time_ms = (capture_time - base::TimeTicks()).InMilliseconds(); + encoded_image.capture_time_ms_ = capture_time_ms; + encoded_image._timeStamp = static_cast<uint32_t>(capture_time_ms * 90); encoded_image.playout_delay_.min_ms = 0; encoded_image.playout_delay_.max_ms = 0; @@ -130,14 +133,8 @@ header.fragmentationPlType[0] = 0; header.fragmentationTimeDiff[0] = 0; - int result = - encoded_callback_->Encoded(encoded_image, &codec_specific_info, &header); - if (result < 0) { - LOG(ERROR) << "Encoded callback failed: " << result; - } else if (result > 0) { - VLOG(1) << "Drop request from webrtc"; - } - return result; + return encoded_callback_->OnEncodedImage(encoded_image, &codec_specific_info, + &header); } void WebrtcVideoEncoder::SetKeyFrameRequestCallback( @@ -204,13 +201,15 @@ DCHECK(false) << "Asked to remove encoder not owned by factory"; } -int WebrtcVideoEncoderFactory::SendEncodedFrame( - std::unique_ptr<VideoPacket> frame) { +webrtc::EncodedImageCallback::Result +WebrtcVideoEncoderFactory::SendEncodedFrame(std::unique_ptr<VideoPacket> frame, + base::TimeTicks capture_time) { if (encoders_.size() != 1) { LOG(ERROR) << "Unexpected number of encoders " << encoders_.size(); - return -1; + return webrtc::EncodedImageCallback::Result( + webrtc::EncodedImageCallback::Result::ERROR_SEND_FAILED); } - return encoders_.front()->SendEncodedFrame(std::move(frame)); + return encoders_.front()->SendEncodedFrame(std::move(frame), capture_time); } void WebrtcVideoEncoderFactory::SetKeyFrameRequestCallback( @@ -238,4 +237,5 @@ << encoders_.size(); } } + } // namespace remoting
diff --git a/remoting/protocol/webrtc_video_encoder_factory.h b/remoting/protocol/webrtc_video_encoder_factory.h index 4e0da80..a4b33f5e 100644 --- a/remoting/protocol/webrtc_video_encoder_factory.h +++ b/remoting/protocol/webrtc_video_encoder_factory.h
@@ -41,7 +41,9 @@ int32_t SetChannelParameters(uint32_t packet_loss, int64_t rtt) override; int32_t SetRates(uint32_t bitrate, uint32_t framerate) override; - int SendEncodedFrame(std::unique_ptr<VideoPacket> pkt); + webrtc::EncodedImageCallback::Result SendEncodedFrame( + std::unique_ptr<VideoPacket> packet, + base::TimeTicks capture_time); void SetKeyFrameRequestCallback(const base::Closure& key_frame_request); void SetTargetBitrateCallback(const TargetBitrateCallback& target_bitrate_cb); @@ -74,7 +76,9 @@ bool EncoderTypeHasInternalSource(webrtc::VideoCodecType type) const override; void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) override; - int SendEncodedFrame(std::unique_ptr<VideoPacket> pkt); + webrtc::EncodedImageCallback::Result SendEncodedFrame( + std::unique_ptr<VideoPacket> packet, + base::TimeTicks capture_time); void SetKeyFrameRequestCallback(const base::Closure& key_frame_request); void SetTargetBitrateCallback(const TargetBitrateCallback& target_bitrate_cb);
diff --git a/remoting/protocol/webrtc_video_renderer_adapter.cc b/remoting/protocol/webrtc_video_renderer_adapter.cc index 1320b9c..f87821d0 100644 --- a/remoting/protocol/webrtc_video_renderer_adapter.cc +++ b/remoting/protocol/webrtc_video_renderer_adapter.cc
@@ -1,4 +1,4 @@ - // Copyright 2015 The Chromium Authors. All rights reserved. +// 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. @@ -15,12 +15,12 @@ #include "base/task_runner_util.h" #include "base/threading/thread_task_runner_handle.h" #include "base/threading/worker_pool.h" +#include "remoting/protocol/client_video_stats_dispatcher.h" #include "remoting/protocol/frame_consumer.h" #include "remoting/protocol/frame_stats.h" #include "remoting/protocol/video_renderer.h" -#include "third_party/libyuv/include/libyuv/convert_argb.h" +#include "remoting/protocol/webrtc_transport.h" #include "third_party/libyuv/include/libyuv/convert_from.h" -#include "third_party/libyuv/include/libyuv/video_common.h" #include "third_party/webrtc/media/base/videoframe.h" #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" @@ -29,6 +29,9 @@ namespace { +// Maximum number of ClientFrameStats instances to keep. +const int kMaxQueuedStats = 200; + std::unique_ptr<webrtc::DesktopFrame> ConvertYuvToRgb( scoped_refptr<webrtc::VideoFrameBuffer> yuv_frame, std::unique_ptr<webrtc::DesktopFrame> rgb_frame, @@ -52,12 +55,27 @@ } // namespace WebrtcVideoRendererAdapter::WebrtcVideoRendererAdapter( - scoped_refptr<webrtc::MediaStreamInterface> media_stream, + const std::string& label, VideoRenderer* video_renderer) - : media_stream_(std::move(media_stream)), + : label_(label), video_renderer_(video_renderer), task_runner_(base::ThreadTaskRunnerHandle::Get()), - weak_factory_(this) { + weak_factory_(this) {} + +WebrtcVideoRendererAdapter::~WebrtcVideoRendererAdapter() { + DCHECK(task_runner_->BelongsToCurrentThread()); + + webrtc::VideoTrackVector video_tracks = media_stream_->GetVideoTracks(); + DCHECK(!video_tracks.empty()); + video_tracks[0]->RemoveSink(this); +} + +void WebrtcVideoRendererAdapter::SetMediaStream( + scoped_refptr<webrtc::MediaStreamInterface> media_stream) { + DCHECK_EQ(media_stream->label(), label()); + + media_stream_ = std::move(media_stream); + webrtc::VideoTrackVector video_tracks = media_stream_->GetVideoTracks(); if (video_tracks.empty()) { LOG(ERROR) << "Received media stream with no video tracks."; @@ -71,12 +89,11 @@ video_tracks[0]->AddOrUpdateSink(this, rtc::VideoSinkWants()); } -WebrtcVideoRendererAdapter::~WebrtcVideoRendererAdapter() { - DCHECK(task_runner_->BelongsToCurrentThread()); - - webrtc::VideoTrackVector video_tracks = media_stream_->GetVideoTracks(); - DCHECK(!video_tracks.empty()); - video_tracks[0]->RemoveSink(this); +void WebrtcVideoRendererAdapter::SetVideoStatsChannel( + std::unique_ptr<MessagePipe> message_pipe) { + // Expect that the host also creates video_stats data channel. + video_stats_dispatcher_.reset(new ClientVideoStatsDispatcher(label_, this)); + video_stats_dispatcher_->Init(std::move(message_pipe), this); } void WebrtcVideoRendererAdapter::OnFrame(const cricket::VideoFrame& frame) { @@ -86,24 +103,72 @@ LOG(WARNING) << "Received frame with playout delay greater than 0."; } - std::unique_ptr<ClientFrameStats> stats(new ClientFrameStats()); - // TODO(sergeyu): |time_received| is not reported correctly here because the - // frame is already decoded at this point. - stats->time_received = base::TimeTicks::Now(); - task_runner_->PostTask( FROM_HERE, base::Bind(&WebrtcVideoRendererAdapter::HandleFrameOnMainThread, - weak_factory_.GetWeakPtr(), base::Passed(&stats), + weak_factory_.GetWeakPtr(), frame.transport_frame_id(), + base::TimeTicks::Now(), scoped_refptr<webrtc::VideoFrameBuffer>( frame.video_frame_buffer().get()))); } +void WebrtcVideoRendererAdapter::OnVideoFrameStats( + uint32_t frame_id, + const HostFrameStats& host_stats) { + DCHECK(task_runner_->BelongsToCurrentThread()); + + // Drop all ClientFrameStats for frames before |frame_id|. Stats messages are + // expected to be received in the same order as the corresponding video + // frames, so we are not going to receive HostFrameStats for the frames before + // |frame_id|. This may happen only if for some reason the host doesn't + // generate stats message for all video frames. + while (!client_stats_queue_.empty() && + client_stats_queue_.front().first != frame_id) { + client_stats_queue_.pop_front(); + } + + // If there are no ClientFrameStats in the queue then queue HostFrameStats + // to be processed in FrameRendered(). + if (client_stats_queue_.empty()) { + if (host_stats_queue_.size() > kMaxQueuedStats) { + LOG(ERROR) << "video_stats channel is out of sync with the video stream. " + "Performance stats will not be reported."; + video_stats_dispatcher_.reset(); + return; + } + host_stats_queue_.push_back(std::make_pair(frame_id, host_stats)); + return; + } + + // The correspond frame has been received and now we have both HostFrameStats + // and ClientFrameStats. Report the stats to FrameStatsConsumer. + DCHECK_EQ(client_stats_queue_.front().first, frame_id); + FrameStats frame_stats; + frame_stats.client_stats = client_stats_queue_.front().second; + client_stats_queue_.pop_front(); + frame_stats.host_stats = host_stats; + video_renderer_->GetFrameStatsConsumer()->OnVideoFrameStats(frame_stats); +} + +void WebrtcVideoRendererAdapter::OnChannelInitialized( + ChannelDispatcherBase* channel_dispatcher) {} + +void WebrtcVideoRendererAdapter::OnChannelClosed( + ChannelDispatcherBase* channel_dispatcher) { + LOG(WARNING) << "video_stats channel was closed by the host."; +} + void WebrtcVideoRendererAdapter::HandleFrameOnMainThread( - std::unique_ptr<ClientFrameStats> stats, + uint32_t frame_id, + base::TimeTicks time_received, scoped_refptr<webrtc::VideoFrameBuffer> frame) { DCHECK(task_runner_->BelongsToCurrentThread()); + std::unique_ptr<ClientFrameStats> stats(new ClientFrameStats()); + // TODO(sergeyu): |time_received| is not reported correctly here because the + // frame is already decoded at this point. + stats->time_received = time_received; + std::unique_ptr<webrtc::DesktopFrame> rgb_frame = video_renderer_->GetFrameConsumer()->AllocateFrame( webrtc::DesktopSize(frame->width(), frame->height())); @@ -114,10 +179,11 @@ base::Passed(&rgb_frame), video_renderer_->GetFrameConsumer()->GetPixelFormat()), base::Bind(&WebrtcVideoRendererAdapter::DrawFrame, - weak_factory_.GetWeakPtr(), base::Passed(&stats))); + weak_factory_.GetWeakPtr(), frame_id, base::Passed(&stats))); } void WebrtcVideoRendererAdapter::DrawFrame( + uint32_t frame_id, std::unique_ptr<ClientFrameStats> stats, std::unique_ptr<webrtc::DesktopFrame> frame) { DCHECK(task_runner_->BelongsToCurrentThread()); @@ -125,12 +191,52 @@ video_renderer_->GetFrameConsumer()->DrawFrame( std::move(frame), base::Bind(&WebrtcVideoRendererAdapter::FrameRendered, - weak_factory_.GetWeakPtr(), base::Passed(&stats))); + weak_factory_.GetWeakPtr(), frame_id, base::Passed(&stats))); } void WebrtcVideoRendererAdapter::FrameRendered( - std::unique_ptr<ClientFrameStats> stats) { - // TODO(sergeyu): Report stats here + uint32_t frame_id, + std::unique_ptr<ClientFrameStats> client_stats) { + DCHECK(task_runner_->BelongsToCurrentThread()); + + if (!video_stats_dispatcher_ || !video_stats_dispatcher_->is_connected()) + return; + + client_stats->time_rendered = base::TimeTicks::Now(); + + // Drop all HostFrameStats for frames before |frame_id|. Stats messages are + // expected to be received in the same order as the corresponding video + // frames. This may happen only if the host generates HostFrameStats without + // the corresponding frame. + while (!host_stats_queue_.empty() && + host_stats_queue_.front().first != frame_id) { + LOG(WARNING) << "Host sent VideoStats message for a frame that was never " + "received."; + host_stats_queue_.pop_front(); + } + + // If HostFrameStats hasn't been received for |frame_id| then queue + // ClientFrameStats to be processed in OnVideoFrameStats(). + if (host_stats_queue_.empty()) { + if (client_stats_queue_.size() > kMaxQueuedStats) { + LOG(ERROR) << "video_stats channel is out of sync with the video " + "stream. Performance stats will not be reported."; + video_stats_dispatcher_.reset(); + return; + } + client_stats_queue_.push_back(std::make_pair(frame_id, *client_stats)); + return; + } + + // The correspond HostFrameStats has been received already and now we have + // both HostFrameStats and ClientFrameStats. Report the stats to + // FrameStatsConsumer. + DCHECK_EQ(host_stats_queue_.front().first, frame_id); + FrameStats frame_stats; + frame_stats.host_stats = host_stats_queue_.front().second; + frame_stats.client_stats = *client_stats; + host_stats_queue_.pop_front(); + video_renderer_->GetFrameStatsConsumer()->OnVideoFrameStats(frame_stats); } } // namespace protocol
diff --git a/remoting/protocol/webrtc_video_renderer_adapter.h b/remoting/protocol/webrtc_video_renderer_adapter.h index e085129..dec60f8a 100644 --- a/remoting/protocol/webrtc_video_renderer_adapter.h +++ b/remoting/protocol/webrtc_video_renderer_adapter.h
@@ -5,10 +5,14 @@ #ifndef REMOTING_PROTOCOL_WEBRTC_VIDEO_RENDERER_ADAPTER_H_ #define REMOTING_PROTOCOL_WEBRTC_VIDEO_RENDERER_ADAPTER_H_ +#include <list> #include <memory> +#include "base/callback.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" +#include "remoting/protocol/client_video_stats_dispatcher.h" +#include "remoting/protocol/video_stats_stub.h" #include "third_party/webrtc/api/mediastreaminterface.h" #include "third_party/webrtc/media/base/videosinkinterface.h" @@ -24,33 +28,59 @@ namespace remoting { namespace protocol { -struct ClientFrameStats; +class MessagePipe; class VideoRenderer; +class WebrtcTransport; +struct ClientFrameStats; +struct HostFrameStats; class WebrtcVideoRendererAdapter - : public rtc::VideoSinkInterface<cricket::VideoFrame> { + : public rtc::VideoSinkInterface<cricket::VideoFrame>, + public VideoStatsStub, + public ClientVideoStatsDispatcher::EventHandler { public: - WebrtcVideoRendererAdapter( - scoped_refptr<webrtc::MediaStreamInterface> media_stream, - VideoRenderer* video_renderer); + WebrtcVideoRendererAdapter(const std::string& label, + VideoRenderer* video_renderer); ~WebrtcVideoRendererAdapter() override; - std::string label() const { return media_stream_->label(); } + std::string label() const { return label_; } + + void SetMediaStream(scoped_refptr<webrtc::MediaStreamInterface> media_stream); + void SetVideoStatsChannel(std::unique_ptr<MessagePipe> message_pipe); // rtc::VideoSinkInterface implementation. void OnFrame(const cricket::VideoFrame& frame) override; private: - void HandleFrameOnMainThread(std::unique_ptr<ClientFrameStats> stats, + // VideoStatsStub interface. + void OnVideoFrameStats(uint32_t frame_id, + const HostFrameStats& frame_stats) override; + + // ClientVideoStatsDispatcher::EventHandler interface. + void OnChannelInitialized(ChannelDispatcherBase* channel_dispatcher) override; + void OnChannelClosed(ChannelDispatcherBase* channel_dispatcher) override; + + void HandleFrameOnMainThread(uint32_t frame_id, + base::TimeTicks time_received, scoped_refptr<webrtc::VideoFrameBuffer> frame); - void DrawFrame(std::unique_ptr<ClientFrameStats> stats, + void DrawFrame(uint32_t frame_id, + std::unique_ptr<ClientFrameStats> stats, std::unique_ptr<webrtc::DesktopFrame> frame); - void FrameRendered(std::unique_ptr<ClientFrameStats> stats); + void FrameRendered(uint32_t frame_id, + std::unique_ptr<ClientFrameStats> stats); + + std::string label_; scoped_refptr<webrtc::MediaStreamInterface> media_stream_; VideoRenderer* video_renderer_; + + std::unique_ptr<ClientVideoStatsDispatcher> video_stats_dispatcher_; + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + std::list<std::pair<uint32_t, ClientFrameStats>> client_stats_queue_; + std::list<std::pair<uint32_t, HostFrameStats>> host_stats_queue_; + base::WeakPtrFactory<WebrtcVideoRendererAdapter> weak_factory_; DISALLOW_COPY_AND_ASSIGN(WebrtcVideoRendererAdapter);
diff --git a/remoting/protocol/webrtc_video_stream.cc b/remoting/protocol/webrtc_video_stream.cc index dc24ecb..2e13a86 100644 --- a/remoting/protocol/webrtc_video_stream.cc +++ b/remoting/protocol/webrtc_video_stream.cc
@@ -10,6 +10,8 @@ #include "base/threading/thread_task_runner_handle.h" #include "remoting/base/constants.h" #include "remoting/proto/video.pb.h" +#include "remoting/protocol/frame_stats.h" +#include "remoting/protocol/host_video_stats_dispatcher.h" #include "remoting/protocol/webrtc_dummy_video_capturer.h" #include "remoting/protocol/webrtc_transport.h" #include "third_party/webrtc/api/mediastreaminterface.h" @@ -22,33 +24,6 @@ namespace { -// Task running on the encoder thread to encode the |frame|. -std::unique_ptr<VideoPacket> EncodeFrame( - VideoEncoder* encoder, - std::unique_ptr<webrtc::DesktopFrame> frame, - uint32_t target_bitrate_kbps, - bool key_frame_request, - int64_t capture_time_ms) { - uint32_t flags = 0; - if (key_frame_request) - flags |= VideoEncoder::REQUEST_KEY_FRAME; - - base::TimeTicks current = base::TimeTicks::Now(); - encoder->UpdateTargetBitrate(target_bitrate_kbps); - std::unique_ptr<VideoPacket> packet = encoder->Encode(*frame, flags); - if (!packet) - return nullptr; - // TODO(isheriff): Note that while VideoPacket capture time is supposed - // to be capture duration, we (ab)use it for capture timestamp here. This - // will go away when we move away from VideoPacket. - packet->set_capture_time_ms(capture_time_ms); - - VLOG(1) << "Encode duration " - << (base::TimeTicks::Now() - current).InMilliseconds() - << " payload size " << packet->data().size(); - return packet; -} - void PostTaskOnTaskRunner( scoped_refptr<base::SingleThreadTaskRunner> task_runner, const base::Closure& task) { @@ -68,9 +43,28 @@ const char kStreamLabel[] = "screen_stream"; const char kVideoLabel[] = "screen_video"; +struct WebrtcVideoStream::FrameTimestamps { + // The following two fields are set only for one frame after each incoming + // input event. |input_event_client_timestamp| is event timestamp + // received from the client. |input_event_received_time| is local time when + // the event was received. + int64_t input_event_client_timestamp = -1; + base::TimeTicks input_event_received_time; + + base::TimeTicks capture_started_time; + base::TimeTicks capture_ended_time; + base::TimeDelta capture_delay; + base::TimeTicks encode_started_time; + base::TimeTicks encode_ended_time; +}; + +struct WebrtcVideoStream::EncodedFrameWithTimestamps { + std::unique_ptr<VideoPacket> frame; + std::unique_ptr<FrameTimestamps> timestamps; +}; + WebrtcVideoStream::WebrtcVideoStream() - : main_task_runner_(base::ThreadTaskRunnerHandle::Get()), - weak_factory_(this) {} + : video_stats_dispatcher_(kStreamLabel), weak_factory_(this) {} WebrtcVideoStream::~WebrtcVideoStream() { if (stream_) { @@ -104,8 +98,6 @@ capturer_ = std::move(desktop_capturer); webrtc_transport_ = webrtc_transport; encoder_ = std::move(video_encoder); - capture_timer_.reset(new base::RepeatingTimer()); - capturer_->Start(this); // Set video stream constraints. @@ -130,23 +122,27 @@ // Register for PLI requests. webrtc_transport_->video_encoder_factory()->SetKeyFrameRequestCallback( - base::Bind(&PostTaskOnTaskRunner, main_task_runner_, + base::Bind(&PostTaskOnTaskRunner, base::ThreadTaskRunnerHandle::Get(), base::Bind(&WebrtcVideoStream::SetKeyFrameRequest, weak_factory_.GetWeakPtr()))); // Register for target bitrate notifications. webrtc_transport_->video_encoder_factory()->SetTargetBitrateCallback( - base::Bind(&PostTaskOnTaskRunnerWithParam<int>, main_task_runner_, + base::Bind(&PostTaskOnTaskRunnerWithParam<int>, + base::ThreadTaskRunnerHandle::Get(), base::Bind(&WebrtcVideoStream::SetTargetBitrate, weak_factory_.GetWeakPtr()))); + video_stats_dispatcher_.Init(webrtc_transport_->CreateOutgoingChannel( + video_stats_dispatcher_.channel_name()), + this); return true; } void WebrtcVideoStream::Pause(bool pause) { DCHECK(thread_checker_.CalledOnValidThread()); if (pause) { - capture_timer_->Stop(); + capture_timer_.Stop(); } else { if (received_first_frame_request_) { StartCaptureTimer(); @@ -155,7 +151,12 @@ } void WebrtcVideoStream::OnInputEventReceived(int64_t event_timestamp) { - NOTIMPLEMENTED(); + DCHECK(thread_checker_.CalledOnValidThread()); + + if (!next_frame_timestamps_) + next_frame_timestamps_.reset(new FrameTimestamps()); + next_frame_timestamps_->input_event_client_timestamp = event_timestamp; + next_frame_timestamps_->input_event_received_time = base::TimeTicks::Now(); } void WebrtcVideoStream::SetLosslessEncode(bool want_lossless) { @@ -178,7 +179,7 @@ if (!received_first_frame_request_) { received_first_frame_request_ = true; StartCaptureTimer(); - main_task_runner_->PostTask( + base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&WebrtcVideoStream::StartCaptureTimer, weak_factory_.GetWeakPtr())); } @@ -186,8 +187,8 @@ void WebrtcVideoStream::StartCaptureTimer() { DCHECK(thread_checker_.CalledOnValidThread()); - capture_timer_->Start(FROM_HERE, base::TimeDelta::FromSeconds(1) / 30, this, - &WebrtcVideoStream::CaptureNextFrame); + capture_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(1) / 30, this, + &WebrtcVideoStream::CaptureNextFrame); } void WebrtcVideoStream::SetTargetBitrate(int target_bitrate_kbps) { @@ -209,12 +210,10 @@ webrtc::DesktopCapturer::Result result, std::unique_ptr<webrtc::DesktopFrame> frame) { DCHECK(thread_checker_.CalledOnValidThread()); - - base::TimeTicks captured_ticks = base::TimeTicks::Now(); - int64_t capture_timestamp_ms = - (captured_ticks - base::TimeTicks()).InMilliseconds(); + DCHECK(capture_pending_); capture_pending_ = false; + if (encode_pending_) { // TODO(isheriff): consider queuing here VLOG(1) << "Dropping captured frame since encoder is still busy"; @@ -233,16 +232,32 @@ if (observer_) observer_->OnVideoSizeChanged(this, frame_size_, frame_dpi_); } + + captured_frame_timestamps_->capture_ended_time = base::TimeTicks::Now(); + captured_frame_timestamps_->capture_delay = + base::TimeDelta::FromMilliseconds(frame->capture_time_ms()); + encode_pending_ = true; base::PostTaskAndReplyWithResult( encode_task_runner_.get(), FROM_HERE, - base::Bind(&EncodeFrame, encoder_.get(), base::Passed(std::move(frame)), - target_bitrate_kbps_, ClearAndGetKeyFrameRequest(), - capture_timestamp_ms), + base::Bind(&WebrtcVideoStream::EncodeFrame, encoder_.get(), + base::Passed(std::move(frame)), + base::Passed(std::move(captured_frame_timestamps_)), + target_bitrate_kbps_, ClearAndGetKeyFrameRequest()), base::Bind(&WebrtcVideoStream::OnFrameEncoded, weak_factory_.GetWeakPtr())); } +void WebrtcVideoStream::OnChannelInitialized( + ChannelDispatcherBase* channel_dispatcher) { + DCHECK(&video_stats_dispatcher_ == channel_dispatcher); +} +void WebrtcVideoStream::OnChannelClosed( + ChannelDispatcherBase* channel_dispatcher) { + DCHECK(&video_stats_dispatcher_ == channel_dispatcher); + LOG(WARNING) << "video_stats channel was closed."; +} + void WebrtcVideoStream::CaptureNextFrame() { DCHECK(thread_checker_.CalledOnValidThread()); @@ -251,37 +266,108 @@ return; } + base::TimeTicks now = base::TimeTicks::Now(); + capture_pending_ = true; VLOG(1) << "Capture next frame after " << (base::TimeTicks::Now() - last_capture_started_ticks_) .InMilliseconds(); - last_capture_started_ticks_ = base::TimeTicks::Now(); + last_capture_started_ticks_ = now; + + + // |next_frame_timestamps_| is not set if no input events were received since + // the previous frame. In that case create FrameTimestamps instance without + // setting |input_event_client_timestamp| and |input_event_received_time|. + if (!next_frame_timestamps_) + next_frame_timestamps_.reset(new FrameTimestamps()); + + captured_frame_timestamps_ = std::move(next_frame_timestamps_); + captured_frame_timestamps_->capture_started_time = now; + capturer_->Capture(webrtc::DesktopRegion()); } -void WebrtcVideoStream::OnFrameEncoded(std::unique_ptr<VideoPacket> packet) { +// static +WebrtcVideoStream::EncodedFrameWithTimestamps WebrtcVideoStream::EncodeFrame( + VideoEncoder* encoder, + std::unique_ptr<webrtc::DesktopFrame> frame, + std::unique_ptr<WebrtcVideoStream::FrameTimestamps> timestamps, + uint32_t target_bitrate_kbps, + bool key_frame_request) { + EncodedFrameWithTimestamps result; + result.timestamps = std::move(timestamps); + result.timestamps->encode_started_time = base::TimeTicks::Now(); + + encoder->UpdateTargetBitrate(target_bitrate_kbps); + result.frame = encoder->Encode( + *frame, key_frame_request ? VideoEncoder::REQUEST_KEY_FRAME : 0); + + result.timestamps->encode_ended_time = base::TimeTicks::Now(); + + return result; +} + +void WebrtcVideoStream::OnFrameEncoded(EncodedFrameWithTimestamps frame) { DCHECK(thread_checker_.CalledOnValidThread()); encode_pending_ = false; - if (!packet) - return; - base::TimeTicks current = base::TimeTicks::Now(); - float encoded_bits = packet->data().size() * 8.0; + + size_t frame_size = frame.frame ? frame.frame->data().size() : 0; + + // Generate HostFrameStats. + HostFrameStats stats; + stats.frame_size = frame_size; + + if (!frame.timestamps->input_event_received_time.is_null()) { + stats.capture_pending_delay = frame.timestamps->capture_started_time - + frame.timestamps->input_event_received_time; + stats.latest_event_timestamp = base::TimeTicks::FromInternalValue( + frame.timestamps->input_event_client_timestamp); + } + + stats.capture_delay = frame.timestamps->capture_delay; + + // Total overhead time for IPC and threading when capturing frames. + stats.capture_overhead_delay = (frame.timestamps->capture_ended_time - + frame.timestamps->capture_started_time) - + stats.capture_delay; + + stats.encode_pending_delay = frame.timestamps->encode_started_time - + frame.timestamps->capture_ended_time; + + stats.encode_delay = frame.timestamps->encode_ended_time - + frame.timestamps->encode_started_time; + + // TODO(sergeyu): Figure out how to measure send_pending time with WebRTC and + // set it here. + stats.send_pending_delay = base::TimeDelta(); + + uint32_t frame_id = 0; + if (frame.frame) { + // Send the frame itself. + webrtc::EncodedImageCallback::Result result = + webrtc_transport_->video_encoder_factory()->SendEncodedFrame( + std::move(frame.frame), frame.timestamps->capture_started_time); + if (result.error != webrtc::EncodedImageCallback::Result::OK) { + // TODO(sergeyu): Stop the stream. + LOG(ERROR) << "Failed to send video frame."; + return; + } + frame_id = result.frame_id; + } + + // Send FrameStats message. + if (video_stats_dispatcher_.is_connected()) + video_stats_dispatcher_.OnVideoFrameStats(frame_id, stats); // Simplistic adaptation of frame polling in the range 5 FPS to 30 FPS. + // TODO(sergeyu): Move this logic to a separate class. + float encoded_bits = frame_size * 8.0; uint32_t next_sched_ms = std::max( 33, std::min(static_cast<int>(encoded_bits / target_bitrate_kbps_), 200)); - if (webrtc_transport_->video_encoder_factory()->SendEncodedFrame( - std::move(packet)) >= 0) { - VLOG(1) << "Send duration " - << (base::TimeTicks::Now() - current).InMilliseconds() - << ", next sched " << next_sched_ms; - } else { - LOG(ERROR) << "SendEncodedFrame() failed"; - } - capture_timer_->Start(FROM_HERE, - base::TimeDelta::FromMilliseconds(next_sched_ms), this, - &WebrtcVideoStream::CaptureNextFrame); + capture_timer_.Start(FROM_HERE, + base::TimeDelta::FromMilliseconds(next_sched_ms), this, + &WebrtcVideoStream::CaptureNextFrame); } } // namespace protocol
diff --git a/remoting/protocol/webrtc_video_stream.h b/remoting/protocol/webrtc_video_stream.h index 1ce0b47..a400c73 100644 --- a/remoting/protocol/webrtc_video_stream.h +++ b/remoting/protocol/webrtc_video_stream.h
@@ -16,6 +16,7 @@ #include "base/threading/thread_checker.h" #include "base/timer/timer.h" #include "remoting/codec/video_encoder.h" +#include "remoting/protocol/host_video_stats_dispatcher.h" #include "remoting/protocol/video_stream.h" #include "third_party/webrtc/modules/desktop_capture/desktop_capturer.h" @@ -29,11 +30,13 @@ namespace remoting { namespace protocol { +class HostVideoStatsDispatcher; class WebrtcVideoCapturerAdapter; class WebrtcTransport; class WebrtcVideoStream : public VideoStream, - public webrtc::DesktopCapturer::Callback { + public webrtc::DesktopCapturer::Callback, + public HostVideoStatsDispatcher::EventHandler { public: WebrtcVideoStream(); ~WebrtcVideoStream() override; @@ -52,25 +55,56 @@ void SetObserver(Observer* observer) override; private: + struct FrameTimestamps; + struct EncodedFrameWithTimestamps; + // webrtc::DesktopCapturer::Callback interface. void OnCaptureResult(webrtc::DesktopCapturer::Result result, std::unique_ptr<webrtc::DesktopFrame> frame) override; + // HostVideoStatsDispatcher::EventHandler interface. + void OnChannelInitialized(ChannelDispatcherBase* channel_dispatcher) override; + void OnChannelClosed(ChannelDispatcherBase* channel_dispatcher) override; + // Starts |capture_timer_|. void StartCaptureTimer(); // Called by |capture_timer_|. void CaptureNextFrame(); - void OnFrameEncoded(std::unique_ptr<VideoPacket> packet); + // Task running on the encoder thread to encode the |frame|. + static EncodedFrameWithTimestamps EncodeFrame( + VideoEncoder* encoder, + std::unique_ptr<webrtc::DesktopFrame> frame, + std::unique_ptr<WebrtcVideoStream::FrameTimestamps> timestamps, + uint32_t target_bitrate_kbps, + bool key_frame_request); + void OnFrameEncoded(EncodedFrameWithTimestamps frame); void SetKeyFrameRequest(); bool ClearAndGetKeyFrameRequest(); void SetTargetBitrate(int bitrate); + // Capturer used to capture the screen. + std::unique_ptr<webrtc::DesktopCapturer> capturer_; + // Used to send across encoded frames. + WebrtcTransport* webrtc_transport_ = nullptr; + // Task runner used to run |encoder_|. + scoped_refptr<base::SingleThreadTaskRunner> encode_task_runner_; + // Used to encode captured frames. Always accessed on the encode thread. + std::unique_ptr<VideoEncoder> encoder_; + scoped_refptr<webrtc::PeerConnectionInterface> peer_connection_; scoped_refptr<webrtc::MediaStreamInterface> stream_; + HostVideoStatsDispatcher video_stats_dispatcher_; + + // Timestamps for the frame to be captured next. + std::unique_ptr<FrameTimestamps> next_frame_timestamps_; + + // Timestamps for the frame that's being captured. + std::unique_ptr<FrameTimestamps> captured_frame_timestamps_; + bool key_frame_request_ = false; uint32_t target_bitrate_kbps_ = 1000; // Initial bitrate. @@ -86,22 +120,7 @@ webrtc::DesktopVector frame_dpi_; Observer* observer_ = nullptr; - // Main task runner. - scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; - - // Task runner used to run |encoder_|. - scoped_refptr<base::SingleThreadTaskRunner> encode_task_runner_; - - // Capturer used to capture the screen. - std::unique_ptr<webrtc::DesktopCapturer> capturer_; - - std::unique_ptr<base::RepeatingTimer> capture_timer_; - - // Used to send across encoded frames. - WebrtcTransport* webrtc_transport_ = nullptr; - - // Used to encode captured frames. Always accessed on the encode thread. - std::unique_ptr<VideoEncoder> encoder_; + base::RepeatingTimer capture_timer_; base::ThreadChecker thread_checker_;
diff --git a/remoting/remoting_host_win.gypi b/remoting/remoting_host_win.gypi index c49c9ff..66b11ef 100644 --- a/remoting/remoting_host_win.gypi +++ b/remoting/remoting_host_win.gypi
@@ -238,6 +238,8 @@ 'host/win/chromoting_module.h', 'host/win/core.cc', 'host/win/core_resource.h', + 'host/win/elevated_native_messaging_host.cc', + 'host/win/elevated_native_messaging_host.h', 'host/win/host_service.cc', 'host/win/host_service.h', 'host/win/launch_native_messaging_host_process.cc',
diff --git a/remoting/remoting_srcs.gypi b/remoting/remoting_srcs.gypi index c114cd5..3ab8cc64 100644 --- a/remoting/remoting_srcs.gypi +++ b/remoting/remoting_srcs.gypi
@@ -311,6 +311,8 @@ 'client/normalizing_input_filter_mac.h', 'client/normalizing_input_filter_win.cc', 'client/normalizing_input_filter_win.h', + 'client/queued_task_poster.cc', + 'client/queued_task_poster.h', 'client/server_log_entry_client.cc', 'client/server_log_entry_client.h', 'client/software_video_renderer.cc',
diff --git a/remoting/remoting_test.gypi b/remoting/remoting_test.gypi index 4a90e40c..9aec872f 100644 --- a/remoting/remoting_test.gypi +++ b/remoting/remoting_test.gypi
@@ -399,6 +399,8 @@ ], }, 'sources': [ + 'host/win/elevated_native_messaging_host.cc', + 'host/win/elevated_native_messaging_host.h', 'host/win/launch_native_messaging_host_process.cc', 'host/win/launch_native_messaging_host_process.h', ],
diff --git a/sandbox/win/BUILD.gn b/sandbox/win/BUILD.gn index 60bb499a..97e5c78e 100644 --- a/sandbox/win/BUILD.gn +++ b/sandbox/win/BUILD.gn
@@ -154,6 +154,12 @@ ] } + # Disable sanitizer coverage in the sandbox code. The sandbox code runs before + # sanitizer coverage can initialize. http://crbug.com/484711 + configs -= [ "//build/config/sanitizers:default_sanitizer_flags" ] + configs += + [ "//build/config/sanitizers:default_sanitizer_flags_but_coverage" ] + configs += [ "//build/config:precompiled_headers" ] deps = [
diff --git a/sdch/BUILD.gn b/sdch/BUILD.gn index 4c6c5205..1cab0b3 100644 --- a/sdch/BUILD.gn +++ b/sdch/BUILD.gn
@@ -30,7 +30,8 @@ "open-vcdiff/src/decodetable.cc", "open-vcdiff/src/decodetable.h", "open-vcdiff/src/encodetable.cc", - "open-vcdiff/src/encodetable.h", + "open-vcdiff/src/google/encodetable.h", + "open-vcdiff/src/google/jsonwriter.h", "open-vcdiff/src/google/output_string.h", "open-vcdiff/src/google/vcdecoder.h", "open-vcdiff/src/google/vcencoder.h", @@ -39,7 +40,6 @@ "open-vcdiff/src/instruction_map.cc", "open-vcdiff/src/instruction_map.h", "open-vcdiff/src/jsonwriter.cc", - "open-vcdiff/src/jsonwriter.h", "open-vcdiff/src/rolling_hash.h", "open-vcdiff/src/testing.h", "open-vcdiff/src/varint_bigendian.cc", @@ -49,8 +49,6 @@ "open-vcdiff/src/vcdiffengine.cc", "open-vcdiff/src/vcdiffengine.h", "open-vcdiff/src/vcencoder.cc", - "open-vcdiff/vsprojects/config.h", - "open-vcdiff/vsprojects/stdint.h", ] configs += [ ":sdch_warnings" ]
diff --git a/sdch/README.chromium b/sdch/README.chromium index 93ae6a0..bc13166a 100644 --- a/sdch/README.chromium +++ b/sdch/README.chromium
@@ -1,19 +1,22 @@ -The linux directory contains a config.h generated from a run of configure on -Ubuntu 10.04.1 LTS x86_64, with VCDIFF_USE_BLOCK_COMPARE_WORDS manually -changed to match the $host_cpu test in configure. +The linux directory contains a config.h generated from Ubuntu 14.04 LTS and +cmake 2.8.12.2. -The mac directory contains a config.h generated from a run of configure on a -Mac, with VCDIFF_USE_BLOCK_COMPARE_WORDS manually changed to match the -$host_cpu test in configure. +The mac directory contains a config.h generated from OS X 10.11.6, XCode 7.3, +and cmake 3.4. -The ios directory contains a config.h generated from a run of configure ---host=arm-apple-darwin10 on a Mac with the following environment variables: - CC=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc-4.2 -x c -arch armv6 - CFLAGS=-mno-thumb -miphoneos-version-min=4.2 - CPPFLAGS=-isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk - CXX=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc-4.2 -x c++ -arch armv6 - CXXFLAGS=-mno-thumb -miphoneos-version-min=4.2 +The ios directory contains a copy of the mac config.h. Since the mac config.h +contains almost nothing, this is probably fine. -The win directory contains a config.h that forwards to one provided with -open-vcdiff. We have this to avoid putting open-vcdiff's minimal stdint.h hack -into our include path. +The win directory contains a config.h generated from Windows 7, VS 2013, and +cmake 3.6 with 682f68732898c8ec621427fdd734b3b0ac223ec5 checked out. In a shell +with the VC tools in the path, do: + + cd \src + git clone https://github.com/google/open-vcdiff + cd open-vcdiff + git submodule update --init --recursive + mkdir buildfoo + cd buildfoo + "C:\Program Files\CMake\bin\cmake.exe" -GNinja .. + +Then copy the generated config.h out of the root of your open-vcdiff checkout.
diff --git a/sdch/ios/config.h b/sdch/ios/config.h index 5dde8c9..26ec0d5 100644 --- a/sdch/ios/config.h +++ b/sdch/ios/config.h
@@ -1,23 +1,25 @@ -/* src/config.h. Generated from config.h.in by configure. */ -/* src/config.h.in. Generated from configure.ac by autoheader. */ +// Copyright 2016 The open-vcdiff Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -/* Define to 1 if you have the <dlfcn.h> header file. */ -#define HAVE_DLFCN_H 1 +/* Defined to PROJECT_VERSION from CMakeLists.txt */ +#define OPEN_VCDIFF_VERSION "0.8.4" /* Define to 1 if you have the <ext/rope> header file. */ /* #undef HAVE_EXT_ROPE */ -/* Define to 1 if you have the <fnmatch.h> header file. */ -#define HAVE_FNMATCH_H 1 - -/* Define to 1 if you have the <getopt.h> header file. */ -#define HAVE_GETOPT_H 1 - /* Define to 1 if you have the `gettimeofday' function. */ -#define HAVE_GETTIMEOFDAY 1 - -/* Define to 1 if you have the <inttypes.h> header file. */ -#define HAVE_INTTYPES_H 1 +#define HAVE_GETTIMEOFDAY /* Define to 1 if you have the <malloc.h> header file. */ /* #undef HAVE_MALLOC_H */ @@ -25,89 +27,27 @@ /* Define to 1 if you have the `memalign' function. */ /* #undef HAVE_MEMALIGN */ -/* Define to 1 if you have the <memory.h> header file. */ -#define HAVE_MEMORY_H 1 - /* Define to 1 if you have the `mprotect' function. */ -#define HAVE_MPROTECT 1 +#define HAVE_MPROTECT /* Define to 1 if you have the `posix_memalign' function. */ -#define HAVE_POSIX_MEMALIGN 1 - -/* Define to 1 if you have the `QueryPerformanceCounter' function. */ -/* #undef HAVE_QUERYPERFORMANCECOUNTER */ - -/* Define to 1 if you have the <stdint.h> header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the <stdlib.h> header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the <strings.h> header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the <string.h> header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the `strtoll' function. */ -#define HAVE_STRTOLL 1 - -/* Define to 1 if you have the `strtoq' function. */ -#define HAVE_STRTOQ 1 +#define HAVE_POSIX_MEMALIGN /* Define to 1 if you have the <sys/mman.h> header file. */ -#define HAVE_SYS_MMAN_H 1 +#define HAVE_SYS_MMAN_H /* Define to 1 if you have the <sys/stat.h> header file. */ -#define HAVE_SYS_STAT_H 1 +#define HAVE_SYS_STAT_H /* Define to 1 if you have the <sys/time.h> header file. */ -#define HAVE_SYS_TIME_H 1 - -/* Define to 1 if you have the <sys/types.h> header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if the system has the type `uint16_t'. */ -#define HAVE_UINT16_T 1 +#define HAVE_SYS_TIME_H /* Define to 1 if you have the <unistd.h> header file. */ -#define HAVE_UNISTD_H 1 - -/* Define to 1 if the system has the type `u_int16_t'. */ -#define HAVE_U_INT16_T 1 +#define HAVE_UNISTD_H /* Define to 1 if you have the <windows.h> header file. */ /* #undef HAVE_WINDOWS_H */ -/* define if your compiler has __attribute__ */ -#define HAVE___ATTRIBUTE__ 1 - -/* Define to 1 if the system has the type `__int16'. */ -/* #undef HAVE___INT16 */ - -/* Name of package */ -#define PACKAGE "open-vcdiff" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "opensource@google.com" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "open-vcdiff" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "open-vcdiff 0.7" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "open-vcdiff" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "0.7" - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - /* Use custom compare function instead of memcmp */ /* #undef VCDIFF_USE_BLOCK_COMPARE_WORDS */ -/* Version number of package */ -#define VERSION "0.7"
diff --git a/sdch/linux/config.h b/sdch/linux/config.h index 3232eae6..6f540f7d 100644 --- a/sdch/linux/config.h +++ b/sdch/linux/config.h
@@ -1,119 +1,53 @@ -/* src/config.h. Generated from config.h.in by configure. */ -/* src/config.h.in. Generated from configure.ac by autoheader. */ +// Copyright 2016 The open-vcdiff Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -/* Define to 1 if you have the <dlfcn.h> header file. */ -#define HAVE_DLFCN_H 1 +/* Defined to PROJECT_VERSION from CMakeLists.txt */ +#define OPEN_VCDIFF_VERSION "0.8.4" /* Define to 1 if you have the <ext/rope> header file. */ /* #undef HAVE_EXT_ROPE */ -/* Define to 1 if you have the <fnmatch.h> header file. */ -#define HAVE_FNMATCH_H 1 - -/* Define to 1 if you have the <getopt.h> header file. */ -#define HAVE_GETOPT_H 1 - /* Define to 1 if you have the `gettimeofday' function. */ -#define HAVE_GETTIMEOFDAY 1 - -/* Define to 1 if you have the <inttypes.h> header file. */ -#define HAVE_INTTYPES_H 1 +#define HAVE_GETTIMEOFDAY /* Define to 1 if you have the <malloc.h> header file. */ -/* Manual edit: This is defined in AndroidConfig.h. */ -#undef HAVE_MALLOC_H -#define HAVE_MALLOC_H 1 +#define HAVE_MALLOC_H /* Define to 1 if you have the `memalign' function. */ -#define HAVE_MEMALIGN 1 - -/* Define to 1 if you have the <memory.h> header file. */ -#define HAVE_MEMORY_H 1 +#define HAVE_MEMALIGN /* Define to 1 if you have the `mprotect' function. */ -#define HAVE_MPROTECT 1 +#define HAVE_MPROTECT /* Define to 1 if you have the `posix_memalign' function. */ -#define HAVE_POSIX_MEMALIGN 1 - -/* Define to 1 if you have the `QueryPerformanceCounter' function. */ -/* #undef HAVE_QUERYPERFORMANCECOUNTER */ - -/* Define to 1 if you have the <stdint.h> header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the <stdlib.h> header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the <strings.h> header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the <string.h> header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the `strtoll' function. */ -#define HAVE_STRTOLL 1 - -/* Define to 1 if you have the `strtoq' function. */ -#define HAVE_STRTOQ 1 +#define HAVE_POSIX_MEMALIGN /* Define to 1 if you have the <sys/mman.h> header file. */ -#define HAVE_SYS_MMAN_H 1 +#define HAVE_SYS_MMAN_H /* Define to 1 if you have the <sys/stat.h> header file. */ -#define HAVE_SYS_STAT_H 1 +#define HAVE_SYS_STAT_H /* Define to 1 if you have the <sys/time.h> header file. */ -#define HAVE_SYS_TIME_H 1 - -/* Define to 1 if you have the <sys/types.h> header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if the system has the type `uint16_t'. */ -#define HAVE_UINT16_T 1 +#define HAVE_SYS_TIME_H /* Define to 1 if you have the <unistd.h> header file. */ -#define HAVE_UNISTD_H 1 - -/* Define to 1 if the system has the type `u_int16_t'. */ -#define HAVE_U_INT16_T 1 +#define HAVE_UNISTD_H /* Define to 1 if you have the <windows.h> header file. */ /* #undef HAVE_WINDOWS_H */ -/* define if your compiler has __attribute__ */ -#define HAVE___ATTRIBUTE__ 1 - -/* Define to 1 if the system has the type `__int16'. */ -/* #undef HAVE___INT16 */ - -/* Name of package */ -#define PACKAGE "open-vcdiff" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "opensource@google.com" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "open-vcdiff" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "open-vcdiff 0.7" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "open-vcdiff" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "0.7" - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - /* Use custom compare function instead of memcmp */ -#if defined(__i386__) || defined(__x86_64__) -#define VCDIFF_USE_BLOCK_COMPARE_WORDS 1 -#else /* #undef VCDIFF_USE_BLOCK_COMPARE_WORDS */ -#endif -/* Version number of package */ -#define VERSION "0.7"
diff --git a/sdch/mac/config.h b/sdch/mac/config.h index e9ee90e..26ec0d5 100644 --- a/sdch/mac/config.h +++ b/sdch/mac/config.h
@@ -1,23 +1,25 @@ -/* src/config.h. Generated from config.h.in by configure. */ -/* src/config.h.in. Generated from configure.ac by autoheader. */ +// Copyright 2016 The open-vcdiff Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -/* Define to 1 if you have the <dlfcn.h> header file. */ -#define HAVE_DLFCN_H 1 +/* Defined to PROJECT_VERSION from CMakeLists.txt */ +#define OPEN_VCDIFF_VERSION "0.8.4" /* Define to 1 if you have the <ext/rope> header file. */ /* #undef HAVE_EXT_ROPE */ -/* Define to 1 if you have the <fnmatch.h> header file. */ -#define HAVE_FNMATCH_H 1 - -/* Define to 1 if you have the <getopt.h> header file. */ -#define HAVE_GETOPT_H 1 - /* Define to 1 if you have the `gettimeofday' function. */ -#define HAVE_GETTIMEOFDAY 1 - -/* Define to 1 if you have the <inttypes.h> header file. */ -#define HAVE_INTTYPES_H 1 +#define HAVE_GETTIMEOFDAY /* Define to 1 if you have the <malloc.h> header file. */ /* #undef HAVE_MALLOC_H */ @@ -25,93 +27,27 @@ /* Define to 1 if you have the `memalign' function. */ /* #undef HAVE_MEMALIGN */ -/* Define to 1 if you have the <memory.h> header file. */ -#define HAVE_MEMORY_H 1 - /* Define to 1 if you have the `mprotect' function. */ -#define HAVE_MPROTECT 1 +#define HAVE_MPROTECT /* Define to 1 if you have the `posix_memalign' function. */ -/* #undef HAVE_POSIX_MEMALIGN */ - -/* Define to 1 if you have the `QueryPerformanceCounter' function. */ -/* #undef HAVE_QUERYPERFORMANCECOUNTER */ - -/* Define to 1 if you have the <stdint.h> header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the <stdlib.h> header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the <strings.h> header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the <string.h> header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the `strtoll' function. */ -#define HAVE_STRTOLL 1 - -/* Define to 1 if you have the `strtoq' function. */ -#define HAVE_STRTOQ 1 +#define HAVE_POSIX_MEMALIGN /* Define to 1 if you have the <sys/mman.h> header file. */ -#define HAVE_SYS_MMAN_H 1 +#define HAVE_SYS_MMAN_H /* Define to 1 if you have the <sys/stat.h> header file. */ -#define HAVE_SYS_STAT_H 1 +#define HAVE_SYS_STAT_H /* Define to 1 if you have the <sys/time.h> header file. */ -#define HAVE_SYS_TIME_H 1 - -/* Define to 1 if you have the <sys/types.h> header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if the system has the type `uint16_t'. */ -#define HAVE_UINT16_T 1 +#define HAVE_SYS_TIME_H /* Define to 1 if you have the <unistd.h> header file. */ -#define HAVE_UNISTD_H 1 - -/* Define to 1 if the system has the type `u_int16_t'. */ -#define HAVE_U_INT16_T 1 +#define HAVE_UNISTD_H /* Define to 1 if you have the <windows.h> header file. */ /* #undef HAVE_WINDOWS_H */ -/* define if your compiler has __attribute__ */ -#define HAVE___ATTRIBUTE__ 1 - -/* Define to 1 if the system has the type `__int16'. */ -/* #undef HAVE___INT16 */ - -/* Name of package */ -#define PACKAGE "open-vcdiff" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "opensource@google.com" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "open-vcdiff" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "open-vcdiff 0.7" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "open-vcdiff" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "0.7" - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - /* Use custom compare function instead of memcmp */ -#if defined(__i386__) || defined(__x86_64__) -#define VCDIFF_USE_BLOCK_COMPARE_WORDS 1 -#else /* #undef VCDIFF_USE_BLOCK_COMPARE_WORDS */ -#endif -/* Version number of package */ -#define VERSION "0.7"
diff --git a/sdch/win/config.h b/sdch/win/config.h index b5fb37c8..d34f02c 100644 --- a/sdch/win/config.h +++ b/sdch/win/config.h
@@ -1,14 +1,53 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. +// Copyright 2016 The open-vcdiff Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -// This file and directory exist so that we can use the provided config.h -// without putting vsprojects into our include path (which would also give us an -// incorrect/incompatible stdint.h). +/* Defined to PROJECT_VERSION from CMakeLists.txt */ +#define OPEN_VCDIFF_VERSION "0.8.4" -#ifndef SDCH_WIN_CONFIG_H_ -#define SDCH_WIN_CONFIG_H_ +/* Define to 1 if you have the <ext/rope> header file. */ +/* #undef HAVE_EXT_ROPE */ -#include "../open-vcdiff/vsprojects/config.h" +/* Define to 1 if you have the `gettimeofday' function. */ +/* #undef HAVE_GETTIMEOFDAY */ -#endif // SDCH_WIN_CONFIG_H_ +/* Define to 1 if you have the <malloc.h> header file. */ +#define HAVE_MALLOC_H + +/* Define to 1 if you have the `memalign' function. */ +/* #undef HAVE_MEMALIGN */ + +/* Define to 1 if you have the `mprotect' function. */ +/* #undef HAVE_MPROTECT */ + +/* Define to 1 if you have the `posix_memalign' function. */ +/* #undef HAVE_POSIX_MEMALIGN */ + +/* Define to 1 if you have the <sys/mman.h> header file. */ +/* #undef HAVE_SYS_MMAN_H */ + +/* Define to 1 if you have the <sys/stat.h> header file. */ +/* #undef HAVE_SYS_STAT_H */ + +/* Define to 1 if you have the <sys/time.h> header file. */ +/* #undef HAVE_SYS_TIME_H */ + +/* Define to 1 if you have the <unistd.h> header file. */ +/* #undef HAVE_UNISTD_H */ + +/* Define to 1 if you have the <windows.h> header file. */ +#define HAVE_WINDOWS_H + +/* Use custom compare function instead of memcmp */ +/* #undef VCDIFF_USE_BLOCK_COMPARE_WORDS */ +
diff --git a/services/navigation/view_impl.cc b/services/navigation/view_impl.cc index 6037e8f..a6451d1 100644 --- a/services/navigation/view_impl.cc +++ b/services/navigation/view_impl.cc
@@ -280,7 +280,8 @@ } void ViewImpl::OnDidDestroyClient(ui::WindowTreeClient* client) {} -void ViewImpl::OnEventObserved(const ui::Event& event, ui::Window* target) {} +void ViewImpl::OnPointerEventObserved(const ui::PointerEvent& event, + ui::Window* target) {} views::View* ViewImpl::GetContentsView() { return web_view_;
diff --git a/services/navigation/view_impl.h b/services/navigation/view_impl.h index ad9b7edc..f502bce 100644 --- a/services/navigation/view_impl.h +++ b/services/navigation/view_impl.h
@@ -82,7 +82,8 @@ // ui::WindowTreeClientDelegate: void OnEmbed(ui::Window* root) override; void OnDidDestroyClient(ui::WindowTreeClient* client) override; - void OnEventObserved(const ui::Event& event, ui::Window* target) override; + void OnPointerEventObserved(const ui::PointerEvent& event, + ui::Window* target) override; // views::WidgetDelegate: views::View* GetContentsView() override;
diff --git a/services/ui/BUILD.gn b/services/ui/BUILD.gn index 1e62118e..d7ca3df 100644 --- a/services/ui/BUILD.gn +++ b/services/ui/BUILD.gn
@@ -13,7 +13,7 @@ testonly = true deps = [ ":ui", - "//services/ui/test_ime", + "//services/ui/ime/test_ime_driver", "//services/ui/test_wm", ] } @@ -90,6 +90,7 @@ "//services/ui/clipboard:lib", "//services/ui/gpu", "//services/ui/gpu/display_compositor", + "//services/ui/ime:lib", "//services/ui/input_devices", "//services/ui/public/interfaces", "//services/ui/surfaces",
diff --git a/services/ui/demo/mus_demo.cc b/services/ui/demo/mus_demo.cc index ac7ed7c8f..30994adf 100644 --- a/services/ui/demo/mus_demo.cc +++ b/services/ui/demo/mus_demo.cc
@@ -85,7 +85,8 @@ timer_.Stop(); } -void MusDemo::OnEventObserved(const Event& event, Window* target) {} +void MusDemo::OnPointerEventObserved(const PointerEvent& event, + Window* target) {} void MusDemo::SetWindowManagerClient(WindowManagerClient* client) {}
diff --git a/services/ui/demo/mus_demo.h b/services/ui/demo/mus_demo.h index 4f4dd27..1920075 100644 --- a/services/ui/demo/mus_demo.h +++ b/services/ui/demo/mus_demo.h
@@ -44,7 +44,8 @@ // WindowTreeClientDelegate: void OnEmbed(Window* root) override; void OnDidDestroyClient(WindowTreeClient* client) override; - void OnEventObserved(const Event& event, Window* target) override; + void OnPointerEventObserved(const PointerEvent& event, + Window* target) override; // WindowManagerDelegate: void SetWindowManagerClient(WindowManagerClient* client) override;
diff --git a/services/ui/ime/BUILD.gn b/services/ui/ime/BUILD.gn new file mode 100644 index 0000000..a9aac00 --- /dev/null +++ b/services/ui/ime/BUILD.gn
@@ -0,0 +1,60 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//services/shell/public/cpp/service.gni") +import("//services/shell/public/service_manifest.gni") +import("//testing/test.gni") + +source_set("lib") { + sources = [ + "ime_registrar_impl.cc", + "ime_registrar_impl.h", + "ime_server_impl.cc", + "ime_server_impl.h", + ] + + deps = [ + "//base", + "//mojo/common", + "//mojo/public/cpp/bindings", + "//services/shell/public/cpp", + "//services/tracing/public/cpp", + "//services/ui/public/interfaces", + ] +} + +group("tests") { + testonly = true + deps = [ + ":mus_ime_unittests", + ] +} + +test("mus_ime_unittests") { + sources = [ + "ime_unittest.cc", + ] + + deps = [ + "//base", + "//mojo/common", + "//services/shell/public/cpp:service_test_support", + "//services/shell/public/cpp:sources", + "//services/shell/public/cpp/test:run_all_shelltests", + "//services/ui/public/interfaces", + ] + + data_deps = [ + ":test_manifest", + ":lib", + "//services/ui", + "//services/ui/ime/test_ime_driver", + ] +} + +service_manifest("test_manifest") { + type = "exe" + name = "mus_ime_unittests" + source = "test_manifest.json" +}
diff --git a/services/ui/ime/ime_registrar_impl.cc b/services/ui/ime/ime_registrar_impl.cc new file mode 100644 index 0000000..1696765 --- /dev/null +++ b/services/ui/ime/ime_registrar_impl.cc
@@ -0,0 +1,24 @@ +// 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 "services/ui/ime/ime_registrar_impl.h" + +namespace ui { + +IMERegistrarImpl::IMERegistrarImpl(IMEServerImpl* ime_server) + : ime_server_(ime_server) {} + +IMERegistrarImpl::~IMERegistrarImpl() {} + +void IMERegistrarImpl::AddBinding(mojom::IMERegistrarRequest request) { + bindings_.AddBinding(this, std::move(request)); +} + +void IMERegistrarImpl::RegisterDriver(mojom::IMEDriverPtr driver) { + // TODO(moshayedi): crbug.com/634441. IMERegistrarImpl currently identifies + // the last registered driver as the current driver. Rethink this once we + // have more usecases. + ime_server_->OnDriverChanged(std::move(driver)); +} +} // namespace ui
diff --git a/services/ui/ime/ime_registrar_impl.h b/services/ui/ime/ime_registrar_impl.h new file mode 100644 index 0000000..07d8982f --- /dev/null +++ b/services/ui/ime/ime_registrar_impl.h
@@ -0,0 +1,33 @@ +// 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 SERVICES_UI_IME_IME_REGISTRAR_IMPL_H_ +#define SERVICES_UI_IME_IME_REGISTRAR_IMPL_H_ + +#include "mojo/public/cpp/bindings/binding_set.h" +#include "services/ui/ime/ime_server_impl.h" +#include "services/ui/public/interfaces/ime.mojom.h" + +namespace ui { + +class IMERegistrarImpl : public mojom::IMERegistrar { + public: + explicit IMERegistrarImpl(IMEServerImpl* ime_server); + ~IMERegistrarImpl() override; + + void AddBinding(mojom::IMERegistrarRequest request); + + private: + // mojom::IMERegistrar: + void RegisterDriver(mojom::IMEDriverPtr driver) override; + + mojo::BindingSet<mojom::IMERegistrar> bindings_; + IMEServerImpl* ime_server_; + + DISALLOW_COPY_AND_ASSIGN(IMERegistrarImpl); +}; + +} // namespace ui + +#endif // SERVICES_UI_IME_IME_REGISTRAR_IMPL_H_
diff --git a/services/ui/ime/ime_server_impl.cc b/services/ui/ime/ime_server_impl.cc new file mode 100644 index 0000000..b295f401 --- /dev/null +++ b/services/ui/ime/ime_server_impl.cc
@@ -0,0 +1,46 @@ +// 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 "services/ui/ime/ime_server_impl.h" + +#include "services/ui/ime/ime_registrar_impl.h" + +namespace ui { + +IMEServerImpl::IMEServerImpl() : current_id_(0) {} + +IMEServerImpl::~IMEServerImpl() {} + +void IMEServerImpl::AddBinding(mojom::IMEServerRequest request) { + bindings_.AddBinding(this, std::move(request)); +} + +void IMEServerImpl::OnDriverChanged(mojom::IMEDriverPtr driver) { + driver_ = std::move(driver); + + while (!pending_requests_.empty()) { + driver_->StartSession(current_id_++, + std::move(pending_requests_.front().first), + std::move(pending_requests_.front().second)); + pending_requests_.pop(); + } +} + +void IMEServerImpl::StartSession( + mojom::TextInputClientPtr client, + mojom::InputMethodRequest input_method_request) { + if (driver_.get()) { + // TODO(moshayedi): crbug.com/634431. This will forward all calls from + // clients to the driver as they are. We may need to check |caret_bounds| + // parameter of InputMethod::OnCaretBoundsChanged() here and limit them to + // client's focused window. + driver_->StartSession(current_id_++, std::move(client), + std::move(input_method_request)); + } else { + pending_requests_.push( + std::make_pair(std::move(client), std::move(input_method_request))); + } +} + +} // namespace ui
diff --git a/services/ui/ime/ime_server_impl.h b/services/ui/ime/ime_server_impl.h new file mode 100644 index 0000000..0b4c9f9 --- /dev/null +++ b/services/ui/ime/ime_server_impl.h
@@ -0,0 +1,41 @@ +// 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 SERVICES_UI_IME_IME_SERVER_IMPL_H_ +#define SERVICES_UI_IME_IME_SERVER_IMPL_H_ + +#include <utility> + +#include "mojo/public/cpp/bindings/binding_set.h" +#include "services/ui/public/interfaces/ime.mojom.h" + +namespace ui { + +class IMEServerImpl : public mojom::IMEServer { + public: + IMEServerImpl(); + ~IMEServerImpl() override; + + void AddBinding(mojom::IMEServerRequest request); + void OnDriverChanged(mojom::IMEDriverPtr driver); + + private: + // mojom::IMEServer: + void StartSession(mojom::TextInputClientPtr client, + mojom::InputMethodRequest input_method) override; + + mojo::BindingSet<mojom::IMEServer> bindings_; + mojom::IMEDriverPtr driver_; + int current_id_; + + using PendingRequest = + std::pair<mojom::TextInputClientPtr, mojom::InputMethodRequest>; + std::queue<PendingRequest> pending_requests_; + + DISALLOW_COPY_AND_ASSIGN(IMEServerImpl); +}; + +} // namespace ui + +#endif // SERVICES_UI_IME_IME_SERVER_IMPL_H_
diff --git a/services/ui/ime/ime_unittest.cc b/services/ui/ime/ime_unittest.cc new file mode 100644 index 0000000..a7754d1 --- /dev/null +++ b/services/ui/ime/ime_unittest.cc
@@ -0,0 +1,85 @@ +// 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 <stdint.h> + +#include "base/bind.h" +#include "base/macros.h" +#include "base/run_loop.h" +#include "mojo/public/cpp/bindings/interface_request.h" +#include "services/shell/public/cpp/service_context.h" +#include "services/shell/public/cpp/service_test.h" +#include "services/ui/public/interfaces/ime.mojom.h" +#include "ui/events/event.h" + +class TestTextInputClient : public ui::mojom::TextInputClient { + public: + explicit TestTextInputClient(ui::mojom::TextInputClientRequest request) + : binding_(this, std::move(request)) {} + + ui::mojom::CompositionEventPtr ReceiveCompositionEvent() { + run_loop_.reset(new base::RunLoop); + run_loop_->Run(); + run_loop_.reset(); + + return std::move(receieved_composition_event_); + } + + private: + void OnCompositionEvent(ui::mojom::CompositionEventPtr event) override { + receieved_composition_event_ = std::move(event); + run_loop_->Quit(); + } + + mojo::Binding<ui::mojom::TextInputClient> binding_; + std::unique_ptr<base::RunLoop> run_loop_; + ui::mojom::CompositionEventPtr receieved_composition_event_; + + DISALLOW_COPY_AND_ASSIGN(TestTextInputClient); +}; + +class IMEAppTest : public shell::test::ServiceTest { + public: + IMEAppTest() : ServiceTest("exe:mus_ime_unittests") {} + ~IMEAppTest() override {} + + // shell::test::ServiceTest: + void SetUp() override { + ServiceTest::SetUp(); + // test_ime_driver will register itself as the current IMEDriver. + connector()->Connect("mojo:test_ime_driver"); + connector()->ConnectToInterface("mojo:ui", &ime_server_); + } + + protected: + ui::mojom::IMEServerPtr ime_server_; + std::unique_ptr<base::RunLoop> run_loop_; + + DISALLOW_COPY_AND_ASSIGN(IMEAppTest); +}; + +// Tests sending a KeyEvent to the IMEDriver through the Mus IMEServer. +TEST_F(IMEAppTest, ProcessKeyEvent) { + ui::mojom::TextInputClientPtr client_ptr; + TestTextInputClient client(GetProxy(&client_ptr)); + + ui::mojom::InputMethodPtr input_method; + ime_server_->StartSession(std::move(client_ptr), GetProxy(&input_method)); + + ui::KeyEvent key_event(ui::ET_KEY_PRESSED, ui::VKEY_A, 0); + + input_method->ProcessKeyEvent(ui::Event::Clone(key_event)); + + ui::mojom::CompositionEventPtr composition_event = + client.ReceiveCompositionEvent(); + ASSERT_EQ(ui::mojom::CompositionEventType::INSERT_CHAR, + composition_event->type); + ASSERT_TRUE(composition_event->key_event); + ASSERT_TRUE(composition_event->key_event.value()->IsKeyEvent()); + + ui::KeyEvent* received_key_event = + composition_event->key_event.value()->AsKeyEvent(); + ASSERT_EQ(ui::ET_KEY_PRESSED, received_key_event->type()); + ASSERT_EQ(key_event.GetCharacter(), received_key_event->GetCharacter()); +}
diff --git a/services/ui/ime/test_ime_driver/BUILD.gn b/services/ui/ime/test_ime_driver/BUILD.gn new file mode 100644 index 0000000..b772076c --- /dev/null +++ b/services/ui/ime/test_ime_driver/BUILD.gn
@@ -0,0 +1,33 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//services/shell/public/cpp/service.gni") +import("//services/shell/public/service_manifest.gni") +import("//testing/test.gni") + +service("test_ime_driver") { + sources = [ + "main.cc", + "test_ime_driver.cc", + "test_ime_driver.h", + ] + + deps = [ + "//base", + "//services/shell/public/cpp", + "//services/ui/public/cpp", + "//services/ui/public/interfaces", + "//ui/gfx/geometry/mojo", + ] + + data_deps = [ + ":manifest", + "//services/ui", + ] +} + +service_manifest("manifest") { + name = "test_ime_driver" + source = "manifest.json" +}
diff --git a/services/ui/ime/test_ime_driver/main.cc b/services/ui/ime/test_ime_driver/main.cc new file mode 100644 index 0000000..795119fa --- /dev/null +++ b/services/ui/ime/test_ime_driver/main.cc
@@ -0,0 +1,39 @@ +// 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 "services/shell/public/c/main.h" +#include "services/shell/public/cpp/connector.h" +#include "services/shell/public/cpp/service.h" +#include "services/shell/public/cpp/service_runner.h" +#include "services/ui/ime/test_ime_driver/test_ime_driver.h" + +namespace ui { +namespace test { + +class TestIME : public shell::Service { + public: + TestIME() {} + ~TestIME() override {} + + private: + // shell::Service: + void OnStart(const shell::Identity& identity) override { + mojom::IMEDriverPtr ime_driver_ptr; + new TestIMEDriver(GetProxy(&ime_driver_ptr)); + + ui::mojom::IMERegistrarPtr ime_registrar; + connector()->ConnectToInterface("mojo:ui", &ime_registrar); + ime_registrar->RegisterDriver(std::move(ime_driver_ptr)); + } + + DISALLOW_COPY_AND_ASSIGN(TestIME); +}; + +} // namespace test +} // namespace ui + +MojoResult ServiceMain(MojoHandle service_request_handle) { + shell::ServiceRunner runner(new ui::test::TestIME); + return runner.Run(service_request_handle); +}
diff --git a/services/ui/ime/test_ime_driver/manifest.json b/services/ui/ime/test_ime_driver/manifest.json new file mode 100644 index 0000000..44fea67 --- /dev/null +++ b/services/ui/ime/test_ime_driver/manifest.json
@@ -0,0 +1,12 @@ +{ + "manifest_version": 1, + "name": "mojo:test_ime_driver", + "display_name": "Test IME Driver", + "capabilities": { + "required": { + "mojo:ui": { + "interfaces": [ "ui::mojom::IMERegistrar" ] + } + } + } +}
diff --git a/services/ui/ime/test_ime_driver/test_ime_driver.cc b/services/ui/ime/test_ime_driver/test_ime_driver.cc new file mode 100644 index 0000000..370ea5f --- /dev/null +++ b/services/ui/ime/test_ime_driver/test_ime_driver.cc
@@ -0,0 +1,59 @@ +// 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 "services/ui/ime/test_ime_driver/test_ime_driver.h" + +#include "services/ui/public/interfaces/ime.mojom.h" + +namespace ui { +namespace test { + +class TestInputMethod : public mojom::InputMethod { + public: + explicit TestInputMethod(mojom::TextInputClientPtr client) + : client_(std::move(client)) {} + ~TestInputMethod() override {} + + private: + // mojom::InputMethod: + void OnTextInputModeChanged(mojom::TextInputMode text_input_mode) override {} + void OnTextInputTypeChanged(mojom::TextInputType text_input_type) override {} + void OnCaretBoundsChanged(const gfx::Rect& caret_bounds) override {} + void ProcessKeyEvent(std::unique_ptr<Event> key_event) override { + DCHECK(key_event->IsKeyEvent()); + mojom::CompositionEventPtr composition_event = + mojom::CompositionEvent::New(); + composition_event->type = mojom::CompositionEventType::INSERT_CHAR; + composition_event->key_event = std::move(key_event); + + client_->OnCompositionEvent(std::move(composition_event)); + }; + void CancelComposition() override {} + + mojom::TextInputClientPtr client_; + + DISALLOW_COPY_AND_ASSIGN(TestInputMethod); +}; + +TestIMEDriver::TestIMEDriver(mojom::IMEDriverRequest request) + : driver_binding_(this, std::move(request)) {} + +TestIMEDriver::~TestIMEDriver() {} + +void TestIMEDriver::StartSession( + int32_t session_id, + mojom::TextInputClientPtr client, + mojom::InputMethodRequest input_method_request) { + input_method_bindings_[session_id].reset( + new mojo::Binding<mojom::InputMethod>( + new TestInputMethod(std::move(client)), + std::move(input_method_request))); +} + +void TestIMEDriver::CancelSession(int32_t session_id) { + input_method_bindings_.erase(session_id); +} + +} // namespace test +} // namespace ui
diff --git a/services/ui/ime/test_ime_driver/test_ime_driver.h b/services/ui/ime/test_ime_driver/test_ime_driver.h new file mode 100644 index 0000000..7a2e1d2b --- /dev/null +++ b/services/ui/ime/test_ime_driver/test_ime_driver.h
@@ -0,0 +1,39 @@ +// 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 SERVICES_UI_IME_TEST_IME_DRIVER_TEST_IME_DRIVER_H_ +#define SERVICES_UI_IME_TEST_IME_DRIVER_TEST_IME_DRIVER_H_ + +#include <map> + +#include "mojo/public/cpp/bindings/strong_binding.h" +#include "services/ui/public/interfaces/ime.mojom.h" + +namespace ui { +namespace test { + +class TestIMEDriver : public ui::mojom::IMEDriver { + public: + explicit TestIMEDriver(mojom::IMEDriverRequest request); + ~TestIMEDriver() override; + + private: + // ui::mojom::IMEDriver: + void StartSession( + int32_t session_id, + ui::mojom::TextInputClientPtr client, + ui::mojom::InputMethodRequest input_method_request) override; + void CancelSession(int32_t session_id) override; + + mojo::StrongBinding<mojom::IMEDriver> driver_binding_; + std::map<int32_t, std::unique_ptr<mojo::Binding<mojom::InputMethod>>> + input_method_bindings_; + + DISALLOW_COPY_AND_ASSIGN(TestIMEDriver); +}; + +} // namespace test +} // namespace ui + +#endif // SERVICES_UI_IME_TEST_IME_DRIVER_TEST_IME_DRIVER_H_
diff --git a/services/ui/ime/test_manifest.json b/services/ui/ime/test_manifest.json new file mode 100644 index 0000000..f5dfbd7d --- /dev/null +++ b/services/ui/ime/test_manifest.json
@@ -0,0 +1,11 @@ +{ + "manifest_version": 1, + "name": "exe:mus_ime_unittests", + "display_name": "IME Service Unittests", + "capabilities": { + "required": { + "mojo:ui": { "interfaces": [ "ui::mojom::IMEServer" ] }, + "mojo:test_ime_driver": {} + } + } +}
diff --git a/services/ui/manifest.json b/services/ui/manifest.json index 6aec83bd..353f0e3 100644 --- a/services/ui/manifest.json +++ b/services/ui/manifest.json
@@ -11,6 +11,7 @@ "ui::mojom::DisplayManager", "ui::mojom::Gpu", "ui::mojom::GpuService", + "ui::mojom::IMEServer", "ui::mojom::InputDeviceServer", "ui::mojom::WindowTreeFactory" ],
diff --git a/services/ui/public/cpp/BUILD.gn b/services/ui/public/cpp/BUILD.gn index fb975af..a4a14d7 100644 --- a/services/ui/public/cpp/BUILD.gn +++ b/services/ui/public/cpp/BUILD.gn
@@ -7,8 +7,6 @@ source_set("cpp") { sources = [ "bitmap_uploader.h", - "context_provider.h", - "gles2_context.h", "input_event_handler.h", "output_surface.h", "property_type_converters.h", @@ -94,7 +92,9 @@ "command_buffer_client_impl.cc", "command_buffer_client_impl.h", "context_provider.cc", + "context_provider.h", "gles2_context.cc", + "gles2_context.h", "in_flight_change.cc", "in_flight_change.h", "output_surface.cc",
diff --git a/services/ui/public/cpp/output_surface.cc b/services/ui/public/cpp/output_surface.cc index 9eacc97..5b96e91 100644 --- a/services/ui/public/cpp/output_surface.cc +++ b/services/ui/public/cpp/output_surface.cc
@@ -7,14 +7,15 @@ #include "base/bind.h" #include "cc/output/compositor_frame.h" #include "cc/output/output_surface_client.h" +#include "services/ui/public/cpp/context_provider.h" #include "services/ui/public/cpp/window_surface.h" namespace ui { -OutputSurface::OutputSurface( - const scoped_refptr<cc::ContextProvider>& context_provider, - std::unique_ptr<ui::WindowSurface> surface) - : cc::OutputSurface(context_provider, nullptr, nullptr), +OutputSurface::OutputSurface(std::unique_ptr<ui::WindowSurface> surface) + : cc::OutputSurface(make_scoped_refptr(new ContextProvider()), + nullptr, + nullptr), surface_(std::move(surface)) { capabilities_.delegated_rendering = true; }
diff --git a/services/ui/public/cpp/output_surface.h b/services/ui/public/cpp/output_surface.h index 384f4ecc..fb38073b 100644 --- a/services/ui/public/cpp/output_surface.h +++ b/services/ui/public/cpp/output_surface.h
@@ -16,8 +16,7 @@ class OutputSurface : public cc::OutputSurface, public WindowSurfaceClient { public: - OutputSurface(const scoped_refptr<cc::ContextProvider>& context_provider, - std::unique_ptr<WindowSurface> surface); + explicit OutputSurface(std::unique_ptr<WindowSurface> surface); ~OutputSurface() override; // cc::OutputSurface implementation.
diff --git a/services/ui/public/cpp/tests/test_window_tree.cc b/services/ui/public/cpp/tests/test_window_tree.cc index 14ca4ed..980eefd 100644 --- a/services/ui/public/cpp/tests/test_window_tree.cc +++ b/services/ui/public/cpp/tests/test_window_tree.cc
@@ -124,8 +124,10 @@ change_id_ = change_id; } -void TestWindowTree::SetEventObserver(mojom::EventMatcherPtr matcher, - uint32_t observer_id) {} +void TestWindowTree::StartPointerWatcher(bool want_moves, + uint32_t pointer_watcher_id) {} + +void TestWindowTree::StopPointerWatcher() {} void TestWindowTree::Embed(uint32_t window_id, mojom::WindowTreeClientPtr client,
diff --git a/services/ui/public/cpp/tests/test_window_tree.h b/services/ui/public/cpp/tests/test_window_tree.h index d1f238d..8027ebc 100644 --- a/services/ui/public/cpp/tests/test_window_tree.h +++ b/services/ui/public/cpp/tests/test_window_tree.h
@@ -78,8 +78,9 @@ const GetWindowTreeCallback& callback) override; void SetCapture(uint32_t change_id, uint32_t window_id) override; void ReleaseCapture(uint32_t change_id, uint32_t window_id) override; - void SetEventObserver(mojom::EventMatcherPtr matcher, - uint32_t observer_id) override; + void StartPointerWatcher(bool want_moves, + uint32_t pointer_watcher_id) override; + void StopPointerWatcher() override; void Embed(uint32_t window_id, mojom::WindowTreeClientPtr client, uint32_t flags,
diff --git a/services/ui/public/cpp/tests/window_server_test_base.cc b/services/ui/public/cpp/tests/window_server_test_base.cc index 025a56d..8d93e708 100644 --- a/services/ui/public/cpp/tests/window_server_test_base.cc +++ b/services/ui/public/cpp/tests/window_server_test_base.cc
@@ -90,8 +90,8 @@ window_tree_client_destroyed_ = true; } -void WindowServerTestBase::OnEventObserved(const ui::Event& event, - Window* target) {} +void WindowServerTestBase::OnPointerEventObserved(const ui::PointerEvent& event, + Window* target) {} void WindowServerTestBase::SetWindowManagerClient(WindowManagerClient* client) { window_manager_client_ = client;
diff --git a/services/ui/public/cpp/tests/window_server_test_base.h b/services/ui/public/cpp/tests/window_server_test_base.h index 5e66744..50c9e0c 100644 --- a/services/ui/public/cpp/tests/window_server_test_base.h +++ b/services/ui/public/cpp/tests/window_server_test_base.h
@@ -69,7 +69,8 @@ // WindowTreeClientDelegate: void OnEmbed(Window* root) override; void OnDidDestroyClient(WindowTreeClient* client) override; - void OnEventObserved(const ui::Event& event, Window* target) override; + void OnPointerEventObserved(const ui::PointerEvent& event, + Window* target) override; // WindowManagerDelegate: void SetWindowManagerClient(WindowManagerClient* client) override;
diff --git a/services/ui/public/cpp/tests/window_tree_client_private.cc b/services/ui/public/cpp/tests/window_tree_client_private.cc index eb75d72..2595f25 100644 --- a/services/ui/public/cpp/tests/window_tree_client_private.cc +++ b/services/ui/public/cpp/tests/window_tree_client_private.cc
@@ -19,8 +19,8 @@ WindowTreeClientPrivate::~WindowTreeClientPrivate() {} -uint32_t WindowTreeClientPrivate::event_observer_id() { - return tree_client_impl_->event_observer_id_; +uint32_t WindowTreeClientPrivate::pointer_watcher_id() { + return tree_client_impl_->pointer_watcher_id_; } void WindowTreeClientPrivate::OnEmbed(mojom::WindowTree* window_tree) {
diff --git a/services/ui/public/cpp/tests/window_tree_client_private.h b/services/ui/public/cpp/tests/window_tree_client_private.h index fa958195..766b49a 100644 --- a/services/ui/public/cpp/tests/window_tree_client_private.h +++ b/services/ui/public/cpp/tests/window_tree_client_private.h
@@ -35,7 +35,7 @@ explicit WindowTreeClientPrivate(Window* window); ~WindowTreeClientPrivate(); - uint32_t event_observer_id(); + uint32_t pointer_watcher_id(); // Calls OnEmbed() on the WindowTreeClient. void OnEmbed(mojom::WindowTree* window_tree);
diff --git a/services/ui/public/cpp/tests/window_tree_client_unittest.cc b/services/ui/public/cpp/tests/window_tree_client_unittest.cc index 2046c3b..14b83a2 100644 --- a/services/ui/public/cpp/tests/window_tree_client_unittest.cc +++ b/services/ui/public/cpp/tests/window_tree_client_unittest.cc
@@ -52,19 +52,20 @@ TestWindowTreeClientDelegate() {} ~TestWindowTreeClientDelegate() override {} - ui::Event* last_event_observed() { return last_event_observed_.get(); } + ui::PointerEvent* last_event_observed() { return last_event_observed_.get(); } void Reset() { last_event_observed_.reset(); } // WindowTreeClientDelegate: void OnEmbed(Window* root) override {} void OnDidDestroyClient(WindowTreeClient* client) override {} - void OnEventObserved(const ui::Event& event, Window* target) override { - last_event_observed_ = ui::Event::Clone(event); + void OnPointerEventObserved(const ui::PointerEvent& event, + Window* target) override { + last_event_observed_.reset(new ui::PointerEvent(event)); } private: - std::unique_ptr<ui::Event> last_event_observed_; + std::unique_ptr<ui::PointerEvent> last_event_observed_; DISALLOW_COPY_AND_ASSIGN(TestWindowTreeClientDelegate); }; @@ -95,8 +96,8 @@ : *client()->GetRoots().begin(); } - uint32_t GetEventObserverId() { - return WindowTreeClientPrivate(&tree_client_).event_observer_id(); + uint32_t GetPointerWatcherId() { + return WindowTreeClientPrivate(&tree_client_).pointer_watcher_id(); } private: @@ -466,112 +467,108 @@ EXPECT_TRUE(setup.window_tree()->WasEventAcked(33)); } -// Tests event observers triggered by events that did not hit a target in this +// Tests pointer watchers triggered by events that did not hit a target in this // window tree. -TEST_F(WindowTreeClientTest, OnEventObserved) { +TEST_F(WindowTreeClientTest, OnPointerEventObserved) { WindowTreeSetup setup; Window* root = setup.GetFirstRoot(); ASSERT_TRUE(root); - // Set up an event observer. - mojom::EventMatcherPtr matcher = mojom::EventMatcher::New(); - matcher->type_matcher = mojom::EventTypeMatcher::New(); - matcher->type_matcher->type = ui::mojom::EventType::POINTER_DOWN; - setup.client()->SetEventObserver(std::move(matcher)); + // Start a pointer watcher for all events excluding move events. + setup.client()->StartPointerWatcher(false /* want_moves */); // Simulate the server sending an observed event. - uint32_t event_observer_id = setup.GetEventObserverId(); - std::unique_ptr<ui::Event> ui_event( - new ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), - ui::EventTimeForNow(), ui::EF_CONTROL_DOWN, 0)); - setup.window_tree_client()->OnEventObserved(ui::Event::Clone(*ui_event.get()), - event_observer_id); + uint32_t pointer_watcher_id = setup.GetPointerWatcherId(); + std::unique_ptr<ui::PointerEvent> pointer_event_down(new ui::PointerEvent( + ui::ET_POINTER_DOWN, gfx::Point(), gfx::Point(), ui::EF_CONTROL_DOWN, 1, + ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH), + base::TimeTicks())); + setup.window_tree_client()->OnPointerEventObserved( + std::move(pointer_event_down), pointer_watcher_id); // Delegate sensed the event. ui::Event* last_event = setup.window_tree_delegate()->last_event_observed(); - EXPECT_EQ(ui::ET_MOUSE_PRESSED, last_event->type()); + EXPECT_EQ(ui::ET_POINTER_DOWN, last_event->type()); EXPECT_EQ(ui::EF_CONTROL_DOWN, last_event->flags()); setup.window_tree_delegate()->Reset(); - // Clear the event observer. - setup.client()->SetEventObserver(nullptr); + // Stop the pointer watcher. + setup.client()->StopPointerWatcher(); // Simulate another event from the server. - setup.window_tree_client()->OnEventObserved(ui::Event::Clone(*ui_event.get()), - event_observer_id); + std::unique_ptr<ui::PointerEvent> pointer_event_up(new ui::PointerEvent( + ui::ET_POINTER_UP, gfx::Point(), gfx::Point(), ui::EF_CONTROL_DOWN, 1, + ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH), + base::TimeTicks())); + setup.window_tree_client()->OnPointerEventObserved( + std::move(pointer_event_up), pointer_watcher_id); // No event was sensed. EXPECT_FALSE(setup.window_tree_delegate()->last_event_observed()); } -// Tests event observers triggered by events that hit this window tree. -TEST_F(WindowTreeClientTest, OnWindowInputEventWithEventObserver) { +// Tests pointer watchers triggered by events that hit this window tree. +TEST_F(WindowTreeClientTest, OnWindowInputEventWithPointerWatcher) { WindowTreeSetup setup; Window* root = setup.GetFirstRoot(); ASSERT_TRUE(root); - // Set up an event observer. - mojom::EventMatcherPtr matcher = mojom::EventMatcher::New(); - matcher->type_matcher = mojom::EventTypeMatcher::New(); - matcher->type_matcher->type = ui::mojom::EventType::POINTER_DOWN; - setup.client()->SetEventObserver(std::move(matcher)); + // Start a pointer watcher for all events excluding move events. + setup.client()->StartPointerWatcher(false /* want_moves */); // Simulate the server dispatching an event that also matched the observer. - uint32_t event_observer_id = setup.GetEventObserverId(); - std::unique_ptr<ui::Event> ui_event( - new ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), - ui::EventTimeForNow(), ui::EF_CONTROL_DOWN, 0)); + uint32_t pointer_watcher_id = setup.GetPointerWatcherId(); + std::unique_ptr<ui::PointerEvent> pointer_event_down(new ui::PointerEvent( + ui::ET_POINTER_DOWN, gfx::Point(), gfx::Point(), ui::EF_CONTROL_DOWN, 1, + ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH), + base::TimeTicks())); setup.window_tree_client()->OnWindowInputEvent( - 1, server_id(root), std::move(ui_event), event_observer_id); + 1, server_id(root), std::move(pointer_event_down), pointer_watcher_id); // Delegate sensed the event. ui::Event* last_event = setup.window_tree_delegate()->last_event_observed(); - EXPECT_EQ(ui::ET_MOUSE_PRESSED, last_event->type()); + EXPECT_EQ(ui::ET_POINTER_DOWN, last_event->type()); EXPECT_EQ(ui::EF_CONTROL_DOWN, last_event->flags()); } -// Tests that replacing an event observer with a new one results in only new -// events being observed. -TEST_F(WindowTreeClientTest, EventObserverReplaced) { +// Tests that replacing a pointer watcher with a new one that has different +// |want_moves| values results in only new events being observed. +TEST_F(WindowTreeClientTest, PointerWatcherReplaced) { WindowTreeSetup setup; Window* root = setup.GetFirstRoot(); ASSERT_TRUE(root); - // Set up an event observer. - mojom::EventMatcherPtr matcher1 = mojom::EventMatcher::New(); - matcher1->type_matcher = mojom::EventTypeMatcher::New(); - matcher1->type_matcher->type = ui::mojom::EventType::POINTER_DOWN; - setup.client()->SetEventObserver(std::move(matcher1)); - uint32_t event_observer_id1 = setup.GetEventObserverId(); + // Start a pointer watcher for all events excluding move events. + setup.client()->StartPointerWatcher(false /* want_moves */); + uint32_t pointer_watcher_id1 = setup.GetPointerWatcherId(); - // Replace it with a second observer. - mojom::EventMatcherPtr matcher2 = mojom::EventMatcher::New(); - matcher2->type_matcher = mojom::EventTypeMatcher::New(); - matcher2->type_matcher->type = ui::mojom::EventType::POINTER_UP; - setup.client()->SetEventObserver(std::move(matcher2)); - uint32_t event_observer_id2 = setup.GetEventObserverId(); + // Replace it with a second watcher that also watches for move events. + setup.client()->StartPointerWatcher(true /* want_moves */); + uint32_t pointer_watcher_id2 = setup.GetPointerWatcherId(); - // Simulate the server sending an observed event that matched the old observer + // Simulate the server sending an observed event that matched the old watcher // (e.g. that was in-flight when the observer was replaced). - std::unique_ptr<ui::Event> pressed_event( - new ui::MouseEvent(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), - ui::EventTimeForNow(), ui::EF_NONE, 0)); - setup.window_tree_client()->OnEventObserved(std::move(pressed_event), - event_observer_id1); + std::unique_ptr<ui::PointerEvent> pointer_event_down(new ui::PointerEvent( + ui::ET_POINTER_DOWN, gfx::Point(), gfx::Point(), ui::EF_CONTROL_DOWN, 1, + ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH), + base::TimeTicks())); + setup.window_tree_client()->OnPointerEventObserved( + std::move(pointer_event_down), pointer_watcher_id1); - // The event was not sensed, because it does not match the current observer. + // The event was not sensed, because it does not match the current watcher. EXPECT_FALSE(setup.window_tree_delegate()->last_event_observed()); - // Simulate another event that matches the new observer. - std::unique_ptr<ui::Event> released_event( - new ui::MouseEvent(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(), - ui::EventTimeForNow(), ui::EF_CONTROL_DOWN, 0)); - setup.window_tree_client()->OnEventObserved(std::move(released_event), - event_observer_id2); + // Simulate another event that matches the new watcher. + std::unique_ptr<ui::PointerEvent> pointer_event_move(new ui::PointerEvent( + ui::ET_POINTER_MOVED, gfx::Point(), gfx::Point(), ui::EF_CONTROL_DOWN, 1, + ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH), + base::TimeTicks())); + setup.window_tree_client()->OnPointerEventObserved( + std::move(pointer_event_move), pointer_watcher_id2); // The delegate sensed the event. ui::Event* last_event = setup.window_tree_delegate()->last_event_observed(); - EXPECT_EQ(ui::ET_MOUSE_RELEASED, last_event->type()); + EXPECT_EQ(ui::ET_POINTER_MOVED, last_event->type()); EXPECT_EQ(ui::EF_CONTROL_DOWN, last_event->flags()); }
diff --git a/services/ui/public/cpp/window_tree_client.cc b/services/ui/public/cpp/window_tree_client.cc index dea50b4..e500935 100644 --- a/services/ui/public/cpp/window_tree_client.cc +++ b/services/ui/public/cpp/window_tree_client.cc
@@ -626,15 +626,20 @@ static_cast<int16_t>(location & 0xFFFF)); } -void WindowTreeClient::SetEventObserver(mojom::EventMatcherPtr matcher) { - if (matcher.is_null()) { - has_event_observer_ = false; - tree_->SetEventObserver(nullptr, 0u); - } else { - has_event_observer_ = true; - event_observer_id_++; - tree_->SetEventObserver(std::move(matcher), event_observer_id_); - } +void WindowTreeClient::StartPointerWatcher(bool want_moves) { + if (has_pointer_watcher_) + StopPointerWatcher(); + has_pointer_watcher_ = true; + pointer_watcher_id_++; + if (pointer_watcher_id_ == 0) + pointer_watcher_id_++; + tree_->StartPointerWatcher(want_moves, pointer_watcher_id_); +} + +void WindowTreeClient::StopPointerWatcher() { + DCHECK(has_pointer_watcher_); + tree_->StopPointerWatcher(); + has_pointer_watcher_ = false; } void WindowTreeClient::PerformWindowMove( @@ -972,15 +977,17 @@ void WindowTreeClient::OnWindowInputEvent(uint32_t event_id, Id window_id, std::unique_ptr<ui::Event> event, - uint32_t event_observer_id) { + uint32_t pointer_watcher_id) { DCHECK(event); Window* window = GetWindowByServerId(window_id); // May be null. - // Non-zero event_observer_id means it matched an event observer on the + // Non-zero pointer_watcher_id means it matched a pointer watcher on the // server. - if (event_observer_id != 0 && has_event_observer_ && - event_observer_id == event_observer_id_) - delegate_->OnEventObserved(*event.get(), window); + if (pointer_watcher_id_ != 0 && has_pointer_watcher_ && + pointer_watcher_id == pointer_watcher_id_) { + DCHECK(event->IsPointerEvent()); + delegate_->OnPointerEventObserved(*event->AsPointerEvent(), window); + } if (!window || !window->input_event_handler_) { tree_->OnWindowInputEventAck(event_id, mojom::EventResult::UNHANDLED); @@ -1011,11 +1018,13 @@ ack_callback->Run(mojom::EventResult::UNHANDLED); } -void WindowTreeClient::OnEventObserved(std::unique_ptr<ui::Event> event, - uint32_t event_observer_id) { +void WindowTreeClient::OnPointerEventObserved(std::unique_ptr<ui::Event> event, + uint32_t pointer_watcher_id) { DCHECK(event); - if (has_event_observer_ && event_observer_id == event_observer_id_) - delegate_->OnEventObserved(*event.get(), nullptr /* target */); + DCHECK(event->IsPointerEvent()); + if (has_pointer_watcher_ && pointer_watcher_id == pointer_watcher_id_) + delegate_->OnPointerEventObserved(*event->AsPointerEvent(), + nullptr /* target */); } void WindowTreeClient::OnWindowFocused(Id focused_window_id) {
diff --git a/services/ui/public/cpp/window_tree_client.h b/services/ui/public/cpp/window_tree_client.h index 5f11f73..df1cf0b2 100644 --- a/services/ui/public/cpp/window_tree_client.h +++ b/services/ui/public/cpp/window_tree_client.h
@@ -178,10 +178,11 @@ // race the asynchronous initialization; but in that case we return (0, 0). gfx::Point GetCursorScreenPoint(); - // See description in window_tree.mojom. When an existing event observer is - // updated or cleared then any future events from the server for that observer + // See description in window_tree.mojom. When an existing pointer watcher is + // updated or cleared then any future events from the server for that watcher // will be ignored. - void SetEventObserver(mojom::EventMatcherPtr matcher); + void StartPointerWatcher(bool want_moves); + void StopPointerWatcher(); // Performs a window move. |callback| will be asynchronously called with the // whether the move loop completed successfully. @@ -309,9 +310,9 @@ void OnWindowInputEvent(uint32_t event_id, Id window_id, std::unique_ptr<ui::Event> event, - uint32_t event_observer_id) override; - void OnEventObserved(std::unique_ptr<ui::Event> event, - uint32_t event_observer_id) override; + uint32_t pointer_watcher_id) override; + void OnPointerEventObserved(std::unique_ptr<ui::Event> event, + uint32_t pointer_watcher_id) override; void OnWindowFocused(Id focused_window_id) override; void OnWindowPredefinedCursorChanged(Id window_id, mojom::Cursor cursor) override; @@ -414,10 +415,10 @@ window_manager_internal_; mojom::WindowManagerClientAssociatedPtr window_manager_internal_client_; - bool has_event_observer_ = false; + bool has_pointer_watcher_ = false; - // Monotonically increasing ID for event observers. - uint32_t event_observer_id_ = 0u; + // Monotonically increasing ID for pointer watchers. + uint32_t pointer_watcher_id_ = 0u; // The current change id for the client. uint32_t current_move_loop_change_ = 0u;
diff --git a/services/ui/public/cpp/window_tree_client_delegate.h b/services/ui/public/cpp/window_tree_client_delegate.h index d7ed4c3..3009e63 100644 --- a/services/ui/public/cpp/window_tree_client_delegate.h +++ b/services/ui/public/cpp/window_tree_client_delegate.h
@@ -40,9 +40,10 @@ virtual void OnDidDestroyClient(WindowTreeClient* client) = 0; // Called when the WindowTreeClient receives an input event observed via - // SetEventObserver(). |target| may be null for events that were sent to + // StartPointerWatcher(). |target| may be null for events that were sent to // windows owned by other processes. - virtual void OnEventObserved(const ui::Event& event, Window* target) = 0; + virtual void OnPointerEventObserved(const ui::PointerEvent& event, + Window* target) = 0; protected: virtual ~WindowTreeClientDelegate() {}
diff --git a/services/ui/public/interfaces/window_tree.mojom b/services/ui/public/interfaces/window_tree.mojom index 65416a8..14b49d1 100644 --- a/services/ui/public/interfaces/window_tree.mojom +++ b/services/ui/public/interfaces/window_tree.mojom
@@ -32,12 +32,12 @@ // // Event processing happens in the following order: // . The event is sent to the accelerator registered for the PRE_TARGET. If -// the client consumes the event, matching event observers are notified and +// the client consumes the event, matching pointer watchers are notified and // processing stops. If the client does not consume the event processing // continues. // . Target window (lookup of the target window depends upon the event type) and -// matching event observers are notified at the same time. The target is only -// notified once, even if it has a matching event observer registered. If the +// matching pointer watchers are notified at the same time. The target is only +// notified once, even if it has a matching pointer watcher registered. If the // target consumes the event, processing stops. // . Accelerator registered for POST_TARGET. No response is expected from the // client for the POST_TARGET and processing of the next continues @@ -80,15 +80,23 @@ // if |window_id| does not currently have capture. ReleaseCapture(uint32 change_id, uint32 window_id); - // Sets an observer that monitors all events, even if they are not targeted - // at a window in this tree. If an event matchs |matcher| the observer reports - // it to the WindowTreeClient via OnWindowInputEvent (if the event target is - // this window tree) or OnEventObserved (if the target is another tree). The - // client must supply a non-zero |observer_id|, which is reported back with - // observed events. Set the matcher to null to clear the observer. + // Starts the pointer watcher that monitors pointer events (up/down events if + // |wants_moves| is false, up/down and move if |wants_moves| is true), even if + // they are not targeted at a window in this tree. For pointer events that + // would normally be sent to the requesting client (if the event target is + // this window tree) OnWindowInputEvent() is called, all other matching + // pointer events (if the target is another tree) result in + // OnPointerEventObserved(). The client must supply a non-zero + // |pointer_watcher_id|, which is reported back with matched events. There is + // only ever one pointer watcher active at a given time. The client should + // prefer |want_moves| to be false, as there's a system-wide performance/ + // battery penalty for listening to moves. // // See class description for details on event delivery. - SetEventObserver(EventMatcher? matcher, uint32 observer_id); + StartPointerWatcher(bool want_moves, uint32 pointer_watcher_id); + + // Stops the pointer watcher for all events. + StopPointerWatcher(); // Sets the specified bounds of the specified window. SetWindowBounds(uint32 change_id, uint32 window_id, gfx.mojom.Rect bounds); @@ -366,18 +374,21 @@ // Invoked when an event is targeted at the specified window. The client must // call WindowTree::OnWindowInputEventAck() with the same |event_id| to notify // that the event has been processed, and with an EventResult value to notify - // if the event was consumed. |event_observer_id| is non-zero if the event - // also matched the active event observer for this client. The client will not - // receive farther events until the event is ack'ed. + // if the event was consumed. |pointer_watcher_id| is the id supplied to + // StartPointerWatcher() if the event is a pointer event and the client called + // StartPointerWatcher(). The client will not receive farther events until the + // event is ack'ed. OnWindowInputEvent(uint32 event_id, uint32 window, ui.mojom.Event event, - uint32 event_observer_id); + uint32 pointer_watcher_id); - // Invoked when an |event| is sent via the EventObserver and not targeted at a - // specific window. The |event_observer_id| is the one supplied to - // SetEventObserver. The client should not acknowledge these events. - OnEventObserved(ui.mojom.Event event, uint32 event_observer_id); + // Called when a pointer event that would not normally be targeted at this + // client is encountered and the client called StartPointerWatcher(). The + // |pointer_watcher_id| is the one supplied to StartPointerWatcher(). See + // StartPointerWatcher() for details.The client should not acknowledge these + // events. + OnPointerEventObserved(ui.mojom.Event event, uint32 pointer_watcher_id); // Called in two distinct cases: when a window known to the connection gains // focus, or when focus moves from a window known to the connection to a
diff --git a/services/ui/service.cc b/services/ui/service.cc index 01a74eb..26ad603 100644 --- a/services/ui/service.cc +++ b/services/ui/service.cc
@@ -22,6 +22,8 @@ #include "services/ui/display/platform_screen.h" #include "services/ui/gpu/gpu_service_impl.h" #include "services/ui/gpu/gpu_service_mus.h" +#include "services/ui/ime/ime_registrar_impl.h" +#include "services/ui/ime/ime_server_impl.h" #include "services/ui/ws/accessibility_manager.h" #include "services/ui/ws/display.h" #include "services/ui/ws/display_binding.h" @@ -80,8 +82,8 @@ Service::Service() : test_config_(false), platform_screen_(display::PlatformScreen::Create()), - weak_ptr_factory_(this) { -} + ime_registrar_(&ime_server_), + weak_ptr_factory_(this) {} Service::~Service() { // Destroy |window_server_| first, since it depends on |event_source_|. @@ -200,6 +202,8 @@ registry->AddInterface<mojom::Clipboard>(this); registry->AddInterface<mojom::DisplayManager>(this); registry->AddInterface<mojom::GpuService>(this); + registry->AddInterface<mojom::IMERegistrar>(this); + registry->AddInterface<mojom::IMEServer>(this); registry->AddInterface<mojom::UserAccessManager>(this); registry->AddInterface<mojom::UserActivityMonitor>(this); registry->AddInterface<WindowTreeHostFactory>(this); @@ -287,6 +291,16 @@ } void Service::Create(const shell::Identity& remote_identity, + mojom::IMERegistrarRequest request) { + ime_registrar_.AddBinding(std::move(request)); +} + +void Service::Create(const shell::Identity& remote_identity, + mojom::IMEServerRequest request) { + ime_server_.AddBinding(std::move(request)); +} + +void Service::Create(const shell::Identity& remote_identity, mojom::UserAccessManagerRequest request) { window_server_->user_id_tracker()->Bind(std::move(request)); }
diff --git a/services/ui/service.h b/services/ui/service.h index 0f6dbc3..9006748 100644 --- a/services/ui/service.h +++ b/services/ui/service.h
@@ -18,12 +18,15 @@ #include "services/shell/public/cpp/service.h" #include "services/shell/public/cpp/service_runner.h" #include "services/tracing/public/cpp/provider.h" +#include "services/ui/ime/ime_registrar_impl.h" +#include "services/ui/ime/ime_server_impl.h" #include "services/ui/input_devices/input_device_server.h" #include "services/ui/public/interfaces/accessibility_manager.mojom.h" #include "services/ui/public/interfaces/clipboard.mojom.h" #include "services/ui/public/interfaces/display.mojom.h" #include "services/ui/public/interfaces/gpu.mojom.h" #include "services/ui/public/interfaces/gpu_service.mojom.h" +#include "services/ui/public/interfaces/ime.mojom.h" #include "services/ui/public/interfaces/user_access_manager.mojom.h" #include "services/ui/public/interfaces/user_activity_monitor.mojom.h" #include "services/ui/public/interfaces/window_manager_window_tree_factory.mojom.h" @@ -67,6 +70,8 @@ public shell::InterfaceFactory<mojom::Clipboard>, public shell::InterfaceFactory<mojom::DisplayManager>, public shell::InterfaceFactory<mojom::GpuService>, + public shell::InterfaceFactory<mojom::IMERegistrar>, + public shell::InterfaceFactory<mojom::IMEServer>, public shell::InterfaceFactory<mojom::UserAccessManager>, public shell::InterfaceFactory<mojom::UserActivityMonitor>, public shell::InterfaceFactory<mojom::WindowManagerWindowTreeFactory>, @@ -122,6 +127,14 @@ void Create(const shell::Identity& remote_identity, mojom::GpuServiceRequest request) override; + // shell::InterfaceFactory<mojom::IMERegistrar> implementation. + void Create(const shell::Identity& remote_identity, + mojom::IMERegistrarRequest request) override; + + // shell::InterfaceFactory<mojom::IMEServer> implementation. + void Create(const shell::Identity& remote_identity, + mojom::IMEServerRequest request) override; + // shell::InterfaceFactory<mojom::UserAccessManager> implementation. void Create(const shell::Identity& remote_identity, mojom::UserAccessManagerRequest request) override; @@ -172,6 +185,8 @@ std::unique_ptr<display::PlatformScreen> platform_screen_; std::unique_ptr<ws::TouchController> touch_controller_; + IMERegistrarImpl ime_registrar_; + IMEServerImpl ime_server_; base::WeakPtrFactory<Service> weak_ptr_factory_;
diff --git a/services/ui/surfaces/BUILD.gn b/services/ui/surfaces/BUILD.gn index 31a22a2..1de4c77 100644 --- a/services/ui/surfaces/BUILD.gn +++ b/services/ui/surfaces/BUILD.gn
@@ -33,6 +33,7 @@ "//services/ui/common:mus_common", "//services/ui/gpu", "//services/ui/public/interfaces", + "//ui/display/types", "//ui/gfx", "//ui/gfx/geometry/mojo", "//ui/gl",
diff --git a/services/ui/surfaces/DEPS b/services/ui/surfaces/DEPS index e21114e..5735aed8 100644 --- a/services/ui/surfaces/DEPS +++ b/services/ui/surfaces/DEPS
@@ -7,4 +7,5 @@ "+mojo/common", "+mojo/converters", "+mojo/public", + "+ui/display/types", ]
diff --git a/services/ui/surfaces/direct_output_surface_ozone.cc b/services/ui/surfaces/direct_output_surface_ozone.cc index 38bf776..50cd34be 100644 --- a/services/ui/surfaces/direct_output_surface_ozone.cc +++ b/services/ui/surfaces/direct_output_surface_ozone.cc
@@ -19,6 +19,7 @@ #include "services/ui/common/mojo_gpu_memory_buffer_manager.h" #include "services/ui/gpu/mus_gpu_memory_buffer_manager.h" #include "services/ui/surfaces/surfaces_context_provider.h" +#include "ui/display/types/display_snapshot.h" using display_compositor::BufferQueue; @@ -35,9 +36,10 @@ context_provider->ContextSupport()), synthetic_begin_frame_source_(synthetic_begin_frame_source), weak_ptr_factory_(this) { - buffer_queue_.reset(new BufferQueue( - context_provider->ContextGL(), target, internalformat, &gl_helper_, - MusGpuMemoryBufferManager::current(), widget)); + buffer_queue_.reset( + new BufferQueue(context_provider->ContextGL(), target, internalformat, + ui::DisplaySnapshot::PrimaryFormat(), &gl_helper_, + MusGpuMemoryBufferManager::current(), widget)); capabilities_.uses_default_gl_framebuffer = false; capabilities_.flipped_output_surface = true;
diff --git a/services/ui/test_ime/BUILD.gn b/services/ui/test_ime/BUILD.gn deleted file mode 100644 index 0ee3383b..0000000 --- a/services/ui/test_ime/BUILD.gn +++ /dev/null
@@ -1,67 +0,0 @@ -# Copyright 2016 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import("//services/shell/public/cpp/service.gni") -import("//services/shell/public/service_manifest.gni") -import("//testing/test.gni") - -service("test_ime") { - sources = [ - "main.cc", - "test_ime_driver.cc", - "test_ime_driver.h", - ] - - deps = [ - "//base", - "//services/shell/public/cpp", - "//services/ui/public/cpp", - "//services/ui/public/interfaces", - "//ui/gfx/geometry/mojo", - ] - - data_deps = [ - ":manifest", - "//services/ui", - ] -} - -group("tests") { - testonly = true - deps = [ - ":test_ime_unittests", - ] -} - -test("test_ime_unittests") { - sources = [ - "test_ime_unittest.cc", - ] - - deps = [ - "//base", - "//mojo/common", - "//services/shell/public/cpp:service_test_support", - "//services/shell/public/cpp:sources", - "//services/shell/public/cpp/test:run_all_shelltests", - "//services/ui/public/interfaces", - ] - - data_deps = [ - ":test_ime", - ":test_manifest", - "//services/ui", - ] -} - -service_manifest("manifest") { - name = "test_ime" - source = "manifest.json" -} - -service_manifest("test_manifest") { - type = "exe" - name = "test_ime_unittests" - source = "test_manifest.json" -}
diff --git a/services/ui/test_ime/main.cc b/services/ui/test_ime/main.cc deleted file mode 100644 index db1f1a4..0000000 --- a/services/ui/test_ime/main.cc +++ /dev/null
@@ -1,46 +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 "services/shell/public/c/main.h" -#include "services/shell/public/cpp/connector.h" -#include "services/shell/public/cpp/service.h" -#include "services/shell/public/cpp/service_runner.h" -#include "services/ui/test_ime/test_ime_driver.h" - -namespace ui { -namespace test { - -class TestIME : public shell::Service, - public shell::InterfaceFactory<mojom::IMEDriver> { - public: - TestIME() {} - ~TestIME() override {} - - private: - // shell::Service: - void OnStart(const shell::Identity& identity) override {} - bool OnConnect(const shell::Identity& remote_identity, - shell::InterfaceRegistry* registry) override { - registry->AddInterface<mojom::IMEDriver>(this); - return true; - } - - // shell::InterfaceFactory<mojom::IMEDriver>: - void Create(const shell::Identity& remote_identity, - mojom::IMEDriverRequest request) override { - ime_driver_.reset(new TestIMEDriver(std::move(request))); - } - - std::unique_ptr<TestIMEDriver> ime_driver_; - - DISALLOW_COPY_AND_ASSIGN(TestIME); -}; - -} // namespace test -} // namespace ui - -MojoResult ServiceMain(MojoHandle service_request_handle) { - shell::ServiceRunner runner(new ui::test::TestIME); - return runner.Run(service_request_handle); -}
diff --git a/services/ui/test_ime/manifest.json b/services/ui/test_ime/manifest.json deleted file mode 100644 index 5d6efb7..0000000 --- a/services/ui/test_ime/manifest.json +++ /dev/null
@@ -1,10 +0,0 @@ -{ - "manifest_version": 1, - "name": "mojo:test_ime", - "display_name": "Test IME Driver", - "capabilities": { - "provided": { - "app": [ "ui::mojom::IMEDriver" ] - } - } -}
diff --git a/services/ui/test_ime/test_ime_driver.cc b/services/ui/test_ime/test_ime_driver.cc deleted file mode 100644 index 1c3dd11..0000000 --- a/services/ui/test_ime/test_ime_driver.cc +++ /dev/null
@@ -1,57 +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 "services/ui/test_ime/test_ime_driver.h" - -namespace ui { -namespace test { - -class TestInputMethod : public mojom::InputMethod { - public: - explicit TestInputMethod(mojom::TextInputClientPtr client) - : client_(std::move(client)) {} - ~TestInputMethod() override {} - - private: - // mojom::InputMethod: - void OnTextInputModeChanged(mojom::TextInputMode text_input_mode) override {} - void OnTextInputTypeChanged(mojom::TextInputType text_input_type) override {} - void OnCaretBoundsChanged(const gfx::Rect& caret_bounds) override {} - void ProcessKeyEvent(std::unique_ptr<Event> key_event) override { - DCHECK(key_event->IsKeyEvent()); - mojom::CompositionEventPtr composition_event = - mojom::CompositionEvent::New(); - composition_event->type = mojom::CompositionEventType::INSERT_CHAR; - composition_event->key_event = std::move(key_event); - - client_->OnCompositionEvent(std::move(composition_event)); - }; - void CancelComposition() override {} - - mojom::TextInputClientPtr client_; - - DISALLOW_COPY_AND_ASSIGN(TestInputMethod); -}; - -TestIMEDriver::TestIMEDriver(mojom::IMEDriverRequest request) - : driver_binding_(this, std::move(request)) {} - -TestIMEDriver::~TestIMEDriver() {} - -void TestIMEDriver::StartSession( - int32_t session_id, - mojom::TextInputClientPtr client, - mojom::InputMethodRequest input_method_request) { - input_method_bindings_[session_id].reset( - new mojo::Binding<mojom::InputMethod>( - new TestInputMethod(std::move(client)), - std::move(input_method_request))); -} - -void TestIMEDriver::CancelSession(int32_t session_id) { - input_method_bindings_.erase(session_id); -} - -} // namespace test -} // namespace ui
diff --git a/services/ui/test_ime/test_ime_driver.h b/services/ui/test_ime/test_ime_driver.h deleted file mode 100644 index 8ec96d56..0000000 --- a/services/ui/test_ime/test_ime_driver.h +++ /dev/null
@@ -1,39 +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 SERVICES_UI_TEST_IME_TEST_IME_DRIVER_H_ -#define SERVICES_UI_TEST_IME_TEST_IME_DRIVER_H_ - -#include <map> - -#include "mojo/public/cpp/bindings/binding.h" -#include "services/ui/public/interfaces/ime.mojom.h" - -namespace ui { -namespace test { - -class TestIMEDriver : public ui::mojom::IMEDriver { - public: - explicit TestIMEDriver(mojom::IMEDriverRequest request); - ~TestIMEDriver() override; - - private: - // ui::mojom::IMEDriver: - void StartSession( - int32_t session_id, - ui::mojom::TextInputClientPtr client, - ui::mojom::InputMethodRequest input_method_request) override; - void CancelSession(int32_t session_id) override; - - mojo::Binding<mojom::IMEDriver> driver_binding_; - std::map<int32_t, std::unique_ptr<mojo::Binding<mojom::InputMethod>>> - input_method_bindings_; - - DISALLOW_COPY_AND_ASSIGN(TestIMEDriver); -}; - -} // namespace test -} // namespace ui - -#endif // SERVICES_UI_TEST_IME_TEST_IME_DRIVER_H_
diff --git a/services/ui/test_ime/test_ime_unittest.cc b/services/ui/test_ime/test_ime_unittest.cc deleted file mode 100644 index 75c6a4c..0000000 --- a/services/ui/test_ime/test_ime_unittest.cc +++ /dev/null
@@ -1,107 +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 <stdint.h> - -#include <utility> - -#include "base/bind.h" -#include "base/macros.h" -#include "base/run_loop.h" -#include "mojo/common/common_type_converters.h" -#include "mojo/public/cpp/bindings/interface_request.h" -#include "services/shell/public/cpp/service_context.h" -#include "services/shell/public/cpp/service_test.h" -#include "services/ui/public/interfaces/ime.mojom.h" -#include "ui/events/event.h" - -class TestTextInputClient : public ui::mojom::TextInputClient { - public: - explicit TestTextInputClient(ui::mojom::TextInputClientRequest request) - : binding_(this, std::move(request)) {} - - ui::mojom::CompositionEventPtr ReceiveCompositionEvent() { - run_loop_.reset(new base::RunLoop); - run_loop_->Run(); - run_loop_.reset(); - - return std::move(receieved_composition_event_); - } - - private: - void OnCompositionEvent(ui::mojom::CompositionEventPtr event) override { - receieved_composition_event_ = std::move(event); - run_loop_->Quit(); - } - - mojo::Binding<ui::mojom::TextInputClient> binding_; - std::unique_ptr<base::RunLoop> run_loop_; - ui::mojom::CompositionEventPtr receieved_composition_event_; - - DISALLOW_COPY_AND_ASSIGN(TestTextInputClient); -}; - -class IMEAppTest : public shell::test::ServiceTest { - public: - IMEAppTest() : ServiceTest("exe:test_ime_unittests") {} - ~IMEAppTest() override {} - - // shell::test::ServiceTest: - void SetUp() override { - ServiceTest::SetUp(); - connector()->ConnectToInterface("mojo:test_ime", &ime_driver_); - ASSERT_TRUE(ime_driver_); - } - - protected: - ui::mojom::IMEDriverPtr ime_driver_; - - DISALLOW_COPY_AND_ASSIGN(IMEAppTest); -}; - -// Test that calling InputMethod::ProcessKeyEvent() after cancelling the session -// encounters an error. -TEST_F(IMEAppTest, TestCancelSession) { - ui::mojom::TextInputClientPtr client_ptr; - TestTextInputClient client(GetProxy(&client_ptr)); - - ui::mojom::InputMethodPtr input_method; - ime_driver_->StartSession(1, std::move(client_ptr), GetProxy(&input_method)); - ASSERT_TRUE(input_method.is_bound()); - - ime_driver_->CancelSession(1); - - base::RunLoop run_loop; - input_method.set_connection_error_handler(run_loop.QuitClosure()); - input_method->ProcessKeyEvent(std::unique_ptr<ui::KeyEvent>( - new ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_RETURN, 0))); - run_loop.Run(); - - ASSERT_TRUE(input_method.encountered_error()); -} - -TEST_F(IMEAppTest, TestProcessKeyEvent) { - ui::mojom::TextInputClientPtr client_ptr; - TestTextInputClient client(GetProxy(&client_ptr)); - - ui::mojom::InputMethodPtr input_method; - ime_driver_->StartSession(1, std::move(client_ptr), GetProxy(&input_method)); - ASSERT_TRUE(input_method.is_bound()); - - ui::KeyEvent key_event(ui::ET_KEY_PRESSED, ui::VKEY_A, 0); - - input_method->ProcessKeyEvent(ui::Event::Clone(key_event)); - - ui::mojom::CompositionEventPtr composition_event = - client.ReceiveCompositionEvent(); - ASSERT_EQ(ui::mojom::CompositionEventType::INSERT_CHAR, - composition_event->type); - ASSERT_TRUE(composition_event->key_event); - ASSERT_TRUE(composition_event->key_event.value()->IsKeyEvent()); - - ui::KeyEvent* received_key_event = - composition_event->key_event.value()->AsKeyEvent(); - ASSERT_EQ(ui::ET_KEY_PRESSED, received_key_event->type()); - ASSERT_EQ(key_event.GetCharacter(), received_key_event->GetCharacter()); -}
diff --git a/services/ui/test_ime/test_manifest.json b/services/ui/test_ime/test_manifest.json deleted file mode 100644 index 9ce863775..0000000 --- a/services/ui/test_ime/test_manifest.json +++ /dev/null
@@ -1,10 +0,0 @@ -{ - "manifest_version": 1, - "name": "exe:test_ime_unittests", - "display_name": "IME Service Unittests", - "capabilities": { - "required": { - "*": { "interfaces": [ "ui::mojom::IMEDriver" ] } - } - } -}
diff --git a/services/ui/test_wm/test_wm.cc b/services/ui/test_wm/test_wm.cc index 69fc00f7..3c9d786 100644 --- a/services/ui/test_wm/test_wm.cc +++ b/services/ui/test_wm/test_wm.cc
@@ -41,7 +41,8 @@ void OnDidDestroyClient(ui::WindowTreeClient* client) override { window_tree_client_ = nullptr; } - void OnEventObserved(const ui::Event& event, ui::Window* target) override { + void OnPointerEventObserved(const ui::PointerEvent& event, + ui::Window* target) override { // Don't care. }
diff --git a/services/ui/ws/test_change_tracker.cc b/services/ui/ws/test_change_tracker.cc index 438069e..3ad10d5 100644 --- a/services/ui/ws/test_change_tracker.cc +++ b/services/ui/ws/test_change_tracker.cc
@@ -103,16 +103,16 @@ std::string result = base::StringPrintf( "InputEvent window=%s event_action=%d", WindowIdToString(change.window_id).c_str(), change.event_action); - if (change.event_observer_id != 0) - base::StringAppendF(&result, " event_observer_id=%u", - change.event_observer_id); + if (change.pointer_watcher_id != 0) + base::StringAppendF(&result, " pointer_watcher_id=%u", + change.pointer_watcher_id); return result; } - case CHANGE_TYPE_EVENT_OBSERVED: + case CHANGE_TYPE_POINTER_WATCHER_EVENT: return base::StringPrintf( - "EventObserved event_action=%d event_observer_id=%u", - change.event_action, change.event_observer_id); + "PointerWatcherEvent event_action=%d pointer_watcher_id=%u", + change.event_action, change.pointer_watcher_id); case CHANGE_TYPE_PROPERTY_CHANGED: return base::StringPrintf("PropertyChanged window=%s key=%s value=%s", @@ -216,7 +216,7 @@ window_id2(0), window_id3(0), event_action(0), - event_observer_id(0u), + pointer_watcher_id(0u), direction(mojom::OrderDirection::ABOVE), bool_value(false), float_value(0.f), @@ -351,21 +351,21 @@ void TestChangeTracker::OnWindowInputEvent(Id window_id, const ui::Event& event, - uint32_t event_observer_id) { + uint32_t pointer_watcher_id) { Change change; change.type = CHANGE_TYPE_INPUT_EVENT; change.window_id = window_id; change.event_action = static_cast<int32_t>(event.type()); - change.event_observer_id = event_observer_id; + change.pointer_watcher_id = pointer_watcher_id; AddChange(change); } -void TestChangeTracker::OnEventObserved(const ui::Event& event, - uint32_t event_observer_id) { +void TestChangeTracker::OnPointerEventObserved(const ui::Event& event, + uint32_t pointer_watcher_id) { Change change; - change.type = CHANGE_TYPE_EVENT_OBSERVED; + change.type = CHANGE_TYPE_POINTER_WATCHER_EVENT; change.event_action = static_cast<int32_t>(event.type()); - change.event_observer_id = event_observer_id; + change.pointer_watcher_id = pointer_watcher_id; AddChange(change); }
diff --git a/services/ui/ws/test_change_tracker.h b/services/ui/ws/test_change_tracker.h index 6fa8611..b7a63ebc 100644 --- a/services/ui/ws/test_change_tracker.h +++ b/services/ui/ws/test_change_tracker.h
@@ -35,7 +35,7 @@ CHANGE_TYPE_NODE_DRAWN_STATE_CHANGED, CHANGE_TYPE_NODE_DELETED, CHANGE_TYPE_INPUT_EVENT, - CHANGE_TYPE_EVENT_OBSERVED, + CHANGE_TYPE_POINTER_WATCHER_EVENT, CHANGE_TYPE_PROPERTY_CHANGED, CHANGE_TYPE_FOCUSED, CHANGE_TYPE_CURSOR_CHANGED, @@ -78,7 +78,7 @@ gfx::Rect bounds; gfx::Rect bounds2; int32_t event_action; - uint32_t event_observer_id; + uint32_t pointer_watcher_id; mojo::String embed_url; mojom::OrderDirection direction; bool bool_value; @@ -157,8 +157,9 @@ void OnWindowParentDrawnStateChanged(Id window_id, bool drawn); void OnWindowInputEvent(Id window_id, const ui::Event& event, - uint32_t event_observer_id); - void OnEventObserved(const ui::Event& event, uint32_t event_observer_id); + uint32_t pointer_watcher_id); + void OnPointerEventObserved(const ui::Event& event, + uint32_t pointer_watcher_id); void OnWindowSharedPropertyChanged(Id window_id, mojo::String name, mojo::Array<uint8_t> data);
diff --git a/services/ui/ws/test_utils.cc b/services/ui/ws/test_utils.cc index e0f83d9..7387a8d 100644 --- a/services/ui/ws/test_utils.cc +++ b/services/ui/ws/test_utils.cc
@@ -139,9 +139,13 @@ WindowTreeTestApi::WindowTreeTestApi(WindowTree* tree) : tree_(tree) {} WindowTreeTestApi::~WindowTreeTestApi() {} -void WindowTreeTestApi::SetEventObserver(mojom::EventMatcherPtr matcher, - uint32_t event_observer_id) { - tree_->SetEventObserver(std::move(matcher), event_observer_id); +void WindowTreeTestApi::StartPointerWatcher(bool want_moves, + uint32_t pointer_watcher_id) { + tree_->StartPointerWatcher(want_moves, pointer_watcher_id); +} + +void WindowTreeTestApi::StopPointerWatcher() { + tree_->StopPointerWatcher(); } // DisplayTestApi ------------------------------------------------------------ @@ -316,9 +320,10 @@ tracker_.OnWindowInputEvent(window, *event.get(), event_observer_id); } -void TestWindowTreeClient::OnEventObserved(std::unique_ptr<ui::Event> event, - uint32_t event_observer_id) { - tracker_.OnEventObserved(*event.get(), event_observer_id); +void TestWindowTreeClient::OnPointerEventObserved( + std::unique_ptr<ui::Event> event, + uint32_t event_observer_id) { + tracker_.OnPointerEventObserved(*event.get(), event_observer_id); } void TestWindowTreeClient::OnWindowFocused(uint32_t focused_window_id) {
diff --git a/services/ui/ws/test_utils.h b/services/ui/ws/test_utils.h index 5a889f87..b7dd8fa 100644 --- a/services/ui/ws/test_utils.h +++ b/services/ui/ws/test_utils.h
@@ -110,8 +110,8 @@ tree_->OnAcceleratorAck(tree_->event_ack_id_, result); } - void SetEventObserver(mojom::EventMatcherPtr matcher, - uint32_t event_observer_id); + void StartPointerWatcher(bool want_moves, uint32_t pointer_watcher_id); + void StopPointerWatcher(); private: WindowTree* tree_; @@ -402,8 +402,8 @@ uint32_t window, std::unique_ptr<ui::Event> event, uint32_t event_observer_id) override; - void OnEventObserved(std::unique_ptr<ui::Event> event, - uint32_t event_observer_id) override; + void OnPointerEventObserved(std::unique_ptr<ui::Event> event, + uint32_t event_observer_id) override; void OnWindowFocused(uint32_t focused_window_id) override; void OnWindowPredefinedCursorChanged(uint32_t window_id, mojom::Cursor cursor_id) override;
diff --git a/services/ui/ws/window_manager_state.cc b/services/ui/ws/window_manager_state.cc index 0765821..943d3c23 100644 --- a/services/ui/ws/window_manager_state.cc +++ b/services/ui/ws/window_manager_state.cc
@@ -241,7 +241,7 @@ } else { // We're not going to process the event any further, notify event observers. // We don't do this first to ensure we don't send an event twice to clients. - window_server()->SendToEventObservers(*event, user_id(), nullptr); + window_server()->SendToPointerWatchers(*event, user_id(), nullptr); ProcessNextEventFromQueue(); } } @@ -359,7 +359,7 @@ } // Ignore |tree| because it will receive the event via normal dispatch. - window_server()->SendToEventObservers(event, user_id(), tree); + window_server()->SendToPointerWatchers(event, user_id(), tree); tree->DispatchInputEvent(target, event); } @@ -535,8 +535,8 @@ } void WindowManagerState::OnEventTargetNotFound(const ui::Event& event) { - window_server()->SendToEventObservers(event, user_id(), - nullptr /* ignore_tree */); + window_server()->SendToPointerWatchers(event, user_id(), + nullptr /* ignore_tree */); } } // namespace ws
diff --git a/services/ui/ws/window_server.cc b/services/ui/ws/window_server.cc index 8403378..29b3b55 100644 --- a/services/ui/ws/window_server.cc +++ b/services/ui/ws/window_server.cc
@@ -426,13 +426,13 @@ } } -void WindowServer::SendToEventObservers(const ui::Event& event, - const UserId& user_id, - WindowTree* ignore_tree) { +void WindowServer::SendToPointerWatchers(const ui::Event& event, + const UserId& user_id, + WindowTree* ignore_tree) { for (auto& pair : tree_map_) { WindowTree* tree = pair.second.get(); if (tree->user_id() == user_id && tree != ignore_tree) - tree->SendToEventObserver(event); + tree->SendToPointerWatcher(event); } }
diff --git a/services/ui/ws/window_server.h b/services/ui/ws/window_server.h index 1ff4e3b..9650e7dd 100644 --- a/services/ui/ws/window_server.h +++ b/services/ui/ws/window_server.h
@@ -194,9 +194,9 @@ // Sends an |event| to all WindowTrees belonging to |user_id| that might be // observing events. Skips |ignore_tree| if it is non-null. - void SendToEventObservers(const ui::Event& event, - const UserId& user_id, - WindowTree* ignore_tree); + void SendToPointerWatchers(const ui::Event& event, + const UserId& user_id, + WindowTree* ignore_tree); // Sets a callback to be called whenever a ServerWindow is scheduled for // a [re]paint. This should only be called in a test configuration.
diff --git a/services/ui/ws/window_tree.cc b/services/ui/ws/window_tree.cc index e87c9c1..ea1f29e 100644 --- a/services/ui/ws/window_tree.cc +++ b/services/ui/ws/window_tree.cc
@@ -455,7 +455,9 @@ void WindowTree::ClientJankinessChanged(WindowTree* tree) { tree->janky_ = !tree->janky_; - if (window_manager_internal_) { + // Don't inform the client if it is the source of jank (which generally only + // happens while debugging). + if (window_manager_internal_ && tree != this) { window_manager_internal_->WmClientJankinessChanged( tree->id(), tree->janky()); } @@ -703,6 +705,12 @@ transient_client_window_id.id); } +void WindowTree::SendToPointerWatcher(const ui::Event& event) { + if (EventMatchesPointerWatcher(event)) + client()->OnPointerEventObserved(ui::Event::Clone(event), + pointer_watcher_id_); +} + bool WindowTree::ShouldRouteToWindowManager(const ServerWindow* window) const { if (window_manager_state_) return false; // We are the window manager, don't route to ourself. @@ -990,16 +998,22 @@ event_source_wms_ = display_root->window_manager_state(); // Should only get events from windows attached to a host. DCHECK(event_source_wms_); - bool matched_observer = - event_observer_matcher_ && event_observer_matcher_->MatchesEvent(event); + bool matched_pointer_watcher = EventMatchesPointerWatcher(event); client()->OnWindowInputEvent( event_ack_id_, ClientWindowIdForWindow(target).id, - ui::Event::Clone(event), matched_observer ? event_observer_id_ : 0); + ui::Event::Clone(event), + matched_pointer_watcher ? pointer_watcher_id_ : 0); } -void WindowTree::SendToEventObserver(const ui::Event& event) { - if (event_observer_matcher_ && event_observer_matcher_->MatchesEvent(event)) - client()->OnEventObserved(ui::Event::Clone(event), event_observer_id_); +bool WindowTree::EventMatchesPointerWatcher(const ui::Event& event) const { + if (pointer_watcher_id_ == 0) + return false; + if (!event.IsPointerEvent()) + return false; + if (pointer_watcher_want_moves_ && event.type() == ui::ET_POINTER_MOVED) + return true; + return event.type() == ui::ET_POINTER_DOWN || + event.type() == ui::ET_POINTER_UP; } void WindowTree::NewWindow( @@ -1165,50 +1179,20 @@ client()->OnChangeCompleted(change_id, success); } -void WindowTree::SetEventObserver(mojom::EventMatcherPtr matcher, - uint32_t observer_id) { - if (matcher.is_null() || observer_id == 0) { - // Clear any existing event observer. - event_observer_matcher_.reset(); - event_observer_id_ = 0; +void WindowTree::StartPointerWatcher(bool want_moves, + uint32_t pointer_watcher_id) { + if (pointer_watcher_id == 0) { + DVLOG(1) << "StartPointerWatcher called with 0."; + StopPointerWatcher(); return; } + pointer_watcher_want_moves_ = want_moves; + pointer_watcher_id_ = pointer_watcher_id; +} - // Do not allow key events to be observed, as a compromised app could register - // itself as an event observer and spy on keystrokes to another app. - if (!matcher->type_matcher && !matcher->pointer_kind_matcher) { - DVLOG(1) << "SetEventObserver must specify an event type."; - return; - } - - const ui::mojom::EventType event_type_whitelist[] = { - ui::mojom::EventType::POINTER_CANCEL, ui::mojom::EventType::POINTER_DOWN, - ui::mojom::EventType::POINTER_MOVE, ui::mojom::EventType::POINTER_UP, - ui::mojom::EventType::MOUSE_EXIT, ui::mojom::EventType::WHEEL, - }; - - if (matcher->type_matcher) { - auto* iter = - std::find(std::begin(event_type_whitelist), - std::end(event_type_whitelist), matcher->type_matcher->type); - if (iter == std::end(event_type_whitelist)) { - DVLOG(1) << "SetEventObserver event type not allowed"; - return; - } - } - if (matcher->pointer_kind_matcher) { - ui::mojom::PointerKind pointer_kind = - matcher->pointer_kind_matcher->pointer_kind; - if (pointer_kind != ui::mojom::PointerKind::MOUSE && - pointer_kind != ui::mojom::PointerKind::TOUCH && - pointer_kind != ui::mojom::PointerKind::PEN) { - DVLOG(1) << "SetEventObserver pointer kind not allowed"; - return; - } - } - - event_observer_matcher_.reset(new EventMatcher(*matcher)); - event_observer_id_ = observer_id; +void WindowTree::StopPointerWatcher() { + pointer_watcher_want_moves_ = false; + pointer_watcher_id_ = 0; } void WindowTree::SetWindowBounds(uint32_t change_id,
diff --git a/services/ui/ws/window_tree.h b/services/ui/ws/window_tree.h index fd404f0..55c1b9a 100644 --- a/services/ui/ws/window_tree.h +++ b/services/ui/ws/window_tree.h
@@ -241,8 +241,8 @@ const ServerWindow* transient_window, bool originated_change); - // Sends this event to the client if it matches an active event observer. - void SendToEventObserver(const ui::Event& event); + // Sends this event to the client if it matches an active pointer watcher. + void SendToPointerWatcher(const ui::Event& event); private: friend class test::WindowTreeTestApi; @@ -337,6 +337,9 @@ void DispatchInputEventImpl(ServerWindow* target, const ui::Event& event); + // Returns true if the client has a pointer watcher and this event matches. + bool EventMatchesPointerWatcher(const ui::Event& event) const; + // Calls OnChangeCompleted() on the client. void NotifyChangeCompleted(uint32_t change_id, mojom::WindowManagerErrorCode error_code); @@ -369,8 +372,9 @@ override; void SetCapture(uint32_t change_id, Id window_id) override; void ReleaseCapture(uint32_t change_id, Id window_id) override; - void SetEventObserver(mojom::EventMatcherPtr matcher, - uint32_t observer_id) override; + void StartPointerWatcher(bool want_moves, + uint32_t pointer_watcher_id) override; + void StopPointerWatcher() override; void SetWindowBounds(uint32_t change_id, Id window_id, const gfx::Rect& bounds) override; @@ -485,12 +489,12 @@ // reasonable timeframe. bool janky_ = false; - // Set when the client is using SetEventObserver() to observe events, - // otherwise null. - std::unique_ptr<EventMatcher> event_observer_matcher_; + // For performance reasons, only send move events if the client explicitly + // requests them. + bool pointer_watcher_want_moves_ = false; - // The ID supplied by the client for the current event observer. - uint32_t event_observer_id_ = 0; + // The ID supplied by the client for the current pointer watcher. + uint32_t pointer_watcher_id_ = 0; // WindowManager the current event came from. WindowManagerState* event_source_wms_ = nullptr;
diff --git a/services/ui/ws/window_tree_client_unittest.cc b/services/ui/ws/window_tree_client_unittest.cc index 31ba777d..b65c0c5 100644 --- a/services/ui/ws/window_tree_client_unittest.cc +++ b/services/ui/ws/window_tree_client_unittest.cc
@@ -357,8 +357,8 @@ // Don't log input events as none of the tests care about them and they // may come in at random points. } - void OnEventObserved(std::unique_ptr<ui::Event>, - uint32_t event_observer_id) override {} + void OnPointerEventObserved(std::unique_ptr<ui::Event>, + uint32_t event_observer_id) override {} void OnWindowSharedPropertyChanged(uint32_t window, const String& name, Array<uint8_t> new_data) override {
diff --git a/services/ui/ws/window_tree_unittest.cc b/services/ui/ws/window_tree_unittest.cc index dc230f89..393e3cbee 100644 --- a/services/ui/ws/window_tree_unittest.cc +++ b/services/ui/ws/window_tree_unittest.cc
@@ -90,13 +90,6 @@ ->capture_window(); } -mojom::EventMatcherPtr CreateEventMatcher(ui::mojom::EventType type) { - mojom::EventMatcherPtr matcher = mojom::EventMatcher::New(); - matcher->type_matcher = mojom::EventTypeMatcher::New(); - matcher->type_matcher->type = type; - return matcher; -} - class TestMoveLoopWindowManager : public TestWindowManager { public: TestMoveLoopWindowManager(WindowTree* tree) : tree_(tree) {} @@ -309,8 +302,8 @@ ChangesToDescription1(*embed_client->tracker()->changes())[1]); } -// Tests that a client can observe events outside its bounds. -TEST_F(WindowTreeTest, SetEventObserver) { +// Tests that a client can watch for events outside its bounds. +TEST_F(WindowTreeTest, StartPointerWatcher) { // Create an embedded client. TestWindowTreeClient* client = nullptr; WindowTree* tree = nullptr; @@ -320,103 +313,95 @@ // Create an event outside the bounds of the client. ui::PointerEvent pointer_down = CreatePointerDownEvent(5, 5); - // Events are not observed before setting an observer. + // Events are not watched before starting a watcher. DispatchEventAndAckImmediately(pointer_down); ASSERT_EQ(0u, client->tracker()->changes()->size()); - // Create an observer for pointer-down events. - WindowTreeTestApi(tree).SetEventObserver( - CreateEventMatcher(ui::mojom::EventType::POINTER_DOWN), 111u); + // Create a watcher for all events excluding move events. + WindowTreeTestApi(tree).StartPointerWatcher(false, 111u); // Pointer-down events are sent to the client. DispatchEventAndAckImmediately(pointer_down); ASSERT_EQ(1u, client->tracker()->changes()->size()); - EXPECT_EQ("EventObserved event_action=16 event_observer_id=111", + EXPECT_EQ("PointerWatcherEvent event_action=16 pointer_watcher_id=111", ChangesToDescription1(*client->tracker()->changes())[0]); client->tracker()->changes()->clear(); - // Clearing the observer stops sending events to the client. - WindowTreeTestApi(tree).SetEventObserver(nullptr, 0u); + // Stopping the watcher stops sending events to the client. + WindowTreeTestApi(tree).StopPointerWatcher(); DispatchEventAndAckImmediately(pointer_down); ASSERT_EQ(0u, client->tracker()->changes()->size()); } -// Tests that a client using an event observer does not receive events that -// don't match the EventMatcher spec. -TEST_F(WindowTreeTest, SetEventObserverNonMatching) { +// Tests that a client using a pointer watcher does not receive events that +// don't match the |want_moves| setting. +TEST_F(WindowTreeTest, StartPointerWatcherNonMatching) { // Create an embedded client. TestWindowTreeClient* client = nullptr; WindowTree* tree = nullptr; ServerWindow* window = nullptr; EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&client, &tree, &window)); - // Create an observer for pointer-down events. - WindowTreeTestApi(tree).SetEventObserver( - CreateEventMatcher(ui::mojom::EventType::POINTER_DOWN), 111u); + // Create a watcher for all events excluding move events. + WindowTreeTestApi(tree).StartPointerWatcher(false, 111u); - // Pointer-up events are not sent to the client, since they don't match. - DispatchEventAndAckImmediately(CreatePointerUpEvent(5, 5)); + // Pointer-move events are not sent to the client, since they don't match. + DispatchEventAndAckImmediately(CreateMouseMoveEvent(5, 5)); ASSERT_EQ(0u, client->tracker()->changes()->size()); } -// Tests that an event that both hits a client window and matches an event -// observer is sent only once to the client. -TEST_F(WindowTreeTest, SetEventObserverSendsOnce) { +// Tests that an event that both hits a client window and matches a pointer +// watcher is sent only once to the client. +TEST_F(WindowTreeTest, StartPointerWatcherSendsOnce) { // Create an embedded client. TestWindowTreeClient* client = nullptr; WindowTree* tree = nullptr; ServerWindow* window = nullptr; EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&client, &tree, &window)); - // Create an observer for pointer-up events (which do not cause focus - // changes). - WindowTreeTestApi(tree).SetEventObserver( - CreateEventMatcher(ui::mojom::EventType::POINTER_UP), 111u); + // Create a watcher for all events excluding move events (which do not + // cause focus changes). + WindowTreeTestApi(tree).StartPointerWatcher(false, 111u); // Create an event inside the bounds of the client. ui::PointerEvent pointer_up = CreatePointerUpEvent(25, 25); - // The event is dispatched once, with a flag set that it matched the event - // observer. + // The event is dispatched once, with a flag set that it matched the pointer + // watcher. DispatchEventAndAckImmediately(pointer_up); ASSERT_EQ(1u, client->tracker()->changes()->size()); - EXPECT_EQ("InputEvent window=2,1 event_action=18 event_observer_id=111", + EXPECT_EQ("InputEvent window=2,1 event_action=18 pointer_watcher_id=111", SingleChangeToDescription(*client->tracker()->changes())); } -// Tests that events generated by user A are not observed by event observers for -// user B. -TEST_F(WindowTreeTest, SetEventObserverWrongUser) { +// Tests that events generated by user A are not watched by pointer watchers +// for user B. +TEST_F(WindowTreeTest, StartPointerWatcherWrongUser) { // Embed a window tree belonging to a different user. TestWindowTreeBinding* other_binding; WindowTree* other_tree = CreateNewTree("other_user", &other_binding); other_binding->client()->tracker()->changes()->clear(); - // Set event observers on both the wm tree and the other user's tree. - WindowTreeTestApi(wm_tree()).SetEventObserver( - CreateEventMatcher(ui::mojom::EventType::POINTER_UP), 111u); - WindowTreeTestApi(other_tree) - .SetEventObserver(CreateEventMatcher(ui::mojom::EventType::POINTER_UP), - 222u); + // Set pointer watchers on both the wm tree and the other user's tree. + WindowTreeTestApi(wm_tree()).StartPointerWatcher(false, 111u); + WindowTreeTestApi(other_tree).StartPointerWatcher(false, 222u); - // An event is observed by the wm tree, but not by the other user's tree. + // An event is watched by the wm tree, but not by the other user's tree. DispatchEventAndAckImmediately(CreatePointerUpEvent(5, 5)); ASSERT_EQ(1u, wm_client()->tracker()->changes()->size()); - EXPECT_EQ("InputEvent window=0,3 event_action=18 event_observer_id=111", + EXPECT_EQ("InputEvent window=0,3 event_action=18 pointer_watcher_id=111", SingleChangeToDescription(*wm_client()->tracker()->changes())); ASSERT_EQ(0u, other_binding->client()->tracker()->changes()->size()); } -// Tests that an event observer cannot observe keystrokes. -TEST_F(WindowTreeTest, SetEventObserverKeyEventsDisallowed) { - WindowTreeTestApi(wm_tree()).SetEventObserver( - CreateEventMatcher(ui::mojom::EventType::KEY_PRESSED), 111u); +// Tests that a pointer watcher cannot watch keystrokes. +TEST_F(WindowTreeTest, StartPointerWatcherKeyEventsDisallowed) { + WindowTreeTestApi(wm_tree()).StartPointerWatcher(false, 111u); ui::KeyEvent key_pressed(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE); DispatchEventAndAckImmediately(key_pressed); EXPECT_EQ(0u, wm_client()->tracker()->changes()->size()); - WindowTreeTestApi(wm_tree()).SetEventObserver( - CreateEventMatcher(ui::mojom::EventType::KEY_RELEASED), 222u); + WindowTreeTestApi(wm_tree()).StartPointerWatcher(false, 222u); ui::KeyEvent key_released(ui::ET_KEY_RELEASED, ui::VKEY_A, ui::EF_NONE); DispatchEventAndAckImmediately(key_released); EXPECT_EQ(0u, wm_client()->tracker()->changes()->size());
diff --git a/services/video_capture/OWNERS b/services/video_capture/OWNERS new file mode 100644 index 0000000..6052c2a --- /dev/null +++ b/services/video_capture/OWNERS
@@ -0,0 +1,3 @@ +chfremer@chromium.org +emircan@chromium.org +mcasas@chromium.org
diff --git a/services/video_capture/public/interfaces/BUILD.gn b/services/video_capture/public/interfaces/BUILD.gn new file mode 100644 index 0000000..1e4d90e --- /dev/null +++ b/services/video_capture/public/interfaces/BUILD.gn
@@ -0,0 +1,19 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//mojo/public/tools/bindings/mojom.gni") + +mojom("interfaces") { + sources = [ + "video_capture_device.mojom", + "video_capture_device_client.mojom", + "video_capture_device_factory.mojom", + "video_capture_format.mojom", + ] + + deps = [ + "//media/mojo/interfaces", + "//ui/gfx/geometry/mojo", + ] +}
diff --git a/ash/sysui/public/interfaces/OWNERS b/services/video_capture/public/interfaces/OWNERS similarity index 100% rename from ash/sysui/public/interfaces/OWNERS rename to services/video_capture/public/interfaces/OWNERS
diff --git a/services/video_capture/public/interfaces/video_capture_device.mojom b/services/video_capture/public/interfaces/video_capture_device.mojom new file mode 100644 index 0000000..be3b97d7 --- /dev/null +++ b/services/video_capture/public/interfaces/video_capture_device.mojom
@@ -0,0 +1,29 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module video_capture.mojom; + +import "services/video_capture/public/interfaces/video_capture_device_client.mojom"; +import "services/video_capture/public/interfaces/video_capture_format.mojom"; + +enum ResolutionChangePolicy { + FIXED_RESOLUTION, + FIXED_ASPECT_RATIO, + ANY_WITHIN_LIMIT, +}; + +enum PowerLineFrequency { + DEFAULT, + HZ_50, + HZ_60 +}; + +// Note: The VideoCaptureDevice is stopped when the corresponding message pipe +// is closed. +interface VideoCaptureDevice { + Start(VideoCaptureFormat requested_format, + ResolutionChangePolicy resolution_change_policy, + PowerLineFrequency power_line_frequency, + VideoCaptureDeviceClient client); +};
diff --git a/services/video_capture/public/interfaces/video_capture_device_client.mojom b/services/video_capture/public/interfaces/video_capture_device_client.mojom new file mode 100644 index 0000000..7c7f210c --- /dev/null +++ b/services/video_capture/public/interfaces/video_capture_device_client.mojom
@@ -0,0 +1,12 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module video_capture.mojom; + +import "media/mojo/interfaces/media_types.mojom"; + +interface VideoCaptureDeviceClient { + OnFrameAvailable(media.mojom.VideoFrame frame); + OnError(string error); +};
diff --git a/services/video_capture/public/interfaces/video_capture_device_factory.mojom b/services/video_capture/public/interfaces/video_capture_device_factory.mojom new file mode 100644 index 0000000..37bd6fc --- /dev/null +++ b/services/video_capture/public/interfaces/video_capture_device_factory.mojom
@@ -0,0 +1,47 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module video_capture.mojom; + +import "services/video_capture/public/interfaces/video_capture_device.mojom"; +import "services/video_capture/public/interfaces/video_capture_format.mojom"; + +enum VideoCaptureApi { + LINUX_V4L2_SINGLE_PLANE, + WIN_MEDIA_FOUNDATION, + WIN_DIRECT_SHOW, + MACOSX_AVFOUNDATION, + MACOSX_DECKLINK, + ANDROID_API1, + ANDROID_API2_LEGACY, + ANDROID_API2_FULL, + ANDROID_API2_LIMITED, + ANDROID_TANGO, + UNKNOWN +}; + +enum VideoCaptureTransportType { + // For AVFoundation Api, identify devices that are built-in or USB. + MACOSX_USB_OR_BUILT_IN, + OTHER_TRANSPORT +}; + +struct VideoCaptureDeviceDescriptor { + string display_name; + string device_id; + string model_id; + VideoCaptureApi capture_api; + VideoCaptureTransportType transport_type; +}; + +interface VideoCaptureDeviceFactory { + EnumerateDeviceDescriptors() + => (array<VideoCaptureDeviceDescriptor> descriptors); + + GetSupportedFormats(VideoCaptureDeviceDescriptor device_descriptor) + => (array<VideoCaptureFormat> supported_formats); + + CreateDevice(VideoCaptureDeviceDescriptor device_descriptor, + VideoCaptureDevice& device_request); +};
diff --git a/services/video_capture/public/interfaces/video_capture_format.mojom b/services/video_capture/public/interfaces/video_capture_format.mojom new file mode 100644 index 0000000..9ae109d --- /dev/null +++ b/services/video_capture/public/interfaces/video_capture_format.mojom
@@ -0,0 +1,21 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module video_capture.mojom; + +import "media/mojo/interfaces/media_types.mojom"; +import "ui/gfx/geometry/mojo/geometry.mojom"; + +enum VideoPixelStorage { + CPU, + GPUMEMORYBUFFER +}; + +struct VideoCaptureFormat { + gfx.mojom.Size frame_size; + float frame_rate; + media.mojom.VideoFormat pixel_format; + VideoPixelStorage pixel_storage; +}; +
diff --git a/services/video_capture/video_capture_device_client_impl.cc b/services/video_capture/video_capture_device_client_impl.cc new file mode 100644 index 0000000..78747e63 --- /dev/null +++ b/services/video_capture/video_capture_device_client_impl.cc
@@ -0,0 +1,19 @@ +// 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 "base/logging.h" +#include "services/video_capture/video_capture_device_client_impl.h" + +namespace video_capture { + +void VideoCaptureDeviceClientImpl::OnFrameAvailable( + media::mojom::VideoFramePtr frame) { + NOTIMPLEMENTED(); +} + +void VideoCaptureDeviceClientImpl::OnError(const std::string& error) { + NOTIMPLEMENTED(); +} + +} // namespace video_capture
diff --git a/services/video_capture/video_capture_device_client_impl.h b/services/video_capture/video_capture_device_client_impl.h new file mode 100644 index 0000000..b94de54 --- /dev/null +++ b/services/video_capture/video_capture_device_client_impl.h
@@ -0,0 +1,22 @@ +// 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 SERVICES_VIDEO_CAPTURE_VIDEO_CAPTURE_DEVICE_CLIENT_IMPL_H_ +#define SERVICES_VIDEO_CAPTURE_VIDEO_CAPTURE_DEVICE_CLIENT_IMPL_H_ + +#include "services/video_capture/public/interfaces/video_capture_device_client.mojom.h" + +namespace video_capture { + +// Implementation of the VideoCaptureDeviceClient Mojo interface. +class VideoCaptureDeviceClientImpl : public mojom::VideoCaptureDeviceClient { + public: + // mojom::VideoCaptureDeviceClient: + void OnFrameAvailable(media::mojom::VideoFramePtr frame) override; + void OnError(const std::string& error) override; +}; + +} // namespace video_capture + +#endif // SERVICES_VIDEO_CAPTURE_VIDEO_CAPTURE_DEVICE_CLIENT_IMPL_H_
diff --git a/services/video_capture/video_capture_device_factory_impl.cc b/services/video_capture/video_capture_device_factory_impl.cc new file mode 100644 index 0000000..3bfcfbcf --- /dev/null +++ b/services/video_capture/video_capture_device_factory_impl.cc
@@ -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. + +#include "base/logging.h" +#include "services/video_capture/video_capture_device_factory_impl.h" + +namespace video_capture { + +void VideoCaptureDeviceFactoryImpl::EnumerateDeviceDescriptors( + const EnumerateDeviceDescriptorsCallback& callback) { + NOTIMPLEMENTED(); +} + +void VideoCaptureDeviceFactoryImpl::GetSupportedFormats( + mojom::VideoCaptureDeviceDescriptorPtr device_descriptor, + const GetSupportedFormatsCallback& callback) { + NOTIMPLEMENTED(); +} + +void VideoCaptureDeviceFactoryImpl::CreateDevice( + mojom::VideoCaptureDeviceDescriptorPtr device_descriptor, + mojom::VideoCaptureDeviceRequest device_request) { + NOTIMPLEMENTED(); +} + +} // namespace video_capture
diff --git a/services/video_capture/video_capture_device_factory_impl.h b/services/video_capture/video_capture_device_factory_impl.h new file mode 100644 index 0000000..9775a57f --- /dev/null +++ b/services/video_capture/video_capture_device_factory_impl.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 SERVICES_VIDEO_CAPTURE_VIDEO_CAPTURE_DEVICE_FACTORY_IMPL_H_ +#define SERVICES_VIDEO_CAPTURE_VIDEO_CAPTURE_DEVICE_FACTORY_IMPL_H_ + +#include "services/video_capture/public/interfaces/video_capture_device_factory.mojom.h" + +namespace video_capture { + +// Implementation of the VideoCaptureDeviceFactory Mojo interface. +class VideoCaptureDeviceFactoryImpl : public mojom::VideoCaptureDeviceFactory { + public: + // mojom::VideoCaptureDeviceFactory: + void EnumerateDeviceDescriptors( + const EnumerateDeviceDescriptorsCallback& callback) override; + void GetSupportedFormats( + mojom::VideoCaptureDeviceDescriptorPtr device_descriptor, + const GetSupportedFormatsCallback& callback) override; + void CreateDevice(mojom::VideoCaptureDeviceDescriptorPtr device_descriptor, + mojom::VideoCaptureDeviceRequest device_request) override; +}; + +} // namespace video_capture + +#endif // SERVICES_VIDEO_CAPTURE_VIDEO_CAPTURE_DEVICE_FACTORY_IMPL_H_
diff --git a/services/video_capture/video_capture_device_impl.cc b/services/video_capture/video_capture_device_impl.cc new file mode 100644 index 0000000..5621865 --- /dev/null +++ b/services/video_capture/video_capture_device_impl.cc
@@ -0,0 +1,18 @@ +// 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 "base/logging.h" +#include "services/video_capture/video_capture_device_impl.h" + +namespace video_capture { + +void VideoCaptureDeviceImpl::Start( + mojom::VideoCaptureFormatPtr requested_format, + mojom::ResolutionChangePolicy resolution_change_policy, + mojom::PowerLineFrequency power_line_frequency, + mojom::VideoCaptureDeviceClientPtr client) { + NOTIMPLEMENTED(); +} + +} // namespace video_capture
diff --git a/services/video_capture/video_capture_device_impl.h b/services/video_capture/video_capture_device_impl.h new file mode 100644 index 0000000..89b18796 --- /dev/null +++ b/services/video_capture/video_capture_device_impl.h
@@ -0,0 +1,24 @@ +// 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 SERVICES_VIDEO_CAPTURE_VIDEO_CAPTURE_DEVICE_IMPL_H_ +#define SERVICES_VIDEO_CAPTURE_VIDEO_CAPTURE_DEVICE_IMPL_H_ + +#include "services/video_capture/public/interfaces/video_capture_device.mojom.h" + +namespace video_capture { + +// Implementation of the VideoCaptureDevice Mojo interface. +class VideoCaptureDeviceImpl : public mojom::VideoCaptureDevice { + public: + // mojom::VideoCaptureDevice: + void Start(mojom::VideoCaptureFormatPtr requested_format, + mojom::ResolutionChangePolicy resolution_change_policy, + mojom::PowerLineFrequency power_line_frequency, + mojom::VideoCaptureDeviceClientPtr client) override; +}; + +} // namespace video_capture + +#endif // SERVICES_VIDEO_CAPTURE_VIDEO_CAPTURE_DEVICE_IMPL_H_
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h index 05b017b..97a9ebb 100644 --- a/skia/config/SkUserConfig.h +++ b/skia/config/SkUserConfig.h
@@ -209,6 +209,10 @@ # define SK_SUPPORT_LEGACY_GETDEVICE #endif +#ifndef SK_SUPPORT_LEGACY_PICTUREINSTALLPIXELREF +# define SK_SUPPORT_LEGACY_PICTUREINSTALLPIXELREF +#endif + #ifndef SK_SUPPORT_LEGACY_ACCESSBITMAP # define SK_SUPPORT_LEGACY_ACCESSBITMAP #endif
diff --git a/storage/browser/blob/blob_reader.cc b/storage/browser/blob/blob_reader.cc index b342fc9..d548a039 100644 --- a/storage/browser/blob/blob_reader.cc +++ b/storage/browser/blob/blob_reader.cc
@@ -76,7 +76,7 @@ } BlobReader::~BlobReader() { - STLDeleteValues(&index_to_reader_); + base::STLDeleteValues(&index_to_reader_); } BlobReader::Status BlobReader::CalculateSize(
diff --git a/storage/browser/blob/blob_storage_registry.cc b/storage/browser/blob/blob_storage_registry.cc index a0f03b2..9ddcb99b 100644 --- a/storage/browser/blob/blob_storage_registry.cc +++ b/storage/browser/blob/blob_storage_registry.cc
@@ -63,7 +63,7 @@ const std::string& uuid, const std::string& content_type, const std::string& content_disposition) { - DCHECK(!ContainsKey(blob_map_, uuid)); + DCHECK(!base::ContainsKey(blob_map_, uuid)); std::unique_ptr<Entry> entry(new Entry(1, BlobState::PENDING)); entry->content_type = content_type; entry->content_disposition = content_disposition; @@ -115,7 +115,7 @@ } bool BlobStorageRegistry::IsURLMapped(const GURL& blob_url) const { - return ContainsKey(url_to_uuid_, blob_url); + return base::ContainsKey(url_to_uuid_, blob_url); } BlobStorageRegistry::Entry* BlobStorageRegistry::GetEntryFromURL(
diff --git a/storage/browser/fileapi/copy_or_move_operation_delegate.cc b/storage/browser/fileapi/copy_or_move_operation_delegate.cc index ca5b409..d406526 100644 --- a/storage/browser/fileapi/copy_or_move_operation_delegate.cc +++ b/storage/browser/fileapi/copy_or_move_operation_delegate.cc
@@ -754,7 +754,7 @@ } CopyOrMoveOperationDelegate::~CopyOrMoveOperationDelegate() { - STLDeleteElements(&running_copy_set_); + base::STLDeleteElements(&running_copy_set_); } void CopyOrMoveOperationDelegate::Run() {
diff --git a/storage/browser/fileapi/external_mount_points.cc b/storage/browser/fileapi/external_mount_points.cc index f9ffdbdb..927bca4c 100644 --- a/storage/browser/fileapi/external_mount_points.cc +++ b/storage/browser/fileapi/external_mount_points.cc
@@ -253,15 +253,15 @@ instance_map_.clear(); path_to_name_map_.clear(); } - STLDeleteContainerPairSecondPointers(instance_map_copy.begin(), - instance_map_copy.end()); + base::STLDeleteContainerPairSecondPointers(instance_map_copy.begin(), + instance_map_copy.end()); } ExternalMountPoints::ExternalMountPoints() {} ExternalMountPoints::~ExternalMountPoints() { - STLDeleteContainerPairSecondPointers(instance_map_.begin(), - instance_map_.end()); + base::STLDeleteContainerPairSecondPointers(instance_map_.begin(), + instance_map_.end()); } FileSystemURL ExternalMountPoints::CrackFileSystemURL(
diff --git a/storage/browser/fileapi/file_system_context.cc b/storage/browser/fileapi/file_system_context.cc index c689d17..9c1de0b 100644 --- a/storage/browser/fileapi/file_system_context.cc +++ b/storage/browser/fileapi/file_system_context.cc
@@ -183,8 +183,8 @@ // Chrome OS the additional backend chromeos::FileSystemBackend handles these // types. isolated_backend_.reset(new IsolatedFileSystemBackend( - !ContainsKey(backend_map_, kFileSystemTypeNativeLocal), - !ContainsKey(backend_map_, kFileSystemTypeNativeForPlatformApp))); + !base::ContainsKey(backend_map_, kFileSystemTypeNativeLocal), + !base::ContainsKey(backend_map_, kFileSystemTypeNativeForPlatformApp))); RegisterBackend(isolated_backend_.get()); if (quota_manager_proxy) {
diff --git a/storage/browser/fileapi/file_system_operation_runner.cc b/storage/browser/fileapi/file_system_operation_runner.cc index a361259..cc6bd38 100644 --- a/storage/browser/fileapi/file_system_operation_runner.cc +++ b/storage/browser/fileapi/file_system_operation_runner.cc
@@ -306,8 +306,8 @@ void FileSystemOperationRunner::Cancel( OperationID id, const StatusCallback& callback) { - if (ContainsKey(finished_operations_, id)) { - DCHECK(!ContainsKey(stray_cancel_callbacks_, id)); + if (base::ContainsKey(finished_operations_, id)) { + DCHECK(!base::ContainsKey(stray_cancel_callbacks_, id)); stray_cancel_callbacks_[id] = callback; return; }
diff --git a/storage/browser/fileapi/file_system_usage_cache.cc b/storage/browser/fileapi/file_system_usage_cache.cc index 8b6ec22..44d291f 100644 --- a/storage/browser/fileapi/file_system_usage_cache.cc +++ b/storage/browser/fileapi/file_system_usage_cache.cc
@@ -161,7 +161,7 @@ void FileSystemUsageCache::CloseCacheFiles() { TRACE_EVENT0("FileSystem", "UsageCache::CloseCacheFiles"); DCHECK(CalledOnValidThread()); - STLDeleteValues(&cache_files_); + base::STLDeleteValues(&cache_files_); timer_.reset(); } @@ -300,7 +300,7 @@ bool FileSystemUsageCache::HasCacheFileHandle(const base::FilePath& file_path) { DCHECK(CalledOnValidThread()); DCHECK_LE(cache_files_.size(), kMaxHandleCacheSize); - return ContainsKey(cache_files_, file_path); + return base::ContainsKey(cache_files_, file_path); } } // namespace storage
diff --git a/storage/browser/fileapi/isolated_context.cc b/storage/browser/fileapi/isolated_context.cc index 6edc40d..0ca6d25 100644 --- a/storage/browser/fileapi/isolated_context.cc +++ b/storage/browser/fileapi/isolated_context.cc
@@ -424,8 +424,8 @@ } IsolatedContext::~IsolatedContext() { - STLDeleteContainerPairSecondPointers(instance_map_.begin(), - instance_map_.end()); + base::STLDeleteContainerPairSecondPointers(instance_map_.begin(), + instance_map_.end()); } FileSystemURL IsolatedContext::CrackFileSystemURL(
diff --git a/storage/browser/fileapi/obfuscated_file_util.cc b/storage/browser/fileapi/obfuscated_file_util.cc index fa151ac..dfe71c6 100644 --- a/storage/browser/fileapi/obfuscated_file_util.cc +++ b/storage/browser/fileapi/obfuscated_file_util.cc
@@ -962,7 +962,7 @@ for (size_t i = 0; i < type_strings_to_prepopulate.size(); ++i) { const std::string type_string = type_strings_to_prepopulate[i]; // Only handles known types. - if (!ContainsKey(known_type_strings_, type_string)) + if (!base::ContainsKey(known_type_strings_, type_string)) continue; base::File::Error error = base::File::FILE_ERROR_FAILED; base::FilePath path = GetDirectoryForOriginAndType( @@ -1264,8 +1264,8 @@ void ObfuscatedFileUtil::DropDatabases() { origin_database_.reset(); - STLDeleteContainerPairSecondPointers( - directories_.begin(), directories_.end()); + base::STLDeleteContainerPairSecondPointers(directories_.begin(), + directories_.end()); directories_.clear(); timer_.reset(); }
diff --git a/storage/browser/fileapi/plugin_private_file_system_backend.cc b/storage/browser/fileapi/plugin_private_file_system_backend.cc index 54b0e7f..06e9aef 100644 --- a/storage/browser/fileapi/plugin_private_file_system_backend.cc +++ b/storage/browser/fileapi/plugin_private_file_system_backend.cc
@@ -48,7 +48,7 @@ const std::string& plugin_id) { DCHECK(task_runner_->RunsTasksOnCurrentThread()); DCHECK(!filesystem_id.empty()); - DCHECK(!ContainsKey(map_, filesystem_id)) << filesystem_id; + DCHECK(!base::ContainsKey(map_, filesystem_id)) << filesystem_id; map_[filesystem_id] = plugin_id; }
diff --git a/storage/browser/fileapi/sandbox_file_system_backend_delegate.cc b/storage/browser/fileapi/sandbox_file_system_backend_delegate.cc index f4714c7..b6b3a62 100644 --- a/storage/browser/fileapi/sandbox_file_system_backend_delegate.cc +++ b/storage/browser/fileapi/sandbox_file_system_backend_delegate.cc
@@ -393,7 +393,8 @@ // Don't use usage cache and return recalculated usage for sticky invalidated // origins. - if (ContainsKey(sticky_dirty_origins_, std::make_pair(origin_url, type))) + if (base::ContainsKey(sticky_dirty_origins_, + std::make_pair(origin_url, type))) return RecalculateUsage(file_system_context, origin_url, type); base::FilePath base_path =
diff --git a/storage/browser/quota/client_usage_tracker.cc b/storage/browser/quota/client_usage_tracker.cc index 477fdb5e..c9c46f6d1 100644 --- a/storage/browser/quota/client_usage_tracker.cc +++ b/storage/browser/quota/client_usage_tracker.cc
@@ -46,7 +46,7 @@ const std::string& host, const GURL& origin) { OriginSetByHost::const_iterator itr = origins.find(host); - return itr != origins.end() && ContainsKey(itr->second, origin); + return itr != origins.end() && base::ContainsKey(itr->second, origin); } void DidGetGlobalUsageForLimitedGlobalUsage(const UsageCallback& callback, @@ -122,9 +122,9 @@ void ClientUsageTracker::GetHostUsage( const std::string& host, const UsageCallback& callback) { - if (ContainsKey(cached_hosts_, host) && - !ContainsKey(non_cached_limited_origins_by_host_, host) && - !ContainsKey(non_cached_unlimited_origins_by_host_, host)) { + if (base::ContainsKey(cached_hosts_, host) && + !base::ContainsKey(non_cached_limited_origins_by_host_, host) && + !base::ContainsKey(non_cached_unlimited_origins_by_host_, host)) { // TODO(kinuko): Drop host_usage_map_ cache periodically. callback.Run(GetCachedHostUsage(host)); return;
diff --git a/storage/browser/quota/quota_manager.cc b/storage/browser/quota/quota_manager.cc index 79268a6..f028616 100644 --- a/storage/browser/quota/quota_manager.cc +++ b/storage/browser/quota/quota_manager.cc
@@ -1578,8 +1578,8 @@ const GURL& origin) { // Make sure the returned origin is (still) not in the origin_in_use_ set // and has not been accessed since we posted the task. - if (ContainsKey(origins_in_use_, origin) || - ContainsKey(access_notified_origins_, origin)) { + if (base::ContainsKey(origins_in_use_, origin) || + base::ContainsKey(access_notified_origins_, origin)) { callback.Run(GURL()); } else { callback.Run(origin);
diff --git a/storage/browser/quota/storage_monitor.cc b/storage/browser/quota/storage_monitor.cc index a0d351fb..87c982e0 100644 --- a/storage/browser/quota/storage_monitor.cc +++ b/storage/browser/quota/storage_monitor.cc
@@ -119,7 +119,7 @@ } void StorageObserverList::ScheduleUpdateForObserver(StorageObserver* observer) { - DCHECK(ContainsKey(observers_, observer)); + DCHECK(base::ContainsKey(observers_, observer)); observers_[observer].requires_update = true; } @@ -247,7 +247,7 @@ } StorageTypeObservers::~StorageTypeObservers() { - STLDeleteValues(&host_observers_map_); + base::STLDeleteValues(&host_observers_map_); } void StorageTypeObservers::AddObserver( @@ -323,7 +323,7 @@ } StorageMonitor::~StorageMonitor() { - STLDeleteValues(&storage_type_observers_map_); + base::STLDeleteValues(&storage_type_observers_map_); } void StorageMonitor::AddObserver(
diff --git a/storage/browser/quota/usage_tracker.cc b/storage/browser/quota/usage_tracker.cc index 03ebecd0..e324bfe 100644 --- a/storage/browser/quota/usage_tracker.cc +++ b/storage/browser/quota/usage_tracker.cc
@@ -42,7 +42,7 @@ } UsageTracker::~UsageTracker() { - STLDeleteValues(&client_tracker_map_); + base::STLDeleteValues(&client_tracker_map_); } ClientUsageTracker* UsageTracker::GetClientTracker(QuotaClient::ID client_id) {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index 585c879..d528804 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -1198,6 +1198,365 @@ } ] }, + "CFI Linux Full": { + "gtest_tests": [ + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "accessibility_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "angle_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "app_shell_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "aura_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "base_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "blimp_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "blink_heap_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "blink_platform_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true, + "shards": 10 + }, + "test": "browser_tests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "cacheinvalidation_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "capture_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "cast_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "cc_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "chromedriver_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "components_browsertests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "components_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "compositor_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "content_browsertests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "content_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "crypto_unittests" + }, + { + "test": "dbus_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "device_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "display_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "events_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "extensions_browsertests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "extensions_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "gcm_unit_tests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "gfx_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "gin_unittests" + }, + { + "test": "gl_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "gn_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "google_apis_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "gpu_ipc_service_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "gpu_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "interactive_ui_tests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "ipc_tests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "jingle_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "media_blink_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "media_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "midi_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "mojo_common_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "mojo_public_bindings_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "mojo_public_system_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "mojo_system_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "nacl_loader_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "net_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "ppapi_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "printing_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "remoting_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "sandbox_linux_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "skia_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "sql_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "ui_base_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "ui_touch_selection_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "unit_tests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "url_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "views_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "webkit_unit_tests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "wm_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "wtf_unittests" + } + ] + }, "CFI Linux ToT": { "gtest_tests": [ { @@ -1997,6 +2356,20 @@ ] }, "ClangToTAndroidASan": { + "gtest_tests": [ + { + "args": [ + "--tool=asan" + ], + "test": "components_browsertests" + }, + { + "args": [ + "--tool=asan" + ], + "test": "gfx_unittests" + } + ], "junit_tests": [ { "test": "base_junit_tests"
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json index 0b362e0..f04ba7e 100644 --- a/testing/buildbot/chromium.linux.json +++ b/testing/buildbot/chromium.linux.json
@@ -1330,6 +1330,12 @@ "swarming": { "can_use_on_swarming_builders": true }, + "test": "mus_ime_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, "test": "mus_public_unittests" }, { @@ -1402,12 +1408,6 @@ "swarming": { "can_use_on_swarming_builders": true }, - "test": "test_ime_unittests" - }, - { - "swarming": { - "can_use_on_swarming_builders": true - }, "test": "ui_base_unittests" }, { @@ -1787,6 +1787,12 @@ "swarming": { "can_use_on_swarming_builders": true }, + "test": "mus_ime_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, "test": "mus_ws_unittests" }, { @@ -1850,12 +1856,6 @@ "swarming": { "can_use_on_swarming_builders": true }, - "test": "test_ime_unittests" - }, - { - "swarming": { - "can_use_on_swarming_builders": true - }, "test": "ui_base_unittests" }, {
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json index 05e39bf..1aed1c8 100644 --- a/testing/buildbot/chromium.mac.json +++ b/testing/buildbot/chromium.mac.json
@@ -192,6 +192,12 @@ "swarming": { "can_use_on_swarming_builders": true }, + "test": "mac_installer_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, "test": "media_blink_unittests" }, { @@ -525,6 +531,12 @@ "swarming": { "can_use_on_swarming_builders": true }, + "test": "mac_installer_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, "test": "media_blink_unittests" }, { @@ -859,6 +871,12 @@ "swarming": { "can_use_on_swarming_builders": true }, + "test": "mac_installer_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, "test": "media_blink_unittests" }, { @@ -1181,6 +1199,12 @@ "swarming": { "can_use_on_swarming_builders": true }, + "test": "mac_installer_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, "test": "media_blink_unittests" }, {
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl index 75e1cfdb..72853ff 100644 --- a/testing/buildbot/gn_isolate_map.pyl +++ b/testing/buildbot/gn_isolate_map.pyl
@@ -392,6 +392,10 @@ #"label": "//third_party/libphonenumber:libphonenumber_unittests", #"type": "console_test_launcher", #}, + "mac_installer_unittests": { + "label": "//chrome/installer/mac/app:mac_installer_unittests", + "type": "console_test_launcher", + }, "media_unittests": { "label": "//media:media_unittests", "type": "windowed_test_launcher", @@ -594,8 +598,8 @@ "../../", ], }, - "test_ime_unittests": { - "label": "//services/ui/test_ime:test_ime_unittests", + "mus_ime_unittests": { + "label": "//services/ui/ime:mus_ime_unittests", "type": "windowed_test_launcher", }, "ui_android_unittests": {
diff --git a/testing/iossim/iossim.mm b/testing/iossim/iossim.mm index f1f0ca86..ebe6249f 100644 --- a/testing/iossim/iossim.mm +++ b/testing/iossim/iossim.mm
@@ -284,6 +284,16 @@ } int main(int argc, char* const argv[]) { + // When the last running simulator is from Xcode 7, an Xcode 8 run will yeild + // a failure to "unload a stale CoreSimulatorService job" message. Sending a + // hidden simctl to do something simple (list devices) helpfully works around + // this issue. + XCRunTask* workaround_task = [[[XCRunTask alloc] + initWithArguments:@[ @"simctl", @"list", @"-j" ]] autorelease]; + [workaround_task setStandardOutput:nil]; + [workaround_task setStandardError:nil]; + [workaround_task run]; + NSString* app_path = nil; NSString* xctest_path = nil; NSString* cmd_args = nil;
diff --git a/testing/libfuzzer/unittest_main.cc b/testing/libfuzzer/unittest_main.cc index 3d0650e..87c70694 100644 --- a/testing/libfuzzer/unittest_main.cc +++ b/testing/libfuzzer/unittest_main.cc
@@ -35,7 +35,16 @@ int main(int argc, char **argv) { if (argc == 1) { - std::cerr << "Usage: " << argv[0] << " <file>..." << std::endl; + std::cerr + << "Usage: " << argv[0] + << " <file>...\n" + "\n" + "Alternatively, try building this target with " + "use_libfuzzer=true for a better test driver. For details see:\n" + "\n" + "https://chromium.googlesource.com/chromium/src/+/master/" + "testing/libfuzzer/getting_started.md" + << std::endl; exit(1); }
diff --git a/testing/variations/fieldtrial_testing_config_android.json b/testing/variations/fieldtrial_testing_config_android.json index 9b635f6..7476b6e 100644 --- a/testing/variations/fieldtrial_testing_config_android.json +++ b/testing/variations/fieldtrial_testing_config_android.json
@@ -129,6 +129,14 @@ } } ], + "DownloadsUi": [ + { + "enable_features": [ + "DownloadsUi" + ], + "group_name": "Enabled" + } + ], "EnableMediaThreadForMediaPlayback": [ { "group_name": "Enabled" @@ -213,6 +221,14 @@ "group_name": "Enabled" } ], + "NTPSnippets": [ + { + "enable_features": [ + "NTPSnippets" + ], + "group_name": "Enabled" + } + ], "NetworkQualityEstimator": [ { "group_name": "Enabled", @@ -289,6 +305,14 @@ "group_name": "Enabled" } ], + "PassiveDocumentEventListeners": [ + { + "enable_features": [ + "PassiveDocumentEventListeners" + ], + "group_name": "Enabled" + } + ], "PasswordBranding": [ { "group_name": "SmartLockBrandingSavePromptOnly" @@ -376,24 +400,6 @@ } }, { - "group_name": "ShowAndPossiblySend", - "params": { - "sendingThreshold": "-1.0" - } - }, - { - "group_name": "ShowAndPossiblySend", - "params": { - "sendingThreshold": "0.0" - } - }, - { - "group_name": "ShowAndPossiblySend", - "params": { - "sendingThreshold": "abcdef" - } - }, - { "group_name": "DontShowAndDontSend" } ], @@ -562,6 +568,11 @@ } } ], + "WebFontsInterventionV2": [ + { + "group_name": "Enabled-slow2g" + } + ], "WebRTC-EnableWebRtcEcdsa": [ { "enable_features": [
diff --git a/testing/variations/fieldtrial_testing_config_chromeos.json b/testing/variations/fieldtrial_testing_config_chromeos.json index e477150..10a44baa 100644 --- a/testing/variations/fieldtrial_testing_config_chromeos.json +++ b/testing/variations/fieldtrial_testing_config_chromeos.json
@@ -20,6 +20,11 @@ "group_name": "Enabled" } ], + "BlockSmallPluginContent": [ + { + "group_name": "Enabled" + } + ], "CaptivePortalInterstitial": [ { "group_name": "Enabled" @@ -123,6 +128,14 @@ "group_name": "Enabled" } ], + "PassiveDocumentEventListeners": [ + { + "enable_features": [ + "PassiveDocumentEventListeners" + ], + "group_name": "Enabled" + } + ], "PasswordBranding": [ { "group_name": "SmartLockBrandingSavePromptOnly" @@ -299,6 +312,11 @@ } } ], + "WebFontsInterventionV2": [ + { + "group_name": "Enabled-slow2g" + } + ], "WebRTC-EnableWebRtcEcdsa": [ { "enable_features": [
diff --git a/testing/variations/fieldtrial_testing_config_linux.json b/testing/variations/fieldtrial_testing_config_linux.json index 46e4784..a60bc56 100644 --- a/testing/variations/fieldtrial_testing_config_linux.json +++ b/testing/variations/fieldtrial_testing_config_linux.json
@@ -25,6 +25,11 @@ "group_name": "Enabled" } ], + "BlockSmallPluginContent": [ + { + "group_name": "Enabled" + } + ], "CaptivePortalInterstitial": [ { "group_name": "Enabled" @@ -155,6 +160,14 @@ "group_name": "Enabled" } ], + "PassiveDocumentEventListeners": [ + { + "enable_features": [ + "PassiveDocumentEventListeners" + ], + "group_name": "Enabled" + } + ], "PasswordBranding": [ { "group_name": "SmartLockBrandingSavePromptOnly" @@ -218,24 +231,6 @@ } }, { - "group_name": "ShowAndPossiblySend", - "params": { - "sendingThreshold": "-1.0" - } - }, - { - "group_name": "ShowAndPossiblySend", - "params": { - "sendingThreshold": "0.0" - } - }, - { - "group_name": "ShowAndPossiblySend", - "params": { - "sendingThreshold": "abcdef" - } - }, - { "group_name": "DontShowAndDontSend" } ], @@ -363,6 +358,11 @@ } } ], + "WebFontsInterventionV2": [ + { + "group_name": "Enabled-slow2g" + } + ], "WebRTC-EnableWebRtcEcdsa": [ { "enable_features": [
diff --git a/testing/variations/fieldtrial_testing_config_mac.json b/testing/variations/fieldtrial_testing_config_mac.json index 5d7b213..6c5b79d 100644 --- a/testing/variations/fieldtrial_testing_config_mac.json +++ b/testing/variations/fieldtrial_testing_config_mac.json
@@ -31,6 +31,11 @@ } } ], + "BlockSmallPluginContent": [ + { + "group_name": "Enabled" + } + ], "CaptivePortalInterstitial": [ { "group_name": "Enabled" @@ -191,6 +196,14 @@ "group_name": "Enabled" } ], + "PassiveDocumentEventListeners": [ + { + "enable_features": [ + "PassiveDocumentEventListeners" + ], + "group_name": "Enabled" + } + ], "PasswordBranding": [ { "group_name": "SmartLockBrandingSavePromptOnly" @@ -254,24 +267,6 @@ } }, { - "group_name": "ShowAndPossiblySend", - "params": { - "sendingThreshold": "-1.0" - } - }, - { - "group_name": "ShowAndPossiblySend", - "params": { - "sendingThreshold": "0.0" - } - }, - { - "group_name": "ShowAndPossiblySend", - "params": { - "sendingThreshold": "abcdef" - } - }, - { "group_name": "DontShowAndDontSend" } ], @@ -415,6 +410,11 @@ "group_name": "Enabled" } ], + "WebFontsInterventionV2": [ + { + "group_name": "Enabled-slow2g" + } + ], "WebRTC-EnableWebRtcEcdsa": [ { "enable_features": [
diff --git a/testing/variations/fieldtrial_testing_config_win.json b/testing/variations/fieldtrial_testing_config_win.json index 4a7d346..6453653 100644 --- a/testing/variations/fieldtrial_testing_config_win.json +++ b/testing/variations/fieldtrial_testing_config_win.json
@@ -31,6 +31,11 @@ } } ], + "BlockSmallPluginContent": [ + { + "group_name": "Enabled" + } + ], "BrowserBlacklist": [ { "group_name": "Enabled" @@ -231,6 +236,14 @@ "group_name": "Enabled" } ], + "PassiveDocumentEventListeners": [ + { + "enable_features": [ + "PassiveDocumentEventListeners" + ], + "group_name": "Enabled" + } + ], "PasswordBranding": [ { "group_name": "SmartLockBrandingSavePromptOnly" @@ -313,24 +326,6 @@ } }, { - "group_name": "ShowAndPossiblySend", - "params": { - "sendingThreshold": "-1.0" - } - }, - { - "group_name": "ShowAndPossiblySend", - "params": { - "sendingThreshold": "0.0" - } - }, - { - "group_name": "ShowAndPossiblySend", - "params": { - "sendingThreshold": "abcdef" - } - }, - { "group_name": "DontShowAndDontSend" } ], @@ -468,6 +463,11 @@ } } ], + "WebFontsInterventionV2": [ + { + "group_name": "Enabled-slow2g" + } + ], "WebRTC-EnableWebRtcEcdsa": [ { "enable_features": [
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 index a499f17..da40741 100644 --- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 +++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
@@ -76,6 +76,7 @@ webmidi/ [ Skip ] xmlviewer/ [ Skip ] +broadcastchannel/blobs.html [ Pass Failure ] compositing/3d-corners.html [ Failure ] compositing/3d-cube.html [ Failure ] compositing/absolute-inside-out-of-view-fixed.html [ Failure ] @@ -90,7 +91,7 @@ compositing/backgrounds/fixed-background-on-descendant.html [ Failure ] compositing/backgrounds/fixed-backgrounds.html [ Failure ] compositing/canvas-with-object-fit-contain-in-composited-layer.html [ Failure ] -compositing/change-compositing-settings.html [ Failure ] +compositing/change-preferCompositingToLCDText-setting.html [ Failure ] compositing/clip-child-by-non-stacking-ancestor.html [ Failure ] compositing/color-matching/image-color-matching.html [ Failure ] compositing/columns/composited-in-paginated.html [ Failure ] @@ -605,6 +606,7 @@ fast/clip/overflow-border-radius-fixed-position.html [ Failure ] fast/clip/overflow-border-radius-transformed.html [ Failure ] fast/css-generated-content/014.html [ Failure ] +fast/css-generated-content/after-order.html [ Failure ] fast/css-generated-content/drag-state.html [ Crash Timeout ] fast/css-generated-content/table-parts-before-and-after.html [ Failure ] fast/css-grid-layout/grid-element-change-columns-repaint.html [ Failure ] @@ -674,10 +676,11 @@ fast/deprecated-flexbox/016.html [ Failure ] fast/dom/34176.html [ Failure ] fast/dom/52776.html [ Failure ] -fast/dom/CompositorProxy/proxy-forces-layer.html [ Failure ] +fast/dom/CompositorProxy/proxy-forces-layer.html [ Failure Timeout Pass ] fast/dom/focus-contenteditable.html [ Failure ] fast/dom/rtl-scroll-to-leftmost-and-resize.html [ Failure ] fast/dom/Window/open-existing-pop-up-blocking.html [ Failure ] +fast/dom/Window/property-access-on-cached-properties-after-frame-navigated.html [ Failure ] fast/dynamic/anchor-lock.html [ Failure ] fast/dynamic/anonymous-block-layer-lost.html [ Failure ] fast/dynamic/first-letter-after-list-marker.html [ Failure ] @@ -686,6 +689,7 @@ fast/events/autoscroll.html [ Failure ] fast/events/context-no-deselect.html [ Failure ] fast/events/drag-display-none-element.html [ Crash Timeout ] +fast/events/move-event-handler-between-framehosts.html [ Failure ] fast/events/onunload-not-on-body.html [ Crash ] fast/events/reveal-link-when-focused.html [ Failure ] fast/events/scale-and-scroll-body.html [ Crash Timeout ] @@ -700,6 +704,7 @@ fast/events/touch/compositor-touch-hit-rects-squashing.html [ Failure ] fast/events/touch/compositor-touch-hit-rects.html [ Failure ] fast/events/touch/touch-rect-crash-on-unpromote-layer.html [ Failure ] +fast/files/domurl-script-execution-context-crash.html [ Failure ] fast/files/file-in-input-display.html [ Failure ] fast/forms/001.html [ Failure ] fast/forms/basic-buttons.html [ Failure ] @@ -822,6 +827,7 @@ fast/forms/select/listbox-scrollbar-incremental-load.html [ Failure ] fast/forms/select/menulist-appearance-basic.html [ Failure ] fast/forms/select/menulist-appearance-none.html [ Failure ] +fast/forms/select/menulist-appearance-rtl.html [ Failure ] fast/forms/select/menulist-clip.html [ Failure ] fast/forms/select/menulist-deselect-update.html [ Crash Failure ] fast/forms/select/menulist-no-overflow.html [ Failure ] @@ -961,6 +967,9 @@ fast/frames/transparent-scrollbar.html [ Failure ] fast/gradients/background-clipped.html [ Failure ] fast/gradients/css3-color-stop-units.html [ Failure ] +fast/hidpi/clip-text-in-hidpi.html [ Failure ] +fast/hidpi/image-set-without-specified-width.html [ Failure ] +fast/hidpi/resize-corner-hidpi.html [ Failure ] fast/html/details-add-summary-1-and-click.html [ Failure ] fast/html/details-add-summary-10-and-click.html [ Failure ] fast/html/details-add-summary-2-and-click.html [ Failure ] @@ -971,6 +980,7 @@ fast/html/details-add-summary-7-and-click.html [ Failure ] fast/html/details-add-summary-8-and-click.html [ Failure ] fast/html/details-add-summary-9-and-click.html [ Failure ] +fast/html/details-add-summary-9.html [ Failure ] fast/html/details-position.html [ Failure ] fast/html/details-remove-summary-1-and-click.html [ Failure ] fast/html/details-remove-summary-2-and-click.html [ Failure ] @@ -992,8 +1002,10 @@ fast/images/color-profile-border-fade.html [ Failure ] fast/images/color-profile-border-radius.html [ Failure ] fast/images/color-profile-filter.html [ Failure ] +fast/images/color-profile-group.html [ Failure ] fast/images/color-profile-image-canvas-svg.html [ Crash ] fast/images/color-profile-image-filter-all.html [ Failure ] +fast/images/color-profile-image-object-fit.html [ Failure ] fast/images/color-profile-image-pseudo-content.html [ Failure ] fast/images/color-profile-image-shape.html [ Failure ] fast/images/color-profile-layer-filter.html [ Failure ] @@ -1004,9 +1016,14 @@ fast/images/color-profile-reflection.html [ Crash Failure ] fast/images/color-profile-svg-fill-text.html [ Failure ] fast/images/color-profile-svg-foreign-object.html [ Failure ] +fast/images/content-url-image-with-alt-text-dynamic-2.html [ Pass Failure ] fast/images/content-url-image-with-alt-text-dynamic.html [ Failure ] fast/images/content-url-image-with-alt-text.html [ Crash Failure ] +fast/images/embed-image.html [ Failure ] +fast/images/exif-orientation-css.html [ Failure ] fast/images/fixed-img-src-change-after-scroll.html [ Failure ] +fast/images/imagemap-case.html [ Failure ] +fast/images/imagemap-overflowing-circle-focus-ring.html [ Failure ] fast/images/mask-box-image-crash.html [ Failure ] fast/images/pixel-crack-image-background-webkit-transform-scale.html [ Failure ] fast/images/sprite-no-bleed.html [ Failure ] @@ -1027,14 +1044,17 @@ fast/layers/scroll-rect-to-visible.html [ Failure ] fast/layers/scroll-with-transform-layer.html [ Failure ] fast/lists/008.html [ Failure ] +fast/lists/ol-display-types.html [ Failure ] fast/lists/ol-start-parsing.html [ Failure ] fast/lists/olstart.html [ Failure ] fast/masking/clip-path-inset-large-radii.html [ Failure ] +fast/media/mq-js-stylesheet-media-03.html [ Failure ] fast/mediacapturefromelement/CanvasCaptureMediaStream-exceptions.html [ Crash ] fast/multicol/abspos-after-break-after.html [ Failure ] fast/multicol/abspos-in-overflow-hidden-in-2nd-column.html [ Failure ] fast/multicol/balance-breakafter-before-nested-block.html [ Failure ] fast/multicol/balance-empty-block-subpixel-column-height.html [ Failure ] +fast/multicol/balance-float-after-forced-break.html [ Pass Failure ] fast/multicol/basic-rtl.html [ Failure ] fast/multicol/border-radius-clipped-layer-second-column.html [ Failure ] fast/multicol/border-radius-clipped-layer.html [ Failure ] @@ -1070,6 +1090,7 @@ fast/multicol/dynamic/insert-spanner-after-spanner-before-content.html [ Failure ] fast/multicol/dynamic/insert-spanner-before-content.html [ Failure ] fast/multicol/dynamic/insert-spanner-into-content.html [ Failure ] +fast/multicol/dynamic/insert-spanner-pseudo-after.html [ Failure ] fast/multicol/dynamic/remove-abspos-next-to-spanner.html [ Failure ] fast/multicol/dynamic/remove-and-insert-block-after-spanner.html [ Failure ] fast/multicol/dynamic/remove-and-insert-block-before-spanner.html [ Failure ] @@ -1099,6 +1120,7 @@ fast/multicol/float-paginate-empty-lines.html [ Failure ] fast/multicol/float-paginate.html [ Failure ] fast/multicol/foreignObject.html [ Failure ] +fast/multicol/hit-test-float.html [ Failure ] fast/multicol/inline-block-baseline.html [ Failure ] fast/multicol/inner-multicol-in-second-column.html [ Failure ] fast/multicol/layers-in-multicol.html [ Failure ] @@ -1142,6 +1164,7 @@ fast/multicol/overflow-across-columns.html [ Failure ] fast/multicol/overflow-into-columngap.html [ Failure ] fast/multicol/overflow-unsplittable.html [ Failure ] +fast/multicol/paged-becomes-multicol-fixed-height.html [ Failure ] fast/multicol/paginate-block-replaced.html [ Failure ] fast/multicol/percent-height.html [ Failure ] fast/multicol/positioned-outside-of-columns.html [ Failure ] @@ -1225,6 +1248,7 @@ fast/overflow/003.xml [ Failure ] fast/overflow/006.html [ Failure ] fast/overflow/007.html [ Failure ] +fast/overflow/add-visual-overflow-and-change-container-position.html [ Failure ] fast/overflow/border-radius-clipping.html [ Failure ] fast/overflow/childFocusRingClip.html [ Failure ] fast/overflow/clip-rects-fixed-ancestor.html [ Failure ] @@ -1232,6 +1256,7 @@ fast/overflow/float-in-relpositioned.html [ Failure ] fast/overflow/hit-test-overflow-controls.html [ Failure ] fast/overflow/image-selection-highlight.html [ Failure ] +fast/overflow/line-clamp.html [ Failure ] fast/overflow/overflow-float-stacking.html [ Crash Failure ] fast/overflow/overflow-focus-ring.html [ Failure ] fast/overflow/overflow-rtl-vertical.html [ Failure ] @@ -1262,7 +1287,14 @@ fast/repaint/absolute-position-change-containing-block.html [ Failure ] fast/repaint/abspos-shift-image-incorrect-repaint.html [ Crash Failure ] fast/repaint/add-table-overpaint.html [ Failure ] +fast/repaint/align-content-change-keeping-geometry.html [ Failure ] +fast/repaint/align-content-change.html [ Failure ] +fast/repaint/align-content-distribution-change-grid.html [ Failure ] +fast/repaint/align-content-position-change-grid.html [ Failure ] +fast/repaint/align-self-change-grid.html [ Failure ] +fast/repaint/align-self-change-no-flex.html [ Failure ] fast/repaint/align-self-change.html [ Failure ] +fast/repaint/align-self-overflow-change.html [ Failure ] fast/repaint/background-generated.html [ Failure ] fast/repaint/background-image-paint-invalidation-large-abspos-div.html [ Failure ] fast/repaint/background-resize-height.html [ Failure ] @@ -1272,11 +1304,13 @@ fast/repaint/block-no-inflow-children.html [ Failure ] fast/repaint/block-shift-repaint.html [ Failure ] fast/repaint/border-box-sizing-invalidation.html [ Crash ] +fast/repaint/border-image-outset-change-repaint.html [ Failure ] fast/repaint/border-radius-repaint-2.html [ Failure ] fast/repaint/border-radius-repaint.html [ Failure ] fast/repaint/border-radius-without-border.html [ Failure ] fast/repaint/border-repaint-glitch.html [ Failure ] fast/repaint/box-inline-resize.html [ Crash Failure ] +fast/repaint/box-shadow-dynamic.html [ Failure ] fast/repaint/box-shadow-inset-repaint.html [ Failure ] fast/repaint/box-sizing.html [ Failure ] fast/repaint/bugzilla-5699.html [ Failure ] @@ -1297,6 +1331,7 @@ fast/repaint/composited-iframe-scroll-repaint.html [ Failure ] fast/repaint/containing-block-position-change.html [ Failure ] fast/repaint/content-into-overflow.html [ Failure ] +fast/repaint/continuation-after-outline.html [ Failure ] fast/repaint/crbug-371640-2.html [ Crash Failure ] fast/repaint/crbug-371640-3.html [ Crash Failure ] fast/repaint/crbug-371640-4.html [ Crash Failure ] @@ -1340,6 +1375,8 @@ fast/repaint/inline-focus.html [ Failure ] fast/repaint/inline-outline-repaint.html [ Failure ] fast/repaint/inline-style-change-in-scrolled-view.html [ Failure ] +fast/repaint/inline-vertical-lr-overflow.html [ Failure ] +fast/repaint/inline-vertical-rl-overflow.html [ Failure ] fast/repaint/intermediate-layout-position-clip.html [ Failure ] fast/repaint/intermediate-layout-position.html [ Failure ] fast/repaint/invalidate-paint-for-fixed-pos-inside-iframe.html [ Failure ] @@ -1347,7 +1384,11 @@ fast/repaint/invalidation-after-opacity-change-subtree.html [ Failure ] fast/repaint/invalidation-with-zero-size-object.html [ Failure ] fast/repaint/justify-content-change.html [ Failure ] +fast/repaint/justify-content-distribution-change-grid.html [ Failure ] +fast/repaint/justify-content-position-change-grid.html [ Failure ] fast/repaint/justify-content-position-change.html [ Failure ] +fast/repaint/justify-self-change.html [ Failure ] +fast/repaint/justify-self-overflow-change.html [ Failure ] fast/repaint/layout-state-scrolloffset3.html [ Failure ] fast/repaint/layoutstate-invalid-invalidation-inline-relative-positioned.html [ Crash Failure ] fast/repaint/line-flow-with-floats-1.html [ Failure ] @@ -1362,6 +1403,8 @@ fast/repaint/line-flow-with-floats-9.html [ Failure ] fast/repaint/line-in-scrolled-clipped-block.html [ Failure ] fast/repaint/list-marker-2.html [ Failure ] +fast/repaint/margin.html [ Failure ] +fast/repaint/mix-blend-mode-separate-stacking-context.html [ Failure ] fast/repaint/multicol-as-paint-container.html [ Failure ] fast/repaint/multicol-nested.html [ Failure ] fast/repaint/multicol-repaint.html [ Failure ] @@ -1392,6 +1435,7 @@ fast/repaint/paint-invalidation-with-reparent-across-frame-boundaries.html [ Failure ] fast/repaint/percent-size-image-resize-container.html [ Failure ] fast/repaint/position-change-keeping-geometry.html [ Failure ] +fast/repaint/positioned-document-element.html [ Failure ] fast/repaint/positioned-great-grandparent-change-location.html [ Crash Failure ] fast/repaint/positioned-list-offset-change-repaint.html [ Failure ] fast/repaint/push-block-with-first-line.html [ Crash Failure ] @@ -1401,6 +1445,7 @@ fast/repaint/relative-margin-change-repaint.html [ Failure ] fast/repaint/relative-positioned-movement-repaint.html [ Crash Failure ] fast/repaint/relayout-fixed-position-after-scale.html [ Crash Timeout ] +fast/repaint/remove-inline-after-layout.html [ Failure ] fast/repaint/remove-inline-block-descendant-of-flex.html [ Failure ] fast/repaint/renderer-destruction-by-invalidateSelection-crash.html [ Failure ] fast/repaint/repaint-composited-child-in-scrolled-container.html [ Failure ] @@ -1426,12 +1471,15 @@ fast/repaint/scroll-stacking-context-backface-visiblity-leaves-traces.html [ Failure ] fast/repaint/scroll-with-transformed-parent-layer.html [ Failure ] fast/repaint/scrollbar-damage-and-full-viewport-repaint.html [ Failure ] +fast/repaint/scrollbar-invalidation-on-resize-with-border.html [ Failure ] fast/repaint/scrolled-iframe-scrollbar-change.html [ Failure ] fast/repaint/selection-after-delete.html [ Failure ] fast/repaint/selection-clear-after-move.html [ Crash Failure ] fast/repaint/selection-clear.html [ Failure ] +fast/repaint/set-text-content-same.html [ Failure ] fast/repaint/shift-relative-positioned-container-with-image-addition.html [ Crash Failure ] fast/repaint/shift-relative-positioned-container-with-image-removal.html [ Crash Failure ] +fast/repaint/stacked-diacritics.html [ Failure ] fast/repaint/stacking-context-lost.html [ Failure ] fast/repaint/subtree-layoutstate-transform.html [ Failure ] fast/repaint/subtree-root-skipped.html [ Failure ] @@ -1448,8 +1496,11 @@ fast/repaint/table-shrink-row-repaint.html [ Crash Failure ] fast/repaint/table-two-pass-layout-overpaint.html [ Failure ] fast/repaint/table-with-padding-row-invalidation.html [ Crash Failure ] +fast/repaint/text-in-relative-positioned-inline.html [ Failure ] +fast/repaint/text-match-document-change.html [ Failure ] fast/repaint/text-selection-rect-in-overflow-2.html [ Failure ] fast/repaint/text-selection-rect-in-overflow.html [ Failure ] +fast/repaint/text-shadow.html [ Failure ] fast/repaint/transform-disable-layoutstate.html [ Failure ] fast/repaint/transform-inline-layered-child.html [ Failure ] fast/repaint/transform-layout-repaint.html [ Failure ] @@ -1478,13 +1529,17 @@ fast/replaced/border-radius-clip-content-edge.html [ Failure ] fast/replaced/border-radius-clip.html [ Failure ] fast/replaced/outline-replaced-elements.html [ Failure ] +fast/replaced/percent-height-in-anonymous-block-widget.html [ Failure ] fast/replaced/replaced-breaking-mixture.html [ Failure ] fast/replaced/replaced-breaking.html [ Failure ] fast/replaced/selection-rect-transform.html [ Failure ] fast/replaced/width100percent-button.html [ Failure ] fast/replaced/width100percent-textarea.html [ Failure ] +fast/ruby/rubyDOM-remove-text2.html [ Failure ] +fast/scrolling/background-paint-scrolled.html [ Failure ] fast/scrolling/overflow-clip-with-page-scale.html [ Crash Timeout ] fast/scrolling/scrollbar-tickmarks-styled.html [ Failure ] +fast/selectors/054.html [ Failure ] fast/selectors/166.html [ Failure ] fast/selectors/input-with-selection-pseudo-element.html [ Failure ] fast/shapes/shape-outside-floats/shape-outside-boxes-001.html [ Failure ] @@ -1527,13 +1582,16 @@ fast/table/form-with-table-style.html [ Failure ] fast/table/frame-and-rules.html [ Failure ] fast/table/height-percent-test.html [ Failure ] +fast/table/insert-cell-before-form.html [ Failure ] fast/table/multiple-captions-display.xhtml [ Failure ] fast/table/overflowHidden.html [ Failure ] fast/table/prepend-in-anonymous-table.html [ Failure ] fast/table/resize-table-repaint-percent-size-cell.html [ Failure ] fast/table/resize-table-repaint-vertical-align-cell.html [ Failure ] fast/table/resize-table-row-repaint.html [ Failure ] +fast/table/split-table-section-before-anonymous-block-2.html [ Failure ] fast/table/table-display-types-vertical.html [ Failure ] +fast/table/table-with-border-radius.html [ Failure ] fast/table/text-field-baseline.html [ Failure ] fast/text-autosizing/hackernews-comments.html [ Failure ] fast/text-autosizing/print-autosizing.html [ Crash Timeout ] @@ -1555,18 +1613,16 @@ fast/text/font-weight-variant.html [ Failure ] fast/text/international/bidi-listbox-atsui.html [ Failure ] fast/text/international/bidi-listbox.html [ Failure ] -fast/text/international/bidi-menulist.html [ Failure ] fast/text/international/bidi-neutral-run.html [ Failure ] fast/text/international/hindi-spacing.html [ Failure ] fast/text/international/inline-block-with-mixed-direction-words.html [ Failure ] -fast/text/international/menulist-width-rtl.html [ Failure ] fast/text/international/mixed-directionality-selection.html [ Failure ] -fast/text/international/pop-up-button-text-alignment-and-direction.html [ Failure ] fast/text/international/text-overflow-ellipsis-bidi.html [ Failure ] fast/text/international/thai-line-breaks.html [ Failure ] fast/text/letter-spacing-negative-opacity.html [ Failure ] fast/text/selection-hard-linebreak.html [ Failure ] fast/text/softHyphen.html [ Failure ] +fast/text/sub-pixel/text-scaling-rtl.html [ Failure ] fast/text/textIteratorNilRenderer.html [ Failure ] fast/text/unicode-fallback-font.html [ Failure ] fast/text/whitespace/024.html [ Failure ] @@ -1897,7 +1953,6 @@ svg/custom/use-css-no-effect-on-shadow-tree.svg [ Failure ] svg/custom/use-detach.svg [ Failure ] svg/custom/use-disappears-after-style-update.svg [ Failure ] -svg/custom/use-event-handler-on-referenced-element.svg [ Failure ] svg/custom/use-event-handler-on-use-element.svg [ Failure ] svg/custom/use-font-face-crash.svg [ Failure ] svg/custom/use-forward-refs.svg [ Failure ] @@ -2319,6 +2374,7 @@ svg/foreignObject/mask.html [ Failure ] svg/foreignObject/svg-document-as-direct-child.svg [ Failure ] svg/hixie/data-types/001.xml [ Failure ] +svg/hixie/error/006.xml [ Failure ] svg/hixie/error/012.xml [ Failure ] svg/hixie/error/013.xml [ Failure ] svg/hixie/error/017.xml [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process b/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process index 5f9177e6..502c5c9 100644 --- a/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process +++ b/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
@@ -8,6 +8,9 @@ http/tests/security/upgrade-insecure-requests/iframe-upgrade.https.html [ Crash ] http/tests/security/upgrade-insecure-requests/iframe-upgrade-csp.https.html [ Crash ] +# https://crbug.com/635400 - Origin header is set to "null" in HTTP POST request made using OpenURL code path. +http/tests/navigation/form-targets-cross-site-frame-post.html [ Failure ] + # https://crbug.com/582494 - [sigsegv / av] blink::Document::styleEngine. http/tests/security/mixedContent/insecure-plugin-in-iframe.html [ Crash ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index 9f6ad2c..8a96a90 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -12,15 +12,81 @@ # ====== Oilpan-only failures until here ====== -# Run these tests with under virtual/scalefactor... only. -crbug.com/567837 fast/hidpi/static [ Skip ] +# ====== Paint team owned tests from here ====== +# The paint team tracks and triages its test failures, and keeping them colocated +# makes tracking much easier. +# Covered directories are: +# compositing subdirectories but not compositing itself or compositing/animations +# fast/images, css3/images, +# fast/repaint +# paint +# svg +# fast/svg +# Some additional bugs that are caused by painting problems are also within this section. -# TODO(yosin): We should convert following tests to use asynchronous spell checker.scroll-in -crbug.com/563265 editing/spelling/context-menu-suggestions.html [ Skip ] -crbug.com/563265 editing/spelling/spellcheck-editable-on-focus-multiframe.html [ Skip ] -crbug.com/563265 editing/spelling/spellcheck-editable-on-focus-sync.html [ Skip ] -crbug.com/563265 editing/spelling/spelling-unified-emulation.html [ Skip ] +# Failures due to SPV2, that don't also fail without SPV2. DO NOT REBASELINE. +# SPv2 paint properties are still being implemented. +# +# These tests should not be rebaselined automatically, as our goal is to exactly match +# existing tests. We have skipped the entire spv2 directory and are adding [ Pass ] lines +# as we go. Please remove [ Pass ] lines instead of rebaselining these tests. +crbug.com/537409 virtual/spv2/ [ Skip ] +crbug.com/537409 virtual/spv2/paint/subpixel [ Pass ] +crbug.com/537409 virtual/spv2/fast/clip [ Pass ] +crbug.com/537409 virtual/spv2/fast/overflow [ Pass ] +crbug.com/563667 virtual/spv2/fast/block/basic/001.html [ Pass ] +crbug.com/563667 virtual/spv2/fast/block/positioning/static-distance-with-positioned-ancestor.html [ Pass ] +crbug.com/563667 virtual/spv2/fast/block/float/clamped-right-float.html [ Pass ] +crbug.com/580355 virtual/spv2/fast/block/basic/018.html [ Pass ] +crbug.com/580355 virtual/spv2/fast/block/basic/adding-near-anonymous-block.html [ Pass ] +crbug.com/580355 virtual/spv2/fast/block/basic/text-indent-rtl.html [ Pass ] +crbug.com/580355 virtual/spv2/fast/block/basic/white-space-pre-wraps.html [ Pass ] +crbug.com/580355 virtual/spv2/fast/block/float/001.html [ Pass ] +crbug.com/580355 virtual/spv2/fast/block/float/independent-align-positioning.html [ Pass ] +crbug.com/580355 virtual/spv2/fast/block/float/intruding-painted-twice.html [ Pass ] +crbug.com/580355 virtual/spv2/fast/block/float/shrink-to-fit-width.html [ Pass ] +crbug.com/580355 virtual/spv2/fast/block/float/table-relayout.html [ Pass ] +crbug.com/580355 virtual/spv2/fast/block/float/vertical-move-relayout.html [ Pass ] +crbug.com/580355 virtual/spv2/fast/block/margin-collapse/001.html [ Pass ] +crbug.com/580355 virtual/spv2/fast/block/margin-collapse/005.html [ Pass ] +crbug.com/580355 virtual/spv2/fast/block/margin-collapse/012.html [ Pass ] +crbug.com/580355 virtual/spv2/fast/block/margin-collapse/015.html [ Pass ] +crbug.com/580355 virtual/spv2/fast/block/margin-collapse/016.html [ Pass ] +crbug.com/580355 virtual/spv2/fast/block/margin-collapse/019.html [ Pass ] +crbug.com/580355 virtual/spv2/fast/block/margin-collapse/020.html [ Pass ] +crbug.com/580355 virtual/spv2/fast/block/margin-collapse/056.html [ Pass ] +crbug.com/580355 virtual/spv2/fast/block/margin-collapse/059.html [ Pass ] +crbug.com/580355 virtual/spv2/fast/block/margin-collapse/block-inside-inline/001.html [ Pass ] +crbug.com/580355 virtual/spv2/fast/block/margin-collapse/block-inside-inline/005.html [ Pass ] +crbug.com/580355 virtual/spv2/fast/block/margin-collapse/block-inside-inline/012.html [ Pass ] +crbug.com/580355 virtual/spv2/fast/block/margin-collapse/block-inside-inline/015.html [ Pass ] +crbug.com/580355 virtual/spv2/fast/block/margin-collapse/block-inside-inline/016.html [ Pass ] +crbug.com/580355 virtual/spv2/fast/block/margin-collapse/block-inside-inline/019.html [ Pass ] +crbug.com/580355 virtual/spv2/fast/block/margin-collapse/block-inside-inline/020.html [ Pass ] +crbug.com/580355 virtual/spv2/fast/block/positioning/height-change.html [ Pass ] +crbug.com/580355 virtual/spv2/fast/block/positioning/relayout-on-position-change.html [ Pass ] +crbug.com/587236 virtual/spv2/compositing/backface-visibility/backface-visibility-3d.html [ Pass ] +crbug.com/587236 virtual/spv2/compositing/backface-visibility/backface-visibility-simple.html [ Pass ] +crbug.com/587970 virtual/spv2/compositing/plugins/webplugin-alpha.html [ Pass ] +crbug.com/587970 virtual/spv2/compositing/plugins/webplugin-no-alpha.html [ Pass ] +crbug.com/596780 virtual/spv2/compositing/framesets/composited-frame-alignment.html [ Pass ] +crbug.com/596780 virtual/spv2/compositing/geometry/outline-change.html [ Pass ] +crbug.com/596780 virtual/spv2/compositing/squashing/incorrect-clip-after-remove-compositing.html [ Pass ] +crbug.com/600618 virtual/spv2/svg/custom/fill-update.svg [ Pass ] +crbug.com/600618 virtual/spv2/svg/custom/getscreenctm-in-mixed-content.xhtml [ Pass ] +crbug.com/600618 virtual/spv2/svg/custom/non-scaling-stroke-markers.svg [ Pass ] +crbug.com/600618 virtual/spv2/svg/custom/object-current-scale.html [ Pass ] +crbug.com/600618 virtual/spv2/svg/custom/object-sizing-explicit-height.xhtml [ Pass ] +crbug.com/600618 virtual/spv2/svg/custom/object-sizing-explicit-width-height.xhtml [ Pass ] +crbug.com/600618 virtual/spv2/svg/custom/object-sizing-explicit-width.xhtml [ Pass ] +crbug.com/600618 virtual/spv2/svg/custom/svg-root-padding-left.html [ Pass ] +crbug.com/600618 virtual/spv2/svg/custom/svg-root-padding-top.html [ Pass ] +crbug.com/600618 virtual/spv2/svg/css/max-height.html [ Pass ] +crbug.com/600618 virtual/spv2/svg/css/max-width.html [ Pass ] +crbug.com/614257 virtual/spv2/fast/block/positioning [ Pass ] +crbug.com/619427 [ Linux ] virtual/spv2/fast/overflow/overflow-height-float-not-removed-crash3.html [ Pass Failure ] +crbug.com/510908 virtual/spv2/svg/custom/object-sizing-no-width-height-change-content-box-size.xhtml [ Failure ] crbug.com/524134 virtual/spv2/paint/invalidation/invalidate-after-composited-scroll.html [ Failure ] crbug.com/524134 virtual/spv2/fast/repaint/focus-ring-on-continuation-move.html [ Failure ] crbug.com/524236 virtual/spv2/compositing/overflow/updating-scrolling-content.html [ Failure ] @@ -36,11 +102,208 @@ crbug.com/524236 virtual/spv2/compositing/repaint/should-not-repaint-composited-transform.html [ Failure ] crbug.com/524236 virtual/spv2/fast/repaint/clip-path-constant-repaint.html [ Failure ] crbug.com/524236 crbug.com/619103 virtual/spv2/fast/repaint/relative-positioned-movement-repaint.html [ Failure Crash Timeout ] -crbug.com/510908 virtual/spv2/svg/custom/object-sizing-no-width-height-change-content-box-size.xhtml [ Failure ] + +# PaintArtifactCompositor doesn't implement effects yet. +crbug.com/563667 virtual/spv2/fast/overflow/007.html [ Failure ] + +# Sub-pixel differences in layout tests for SPv2 +crbug.com/589265 virtual/spv2/fast/clip/nestedTransparencyClip.html [ Failure ] +crbug.com/589265 virtual/spv2/fast/clip/outline-overflowClip.html [ Failure ] +crbug.com/589265 virtual/spv2/fast/block/float/002.html [ Failure ] +crbug.com/589265 virtual/spv2/fast/overflow/001.html [ Failure ] +crbug.com/589265 virtual/spv2/fast/overflow/003.xml [ Failure ] +crbug.com/589265 virtual/spv2/fast/overflow/border-radius-clipping.html [ Failure ] +crbug.com/589265 virtual/spv2/fast/overflow/childFocusRingClip.html [ Failure ] +crbug.com/589265 virtual/spv2/fast/overflow/clip-rects-fixed-ancestor.html [ Failure ] +crbug.com/589265 virtual/spv2/fast/overflow/dynamic-hidden.html [ Failure ] +crbug.com/589265 virtual/spv2/fast/overflow/float-in-relpositioned.html [ Failure ] +crbug.com/589265 virtual/spv2/fast/overflow/hit-test-overflow-controls.html [ Failure ] +crbug.com/589265 virtual/spv2/fast/overflow/image-selection-highlight.html [ Failure ] +crbug.com/589265 virtual/spv2/fast/overflow/overflow-float-stacking.html [ Failure ] +crbug.com/589265 virtual/spv2/fast/overflow/overflow-focus-ring.html [ Failure ] +crbug.com/589265 virtual/spv2/fast/overflow/overflow-stacking.html [ Failure ] +crbug.com/589265 virtual/spv2/fast/overflow/overflow-text-hit-testing.html [ Failure ] +crbug.com/589265 virtual/spv2/fast/overflow/overflow-update-transform.html [ Failure ] +crbug.com/589265 virtual/spv2/fast/overflow/overflow-with-local-background-attachment.html [ Failure ] +crbug.com/589265 virtual/spv2/fast/overflow/scroll-nested-positioned-layer-in-overflow.html [ Failure ] +crbug.com/589265 virtual/spv2/fast/overflow/scrollbar-position-update.html [ Failure ] +crbug.com/589265 virtual/spv2/compositing/geometry/root-layer-update.html [ Failure ] + +# Implement scrollbars in FramePainter for SPv2 +crbug.com/589279 virtual/spv2/fast/overflow/006.html [ Failure ] +crbug.com/589279 virtual/spv2/fast/overflow/hidden-viewport-x.html [ Failure ] +crbug.com/589279 virtual/spv2/fast/overflow/hidden-viewport-y.html [ Failure ] +crbug.com/589279 virtual/spv2/fast/overflow/overflow-x-y.html [ Failure ] +crbug.com/589279 virtual/spv2/fast/overflow/position-fixed-transform-clipping.html [ Failure ] +crbug.com/589279 virtual/spv2/fast/overflow/scrollRevealButton.html [ Failure ] +crbug.com/589279 virtual/spv2/fast/block/positioning/047.html [ Failure ] +crbug.com/589279 virtual/spv2/fast/block/positioning/051.html [ Failure ] +crbug.com/589279 virtual/spv2/fast/block/positioning/055.html [ Failure ] +crbug.com/589279 virtual/spv2/fast/block/positioning/auto/007.html [ Failure ] +crbug.com/589279 virtual/spv2/fast/block/positioning/fixed-positioning-scrollbar-bug.html [ Failure ] +crbug.com/589279 virtual/spv2/fast/block/positioning/relative-overflow-block.html [ Failure ] +crbug.com/589279 virtual/spv2/fast/block/positioning/relative-overflow-replaced-float.html [ Failure ] +crbug.com/589279 virtual/spv2/fast/block/positioning/relative-overflow-replaced.html [ Failure ] +crbug.com/589279 virtual/spv2/fast/block/positioning/vertical-lr/002.html [ Failure ] +crbug.com/589279 virtual/spv2/fast/block/positioning/vertical-rl/002.html [ Failure ] +crbug.com/589279 virtual/spv2/fast/block/positioning/auto/vertical-lr/005.html [ Failure ] +crbug.com/589279 virtual/spv2/fast/block/positioning/auto/vertical-rl/005.html [ Failure ] + +# Implement table walk in PaintPropertyTreeBuilder. +crbug.com/593525 virtual/spv2/fast/overflow/002.html [ Failure ] +crbug.com/593525 virtual/spv2/fast/overflow/overflow-rtl-vertical.html [ Failure ] +crbug.com/593525 virtual/spv2/fast/overflow/overflow-rtl.html [ Failure ] +crbug.com/593525 virtual/spv2/fast/overflow/table-overflow-float.html [ Failure ] + +# These failures have been manually verified to be only paint invalidation text differences. +crbug.com/596780 virtual/spv2/compositing/geometry/bounds-clipped-composited-child.html [ Failure ] +crbug.com/596780 virtual/spv2/compositing/geometry/bounds-ignores-hidden-dynamic-negzindex.html [ Failure ] +crbug.com/596780 virtual/spv2/compositing/geometry/bounds-ignores-hidden-dynamic.html [ Failure ] +crbug.com/596780 virtual/spv2/compositing/rtl/rtl-iframe-absolute-overflow.html [ Failure ] +crbug.com/596780 virtual/spv2/compositing/rtl/rtl-iframe-absolute.html [ Failure ] +crbug.com/596780 virtual/spv2/compositing/rtl/rtl-iframe-fixed-overflow.html [ Failure ] +crbug.com/596780 virtual/spv2/compositing/rtl/rtl-iframe-fixed.html [ Failure ] +crbug.com/596780 virtual/spv2/compositing/rtl/rtl-iframe-relative.html [ Failure ] +crbug.com/596780 virtual/spv2/compositing/visibility/layer-visible-content.html [ Failure ] + +# [SPv2] Handle transform space reversion in PaintArtifactCompositor +crbug.com/597156 virtual/spv2/fast/clip/010.html [ Crash Failure Timeout ] + +# [SPv2] Implement border radius rasterizing / drawing +crbug.com/597158 virtual/spv2/fast/clip/overflow-border-radius-clip.html [ Failure ] +crbug.com/597158 virtual/spv2/fast/clip/overflow-border-radius-combinations.html [ Failure ] +crbug.com/597158 virtual/spv2/fast/clip/overflow-border-radius-composited-parent.html [ Failure ] +crbug.com/597158 virtual/spv2/fast/clip/overflow-border-radius-composited.html [ Failure ] +crbug.com/597158 virtual/spv2/fast/clip/overflow-border-radius-fixed-position.html [ Failure ] +crbug.com/597158 virtual/spv2/fast/clip/overflow-border-radius-transformed.html [ Failure ] + +# This test has a paint invalidation failure that needs to be investigated. +crbug.com/600618 virtual/spv2/svg/as-image/svg-image-with-data-uri.html [ Failure Crash ] + +# SkiaBitLocker should avoid allocating huge offscreen buffer +crbug.com/605812 [ Mac ] virtual/spv2/fast/overflow/overflow-height-float-not-removed-crash.html [ Skip ] +crbug.com/605812 [ Mac ] virtual/spv2/fast/overflow/overflow-height-float-not-removed-crash2.html [ Skip ] + +# Multicolumn still fails to fragment in spv2. +crbug.com/616287 virtual/spv2/fast/block/positioning/offsetLeft-offsetTop-multicolumn.html [ Failure ] + +# --- End SPV2 Tests --- + +crbug.com/240374 compositing/overlap-blending/reflection-opacity-huge.html [ Failure ] +crbug.com/240374 compositing/overlap-blending/children-opacity-huge.html [ Failure ] +crbug.com/240374 compositing/overlap-blending/children-opacity-no-overlap.html [ Failure ] + +crbug.com/245556 compositing/transitions/transform-on-large-layer.html [ Failure ] + +crbug.com/309675 compositing/gestures/gesture-tapHighlight-simple-longPress.html [ Failure ] + +crbug.com/320139 fast/repaint/block-layout-inline-children-replaced.html [ Pass Failure ] + +# Started failing after r162705. +crbug.com/324370 compositing/video/video-reflection.html [ Failure ] + +crbug.com/396775 compositing/overflow/reflected-overlay-scrollbars-should-appear-without-compositing.html [ Failure ] +crbug.com/396775 virtual/prefer_compositing_to_lcd_text/compositing/overflow/reflected-overlay-scrollbars-should-appear-without-compositing.html [ Failure ] + +crbug.com/425113 svg/clip-path/clip-path-multiple-children.svg [ Failure ] + +# Significant Slimming Paint failure. +crbug.com/459305 [ Mac ] svg/custom/foreign-object-skew.svg [ Failure ] + +crbug.com/463358 [ Mac Linux ] fast/transforms/transformed-caret.html [ Pass Failure ] +crbug.com/463358 [ Mac Linux ] svg/W3C-SVG-1.1/paths-data-02-t.svg [ Pass Failure ] +crbug.com/466200 svg/custom/repaint-on-constant-size-change.svg [ Failure ] +crbug.com/474798 fast/repaint/align-self-change-keeping-geometry-grid.html [ Failure ] +crbug.com/474798 fast/repaint/justify-self-change-keeping-geometry.html [ Failure ] +crbug.com/482229 compositing/layer-creation/fixed-position-under-transform.html [ Failure ] +crbug.com/484370 [ Win Debug ] svg/custom/gradient-userSpaceOnUse-with-percentage.svg [ Failure ] +crbug.com/487344 compositing/video/video-controls-layer-creation.html [ Failure ] +crbug.com/495523 svg/wicd/test-rightsizing-b.xhtml [ Failure Pass ] + +crbug.com/502531 fast/borders/border-antialiasing.html [ Failure ] crbug.com/504613 crbug.com/524248 paint/images/image-backgrounds-not-antialiased.html [ Skip ] crbug.com/504613 crbug.com/524248 virtual/spv2/paint/images/image-backgrounds-not-antialiased.html [ Skip ] -crbug.com/502531 fast/borders/border-antialiasing.html [ Failure ] + +crbug.com/509025 [ Mac10.10 ] virtual/prefer_compositing_to_lcd_text/compositing/overflow/theme-affects-visual-overflow.html [ Failure ] +crbug.com/516364 svg/animations/smil-leak-element-instances.svg [ Failure Pass ] +crbug.com/517449 [ Android ] css3/images/optimize-contrast-image.html [ Failure ] +crbug.com/520166 compositing/overflow/do-not-repaint-if-scrolling-composited-layers.html [ Failure Pass ] + +crbug.com/520177 [ Android ] fast/images/style-access-during-imageChanged-crash.html [ Crash Failure Pass ] +crbug.com/552433 [ Win7 Debug ] svg/W3C-SVG-1.1/coords-units-02-b.svg [ Failure ] +crbug.com/582230 fast/repaint/align-items-change.html [ Skip ] +crbug.com/582230 fast/repaint/align-items-overflow-change.html [ Skip ] + +crbug.com/591500 [ Win10 ] compositing/squashing/squashing-print.html [ Failure ] + +crbug.com/592185 fast/repaint/fixed-right-in-page-scale.html [ Failure Pass ] + +crbug.com/600087 virtual/gpu-rasterization/fast/images/pixel-crack-image-background-webkit-transform-scale.html [ Timeout ] + +crbug.com/601669 [ Win ] svg/as-image/svg-nested.html [ Crash Pass ] + +crbug.com/603997 compositing/overflow/clear-scroll-parent.html [ Failure ] +crbug.com/603997 virtual/prefer_compositing_to_lcd_text/compositing/overflow/clear-scroll-parent.html [ Failure ] + +crbug.com/619103 fast/repaint/background-resize-width.html [ Failure ] +crbug.com/619103 fast/repaint/hover-invalidation-table.html [ Failure ] +crbug.com/619103 fast/repaint/selected-replaced.html [ Failure ] +crbug.com/619103 paint/invalidation/invalidate-after-composited-scroll-of-window.html [ Failure ] +crbug.com/619103 paint/invalidation/animated-gif.html [ Pass Failure ] +crbug.com/619103 paint/invalidation/animated-gif-background.html [ Pass Failure ] +crbug.com/619103 paint/invalidation/animated-gif-background-offscreen.html [ Pass Failure ] +crbug.com/619103 [ Win ] svg/text/text-viewbox-rescale.html [ Pass Failure ] +crbug.com/619103 paint/overflow/interest-rect-change-scroll-down.html [ Failure ] +crbug.com/619103 paint/selection/text-selection-newline-mixed-ltr-rtl.html [ Failure ] +crbug.com/619103 paint/selection/text-selection-newline-rtl-double-linebreak.html [ Failure ] +crbug.com/619103 fast/layers/remove-layer-with-nested-stacking.html [ Pass Crash Timeout ] +crbug.com/619103 compositing/iframes/become-composited-nested-iframes.html [ Pass Crash Timeout ] + +crbug.com/622368 [ Linux Win Debug ] fast/repaint/obscured-background-no-repaint.html [ Pass Failure ] + +# TODO(fmalita): re-enable +# crbug.com/624709 [ Win ] virtual/gpu-rasterization/fast/images/png-with-color-profile.html [ Failure ] +crbug.com/624709 [ Win ] virtual/gpu-rasterization/fast/images/webp-color-profile-lossy.html [ Failure ] +crbug.com/587737 [ Mac10.11 Retina ] virtual/gpu-rasterization/fast/images/color-profile-filter.html [ Timeout Failure ] +crbug.com/603728 [ Linux ] virtual/gpu-rasterization/fast/images/color-profile-filter.html [ Failure Timeout Pass ] +crbug.com/624233 [ Win ] virtual/gpu-rasterization/fast/images/color-profile-background-clip-text.html [ Failure ] + +crbug.com/627782 [ Win ] svg/filters/filter-source-position.svg [ Pass Failure ] + +crbug.com/630615 [ Win7 ] fast/images/color-profile-background-image-space.html [ Skip ] + +crbug.com/630870 svg/animations/use-animate-width-and-height.html [ Skip ] + +crbug.com/630967 [ Linux Debug ] svg/parser/whitespace-length-invalid-1.html [ Skip ] +crbug.com/630967 [ Linux Debug ] svg/parser/whitespace-length-invalid-2.html [ Skip ] +crbug.com/630967 [ Linux Debug ] svg/parser/whitespace-angle.html [ Skip ] + +crbug.com/632000 [ Win ] fast/images/paint-subrect-grid.html [ Pass Failure ] + +# Broken on Win10 +crbug.com/632217 [ Win10 ] svg/W3C-SVG-1.1/filters-composite-02-b.svg [ Failure ] + +crbug.com/632548 [ Win ] fast/repaint/overflow-scroll-body-appear.html [ Pass Failure ] +crbug.com/632548 [ Win ] fast/repaint/invalidation-after-opacity-change-subtree.html [ Pass Failure ] +crbug.com/632548 [ Win ] compositing/overflow/text-match-highlight.html [ Pass Failure ] + +crbug.com/636222 [ Mac10.10 ] fast/repaint/fixed-and-absolute-position-scrolled.html [ Failure ] + +crbug.com/636271 [ Mac10.10 ] fast/repaint/resize-iframe-text.html [ Pass Failure ] + +crbug.com/636311 [ Win10 ] svg/custom/use-clipped-hit.svg [ Pass Failure ] + +# ====== Paint team owned tests to here ====== + +# Run these tests with under virtual/scalefactor... only. +crbug.com/567837 fast/hidpi/static [ Skip ] + +# TODO(yosin): We should convert following tests to use asynchronous spell checker.scroll-in +crbug.com/563265 editing/spelling/context-menu-suggestions.html [ Skip ] +crbug.com/563265 editing/spelling/spellcheck-editable-on-focus-multiframe.html [ Skip ] +crbug.com/563265 editing/spelling/spellcheck-editable-on-focus-sync.html [ Skip ] +crbug.com/563265 editing/spelling/spelling-unified-emulation.html [ Skip ] crbug.com/538697 [ Win7 Debug ] virtual/threaded/printing/webgl-oversized-printing.html [ Failure Crash ] crbug.com/538697 [ Win7 Debug ] printing/webgl-oversized-printing.html [ Failure Crash ] @@ -62,8 +325,6 @@ crbug.com/492664 [ Mac ] imported/csswg-test/css-writing-modes-3/bidi-isolate-002.html [ Failure ] crbug.com/492664 [ Win ] imported/csswg-test/css-writing-modes-3/bidi-override-005.html [ Failure ] crbug.com/492664 [ Win ] imported/csswg-test/css-writing-modes-3/bidi-plaintext-001.html [ Failure ] -crbug.com/463358 [ Mac Linux ] fast/transforms/transformed-caret.html [ Pass Failure ] -crbug.com/463358 [ Mac Linux ] svg/W3C-SVG-1.1/paths-data-02-t.svg [ Pass Failure ] crbug.com/267206 [ Mac ] virtual/rootlayerscrolls/fast/scrolling/scrollbar-tickmarks-hittest.html [ Timeout ] @@ -87,11 +348,9 @@ crbug.com/521094 [ Mac ] http/tests/navigation/beacon-cross-origin.https.html [ Crash Failure Pass ] crbug.com/521096 imported/wpt/webstorage/event_case_sensitive.html [ Failure Pass ] crbug.com/521107 [ Debug ] fast/html/imports/import-custom-element-abort.html [ Crash Pass ] -crbug.com/520166 compositing/overflow/do-not-repaint-if-scrolling-composited-layers.html [ Failure Pass ] crbug.com/520169 [ Win ] fast/dom/Geolocation/timestamp.html [ Failure Pass ] crbug.com/520170 [ Win ] fast/dom/timer-throttling-hidden-page.html [ Failure Pass ] crbug.com/520174 fast/events/message-port-start-and-close-different-microtask.html [ Failure Pass ] -crbug.com/520177 [ Android ] fast/images/style-access-during-imageChanged-crash.html [ Crash Failure Pass ] crbug.com/520180 [ Linux ] fast/text/basic/001.html [ Pass Timeout ] crbug.com/520183 http/tests/fouc/scroll-left-while-loading.html [ Pass Timeout ] crbug.com/520184 http/tests/history/frameset-repeated-name.html [ Failure Pass ] @@ -134,12 +393,18 @@ crbug.com/567965 [ Debug ] imported/wpt/user-timing/test_user_timing_mark.html [ Skip ] crbug.com/518993 imported/wpt/user-timing/test_user_timing_measure_navigation_timing.html [ Skip ] +crbug.com/636053 [ Mac Win ] printing/thead-repeats-at-top-of-each-page-multiple-tables.html [ NeedsManualRebaseline ] +crbug.com/636053 [ Mac Win ] virtual/threaded/printing/thead-repeats-at-top-of-each-page-multiple-tables.html [ NeedsManualRebaseline ] + crbug.com/519001 storage/indexeddb/pending-version-change-stuck-works-with-terminate.html [ Pass Timeout ] crbug.com/519002 storage/indexeddb/pending-version-change-stuck.html [ Pass Timeout ] crbug.com/410949 http/tests/security/local-image-from-remote-whitelisted.html [ Failure Pass ] crbug.com/518915 [ Android ] accessibility/aria-labelledby-on-input.html [ Crash Pass ] crbug.com/445100 fast/block/float/marquee-shrink-to-avoid-floats.html [ Failure Pass ] +crbug.com/636239 [ Mac10.10 Mac10.11 Retina ] media/video-zoom-controls.html [ Failure Pass ] +crbug.com/636239 [ Win7 ] media/video-zoom-controls.html [ Failure ] + crbug.com/548226 [ Win ] fast/events/pointerevents/mouse-pointer-event-properties.html [ Failure Pass ] crbug.com/548226 [ Win ] fast/events/pointerevents/multi-pointer-preventdefault.html [ Failure Pass ] @@ -151,8 +416,6 @@ crbug.com/248938 virtual/threaded/animations/change-one-anim.html [ Failure Pass ] crbug.com/326139 crbug.com/390125 media/video-frame-accurate-seek.html [ Failure Pass ] crbug.com/413604 http/tests/loading/script-priorities.html [ Failure Pass ] -crbug.com/495523 svg/wicd/test-rightsizing-b.xhtml [ Failure Pass ] -crbug.com/516364 svg/animations/smil-leak-element-instances.svg [ Failure Pass ] crbug.com/248938 virtual/threaded/animations/3d/transform-origin-vs-functions.html [ Pass Failure ] crbug.com/248938 virtual/threaded/transitions/cancel-transition.html [ Pass Failure ] crbug.com/248938 virtual/threaded/transitions/extra-transition.html [ Pass Failure ] @@ -199,6 +462,8 @@ crbug.com/389648 crbug.com/517123 crbug.com/410145 fast/text-autosizing/table-inflation-crash.html [ Pass Crash Timeout ] crbug.com/419696 [ Mac Debug ] fast/text/font-linux-normalize.html [ Crash Pass ] +crbug.com/636207 [ Win Debug ] fast/dom/HTMLImageElement/image-srcset-w-onerror.html [ Failure Pass ] + crbug.com/569139 fast/js/string-replace-2.html [ Failure ] crbug.com/569139 fast/js/regexp-caching.html [ Failure ] crbug.com/597221 fast/dom/Window/window-postmessage-clone-deep-array.html [ Failure ] @@ -261,8 +526,6 @@ crbug.com/548904 [ Linux Win ] fast/writing-mode/Kusa-Makura-background-canvas.html [ Failure Pass ] -crbug.com/552433 [ Win7 Debug ] svg/W3C-SVG-1.1/coords-units-02-b.svg [ Failure ] - # This directly has manual tests that don't have to run with run-webkit-tests crbug.com/359838 http/tests/ManualTests/ [ Skip ] @@ -272,157 +535,11 @@ # Text::inDocument() returns false but should not. crbug.com/264138 dom/xhtml/level3/core/nodecomparedocumentposition38.xhtml [ Failure ] -crbug.com/240374 compositing/overlap-blending/reflection-opacity-huge.html [ Failure ] -crbug.com/240374 compositing/overlap-blending/children-opacity-huge.html [ Failure ] -crbug.com/240374 compositing/overlap-blending/children-opacity-no-overlap.html [ Failure ] - crbug.com/410145 [ Win ] fast/table/column-in-inline.html [ Failure ] crbug.com/411164 [ Win ] http/tests/security/powerfulFeatureRestrictions/serviceworker-on-insecure-origin.html [ Pass ] crbug.com/475984 [ Mac Debug ] css2.1/t100801-c544-valgn-03-d-agi.html [ Failure ] -# SPv2 paint properties are still being implemented. -# -# These tests should not be rebaselined automatically, as our goal is to exactly match -# existing tests. We have skipped the entire spv2 directory and are adding [ Pass ] lines -# as we go. Please remove [ Pass ] lines instead of rebaselining these tests. -crbug.com/537409 virtual/spv2/ [ Skip ] -crbug.com/563667 virtual/spv2/fast/block/basic/001.html [ Pass ] -crbug.com/563667 virtual/spv2/fast/block/positioning/static-distance-with-positioned-ancestor.html [ Pass ] -crbug.com/563667 virtual/spv2/fast/block/float/clamped-right-float.html [ Pass ] -crbug.com/580355 virtual/spv2/fast/block/basic/018.html [ Pass ] -crbug.com/580355 virtual/spv2/fast/block/basic/adding-near-anonymous-block.html [ Pass ] -crbug.com/580355 virtual/spv2/fast/block/basic/text-indent-rtl.html [ Pass ] -crbug.com/580355 virtual/spv2/fast/block/basic/white-space-pre-wraps.html [ Pass ] -crbug.com/580355 virtual/spv2/fast/block/float/001.html [ Pass ] -crbug.com/580355 virtual/spv2/fast/block/float/independent-align-positioning.html [ Pass ] -crbug.com/580355 virtual/spv2/fast/block/float/intruding-painted-twice.html [ Pass ] -crbug.com/580355 virtual/spv2/fast/block/float/shrink-to-fit-width.html [ Pass ] -crbug.com/580355 virtual/spv2/fast/block/float/table-relayout.html [ Pass ] -crbug.com/580355 virtual/spv2/fast/block/float/vertical-move-relayout.html [ Pass ] -crbug.com/580355 virtual/spv2/fast/block/margin-collapse/001.html [ Pass ] -crbug.com/580355 virtual/spv2/fast/block/margin-collapse/005.html [ Pass ] -crbug.com/580355 virtual/spv2/fast/block/margin-collapse/012.html [ Pass ] -crbug.com/580355 virtual/spv2/fast/block/margin-collapse/015.html [ Pass ] -crbug.com/580355 virtual/spv2/fast/block/margin-collapse/016.html [ Pass ] -crbug.com/580355 virtual/spv2/fast/block/margin-collapse/019.html [ Pass ] -crbug.com/580355 virtual/spv2/fast/block/margin-collapse/020.html [ Pass ] -crbug.com/580355 virtual/spv2/fast/block/margin-collapse/056.html [ Pass ] -crbug.com/580355 virtual/spv2/fast/block/margin-collapse/059.html [ Pass ] -crbug.com/580355 virtual/spv2/fast/block/margin-collapse/block-inside-inline/001.html [ Pass ] -crbug.com/580355 virtual/spv2/fast/block/margin-collapse/block-inside-inline/005.html [ Pass ] -crbug.com/580355 virtual/spv2/fast/block/margin-collapse/block-inside-inline/012.html [ Pass ] -crbug.com/580355 virtual/spv2/fast/block/margin-collapse/block-inside-inline/015.html [ Pass ] -crbug.com/580355 virtual/spv2/fast/block/margin-collapse/block-inside-inline/016.html [ Pass ] -crbug.com/580355 virtual/spv2/fast/block/margin-collapse/block-inside-inline/019.html [ Pass ] -crbug.com/580355 virtual/spv2/fast/block/margin-collapse/block-inside-inline/020.html [ Pass ] -crbug.com/580355 virtual/spv2/fast/block/positioning/height-change.html [ Pass ] -crbug.com/580355 virtual/spv2/fast/block/positioning/relayout-on-position-change.html [ Pass ] -crbug.com/596780 virtual/spv2/compositing/framesets/composited-frame-alignment.html [ Pass ] -crbug.com/596780 virtual/spv2/compositing/geometry/outline-change.html [ Pass ] -crbug.com/596780 virtual/spv2/compositing/squashing/incorrect-clip-after-remove-compositing.html [ Pass ] -crbug.com/600618 virtual/spv2/svg/custom/fill-update.svg [ Pass ] -crbug.com/600618 virtual/spv2/svg/custom/getscreenctm-in-mixed-content.xhtml [ Pass ] -crbug.com/600618 virtual/spv2/svg/custom/non-scaling-stroke-markers.svg [ Pass ] -crbug.com/600618 virtual/spv2/svg/custom/object-current-scale.html [ Pass ] -crbug.com/600618 virtual/spv2/svg/custom/object-sizing-explicit-height.xhtml [ Pass ] -crbug.com/600618 virtual/spv2/svg/custom/object-sizing-explicit-width-height.xhtml [ Pass ] -crbug.com/600618 virtual/spv2/svg/custom/object-sizing-explicit-width.xhtml [ Pass ] -crbug.com/600618 virtual/spv2/svg/custom/svg-root-padding-left.html [ Pass ] -crbug.com/600618 virtual/spv2/svg/custom/svg-root-padding-top.html [ Pass ] -crbug.com/600618 virtual/spv2/svg/css/max-height.html [ Pass ] -crbug.com/600618 virtual/spv2/svg/css/max-width.html [ Pass ] - -crbug.com/537409 virtual/spv2/paint/subpixel [ Pass ] -crbug.com/537409 virtual/spv2/fast/clip [ Pass ] -crbug.com/537409 virtual/spv2/fast/overflow [ Pass ] -crbug.com/619427 [ Linux ] virtual/spv2/fast/overflow/overflow-height-float-not-removed-crash3.html [ Pass Failure ] -crbug.com/614257 virtual/spv2/fast/block/positioning [ Pass ] - -# PaintArtifactCompositor doesn't implement effects yet. -crbug.com/563667 virtual/spv2/fast/overflow/007.html [ Failure ] -# Sub-pixel differences in layout tests for SPv2 -crbug.com/589265 virtual/spv2/fast/clip/nestedTransparencyClip.html [ Failure ] -crbug.com/589265 virtual/spv2/fast/clip/outline-overflowClip.html [ Failure ] -crbug.com/589265 virtual/spv2/fast/block/float/002.html [ Failure ] -crbug.com/589265 virtual/spv2/fast/overflow/001.html [ Failure ] -crbug.com/589265 virtual/spv2/fast/overflow/003.xml [ Failure ] -crbug.com/589265 virtual/spv2/fast/overflow/border-radius-clipping.html [ Failure ] -crbug.com/589265 virtual/spv2/fast/overflow/childFocusRingClip.html [ Failure ] -crbug.com/589265 virtual/spv2/fast/overflow/clip-rects-fixed-ancestor.html [ Failure ] -crbug.com/589265 virtual/spv2/fast/overflow/dynamic-hidden.html [ Failure ] -crbug.com/589265 virtual/spv2/fast/overflow/float-in-relpositioned.html [ Failure ] -crbug.com/589265 virtual/spv2/fast/overflow/hit-test-overflow-controls.html [ Failure ] -crbug.com/589265 virtual/spv2/fast/overflow/image-selection-highlight.html [ Failure ] -crbug.com/589265 virtual/spv2/fast/overflow/overflow-float-stacking.html [ Failure ] -crbug.com/589265 virtual/spv2/fast/overflow/overflow-focus-ring.html [ Failure ] -crbug.com/589265 virtual/spv2/fast/overflow/overflow-stacking.html [ Failure ] -crbug.com/589265 virtual/spv2/fast/overflow/overflow-text-hit-testing.html [ Failure ] -crbug.com/589265 virtual/spv2/fast/overflow/overflow-update-transform.html [ Failure ] -crbug.com/589265 virtual/spv2/fast/overflow/overflow-with-local-background-attachment.html [ Failure ] -crbug.com/589265 virtual/spv2/fast/overflow/scroll-nested-positioned-layer-in-overflow.html [ Failure ] -crbug.com/589265 virtual/spv2/fast/overflow/scrollbar-position-update.html [ Failure ] -crbug.com/589265 virtual/spv2/compositing/geometry/root-layer-update.html [ Failure ] - -# Multicolumn still fails to fragment in spv2. -crbug.com/616287 virtual/spv2/fast/block/positioning/offsetLeft-offsetTop-multicolumn.html [ Failure ] - -# Implement scrollbars in FramePainter for SPv2 -crbug.com/589279 virtual/spv2/fast/overflow/006.html [ Failure ] -crbug.com/589279 virtual/spv2/fast/overflow/hidden-viewport-x.html [ Failure ] -crbug.com/589279 virtual/spv2/fast/overflow/hidden-viewport-y.html [ Failure ] -crbug.com/589279 virtual/spv2/fast/overflow/overflow-x-y.html [ Failure ] -crbug.com/589279 virtual/spv2/fast/overflow/position-fixed-transform-clipping.html [ Failure ] -crbug.com/589279 virtual/spv2/fast/overflow/scrollRevealButton.html [ Failure ] -crbug.com/589279 virtual/spv2/fast/block/positioning/047.html [ Failure ] -crbug.com/589279 virtual/spv2/fast/block/positioning/051.html [ Failure ] -crbug.com/589279 virtual/spv2/fast/block/positioning/055.html [ Failure ] -crbug.com/589279 virtual/spv2/fast/block/positioning/auto/007.html [ Failure ] -crbug.com/589279 virtual/spv2/fast/block/positioning/fixed-positioning-scrollbar-bug.html [ Failure ] -crbug.com/589279 virtual/spv2/fast/block/positioning/relative-overflow-block.html [ Failure ] -crbug.com/589279 virtual/spv2/fast/block/positioning/relative-overflow-replaced-float.html [ Failure ] -crbug.com/589279 virtual/spv2/fast/block/positioning/relative-overflow-replaced.html [ Failure ] -crbug.com/589279 virtual/spv2/fast/block/positioning/vertical-lr/002.html [ Failure ] -crbug.com/589279 virtual/spv2/fast/block/positioning/vertical-rl/002.html [ Failure ] -crbug.com/589279 virtual/spv2/fast/block/positioning/auto/vertical-lr/005.html [ Failure ] -crbug.com/589279 virtual/spv2/fast/block/positioning/auto/vertical-rl/005.html [ Failure ] -# Implement table walk in PaintPropertyTreeBuilder. -crbug.com/593525 virtual/spv2/fast/overflow/002.html [ Failure ] -crbug.com/593525 virtual/spv2/fast/overflow/overflow-rtl-vertical.html [ Failure ] -crbug.com/593525 virtual/spv2/fast/overflow/overflow-rtl.html [ Failure ] -crbug.com/593525 virtual/spv2/fast/overflow/table-overflow-float.html [ Failure ] -# [SPv2] Handle transform space reversion in PaintArtifactCompositor -crbug.com/597156 virtual/spv2/fast/clip/010.html [ Crash Failure Timeout ] -# [SPv2] Implement border radius rasterizing / drawing -crbug.com/597158 virtual/spv2/fast/clip/overflow-border-radius-clip.html [ Failure ] -crbug.com/597158 virtual/spv2/fast/clip/overflow-border-radius-combinations.html [ Failure ] -crbug.com/597158 virtual/spv2/fast/clip/overflow-border-radius-composited-parent.html [ Failure ] -crbug.com/597158 virtual/spv2/fast/clip/overflow-border-radius-composited.html [ Failure ] -crbug.com/597158 virtual/spv2/fast/clip/overflow-border-radius-fixed-position.html [ Failure ] -crbug.com/597158 virtual/spv2/fast/clip/overflow-border-radius-transformed.html [ Failure ] -# SkiaBitLocker should avoid allocating huge offscreen buffer -crbug.com/605812 [ Mac ] virtual/spv2/fast/overflow/overflow-height-float-not-removed-crash.html [ Skip ] -crbug.com/605812 [ Mac ] virtual/spv2/fast/overflow/overflow-height-float-not-removed-crash2.html [ Skip ] - -crbug.com/587236 virtual/spv2/compositing/backface-visibility/backface-visibility-3d.html [ Pass ] -crbug.com/587236 virtual/spv2/compositing/backface-visibility/backface-visibility-simple.html [ Pass ] -crbug.com/587970 virtual/spv2/compositing/plugins/webplugin-alpha.html [ Pass ] -crbug.com/587970 virtual/spv2/compositing/plugins/webplugin-no-alpha.html [ Pass ] - -# These failures have been manually verified to be only paint invalidation text differences. -crbug.com/596780 virtual/spv2/compositing/geometry/bounds-clipped-composited-child.html [ Failure ] -crbug.com/596780 virtual/spv2/compositing/geometry/bounds-ignores-hidden-dynamic-negzindex.html [ Failure ] -crbug.com/596780 virtual/spv2/compositing/geometry/bounds-ignores-hidden-dynamic.html [ Failure ] -crbug.com/596780 virtual/spv2/compositing/rtl/rtl-iframe-absolute-overflow.html [ Failure ] -crbug.com/596780 virtual/spv2/compositing/rtl/rtl-iframe-absolute.html [ Failure ] -crbug.com/596780 virtual/spv2/compositing/rtl/rtl-iframe-fixed-overflow.html [ Failure ] -crbug.com/596780 virtual/spv2/compositing/rtl/rtl-iframe-fixed.html [ Failure ] -crbug.com/596780 virtual/spv2/compositing/rtl/rtl-iframe-relative.html [ Failure ] -crbug.com/596780 virtual/spv2/compositing/visibility/layer-visible-content.html [ Failure ] - -# This test has a paint invalidation failure that needs to be investigated. -crbug.com/600618 virtual/spv2/svg/as-image/svg-image-with-data-uri.html [ Failure Crash ] - # In imported/wpt/html/, we prefer checking in failure # expectation files. The following tests with [ Failure ] don't have failure # expectation files because they contain local path names. @@ -483,9 +600,6 @@ crbug.com/517840 imported/wpt/webrtc/rtcpeerconnection/rtcpeerconnection-idl.html [ Failure Timeout ] -crbug.com/603997 compositing/overflow/clear-scroll-parent.html [ Failure ] -crbug.com/603997 virtual/prefer_compositing_to_lcd_text/compositing/overflow/clear-scroll-parent.html [ Failure ] - crbug.com/552494 scrollbars/overflow-scrollbar-combinations.html [ Pass Failure ] crbug.com/552494 virtual/prefer_compositing_to_lcd_text/scrollbars/overflow-scrollbar-combinations.html [ Pass Failure ] crbug.com/552494 virtual/rootlayerscrolls/scrollbars/overflow-scrollbar-combinations.html [ Pass Failure ] @@ -695,14 +809,9 @@ crbug.com/443379 imported/wpt/gamepad/idlharness.html [ Failure Timeout ] -crbug.com/396775 compositing/overflow/reflected-overlay-scrollbars-should-appear-without-compositing.html [ Failure ] -crbug.com/396775 virtual/prefer_compositing_to_lcd_text/compositing/overflow/reflected-overlay-scrollbars-should-appear-without-compositing.html [ Failure ] - crbug.com/381684 [ Mac Win ] fonts/family-fallback-gardiner.html [ Skip ] crbug.com/467635 fast/dom/HTMLImageElement/image-sizes-meta-viewport.html [ Skip ] -crbug.com/484370 [ Win Debug ] svg/custom/gradient-userSpaceOnUse-with-percentage.svg [ Failure ] - # Printing Layout broken in these tests. crbug.com/377696 printing/setPrinting.html [ Skip ] crbug.com/377696 printing/width-overflow.html [ Skip ] @@ -733,16 +842,8 @@ # benefit to running them again with gpu acceleration enabled. crbug.com/555703 [ Linux Mac Win ] virtual/media-gpu-accelerated [ Skip ] -crbug.com/517449 [ Android ] css3/images/optimize-contrast-image.html [ Failure ] - -crbug.com/309675 compositing/gestures/gesture-tapHighlight-simple-longPress.html [ Failure ] -crbug.com/245556 compositing/transitions/transform-on-large-layer.html [ Failure ] - crbug.com/253763 fast/text-autosizing/first-line-scale-factor.html [ Failure ] -# Started failing after r162705. -crbug.com/324370 compositing/video/video-reflection.html [ Failure ] - crbug.com/390377 [ Release ] fast/dom/private_script_unittest.html [ Skip ] crbug.com/613887 http/tests/preload/meta-viewport-link-headers.html [ Failure Pass ] @@ -822,11 +923,6 @@ crbug.com/417782 virtual/rootlayerscrolls/fast/scrolling/scrollable-area-frame.html [ Failure ] crbug.com/417782 virtual/rootlayerscrolls/fast/scrolling/scrollbar-tickmarks-styled.html [ Failure ] -crbug.com/600087 virtual/gpu-rasterization/fast/images/pixel-crack-image-background-webkit-transform-scale.html [ Timeout ] - -# Flaky on Win10 and Win7 -crbug.com/624233 [ Win ] virtual/gpu-rasterization/fast/images/color-profile-background-clip-text.html [ Failure ] - crbug.com/385014 crbug.com/410145 accessibility/canvas-fallback-content-2.html [ Pass Failure Timeout ] crbug.com/574283 [ Mac ] virtual/threaded/fast/scroll-behavior/smooth-scroll/fixed-background-in-iframe.html [ Skip ] @@ -841,7 +937,6 @@ crbug.com/487880 virtual/threaded/fast/scroll-behavior/overflow-scroll-root-frame-animates.html [ Pass Timeout ] crbug.com/487880 virtual/threaded/fast/scroll-behavior/overflow-scroll-animates.html [ Pass Timeout ] crbug.com/552556 virtual/threaded/fast/scroll-behavior/smooth-scroll/mousewheel-scroll.html [ Pass Failure ] -crbug.com/425113 svg/clip-path/clip-path-multiple-children.svg [ Failure ] crbug.com/480769 http/tests/inspector/service-workers/service-workers-redundant.html [ Crash Pass Failure ] crbug.com/480769 http/tests/inspector/service-workers/service-worker-agents.html [ Crash Pass Timeout ] @@ -856,8 +951,6 @@ # Flaky on Win10 and Win7 crbug.com/619539 [ Win ] http/tests/workers/terminate-during-sync-operation-file.html [ Pass Timeout ] -crbug.com/466200 svg/custom/repaint-on-constant-size-change.svg [ Failure ] - # Temporary until we start generating Trusty baselines. crbug.com/498021 [ Linux ] fast/text/unicode-fallback-font.html [ Failure ] crbug.com/498021 [ Linux ] fast/forms/month/month-appearance-l10n.html [ Failure ] @@ -870,14 +963,6 @@ crbug.com/498021 [ Linux ] fast/text/emoticons.html [ Failure ] crbug.com/498021 [ Linux ] fast/text/international/hindi-spacing.html [ Failure ] -# Significant Slimming Paint failure. -crbug.com/459305 [ Mac ] svg/custom/foreign-object-skew.svg [ Failure ] - -crbug.com/482229 compositing/layer-creation/fixed-position-under-transform.html [ Failure ] - -# Broken on Win10 -crbug.com/632217 [ Win10 ] svg/W3C-SVG-1.1/filters-composite-02-b.svg [ Failure ] - # These are the failing tests because Chrome implements the changes proposed to the spec. crbug.com/630671 imported/wpt/pointerevents/pointerevent_capture_suppressing_mouse-manual.html [ Skip ] crbug.com/630671 imported/wpt/pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual.html [ Skip ] @@ -956,30 +1041,45 @@ crbug.com/599828 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-content-horiz-001b.xhtml [ Failure ] crbug.com/599828 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-content-vert-001a.xhtml [ Failure ] -crbug.com/553838 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-basic-canvas-vert-001.xhtml [ Failure ] -crbug.com/553838 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-basic-iframe-vert-001.xhtml [ Failure ] -crbug.com/553838 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-basic-img-vert-001.xhtml [ Failure ] -crbug.com/553838 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-basic-textarea-vert-001.xhtml [ Failure ] -crbug.com/553838 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-basic-video-vert-001.xhtml [ Failure ] -crbug.com/553838 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-break-request-horiz-001a.html [ Failure ] -crbug.com/553838 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-break-request-horiz-001b.html [ Failure ] -crbug.com/553838 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-break-request-vert-001a.html [ Failure ] -crbug.com/553838 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-break-request-vert-001b.html [ Failure ] -crbug.com/553838 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-collapsed-item-baseline-001.html [ Failure ] -crbug.com/553838 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-collapsed-item-horiz-001.html [ Failure ] -crbug.com/553838 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-collapsed-item-horiz-002.html [ Failure ] -crbug.com/553838 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-collapsed-item-horiz-003.html [ Failure ] -crbug.com/553838 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-001.html [ Failure ] -crbug.com/553838 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-002.html [ Failure ] -crbug.com/553838 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-005.html [ Failure ] -crbug.com/553838 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-006.html [ Failure ] -crbug.com/553838 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-mbp-horiz-004.xhtml [ Failure ] +# We render the expectation incorrectly for these five tests +crbug.com/310004 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-basic-canvas-vert-001.xhtml [ Failure ] +crbug.com/310004 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-basic-iframe-vert-001.xhtml [ Failure ] +crbug.com/310004 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-basic-img-vert-001.xhtml [ Failure ] +crbug.com/310004 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-basic-textarea-vert-001.xhtml [ Failure ] +crbug.com/310004 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-basic-video-vert-001.xhtml [ Failure ] + +# We don't support requesting flex line breaks and it is not clear that we should. +# See https://lists.w3.org/Archives/Public/www-style/2015May/0065.html +crbug.com/473481 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-break-request-horiz-001a.html [ Failure ] +crbug.com/473481 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-break-request-horiz-001b.html [ Failure ] +crbug.com/473481 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-break-request-vert-001a.html [ Failure ] +crbug.com/473481 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-break-request-vert-001b.html [ Failure ] + +# We don't currently support visibility: collapse in flexbox +crbug.com/336604 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-collapsed-item-baseline-001.html [ Failure ] +crbug.com/336604 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-collapsed-item-horiz-001.html [ Failure ] +crbug.com/336604 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-collapsed-item-horiz-002.html [ Failure ] +crbug.com/336604 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-collapsed-item-horiz-003.html [ Failure ] + +# We don't correctly implement aspect ratios for images in Flexbox +crbug.com/531199 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-001.html [ Failure ] +crbug.com/531199 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-002.html [ Failure ] +crbug.com/531199 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-005.html [ Failure ] +crbug.com/531199 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-006.html [ Failure ] +crbug.com/531199 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-min-height-auto-002b.html [ Failure ] + +# Tests vertical padding, which we implement different from Firefox (the spec allows either way) +crbug.com/229568 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-mbp-horiz-004.xhtml [ Failure ] + +# These tests are incorrect, as Firefox has a bug in this area. https://bugzilla.mozilla.org/show_bug.cgi?id=1136312 crbug.com/553838 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-min-height-auto-002a.html [ Failure ] -crbug.com/553838 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-min-height-auto-002b.html [ Failure ] crbug.com/553838 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-min-height-auto-002c.html [ Failure ] crbug.com/553838 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-min-width-auto-002a.html [ Failure ] crbug.com/553838 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-min-width-auto-002c.html [ Failure ] -crbug.com/553838 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-paint-ordering-002.xhtml [ Failure ] + +# We paint in an incorrect order when layers are present +crbug.com/370604 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-paint-ordering-002.xhtml [ Failure ] + crbug.com/553838 [ Mac ] imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-self-baseline-horiz-001a.xhtml [ Failure ] crbug.com/553838 [ Mac ] imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-self-baseline-horiz-001b.xhtml [ Failure ] @@ -1025,12 +1125,8 @@ crbug.com/483653 accessibility/scroll-containers.html [ Skip ] crbug.com/491764 http/tests/inspector/service-workers/user-agent-override.html [ Pass Timeout ] -crbug.com/474798 fast/repaint/align-self-change-keeping-geometry-grid.html [ Failure ] -crbug.com/474798 fast/repaint/justify-self-change-keeping-geometry.html [ Failure ] crbug.com/582230 fast/css-grid-layout/relayout-align-items-changed.html [ Skip ] -crbug.com/582230 fast/repaint/align-items-change.html [ Skip ] -crbug.com/582230 fast/repaint/align-items-overflow-change.html [ Skip ] # Fails with leak detector. crbug.com/622915 [ Linux ] ietestcenter/css3/grid/grid-column-003.htm [ Skip ] @@ -1065,32 +1161,14 @@ crbug.com/545140 [ Mac10.10 Mac10.11 Retina ] fast/encoding/denormalised-voiced-japanese-chars.html [ Failure ] +crbug.com/636248 [ Mac ] http/tests/security/img-crossorigin-no-credentials-prompt.html [ Failure Pass ] + crbug.com/509025 [ Mac10.10 ] fast/events/context-no-deselect.html [ Failure ] -crbug.com/509025 [ Mac10.10 ] virtual/prefer_compositing_to_lcd_text/compositing/overflow/theme-affects-visual-overflow.html [ Failure ] crbug.com/509025 [ Mac10.10 ] virtual/rootlayerscrolls/scrollbars/rtl/overflow-scroll-rtl.html [ Failure ] crbug.com/509025 [ Mac10.10 ] virtual/rootlayerscrolls/scrollbars/short-scrollbar.html [ Failure ] -crbug.com/633026 compositing/overflow/updating-scrolling-container-and-content.html [ Pass Failure Crash Timeout ] - -crbug.com/619103 fast/repaint/background-resize-width.html [ Failure ] -crbug.com/619103 fast/repaint/hover-invalidation-table.html [ Failure ] -crbug.com/619103 fast/repaint/selected-replaced.html [ Failure ] crbug.com/619103 fast/table/border-collapsing/cached-change-row-border-color.html [ Failure ] crbug.com/619103 fast/table/border-collapsing/cached-change-tbody-border-color.html [ Failure ] -crbug.com/619103 paint/invalidation/invalidate-after-composited-scroll-of-window.html [ Failure ] -crbug.com/619103 paint/invalidation/animated-gif.html [ Pass Failure ] -crbug.com/619103 paint/invalidation/animated-gif-background.html [ Pass Failure ] -crbug.com/619103 paint/invalidation/animated-gif-background-offscreen.html [ Pass Failure ] -crbug.com/619103 [ Win ] svg/text/text-viewbox-rescale.html [ Pass Failure ] -crbug.com/619103 paint/overflow/interest-rect-change-scroll-down.html [ Failure ] -crbug.com/619103 paint/selection/text-selection-newline-mixed-ltr-rtl.html [ Failure ] -crbug.com/619103 paint/selection/text-selection-newline-rtl-double-linebreak.html [ Failure ] -crbug.com/619103 fast/layers/remove-layer-with-nested-stacking.html [ Pass Crash Timeout ] -crbug.com/619103 compositing/iframes/become-composited-nested-iframes.html [ Pass Crash Timeout ] - -crbug.com/632548 [ Win ] fast/repaint/overflow-scroll-body-appear.html [ Pass Failure ] -crbug.com/632548 [ Win ] fast/repaint/invalidation-after-opacity-change-subtree.html [ Pass Failure ] -crbug.com/632548 [ Win ] compositing/overflow/text-match-highlight.html [ Pass Failure ] crbug.com/464736 http/tests/xmlhttprequest/ontimeout-event-override-after-failure.html [ Pass Failure ] @@ -1134,7 +1212,6 @@ crbug.com/591500 [ Win10 ] virtual/threaded/printing/iframe-print.html [ Failure ] crbug.com/591500 [ Win10 ] printing/list-item-with-empty-first-line.html [ Failure ] crbug.com/591500 [ Win10 ] virtual/threaded/printing/list-item-with-empty-first-line.html [ Failure ] -crbug.com/591500 [ Win10 ] compositing/squashing/squashing-print.html [ Failure ] crbug.com/618082 [ Win10 ] printing/thead-repeats-at-top-of-each-page.html [ Failure ] crbug.com/618082 [ Win10 ] virtual/threaded/printing/thead-repeats-at-top-of-each-page.html [ Failure ] @@ -1181,6 +1258,8 @@ crbug.com/543369 [ Linux ] fast/forms/select-popup/popup-menu-appearance-tall.html [ Failure ] crbug.com/613510 fast/forms/suggestion-picker/date-suggestion-picker-appearance-rtl.html [ Pass Timeout ] +crbug.com/636258 [ Win7 ] fast/forms/select-popup/popup-menu-appearance-fractional-width.html [ Failure ] + crbug.com/546215 [ Android ] fast/inline-block/overflow-clip.html [ Failure ] crbug.com/548765 http/tests/inspector/console-fetch-logging.html [ Failure Pass ] @@ -1189,8 +1268,6 @@ crbug.com/571376 http/tests/webfont/font-display-intervention.html [ Pass Failure ] -crbug.com/320139 fast/repaint/block-layout-inline-children-replaced.html [ Pass Failure ] - crbug.com/575766 http/tests/inspector/resource-tree/resource-tree-frame-add.html [ Timeout Pass ] crbug.com/581468 http/tests/inspector/resource-tree/resource-tree-non-unique-url.html [ Pass Failure ] @@ -1207,7 +1284,6 @@ crbug.com/577380 [ Linux Debug ] http/tests/serviceworker/chromium/registration-stress.html [ Failure ] -crbug.com/635390 fast/repaint/scrollbar-damage-and-full-viewport-repaint.html [ Failure Pass ] crbug.com/634264 http/tests/security/xss-DENIED-cross-origin-stack-overflow.html [ Crash Timeout ] crbug.com/587593 [ Android ] fast/js/pic/cached-single-entry-transition.html [ Pass Failure ] @@ -1220,14 +1296,11 @@ crbug.com/594672 fast/events/scale-and-scroll-iframe-body.html [ Failure Pass ] crbug.com/594672 fast/events/updateLayoutForHitTest.html [ Failure Pass ] crbug.com/594672 fast/events/scale-and-scroll-iframe-window.html [ Failure Pass ] -crbug.com/603728 [ Linux ] virtual/gpu-rasterization/fast/images/color-profile-filter.html [ Failure Timeout Pass ] crbug.com/593568 [ Win Debug ] virtual/threaded/fast/scroll-behavior/smooth-scroll/horizontal-smooth-scroll-in-rtl.html [ Failure ] crbug.com/591902 [ Linux Mac10.10 Mac10.11 Retina ] http/tests/security/contentTypeOptions/nosniff-script-without-content-type-blocked.html [ Failure ] -crbug.com/592185 fast/repaint/fixed-right-in-page-scale.html [ Failure Pass ] - crbug.com/594595 [ Linux ] http/tests/security/mixedContent/websocket/insecure-websocket-in-secure-page-worker-allowed.html [ Timeout Pass ] crbug.com/453002 [ Win ] fast/text/international/text-combine-image-test.html [ Failure Pass ] @@ -1235,16 +1308,10 @@ crbug.com/453002 [ Win ] fast/text/justify-ideograph-vertical.html [ Failure Pass ] crbug.com/453002 [ Win ] fast/text/orientation-sideways.html [ Failure Pass ] -crbug.com/587737 [ Mac10.11 Retina ] virtual/gpu-rasterization/fast/images/color-profile-filter.html [ Timeout Failure ] - -crbug.com/632007 [ Linux ] svg/zoom/page/zoom-mask-with-percentages.svg [ Failure Pass ] - # DocumentWriteEvaluator is still experimental crbug.com/599115 http/tests/preload/document-write [ Failure ] crbug.com/599115 http/tests/preload/document-write/document_write_no_preload.html [ Pass ] -crbug.com/601669 [ Win ] svg/as-image/svg-nested.html [ Crash ] - crbug.com/600261 imported/wpt/mediacapture-streams/GUM-deny.https.html [ Failure ] crbug.com/600261 imported/wpt/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html [ Failure ] @@ -1279,7 +1346,6 @@ crbug.com/624019 [ Mac ] bluetooth/notifications/stop-twice.html [ Skip ] crbug.com/624019 [ Mac ] bluetooth/notifications/stop-without-starting.html [ Skip ] -crbug.com/487344 compositing/video/video-controls-layer-creation.html [ Failure ] crbug.com/487344 fast/hidpi/video-controls-in-hidpi.html [ Failure ] crbug.com/487344 fast/layers/video-layer.html [ Failure ] crbug.com/487344 http/tests/media/video-buffered-range-contains-currentTime.html [ Failure ] @@ -1306,8 +1372,6 @@ crbug.com/606302 [ Win7 Debug ] compositing/perpendicular-layer-sorting.html [ Failure ] crbug.com/606302 [ Win7 Debug ] transforms/3d/point-mapping/3d-point-mapping-deep.html [ Failure ] -crbug.com/632000 [ Win ] fast/images/paint-subrect-grid.html [ Pass Failure ] - crbug.com/613659 imported/wpt/quirks-mode/percentage-height-calculation.html [ Failure ] crbug.com/613661 imported/wpt/quirks-mode/table-cell-nowrap-minimum-width-calculation.html [ Failure ] crbug.com/613663 imported/wpt/quirks-mode/table-cell-width-calculation.html [ Failure ] @@ -1315,8 +1379,6 @@ # Note: this test was previously marked as slow on Debug builds. Skipping until crash is fixed crbug.com/619978 fast/css/giant-stylesheet-crash.html [ Skip ] -crbug.com/622368 [ Linux Win Debug ] fast/repaint/obscured-background-no-repaint.html [ Pass Failure ] - crbug.com/622819 imported/wpt/IndexedDB/transaction-lifetime-empty.html [ Skip ] crbug.com/621892 css3/filters/effect-brightness-clamping-hw.html [ Pass Failure ] @@ -1329,29 +1391,18 @@ crbug.com/624430 [ Win10 ] fast/text/font-features/caps-casemapping.html [ Failure ] -# TODO(fmalita): re-enable -# crbug.com/624709 [ Win ] virtual/gpu-rasterization/fast/images/png-with-color-profile.html [ Failure ] -crbug.com/624709 [ Win ] virtual/gpu-rasterization/fast/images/webp-color-profile-lossy.html [ Failure ] - crbug.com/620432 accessibility/aria-activedescendant.html [ Failure ] crbug.com/593567 [ Linux Debug ] virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance.html [ Skip ] crbug.com/593567 [ Linux Debug ] virtual/scalefactor150/fast/hidpi/static/data-suggestion-picker-appearance.html [ Skip ] -crbug.com/627782 [ Win ] svg/filters/filter-source-position.svg [ Pass Failure ] - # Very slight rendering changes caused by Skia rect clipping change. crbug.com/627844 virtual/gpu/fast/canvas/canvas-createImageBitmap-colorClamping.html [ Pass Failure ] crbug.com/629711 [ Linux Debug ] fast/workers/shared-worker-exception.html [ Crash Pass ] crbug.com/629711 [ Linux Debug ] virtual/sharedarraybuffer/fast/workers/shared-worker-exception.html [ Crash Pass ] -crbug.com/630967 [ Linux Debug ] svg/parser/whitespace-length-invalid-1.html [ Skip ] -crbug.com/630967 [ Linux Debug ] svg/parser/whitespace-length-invalid-2.html [ Skip ] -crbug.com/630967 [ Linux Debug ] svg/parser/whitespace-angle.html [ Skip ] - -crbug.com/630615 [ Win7 ] fast/images/color-profile-background-image-space.html [ Skip ] -crbug.com/399507 [ Mac10.9 Mac10.10 Linux ] virtual/threaded/inspector/tracing/timeline-paint/layer-tree.html [ Skip ] +crbug.com/399507 [ Mac Linux Win10 ] virtual/threaded/inspector/tracing/timeline-paint/layer-tree.html [ Skip ] crbug.com/631039 [ Win7 ] virtual/threaded/fast/scroll-behavior/subframe-scrollBy.html [ Pass Failure ] crbug.com/631039 [ Win7 ] virtual/threaded/fast/scroll-behavior/main-frame-element-scroll.html [ Pass Failure ] @@ -1360,10 +1411,13 @@ crbug.com/631039 [ Win7 ] virtual/threaded/fast/scroll-behavior/main-frame-scroll.html [ Pass Failure ] crbug.com/631039 [ Win7 ] virtual/threaded/fast/scroll-behavior/overflow-scroll-scroll.html [ Pass Failure ] -crbug.com/630870 svg/animations/use-animate-width-and-height.html [ Skip ] # Flaky on Win7 dbg and Mac10.11 (retina) crbug.com/634019 [ Win7 Debug Mac10.11 Retina ] virtual/asyncawait/inspector/sources/debugger-async/async-await/async-callstack-async-await1.html [ Pass Timeout ] +crbug.com/635909 [ Debug ] inspector/sources/debugger-frameworks/frameworks-dom-xhr-event-breakpoints.html [ Pass Timeout ] + +crbug.com/636424 [ Win7 Debug ] editing/selection/modify_move/move-by-word-visually-crash-test-5.html [ Pass Timeout ] + # This test breaks when the feature introduced in the bug is enabled. We keep # this tested without the feature by using the virtual test. See # virtual/stable/http/tests/navigation/beacon-cross-origin-redirect-blob-expected.txt
diff --git a/third_party/WebKit/LayoutTests/accessibility/press-works-on-control-types-expected.txt b/third_party/WebKit/LayoutTests/accessibility/press-works-on-control-types-expected.txt index c6333b1..b332db4d 100644 --- a/third_party/WebKit/LayoutTests/accessibility/press-works-on-control-types-expected.txt +++ b/third_party/WebKit/LayoutTests/accessibility/press-works-on-control-types-expected.txt
@@ -6,7 +6,6 @@ menu item menu item checkbox menu item radio -list item This tests that when certain control type elements are pressed, a valid event is sent that references the right element. On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". @@ -20,7 +19,6 @@ PASS eventSrcElement == document.getElementById('menuitem') is true PASS eventSrcElement == document.getElementById('menuitemcheckbox') is true PASS eventSrcElement == document.getElementById('menuitemradio') is true -PASS eventSrcElement == document.getElementById('listitem') is true PASS successfullyParsed is true TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/accessibility/press-works-on-control-types.html b/third_party/WebKit/LayoutTests/accessibility/press-works-on-control-types.html index 0db05b7..979271c5 100644 --- a/third_party/WebKit/LayoutTests/accessibility/press-works-on-control-types.html +++ b/third_party/WebKit/LayoutTests/accessibility/press-works-on-control-types.html
@@ -14,7 +14,6 @@ <div role="menuitem" id="menuitem" tabindex="0">menu item</div> <div role="menuitemcheckbox" id="menuitemcheckbox" tabindex="0">menu item checkbox</div> <div role="menuitemradio" id="menuitemradio" tabindex="0">menu item radio</div> - <div role="listitem" id="listitem" tabindex="0">list item</div> </div> <p id="description"></p> @@ -47,8 +46,6 @@ shouldBeTrue("eventSrcElement == document.getElementById('menuitemcheckbox')"); else if (pressCount == 7) shouldBeTrue("eventSrcElement == document.getElementById('menuitemradio')"); - else if (pressCount == 8) - shouldBeTrue("eventSrcElement == document.getElementById('listitem')"); pressCount++; } @@ -57,7 +54,7 @@ if (window.accessibilityController) { - var items = new Array("group", "button", "tab", "radio", "checkbox", "menuitem", "menuitemcheckbox", "menuitemradio", "listitem"); + var items = new Array("group", "button", "tab", "radio", "checkbox", "menuitem", "menuitemcheckbox", "menuitemradio"); for (var k = 0; k < items.length; k++) { document.getElementById(items[k]).focus(); accessibilityController.focusedElement.press();
diff --git a/third_party/WebKit/LayoutTests/animations/text-decoration-expected.html b/third_party/WebKit/LayoutTests/animations/text-decoration-expected.html new file mode 100644 index 0000000..bba7b289 --- /dev/null +++ b/third_party/WebKit/LayoutTests/animations/text-decoration-expected.html
@@ -0,0 +1,5 @@ +<!DOCTYPE html> +<svg height="200" width="200"> + <text fill="blue" font-size="40" x="100" y="100" + text-decoration="overline">text</text> +</svg>
diff --git a/third_party/WebKit/LayoutTests/animations/text-decoration.html b/third_party/WebKit/LayoutTests/animations/text-decoration.html new file mode 100644 index 0000000..a3eaa59 --- /dev/null +++ b/third_party/WebKit/LayoutTests/animations/text-decoration.html
@@ -0,0 +1,15 @@ +<!DOCTYPE html> +<style> +text { + text-decoration: line-through; + animation: anim 0s forwards; +} +@keyframes anim { + 0% { text-decoration: overline; } + 100% { text-decoration: overline; } +} +</style> +<svg height="200" width="200"> + <text fill="blue" font-size="40" x="100" y="100" + text-decoration="underline">text</text> +</svg>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/chooser/consecutive-calls.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/chooser/consecutive-calls.html new file mode 100644 index 0000000..4ce17d7 --- /dev/null +++ b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/chooser/consecutive-calls.html
@@ -0,0 +1,47 @@ +<!DOCTYPE html> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<script src="../../../resources/bluetooth/bluetooth-helpers.js"></script> +<script> +'use strict'; +promise_test(() => { + function assert_expected_events(events) { + assert_equals(events.length, 4); + assert_equals(events[0], 'chooser-opened(file://)'); + assert_equals(events[1], 'discovering'); + let idsByName = new AddDeviceEventSet(); + idsByName.assert_add_device_event(events[2]); + assert_true(idsByName.has('Heart Rate Device')); + assert_equals(events[3], 'discovery-idle'); + return idsByName; + }; + + testRunner.setBluetoothManualChooser(true); + // Open a chooser. + let firstRequestDevicePromise = setBluetoothFakeAdapter('HeartRateAdapter') + .then(() => assert_promise_rejects_with_message( + requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]}), + new DOMException('User cancelled the requestDevice() chooser.', + 'NotFoundError'))); + + return getBluetoothManualChooserEvents(4) + .then(assert_expected_events) + .then(() => { + // Open another chooser. + let secondRequestDevicePromise = + requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]}) + .then(device => assert_equals(device.constructor.name, + 'BluetoothDevice')); + return getBluetoothManualChooserEvents(4) + .then(assert_expected_events) + .then(idsByName => { + testRunner.sendBluetoothManualChooserEvent( + 'selected', idsByName.get('Heart Rate Device')); + return Promise.all([ + firstRequestDevicePromise, + secondRequestDevicePromise]); + }); + }); +}, 'A second call to requestDevice with the chooser opened will close the ' + + 'previous chooser.'); +</script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/chooser/multiple-matching-devices.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/chooser/multiple-matching-devices.html new file mode 100644 index 0000000..58ed1ace3 --- /dev/null +++ b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/chooser/multiple-matching-devices.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<script src="../../../resources/bluetooth/bluetooth-helpers.js"></script> +<script> +'use strict'; +promise_test(() => { + testRunner.setBluetoothManualChooser(true); + let requestDevicePromise = + setBluetoothFakeAdapter('GlucoseHeartRateAdapter') + .then(() => requestDeviceWithKeyDown({ + filters: [{services: ['glucose']}, + {services: ['heart_rate']}] + })); + return getBluetoothManualChooserEvents(5) + .then(events => { + assert_equals(events.length, 5, events); + assert_equals(events[0], 'chooser-opened(file://)'); + assert_equals(events[1], 'discovering'); + let idsByName = new AddDeviceEventSet(); + for (let addedDevice of [events[2], events[3]]) { + idsByName.assert_add_device_event(addedDevice); + } + assert_true(idsByName.has('Heart Rate Device')); + assert_true(idsByName.has('Glucose Device')); + assert_equals(events[4], 'discovery-idle'); + testRunner.sendBluetoothManualChooserEvent( + 'selected', idsByName.get('Glucose Device')); + return requestDevicePromise; + }).then(device => assert_equals(device.name, 'Glucose Device')); +}, 'The chooser includes all devices.'); +</script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/chooser/new-scan-all-types.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/chooser/new-scan-all-types.html new file mode 100644 index 0000000..6d3a8c9 --- /dev/null +++ b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/chooser/new-scan-all-types.html
@@ -0,0 +1,39 @@ +<!DOCTYPE html> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<script src="../../../resources/bluetooth/bluetooth-helpers.js"></script> +<script> +'use strict'; +promise_test(() => { + testRunner.setBluetoothManualChooser(true); + + let requestDevicePromise = + setBluetoothFakeAdapter('DeviceEventAdapter') + .then(() => requestDeviceWithKeyDown({ + filters: [ + {services: ['heart_rate']}, + {services: ['battery_service']}, + {services: ['tx_power']}, + {services: ['generic_access']}, + {services: ['glucose']}] + })); + return getBluetoothManualChooserEvents(7).then(events => { + assert_equals(events[0], 'chooser-opened(file://)'); + let idsByName = new AddDeviceEventSet(); + idsByName.assert_add_device_event(events[1]); + assert_true(idsByName.has('Connected Heart Rate Device')); + assert_equals(events[2], 'discovering'); + idsByName.assert_add_device_event(events[3]); + idsByName.assert_add_device_event(events[4]); + idsByName.assert_add_device_event(events[5]); + assert_true(idsByName.has('New Glucose Device'), 'Glucose Device'); + assert_true(idsByName.has('Changing Battery Device'), 'Battery Device'); + assert_true(idsByName.has('Discovery Generic Access Device', + 'Generic Access Device')); + assert_equals(events[6], 'discovery-idle'); + testRunner.sendBluetoothManualChooserEvent( + 'selected', idsByName.get('Connected Heart Rate Device')); + return requestDevicePromise; + }); +}); +</script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/chooser/new-scan-connected-devices.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/chooser/new-scan-connected-devices.html new file mode 100644 index 0000000..56f8930 --- /dev/null +++ b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/chooser/new-scan-connected-devices.html
@@ -0,0 +1,26 @@ +<!DOCTYPE html> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<script src="../../../resources/bluetooth/bluetooth-helpers.js"></script> +<script> +'use strict'; +promise_test(() => { + testRunner.setBluetoothManualChooser(true); + + let requestDevicePromise = + setBluetoothFakeAdapter('DeviceEventAdapter') + .then(() => requestDeviceWithKeyDown({ + filters: [{services: ['heart_rate']}]})); + return getBluetoothManualChooserEvents(4).then(events => { + assert_equals(events[0], 'chooser-opened(file://)'); + let idsByName = new AddDeviceEventSet(); + idsByName.assert_add_device_event(events[1]); + assert_true(idsByName.has('Connected Heart Rate Device'), events[1]); + assert_equals(events[2], 'discovering'); + assert_equals(events[3], 'discovery-idle'); + testRunner.sendBluetoothManualChooserEvent( + 'selected', idsByName.get('Connected Heart Rate Device')); + return requestDevicePromise; + }); +}); +</script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/chooser/new-scan-device-added.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/chooser/new-scan-device-added.html new file mode 100644 index 0000000..e63429d5 --- /dev/null +++ b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/chooser/new-scan-device-added.html
@@ -0,0 +1,26 @@ +<!DOCTYPE html> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<script src="../../../resources/bluetooth/bluetooth-helpers.js"></script> +<script> +'use strict'; +promise_test(() => { + testRunner.setBluetoothManualChooser(true); + + let requestDevicePromise = + setBluetoothFakeAdapter('DeviceEventAdapter') + .then(() => requestDeviceWithKeyDown({ + filters: [{services: ['glucose']}]})); + return getBluetoothManualChooserEvents(4).then(events => { + assert_equals(events[0], 'chooser-opened(file://)'); + assert_equals(events[1], 'discovering'); + let idsByName = new AddDeviceEventSet(); + idsByName.assert_add_device_event(events[2]); + assert_true(idsByName.has('New Glucose Device')); + assert_equals(events[3], 'discovery-idle'); + testRunner.sendBluetoothManualChooserEvent( + 'selected', idsByName.get('New Glucose Device')); + return requestDevicePromise; + }); +}); +</script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/chooser/new-scan-device-changed.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/chooser/new-scan-device-changed.html new file mode 100644 index 0000000..99eef17 --- /dev/null +++ b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/chooser/new-scan-device-changed.html
@@ -0,0 +1,26 @@ +<!DOCTYPE html> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<script src="../../../resources/bluetooth/bluetooth-helpers.js"></script> +<script> +'use strict'; +promise_test(() => { + testRunner.setBluetoothManualChooser(true); + + let requestDevicePromise = + setBluetoothFakeAdapter('DeviceEventAdapter') + .then(() => requestDeviceWithKeyDown({ + filters: [{services: ['battery_service']}]})); + return getBluetoothManualChooserEvents(4).then(events => { + assert_equals(events[0], 'chooser-opened(file://)'); + assert_equals(events[1], 'discovering'); + let idsByName = new AddDeviceEventSet(); + idsByName.assert_add_device_event(events[2]); + assert_true(idsByName.has('Changing Battery Device')); + assert_equals(events[3], 'discovery-idle'); + testRunner.sendBluetoothManualChooserEvent( + 'selected', idsByName.get('Changing Battery Device')); + return requestDevicePromise; + }); +}); +</script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/chooser/new-scan-services-discovered.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/chooser/new-scan-services-discovered.html new file mode 100644 index 0000000..fbe2af4 --- /dev/null +++ b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/chooser/new-scan-services-discovered.html
@@ -0,0 +1,26 @@ +<!DOCTYPE html> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<script src="../../../resources/bluetooth/bluetooth-helpers.js"></script> +<script> +'use strict'; +promise_test(() => { + testRunner.setBluetoothManualChooser(true); + + let requestDevicePromise = + setBluetoothFakeAdapter('DeviceEventAdapter') + .then(() => requestDeviceWithKeyDown({ + filters: [{services: ['generic_access']}]})); + return getBluetoothManualChooserEvents(4).then(events => { + assert_equals(events[0], 'chooser-opened(file://)'); + assert_equals(events[1], 'discovering'); + let idsByName = new AddDeviceEventSet(); + idsByName.assert_add_device_event(events[2]); + assert_true(idsByName.has('Discovery Generic Access Device')); + assert_equals(events[3], 'discovery-idle'); + testRunner.sendBluetoothManualChooserEvent( + 'selected', idsByName.get('Discovery Generic Access Device')); + return requestDevicePromise; + }); +}); +</script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/chooser/restart-scan-finds-new-device.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/chooser/restart-scan-finds-new-device.html new file mode 100644 index 0000000..58d2582f --- /dev/null +++ b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/chooser/restart-scan-finds-new-device.html
@@ -0,0 +1,42 @@ +<!DOCTYPE html> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<script src="../../../resources/bluetooth/bluetooth-helpers.js"></script> +<script> +'use strict'; +promise_test(() => { + testRunner.setBluetoothManualChooser(true); + + // Open the chooser, looking for a Heart Rate device. + let requestDevicePromise = + setBluetoothFakeAdapter('SecondDiscoveryFindsHeartRateAdapter') + .then(() => requestDeviceWithKeyDown({ + filters: [{services: ['heart_rate']}] + })); + + // The adapter finds nothing, so we just see discovery start and stop. + return getBluetoothManualChooserEvents(3).then(events => { + assert_array_equals(events, + ['chooser-opened(file://)', + 'discovering', + 'discovery-idle', + ]); + + // On the second discovery, the adapter finds the Heart Rate device. + testRunner.sendBluetoothManualChooserEvent('rescan', ''); + return getBluetoothManualChooserEvents(3); + }).then(events => { + assert_equals(events.length, 3, events); + assert_equals(events[0], 'discovering', 'events[0]'); + let idsByName = new AddDeviceEventSet(); + idsByName.assert_add_device_event(events[1]); + assert_true(idsByName.has('Heart Rate Device')); + assert_equals(events[2], 'discovery-idle'); + + // Select it and let the test complete. + testRunner.sendBluetoothManualChooserEvent('selected', + idsByName.get('Heart Rate Device')); + return requestDevicePromise; + }).then(device => assert_equals(device.name, 'Heart Rate Device')); +}, 'The chooser can restart the BT scan.'); +</script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/chooser/restart-scan-includes-previous-device.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/chooser/restart-scan-includes-previous-device.html new file mode 100644 index 0000000..9acdc87d --- /dev/null +++ b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/chooser/restart-scan-includes-previous-device.html
@@ -0,0 +1,45 @@ +<!DOCTYPE html> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<script src="../../../resources/bluetooth/bluetooth-helpers.js"></script> +<script> +'use strict'; +promise_test(() => { + testRunner.setBluetoothManualChooser(true); + + // Open the chooser, looking for a Heart Rate device. + let requestDevicePromise = + setBluetoothFakeAdapter('DeviceEventAdapter') + .then(() => requestDeviceWithKeyDown({ + filters: [{services: ['heart_rate']}] + })); + + // The connected Heart Rate Device is added to the chooser. + return getBluetoothManualChooserEvents(4).then(events => { + assert_equals(events.length, 4, events); + assert_equals(events[0], 'chooser-opened(file://)'); + let idsByName = new AddDeviceEventSet(); + idsByName.assert_add_device_event(events[1]); + assert_true(idsByName.has('Connected Heart Rate Device')); + assert_equals(events[2], 'discovering'); + assert_equals(events[3], 'discovery-idle'); + + // After restarting a scan the connected device should be added to the + // chooser. + testRunner.sendBluetoothManualChooserEvent('rescan', ''); + return getBluetoothManualChooserEvents(3); + }).then(events => { + let idsByName = new AddDeviceEventSet(); + assert_equals(events.length, 3, events); + idsByName.assert_add_device_event(events[0]); + assert_true(idsByName.has('Connected Heart Rate Device')); + assert_equals(events[1], 'discovering', events[1]); + assert_equals(events[2], 'discovery-idle'); + + // Select it and let the test complete. + testRunner.sendBluetoothManualChooserEvent( + 'selected', idsByName.get('Connected Heart Rate Device')); + return requestDevicePromise; + }).then(device => assert_equals(device.name, 'Connected Heart Rate Device')); +}, 'The chooser shows previously connected devices.'); +</script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/consecutive-calls.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/consecutive-calls.html deleted file mode 100644 index 30d60860d..0000000 --- a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/consecutive-calls.html +++ /dev/null
@@ -1,47 +0,0 @@ -<!DOCTYPE html> -<script src="../../resources/testharness.js"></script> -<script src="../../resources/testharnessreport.js"></script> -<script src="../../resources/bluetooth/bluetooth-helpers.js"></script> -<script> -'use strict'; -promise_test(() => { - function assert_expected_events(events) { - assert_equals(events.length, 4); - assert_equals(events[0], 'chooser-opened(file://)'); - let idsByName = new AddDeviceEventSet(); - idsByName.assert_add_device_event(events[1]); - assert_true(idsByName.has('Heart Rate Device')); - assert_equals(events[2], 'discovering'); - assert_equals(events[3], 'discovery-idle'); - return idsByName; - }; - - testRunner.setBluetoothManualChooser(true); - // Open a chooser. - let firstRequestDevicePromise = setBluetoothFakeAdapter('HeartRateAdapter') - .then(() => assert_promise_rejects_with_message( - requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]}), - new DOMException('User cancelled the requestDevice() chooser.', - 'NotFoundError'))); - - return getBluetoothManualChooserEvents(4) - .then(assert_expected_events) - .then(() => { - // Open another chooser. - let secondRequestDevicePromise = - requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]}) - .then(device => assert_equals(device.constructor.name, - 'BluetoothDevice')); - return getBluetoothManualChooserEvents(4) - .then(assert_expected_events) - .then(idsByName => { - testRunner.sendBluetoothManualChooserEvent( - 'selected', idsByName.get('Heart Rate Device')); - return Promise.all([ - firstRequestDevicePromise, - secondRequestDevicePromise]); - }); - }); -}, 'A second call to requestDevice with the chooser opened will close the ' + - 'previous chooser.'); -</script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/multiple-matching-devices.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/multiple-matching-devices.html deleted file mode 100644 index 435feb20..0000000 --- a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/multiple-matching-devices.html +++ /dev/null
@@ -1,32 +0,0 @@ -<!DOCTYPE html> -<script src="../../resources/testharness.js"></script> -<script src="../../resources/testharnessreport.js"></script> -<script src="../../resources/bluetooth/bluetooth-helpers.js"></script> -<script> -'use strict'; -promise_test(() => { - testRunner.setBluetoothManualChooser(true); - let requestDevicePromise = - setBluetoothFakeAdapter('GlucoseHeartRateAdapter') - .then(() => requestDeviceWithKeyDown({ - filters: [{services: ['glucose']}, - {services: ['heart_rate']}] - })); - return getBluetoothManualChooserEvents(5) - .then(events => { - assert_equals(events.length, 5, events); - assert_equals(events[0], 'chooser-opened(file://)', 'events[0]'); - let idsByName = new AddDeviceEventSet(); - for (let addedDevice of [events[1], events[2]]) { - idsByName.assert_add_device_event(addedDevice); - } - assert_true(idsByName.has('Heart Rate Device')); - assert_true(idsByName.has('Glucose Device')); - assert_equals(events[3], 'discovering'); - assert_equals(events[4], 'discovery-idle'); - testRunner.sendBluetoothManualChooserEvent('selected', - idsByName.get('Glucose Device')); - return requestDevicePromise; - }).then(device => assert_equals(device.name, 'Glucose Device')); -}, 'The chooser includes all devices.'); -</script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/restart-scan-finds-new-device.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/restart-scan-finds-new-device.html deleted file mode 100644 index c5ebe85..0000000 --- a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/restart-scan-finds-new-device.html +++ /dev/null
@@ -1,42 +0,0 @@ -<!DOCTYPE html> -<script src="../../resources/testharness.js"></script> -<script src="../../resources/testharnessreport.js"></script> -<script src="../../resources/bluetooth/bluetooth-helpers.js"></script> -<script> -'use strict'; -promise_test(() => { - testRunner.setBluetoothManualChooser(true); - - // Open the chooser, looking for a Heart Rate device. - let requestDevicePromise = - setBluetoothFakeAdapter('SecondDiscoveryFindsHeartRateAdapter') - .then(() => requestDeviceWithKeyDown({ - filters: [{services: ['heart_rate']}] - })); - - // The adapter finds nothing, so we just see discovery start and stop. - return getBluetoothManualChooserEvents(3).then(events => { - assert_array_equals(events, - ['chooser-opened(file://)', - 'discovering', - 'discovery-idle', - ]); - - // On the second discovery, the adapter finds the Heart Rate device. - testRunner.sendBluetoothManualChooserEvent('rescan', ''); - return getBluetoothManualChooserEvents(3); - }).then(events => { - assert_equals(events.length, 3, events); - assert_equals(events[0], 'discovering', 'events[0]'); - let idsByName = new AddDeviceEventSet(); - idsByName.assert_add_device_event(events[1]); - assert_true(idsByName.has('Heart Rate Device')); - assert_equals(events[2], 'discovery-idle'); - - // Select it and let the test complete. - testRunner.sendBluetoothManualChooserEvent('selected', - idsByName.get('Heart Rate Device')); - return requestDevicePromise; - }).then(device => assert_equals(device.name, 'Heart Rate Device')); -}, 'The chooser can restart the BT scan.'); -</script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/restart-scan-includes-previous-device.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/restart-scan-includes-previous-device.html deleted file mode 100644 index 46881ff..0000000 --- a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/restart-scan-includes-previous-device.html +++ /dev/null
@@ -1,45 +0,0 @@ -<!DOCTYPE html> -<script src="../../resources/testharness.js"></script> -<script src="../../resources/testharnessreport.js"></script> -<script src="../../resources/bluetooth/bluetooth-helpers.js"></script> -<script> -'use strict'; -promise_test(() => { - testRunner.setBluetoothManualChooser(true); - - // Open the chooser, looking for a Heart Rate device. - let requestDevicePromise = - setBluetoothFakeAdapter('HeartRateAdapter') - .then(() => requestDeviceWithKeyDown({ - filters: [{services: ['heart_rate']}] - })); - - // The existing Heart Rate Device is added to the chooser. - return getBluetoothManualChooserEvents(4).then(events => { - assert_equals(events.length, 4, events); - assert_equals(events[0], 'chooser-opened(file://)'); - let idsByName = new AddDeviceEventSet(); - idsByName.assert_add_device_event(events[1]); - assert_true(idsByName.has('Heart Rate Device')); - assert_equals(events[2], 'discovering'); - assert_equals(events[3], 'discovery-idle'); - - // After restarting a scan the existing device should be added to the - // chooser. - testRunner.sendBluetoothManualChooserEvent('rescan', ''); - return getBluetoothManualChooserEvents(3); - }).then(events => { - let idsByName = new AddDeviceEventSet(); - assert_equals(events.length, 3, events); - idsByName.assert_add_device_event(events[0]); - assert_true(idsByName.has('Heart Rate Device')); - assert_equals(events[1], 'discovering', events[0]); - assert_equals(events[2], 'discovery-idle'); - - // Select it and let the test complete. - testRunner.sendBluetoothManualChooserEvent('selected', - idsByName.get('Heart Rate Device')); - return requestDevicePromise; - }).then(device => assert_equals(device.name, 'Heart Rate Device')); -}, 'The chooser shows previously discovered devices.'); -</script>
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-with-local-background-and-child-expected.html b/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-with-local-background-and-child-expected.html new file mode 100644 index 0000000..a5c9682 --- /dev/null +++ b/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-with-local-background-and-child-expected.html
@@ -0,0 +1,30 @@ +<style> +#scroller { + background: gray local content-box; + border: 10px solid rgba(0, 255, 0, 0.5); + overflow: scroll; + padding: 10px; + width: 200px; + height: 200px; +} + +.child { + width: 30px; + height: 30px; + padding: 10px; + border: 10px solid green; + background: green content-box; +} + +.spacer { + height: 300px; +} +</style> +<!-- When the #scroller is composited, its local attached background will be + drawn into the composited layer as well as the background of its non + composited .child. This tests that the .child background is drawn + correctly to its bounds as they do include borders unlike #scroller. --> +<div id="scroller"> + <div class="child"></div> + <div class="spacer"></div> +</div>
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-with-local-background-and-child.html b/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-with-local-background-and-child.html new file mode 100644 index 0000000..2c3d696 --- /dev/null +++ b/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-with-local-background-and-child.html
@@ -0,0 +1,31 @@ +<style> +#scroller { + background: gray local content-box; + border: 10px solid rgba(0, 255, 0, 0.5); + overflow: scroll; + padding: 10px; + width: 200px; + height: 200px; + will-change: transform; +} + +.child { + width: 30px; + height: 30px; + padding: 10px; + border: 10px solid green; + background: green content-box; +} + +.spacer { + height: 300px; +} +</style> +<!-- When the #scroller is composited, its local attached background will be + drawn into the composited layer as well as the background of its non + composited .child. This tests that the .child background is drawn + correctly to its bounds as they do include borders unlike #scroller. --> +<div id="scroller"> + <div class="child"></div> + <div class="spacer"></div> +</div>
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-with-local-background-expected.html b/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-with-local-background-expected.html new file mode 100644 index 0000000..1e87c7b --- /dev/null +++ b/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-with-local-background-expected.html
@@ -0,0 +1,27 @@ +<script> +onload = function() { + document.getElementById('scroller').scrollTo(0, 200); +} +</script> +<style> +#scroller { + background: gray local content-box; + border: 10px solid rgba(0, 255, 0, 0.5); + overflow: scroll; + padding: 10px; + width: 200px; + height: 200px; +} + +.spacer { + height: 300px; +} +</style> +<!-- #scroller has a locally attached background with padding so when it is + scrolled we can see the background slide up. Doing this on a composited + element without repainting requires the background to be painted into + the scrolling contents layer and correctly account for that layer not + including the border in its bounds. --> +<div id="scroller"> + <div class="spacer"></div> +</div>
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-with-local-background.html b/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-with-local-background.html new file mode 100644 index 0000000..6dc6ab4a --- /dev/null +++ b/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-with-local-background.html
@@ -0,0 +1,37 @@ +<script> +if (window.testRunner) + testRunner.waitUntilDone(); +onload = function() { + // Double rAF to ensure content is painted before scroll. + requestAnimationFrame(function() { + requestAnimationFrame(function() { + document.getElementById('scroller').scrollTo(0, 200); + if (window.testRunner) + window.testRunner.notifyDone(); + }) + }); +} +</script> +<style> +#scroller { + background: gray local content-box; + border: 10px solid rgba(0, 255, 0, 0.5); + overflow: scroll; + padding: 10px; + width: 200px; + height: 200px; + will-change: transform; +} + +.spacer { + height: 300px; +} +</style> +<!-- #scroller has a locally attached background with padding so when it is + scrolled we can see the background slide up. Doing this on a composited + element without repainting requires the background to be painted into + the scrolling contents layer and correctly account for that layer not + including the border in its bounds. --> +<div id="scroller"> + <div class="spacer"></div> +</div>
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-with-opaque-background-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-with-opaque-background-expected.txt new file mode 100644 index 0000000..9dd56eec --- /dev/null +++ b/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-with-opaque-background-expected.txt
@@ -0,0 +1,2 @@ +Should have opaque composited scrolling contents layer: Pass. +
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-with-opaque-background.html b/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-with-opaque-background.html new file mode 100644 index 0000000..ac1de10a --- /dev/null +++ b/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-with-opaque-background.html
@@ -0,0 +1,48 @@ +<script> +if (window.testRunner) + window.testRunner.dumpAsText(); + +function hasOpaqueCompositedScrollingContentsLayer(layer) { + if (layer.name == "Scrolling Contents Layer") + return layer.contentsOpaque; + if (layer.children) { + for (var i = 0; i < layer.children.length; i++) { + if (hasOpaqueCompositedScrollingContentsLayer(layer.children[i])) + return true; + } + } + return false; +} + +onload = function() { + if (!window.testRunner || !window.internals) + return; + + var result = ""; + result += "Should have opaque composited scrolling contents layer: "; + if (hasOpaqueCompositedScrollingContentsLayer(JSON.parse(window.internals.layerTreeAsText(document)))) + result += "Pass.\n"; + else + result += "Fail.\n"; + window.testRunner.setCustomTextOutput(result); +} +</script> +<style> +#scroller { + background: white local content-box; + border: 10px solid rgba(0, 255, 0, 0.5); + overflow: scroll; + width: 200px; + height: 200px; + will-change: transform; +} +.spacer { + height: 300px; +} +</style> +<!-- The scroller's Scrolling Contents Layer should be opaque due to the opaque + color background. Even though the background has a content-box clip there + is no gap because the scroller has no padding. This means that we will be + able to draw text with subpixel anti-aliasing. +--> +<div id="scroller"><div class="spacer"></div></div>
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-with-transparent-background-expected.txt b/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-with-transparent-background-expected.txt new file mode 100644 index 0000000..9440e166 --- /dev/null +++ b/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-with-transparent-background-expected.txt
@@ -0,0 +1,2 @@ +Should not have opaque composited scrolling contents layer: Pass. +
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-with-transparent-background.html b/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-with-transparent-background.html new file mode 100644 index 0000000..331d013 --- /dev/null +++ b/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-with-transparent-background.html
@@ -0,0 +1,48 @@ +<script> +if (window.testRunner) + window.testRunner.dumpAsText(); + +function hasNotOpaqueCompositedScrollingContentsLayer(layer) { + if (layer.name == "Scrolling Contents Layer") + return !layer.contentsOpaque; + if (layer.children) { + for (var i = 0; i < layer.children.length; i++) { + if (hasNotOpaqueCompositedScrollingContentsLayer(layer.children[i])) + return true; + } + } + return false; +} + +onload = function() { + if (!window.testRunner || !window.internals) + return; + + var result = ""; + result += "Should not have opaque composited scrolling contents layer: "; + if (hasNotOpaqueCompositedScrollingContentsLayer(JSON.parse(window.internals.layerTreeAsText(document)))) + result += "Pass.\n"; + else + result += "Fail.\n"; + window.testRunner.setCustomTextOutput(result); +} +</script> +<style> +#scroller { + background: white local content-box; + border: 10px solid rgba(0, 255, 0, 0.5); + overflow: scroll; + padding: 10px; + width: 180px; + height: 180px; + will-change: transform; +} +.spacer { + height: 280px; +} +</style> +<!-- The scroller's Scrolling Contents Layer should be transparent due to the + content-box clip with a 10px padding leaving a transparent gap between. +--> +<div id="scroller"><div class="spacer"></div></div> +<pre id="layertree"></pre>
diff --git a/third_party/WebKit/LayoutTests/compositing/will-change/containing-block-added-expected.txt b/third_party/WebKit/LayoutTests/compositing/will-change/containing-block-added-expected.txt index 56d9495..db951d9 100644 --- a/third_party/WebKit/LayoutTests/compositing/will-change/containing-block-added-expected.txt +++ b/third_party/WebKit/LayoutTests/compositing/will-change/containing-block-added-expected.txt
@@ -26,7 +26,7 @@ { "object": "LayoutBlockFlow (positioned) DIV class='fixed'", "rect": [50, 50, 75, 75], - "reason": "bounds change" + "reason": "style change" } ] } @@ -40,7 +40,7 @@ }, { "object": "LayoutBlockFlow (positioned) DIV class='fixed'", - "reason": "bounds change" + "reason": "style change" } ] }
diff --git a/third_party/WebKit/LayoutTests/compositing/will-change/containing-block-removed-expected.txt b/third_party/WebKit/LayoutTests/compositing/will-change/containing-block-removed-expected.txt index af8fb38..09fc2e8 100644 --- a/third_party/WebKit/LayoutTests/compositing/will-change/containing-block-removed-expected.txt +++ b/third_party/WebKit/LayoutTests/compositing/will-change/containing-block-removed-expected.txt
@@ -12,7 +12,7 @@ { "object": "LayoutBlockFlow (positioned) DIV class='fixed'", "rect": [50, 50, 75, 75], - "reason": "bounds change" + "reason": "style change" } ], "children": [ @@ -27,7 +27,7 @@ { "object": "LayoutBlockFlow (positioned) DIV id='container'", "rect": [0, 0, 100, 100], - "reason": "became visible" + "reason": "style change" }, { "object": "LayoutBlockFlow (positioned) DIV id='container'", @@ -59,11 +59,11 @@ }, { "object": "LayoutBlockFlow (positioned) DIV id='container'", - "reason": "became visible" + "reason": "style change" }, { "object": "LayoutBlockFlow (positioned) DIV class='fixed'", - "reason": "bounds change" + "reason": "style change" } ] }
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/delete-misspelled-word-expected.txt b/third_party/WebKit/LayoutTests/editing/spelling/delete-misspelled-word-expected.txt deleted file mode 100644 index 0e7d99b..0000000 --- a/third_party/WebKit/LayoutTests/editing/spelling/delete-misspelled-word-expected.txt +++ /dev/null
@@ -1,14 +0,0 @@ -Test if Chrome spellchecks a word again when changing a misspelled word.To test manually, type a misspelled word "zz " and type a backspace key twice.This test succeeds when "z" is not marked as misspelled. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS insertText("z"); insertText("z"); insertText(" "); internals.hasSpellingMarker(document, 0, 2) is true -Enable asynchronous spellchecking, delete two characters, and insert a space -PASS internals.hasSpellingMarker(document, 0, 1) became false -PASS successfullyParsed is true - -TEST COMPLETE -z - -
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/delete-misspelled-word.html b/third_party/WebKit/LayoutTests/editing/spelling/delete-misspelled-word.html index 60b48aee..b8a19423 100644 --- a/third_party/WebKit/LayoutTests/editing/spelling/delete-misspelled-word.html +++ b/third_party/WebKit/LayoutTests/editing/spelling/delete-misspelled-word.html
@@ -1,33 +1,36 @@ <!DOCTYPE html> <html> <head> -<script src=../../resources/js-test.js language="javascript" type="text/javascript"></script> -<title>Testing moving cursor to a misspelled word</title> -</head> +<script src=../../resources/testharness.js></script> +<script src=../../resources/testharnessreport.js></script> +<script src=resources/util.js></script> +<title>Testing moving cursor to a misspelled word</title> +</head> <body> -<div id="src" contenteditable="true" spellcheck="true"></div><br/> -<script language="javascript"> -description('Test if Chrome spellchecks a word again when changing a misspelled word.' + - 'To test manually, type a misspelled word "zz " and type a backspace key twice.' + - 'This test succeeds when "z" is not marked as misspelled.'); - -jsTestIsAsync = true; - +<div id="src" contenteditable></div> +<script> var node = document.getElementById('src'); -node.focus(); -function insertText(text) { - document.execCommand("InsertText", false, text); -} -shouldBeTrue('insertText("z"); insertText("z"); insertText(" "); internals.hasSpellingMarker(document, 0, 2)'); -debug('Enable asynchronous spellchecking, delete two characters, and insert a space'); -internals.settings.setUnifiedTextCheckerEnabled(true); +var steps = [ + function() { + node.focus(); + document.execCommand('InsertText', false, 'z'); + document.execCommand('InsertText', false, 'z'); + document.execCommand('InsertText', false, ' '); + }, + function() { + testRunner.execCommand('DeleteBackward'); + testRunner.execCommand('DeleteBackward'); + document.execCommand('InsertText', false, ' '); + } +]; -testRunner.execCommand("DeleteBackward"); -testRunner.execCommand("DeleteBackward"); -document.execCommand("InsertText", false, ' '); +var assertions = [ + () => assert_true(internals.hasSpellingMarker(document, 0, 2)), + () => assert_false(internals.hasSpellingMarker(document, 0, 1)) +]; -shouldBecomeEqual('internals.hasSpellingMarker(document, 0, 1)', 'false', finishJSTest); +runSpellingTest(steps, assertions, 'Blink spellchecks a word again when changing a misspelled word'); </script> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/focusing-other-frame-expected.txt b/third_party/WebKit/LayoutTests/editing/spelling/focusing-other-frame-expected.txt deleted file mode 100644 index 227eab29..0000000 --- a/third_party/WebKit/LayoutTests/editing/spelling/focusing-other-frame-expected.txt +++ /dev/null
@@ -1,11 +0,0 @@ -Last word written in an editable in one frame should be spellchecked when focusing other frame. To test manually type some misspelled word in one frame and focus other frame. The word should be marked. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS internals.markerCountForNode(testEditable1.childNodes[0], "spelling") is 0 -PASS internals.markerCountForNode(testEditable1.childNodes[0], "spelling") is 1 -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/focusing-other-frame.html b/third_party/WebKit/LayoutTests/editing/spelling/focusing-other-frame.html index 4ccb20c8..ae5ba9a 100644 --- a/third_party/WebKit/LayoutTests/editing/spelling/focusing-other-frame.html +++ b/third_party/WebKit/LayoutTests/editing/spelling/focusing-other-frame.html
@@ -1,37 +1,41 @@ <!DOCTYPE html> <html> <head> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <script src="resources/util.js"></script> -<script src="../../resources/js-test.js"></script> </head> <body> <pre id="console"></pre> -<iframe id="frame1" src="data:text/html,<body contenteditable></body>"></iframe> -<iframe id="frame2" src="data:text/html,<body contenteditable></body>"></iframe> +<iframe id="frame1"></iframe> +<iframe id="frame2"></iframe> <script> +var frame1 = document.getElementById('frame1'); +var testEditable1 = frame1.contentWindow.document.createElement('div'); +testEditable1.setAttribute('contentEditable', 'true'); +frame1.contentWindow.document.body.appendChild(testEditable1); +var frame2 = document.getElementById('frame2'); +var testEditable2 = frame2.contentWindow.document.createElement('div'); +testEditable2.setAttribute('contentEditable', 'true'); +frame2.contentWindow.document.body.appendChild(testEditable2); -description("Last word written in an editable in one frame should be " + -"spellchecked when focusing other frame. To test manually type some " + -"misspelled word in one frame and focus other frame. The word should be marked."); +var steps = [ + function() { + testEditable1.focus(); + frame1.contentWindow.document.execCommand('InsertText', false, 'zz'); + }, + function() { + testEditable2.focus(); + } +]; -if (window.internals) { - var frame1 = document.getElementById("frame1"); - var testEditable1 = frame1.contentWindow.document.createElement("div"); - testEditable1.setAttribute("contentEditable", "true"); - frame1.contentWindow.document.body.appendChild(testEditable1); - var frame2 = document.getElementById("frame2"); - var testEditable2 = frame1.contentWindow.document.createElement("div"); - testEditable2.setAttribute("contentEditable", "true"); - frame2.contentWindow.document.body.appendChild(testEditable2); - testEditable1.focus(); - frame1.contentWindow.document.execCommand("InsertText", false, "zz"); - shouldBe('internals.markerCountForNode(testEditable1.childNodes[0], "spelling")', '0'); - testEditable2.focus(); - shouldBe('internals.markerCountForNode(testEditable1.childNodes[0], "spelling")', '1'); -} else { - log("Automatic testing impossible. Test manually. See steps in the description."); -} +var assertions = [ + () => assert_equals(internals.markerCountForNode(testEditable1.childNodes[0], 'spelling'), 0), + () => assert_equals(internals.markerCountForNode(testEditable1.childNodes[0], 'spelling'), 1) +]; + +runSpellingTest(steps, assertions,'Text written in an editable in one frame should be spellchecked when focusing other frame') </script> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/resources/util.js b/third_party/WebKit/LayoutTests/editing/spelling/resources/util.js index 5f25220..4f1c4d1 100644 --- a/third_party/WebKit/LayoutTests/editing/spelling/resources/util.js +++ b/third_party/WebKit/LayoutTests/editing/spelling/resources/util.js
@@ -66,3 +66,32 @@ typeCharacterCommand(text[i]); } } + +function runNextStep(test, steps, assertions) { + if (!steps.length) { + test.done(); + return; + } + + var step = steps.shift(); + var assertion = assertions.shift(); + + step(); + step_timeout(() => { + test.step(() => assertion()); + runNextStep(test, steps, assertions); + }, 50); +} + +function runSpellingTest(steps, assertions, opt_title) +{ + var t = async_test(opt_title); + if (!window.internals) { + t.step(() => assert_unreached('internals is required for this test')); + t.done(); + return; + } + + internals.settings.setUnifiedTextCheckerEnabled(true); + runNextStep(t, steps, assertions); +}
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/spellcheck-paste-continuous-disabled-expected.txt b/third_party/WebKit/LayoutTests/editing/spelling/spellcheck-paste-continuous-disabled-expected.txt deleted file mode 100644 index 0a88907..0000000 --- a/third_party/WebKit/LayoutTests/editing/spelling/spellcheck-paste-continuous-disabled-expected.txt +++ /dev/null
@@ -1,11 +0,0 @@ -Test if WebKit does not spellcheck text when pasting text and continuous spellcheck is turned off. To test manually, disable continuous spellcheck, copy the text "zz apple" and paste it to the textarea. When "zz" is not marked as misspelled, this test succeeds. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS internals.hasSpellingMarker(document, 0, 2) became true -PASS internals.hasSpellingMarker(document, 0, 2) became different from true -PASS successfullyParsed is true - -TEST COMPLETE -zz apple
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/spellcheck-paste-continuous-disabled.html b/third_party/WebKit/LayoutTests/editing/spelling/spellcheck-paste-continuous-disabled.html index 0fa9f1f..a6d58d0 100644 --- a/third_party/WebKit/LayoutTests/editing/spelling/spellcheck-paste-continuous-disabled.html +++ b/third_party/WebKit/LayoutTests/editing/spelling/spellcheck-paste-continuous-disabled.html
@@ -1,39 +1,49 @@ <!DOCTYPE HTML> <html> <head> -<script src="../../resources/js-test.js"></script> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script src="resources/util.js"></script> </head> <body> <div> -<div id="src" contenteditable="true" spellcheck="true"></div> +<div id="src" contenteditable></div><br/> </div> -<script language="javascript"> -description('Test if WebKit does not spellcheck text when pasting text and continuous spellcheck is turned off. ' + - 'To test manually, disable continuous spellcheck, copy the text "zz apple" and paste it to the textarea. ' + - 'When "zz" is not marked as misspelled, this test succeeds.'); - -jsTestIsAsync = true; - -// Insert a misspelled word to initialize a spellchecker. +<script> var srcNode = document.getElementById('src'); -srcNode.focus(); -document.execCommand("InsertText", false, 'z'); -document.execCommand("InsertText", false, 'z'); -document.execCommand("InsertText", false, ' '); -document.execCommand("InsertText", false, 'a'); -document.execCommand("InsertText", false, 'p'); -document.execCommand("InsertText", false, 'p'); -document.execCommand("InsertText", false, 'l'); -document.execCommand("InsertText", false, 'e'); -shouldBecomeEqual('internals.hasSpellingMarker(document, 0, 2)', 'true', function() {}); -window.getSelection().selectAllChildren(srcNode); -document.execCommand('Copy'); -internals.setContinuousSpellCheckingEnabled(false); +steps = [ + // Insert a misspelled word to initialize a spellchecker. + // Break the insertion of 'zz apple' into two parts to wait for the spelling + // markers under 'zz' to appear. + function() { + srcNode.focus(); + document.execCommand('InsertText', false, 'z'); + document.execCommand('InsertText', false, 'z'); + document.execCommand('InsertText', false, ' '); + }, + function() { + document.execCommand('InsertText', false, 'a'); + document.execCommand('InsertText', false, 'p'); + document.execCommand('InsertText', false, 'p'); + document.execCommand('InsertText', false, 'l'); + document.execCommand('InsertText', false, 'e'); + }, + function() { + window.getSelection().selectAllChildren(srcNode); + document.execCommand('Copy'); + internals.setContinuousSpellCheckingEnabled(false); + document.execCommand('Paste'); + } +]; -document.execCommand('Paste'); -shouldBecomeDifferent('internals.hasSpellingMarker(document, 0, 2)', 'true', finishJSTest); +assertions = [ + () => {}, + () => assert_true(internals.hasSpellingMarker(document, 0, 2)), + () => assert_false(internals.hasSpellingMarker(document, 0, 2)) +]; +runSpellingTest(steps, assertions, 'Blink does not spellcheck text when pasting text and continuous spellcheck is turned off.') </script> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/spellcheck-paste-disabled-expected.txt b/third_party/WebKit/LayoutTests/editing/spelling/spellcheck-paste-disabled-expected.txt deleted file mode 100644 index 90c42b4..0000000 --- a/third_party/WebKit/LayoutTests/editing/spelling/spellcheck-paste-disabled-expected.txt +++ /dev/null
@@ -1,13 +0,0 @@ -Test if WebKit does not spellcheck text when pasting text to an element having spellchecking disabled. To test manually, copy the text "zz apple" and paste it to the textarea. When "zz" is not marked as misspelled, this test succeeds. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS internals.hasSpellingMarker(document, 0, 2) became true -PASS internals.hasSpellingMarker(document, 0, 2) became different from true -PASS successfullyParsed is true - -TEST COMPLETE -zz apple - -zz apple
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/spellcheck-paste-disabled.html b/third_party/WebKit/LayoutTests/editing/spelling/spellcheck-paste-disabled.html index f6bddf7..6ed31d42 100644 --- a/third_party/WebKit/LayoutTests/editing/spelling/spellcheck-paste-disabled.html +++ b/third_party/WebKit/LayoutTests/editing/spelling/spellcheck-paste-disabled.html
@@ -1,40 +1,51 @@ <!DOCTYPE HTML> <html> <head> -<script src="../../resources/js-test.js"></script> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script src="resources/util.js"></script> </head> <body> <div> -<div id="src" contenteditable="true" spellcheck="true"></div><br/> -<div id="dst" contenteditable="true" spellcheck="false"></div> +<div id="src" contenteditable></div><br/> +<div id="dst" contenteditable spellcheck="false"></div> </div> -<script language="javascript"> -description('Test if WebKit does not spellcheck text when pasting text to an element having spellchecking disabled. ' + - 'To test manually, copy the text "zz apple" and paste it to the textarea. ' + - 'When "zz" is not marked as misspelled, this test succeeds.'); - -jsTestIsAsync = true; - -// Insert a misspelled word to initialize a spellchecker. +<script> var srcNode = document.getElementById('src'); -srcNode.focus(); -document.execCommand("InsertText", false, 'z'); -document.execCommand("InsertText", false, 'z'); -document.execCommand("InsertText", false, ' '); -document.execCommand("InsertText", false, 'a'); -document.execCommand("InsertText", false, 'p'); -document.execCommand("InsertText", false, 'p'); -document.execCommand("InsertText", false, 'l'); -document.execCommand("InsertText", false, 'e'); -shouldBecomeEqual('internals.hasSpellingMarker(document, 0, 2)', 'true', function(){}); -window.getSelection().selectAllChildren(srcNode); -document.execCommand('Copy'); - var dstNode = document.getElementById('dst'); -dstNode.focus(); -document.execCommand('Paste'); -shouldBecomeDifferent('internals.hasSpellingMarker(document, 0, 2)', 'true', finishJSTest); +steps = [ + // Insert a misspelled word to initialize a spellchecker. + // Break the insertion of 'zz apple' into two parts to wait for the spelling + // markers under 'zz' to appear. + function() { + srcNode.focus(); + document.execCommand('InsertText', false, 'z'); + document.execCommand('InsertText', false, 'z'); + document.execCommand('InsertText', false, ' '); + }, + function() { + document.execCommand('InsertText', false, 'a'); + document.execCommand('InsertText', false, 'p'); + document.execCommand('InsertText', false, 'p'); + document.execCommand('InsertText', false, 'l'); + document.execCommand('InsertText', false, 'e'); + }, + function() { + window.getSelection().selectAllChildren(srcNode); + document.execCommand('Copy'); + dstNode.focus(); + document.execCommand('Paste'); + } +]; + +assertions = [ + () => {}, + () => assert_true(internals.hasSpellingMarker(document, 0, 2)), + () => assert_false(internals.hasSpellingMarker(document, 0, 2)) +]; + +runSpellingTest(steps, assertions, 'Blink does not spellcheck text when pasting text to an element having spellchecking disabled.') </script> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/spelling-insert-html-expected.txt b/third_party/WebKit/LayoutTests/editing/spelling/spelling-insert-html-expected.txt deleted file mode 100644 index 0d0fb56..0000000 --- a/third_party/WebKit/LayoutTests/editing/spelling/spelling-insert-html-expected.txt +++ /dev/null
@@ -1,10 +0,0 @@ -The spellchecker shouldn't mark substrings of words after pasting. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - -PASS markedText is "zz" -PASS successfullyParsed is true - -TEST COMPLETE -foo zz -food.
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/spelling-insert-html.html b/third_party/WebKit/LayoutTests/editing/spelling/spelling-insert-html.html deleted file mode 100644 index df93680..0000000 --- a/third_party/WebKit/LayoutTests/editing/spelling/spelling-insert-html.html +++ /dev/null
@@ -1,41 +0,0 @@ -<!DOCTYPE html> -<html> -<head> -<script src="../../resources/js-test.js"></script> -</head> -<body> -<pre id="description"></pre> -<pre id="console"></pre> -<div id="container"> - <div id="destination" contentEditable>food.</div> -</div> - -<script> -description("The spellchecker shouldn't mark substrings of words after pasting."); - -var sel = window.getSelection(); -var destination = document.getElementById("destination"); -var destinationText = destination.firstChild; -sel.setBaseAndExtent(destinationText, 2, destinationText, 2); - -document.execCommand("InsertHTML", false, "<div>o zz</div><div>fo</div>"); - -if (window.internals) { - // The destination node has multiple text nodes, - // so we need concatenate the marked text. - var texts = destination.childNodes; - var markedText = ""; - for (var i = 0; i < texts.length; ++i) { - var marked = internals.markerRangeForNode(texts[i], "spelling", 0); - if (marked) - markedText += marked.toString() - } - - // The first "foo" isn't checked because it crosses the pasted and base html. - // See http://webkit.org/b/66450. - shouldBeEqualToString("markedText", "zz"); -} - -</script> -</body> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-svg-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-svg-expected.txt index 0333739..e171b1b 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-svg-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-svg-expected.txt
@@ -21,6 +21,24 @@ PASS d[1] is 0 PASS d[2] is 255 PASS d[3] is 255 +PASS bitmap.width is 50 +PASS bitmap.height is 50 +PASS d[0] is 0 +PASS d[1] is 0 +PASS d[2] is 255 +PASS d[3] is 255 +PASS d[0] is 0 +PASS d[1] is 0 +PASS d[2] is 255 +PASS d[3] is 255 +PASS d[0] is 0 +PASS d[1] is 0 +PASS d[2] is 255 +PASS d[3] is 255 +PASS d[0] is 0 +PASS d[1] is 0 +PASS d[2] is 255 +PASS d[3] is 255 PASS successfullyParsed is true TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-svg-no-intrinsic-size-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-svg-no-intrinsic-size-expected.txt index 052d6be..fc6b4741 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-svg-no-intrinsic-size-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-svg-no-intrinsic-size-expected.txt
@@ -3,8 +3,8 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". -PASS createImageBitmap from a SVG without intrinsic size rejected: InvalidStateError: Failed to execute 'createImageBitmap' on 'Window': The image element contains an SVG image without intrinsic dimensions. -PASS createImageBitmap from a SVG with zero size rejected: InvalidStateError: Failed to execute 'createImageBitmap' on 'Window': The image element contains an SVG image without intrinsic dimensions. +PASS createImageBitmap from a SVG without intrinsic size rejected: InvalidStateError: Failed to execute 'createImageBitmap' on 'Window': The image element contains an SVG image without intrinsic dimensions, and no resize options or crop region are specified. +PASS createImageBitmap from a SVG with zero size rejected: InvalidStateError: Failed to execute 'createImageBitmap' on 'Window': The image element contains an SVG image without intrinsic dimensions, and no resize options or crop region are specified. PASS createImageBitmap from a zero size SVG with cropRect succeed PASS d[0] is 0 PASS d[1] is 0 @@ -22,6 +22,7 @@ PASS d[1] is 0 PASS d[2] is 0 PASS d[3] is 0 +PASS createImageBitmap from a zero size SVG with resize and cropRect succeed PASS successfullyParsed is true TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-svg-no-intrinsic-size.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-svg-no-intrinsic-size.html index 3195433..539ed30 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-svg-no-intrinsic-size.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-svg-no-intrinsic-size.html
@@ -40,7 +40,13 @@ createImageBitmap(image2, 0, 0, 100, 100).then(function(bitmap3) { testPassed("createImageBitmap from a zero size SVG with cropRect succeed"); checkImageBitmap(bitmap3); - finishJSTest(); + createImageBitmap(image2, {resizeWidth: 50, resizeHeight: 50, resizeQuality: "high"}).then(function(bitmap4) { + testPassed("createImageBitmap from a zero size SVG with resize and cropRect succeed"); + finishJSTest(); + }, function(e) { + testFailed("createImageBitmap from a zero size SVG with resize and cropRect rejected: " + e); + finishJSTest(); + }); }, function(e) { testFailed("createImageBitmap from a zero size SVG with cropRect rejected: " + e); finishJSTest();
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-svg.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-svg.html index f494a779..bd28ef5 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-svg.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-svg.html
@@ -17,6 +17,24 @@ shouldBeEqualToNumber("d[3]", 255); } +function checkBitmap(imageBitmap, width, height) +{ + bitmap = imageBitmap; + if (width == 200) { + shouldBe("bitmap.width", "200"); + shouldBe("bitmap.height", "200"); + } else { + shouldBe("bitmap.width", "50"); + shouldBe("bitmap.height", "50"); + } + ctx.clearRect(0, 0, 200, 200); + ctx.drawImage(bitmap, 0, 0); + shouldBeBlue(0, 0); + shouldBeBlue(0, width - 1); + shouldBeBlue(height - 1, 0); + shouldBeBlue(height - 1, width - 1); +} + var canvas = document.createElement("canvas"); canvas.setAttribute("width", "200"); canvas.setAttribute("height", "200"); @@ -25,16 +43,12 @@ var image = new Image(); image.onload = function() { - createImageBitmap(image).then(function(imageBitmap) { - bitmap = imageBitmap; - shouldBe("bitmap.width", "200"); - shouldBe("bitmap.height", "200"); - ctx.clearRect(0, 0, 200, 200); - ctx.drawImage(imageBitmap, 0, 0); - shouldBeBlue(0, 0); - shouldBeBlue(0, 199); - shouldBeBlue(199, 0); - shouldBeBlue(199, 199); + imageBitmaps = {}; + var p1 = createImageBitmap(image).then(function(image) { imageBitmaps.noResize = image }); + var p2 = createImageBitmap(image, {resizeWidth: 50, resizeHeight: 50, resizeQuality: "high"}).then(function(image) { imageBitmaps.resize = image }); + Promise.all([p1, p2]).then(function() { + checkBitmap(imageBitmaps.noResize, 200, 200); + checkBitmap(imageBitmaps.resize, 50, 50); finishJSTest(); }, function (e) { testFailed("createImageBitmap promise rejected: " + e);
diff --git a/third_party/WebKit/LayoutTests/fast/css/background-serialize-expected.txt b/third_party/WebKit/LayoutTests/fast/css/background-serialize-expected.txt deleted file mode 100644 index 19063886..0000000 --- a/third_party/WebKit/LayoutTests/fast/css/background-serialize-expected.txt +++ /dev/null
@@ -1,26 +0,0 @@ -Test background properties obtained by using cssText when the properties are set by using style element's textContent. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS test('.test { background: none; }') is ".test { background: none; }" -PASS test('.test { background: none; background-color: black;}') is ".test { background: none black; }" -PASS test('.test { background: none; background-color: initial !important;}') is ".test { background-image: none; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: initial !important; }" -PASS test('.test { background: initial; }') is ".test { background: initial; }" -PASS test('.test { background: initial; background-color: black; }') is ".test { background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: black; }" -PASS test('.test { background: inherit; }') is ".test { background: inherit; }" -PASS test('.test { background: inherit; background-color: black; }') is ".test { background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: black; }" -PASS test('.test { background: none; background-repeat: repeat-x !important;}') is ".test { background-image: none; background-position: initial; background-size: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: initial; background-repeat: repeat-x !important; }" -PASS test('.test { background: none; background-repeat: repeat-x;}') is ".test { background: none repeat-x; }" -PASS test('.test { background: none; background-position-x: 0%;}') is ".test { background: none 0%; }" -PASS test('.test { background: none; background-position: 20% 80%;}') is ".test { background: none 20% 80%; }" -PASS test('.test { background-position-x: 5%; }') is ".test { background-position-x: 5%; }" -PASS test('.test { background-position-y: 5%; }') is ".test { background-position-y: 5%; }" -PASS test('.test { background-position-x: 5%; background-position-y: 10%; }') is ".test { background-position: 5% 10%; }" -PASS test('.test { background-position-x: 5%; background-position-y: 10% !important; }') is ".test { background-position-x: 5%; background-position-y: 10% !important; }" -PASS test('.test { background: url(dummy://test.png); }') is ".test { background: url(\"dummy://test.png\"); }" -PASS test('.test { background: url(dummy://test.png); background-color: black; }') is ".test { background: url(\"dummy://test.png\") black; }" -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/css/background-serialize.html b/third_party/WebKit/LayoutTests/fast/css/background-serialize.html index d055832..0808de2e 100644 --- a/third_party/WebKit/LayoutTests/fast/css/background-serialize.html +++ b/third_party/WebKit/LayoutTests/fast/css/background-serialize.html
@@ -1,40 +1,34 @@ <!doctype html> -<html> <head> -<script src="../../resources/js-test.js"></script> +<title>Test background properties obtained by using cssText when the properties are set by using style element's textContent.</title> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> </head> -<body> - <pre id='console'></pre> -</body> <script> +test(function() { var style = document.createElement('style'); document.head.appendChild(style); +assert_equals(getStyle('.test { background: none; }'), '.test { background: none; }'); +assert_equals(getStyle('.test { background: none; background-color: black;}'), '.test { background: none black; }'); +assert_equals(getStyle('.test { background: none; background-color: initial !important;}'), '.test { background-image: none; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: initial !important; }'); +assert_equals(getStyle('.test { background: initial; }'), '.test { background: initial; }'); +assert_equals(getStyle('.test { background: initial; background-color: black; }'), '.test { background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: black; }'); +assert_equals(getStyle('.test { background: inherit; }'), '.test { background: inherit; }'); +assert_equals(getStyle('.test { background: inherit; background-color: black; }'), '.test { background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: black; }'); +assert_equals(getStyle('.test { background: none; background-repeat: repeat-x !important;}'), '.test { background-image: none; background-position: initial; background-size: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: initial; background-repeat: repeat-x !important; }'); +assert_equals(getStyle('.test { background: none; background-repeat: repeat-x;}'), '.test { background: none repeat-x; }'); +assert_equals(getStyle('.test { background: none; background-position-x: 0%;}'), '.test { background: none 0%; }'); +assert_equals(getStyle('.test { background: none; background-position: 20% 80%;}'), '.test { background: none 20% 80%; }'); +assert_equals(getStyle('.test { background-position-x: 5%; }'), '.test { background-position-x: 5%; }'); +assert_equals(getStyle('.test { background-position-y: 5%; }'), '.test { background-position-y: 5%; }'); +assert_equals(getStyle('.test { background-position-x: 5%; background-position-y: 10%; }'), '.test { background-position: 5% 10%; }'); +assert_equals(getStyle('.test { background-position-x: 5%; background-position-y: 10% !important; }'), '.test { background-position-x: 5%; background-position-y: 10% !important; }'); +assert_equals(getStyle('.test { background: url(dummy://test.png); }'), '.test { background: url("dummy://test.png"); }'); +assert_equals(getStyle('.test { background: url(dummy://test.png); background-color: black; }'), '.test { background: url("dummy://test.png") black; }'); -function test(text) { +function getStyle(text) { style.textContent = text; return style.sheet.cssRules[0].cssText; } - -description("Test background properties obtained by using cssText when the properties are set by using style element's textContent."); - -shouldBeEqualToString("test('.test { background: none; }')", ".test { background: none; }"); -shouldBeEqualToString("test('.test { background: none; background-color: black;}')", ".test { background: none black; }"); -shouldBeEqualToString("test('.test { background: none; background-color: initial !important;}')", ".test { background-image: none; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: initial !important; }"); -shouldBeEqualToString("test('.test { background: initial; }')", ".test { background: initial; }"); -shouldBeEqualToString("test('.test { background: initial; background-color: black; }')", ".test { background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: black; }"); -shouldBeEqualToString("test('.test { background: inherit; }')", ".test { background: inherit; }"); -shouldBeEqualToString("test('.test { background: inherit; background-color: black; }')", ".test { background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: black; }"); -shouldBeEqualToString("test('.test { background: none; background-repeat: repeat-x !important;}')", ".test { background-image: none; background-position: initial; background-size: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: initial; background-repeat: repeat-x !important; }"); -shouldBeEqualToString("test('.test { background: none; background-repeat: repeat-x;}')", ".test { background: none repeat-x; }"); -shouldBeEqualToString("test('.test { background: none; background-position-x: 0%;}')", ".test { background: none 0%; }"); -shouldBeEqualToString("test('.test { background: none; background-position: 20% 80%;}')", ".test { background: none 20% 80%; }"); -shouldBeEqualToString("test('.test { background-position-x: 5%; }')", ".test { background-position-x: 5%; }"); -shouldBeEqualToString("test('.test { background-position-y: 5%; }')", ".test { background-position-y: 5%; }"); -shouldBeEqualToString("test('.test { background-position-x: 5%; background-position-y: 10%; }')", ".test { background-position: 5% 10%; }"); -shouldBeEqualToString("test('.test { background-position-x: 5%; background-position-y: 10% !important; }')", ".test { background-position-x: 5%; background-position-y: 10% !important; }"); -shouldBeEqualToString("test('.test { background: url(dummy://test.png); }')", '.test { background: url("dummy://test.png"); }'); -shouldBeEqualToString("test('.test { background: url(dummy://test.png); background-color: black; }')", '.test { background: url("dummy://test.png") black; }'); - +}); </script> -<script src="../js/resources/js-test-post.js"></script> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/invalidation/nth-pseudo.html b/third_party/WebKit/LayoutTests/fast/css/invalidation/nth-pseudo.html new file mode 100644 index 0000000..bcf504a1 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css/invalidation/nth-pseudo.html
@@ -0,0 +1,43 @@ +<!DOCTYPE html> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<style> + #t1 > :nth-child(even) { + background-color: green + } + #t2 > :nth-last-child(even) { + background-color: green + } +</style> +<div id="t1"> + <span></span> +</div> +<div id="t2"> + <span></span> +</div> + +<script> + function backgroundIsGreen(element) { + assert_equals(getComputedStyle(element).backgroundColor, "rgb(0, 128, 0)"); + } + + function backgroundIsTransparent(element) { + assert_equals(getComputedStyle(element).backgroundColor, "rgba(0, 0, 0, 0)"); + } + + test(() => { + t1.offsetTop; + assert_equals(t1.lastChild.nodeType, Node.TEXT_NODE); + t1.insertBefore(document.createElement("span"), t1.lastChild); + assert_equals(internals.updateStyleAndReturnAffectedElementCount(), 1); + }, "Appending an element sibling should not affect :nth-child of preceeding siblings."); + + test(() => { + t2.offsetTop; + assert_equals(t2.firstChild.nodeType, Node.TEXT_NODE); + assert_equals(t2.firstChild.nextSibling.nodeType, Node.ELEMENT_NODE); + t2.insertBefore(document.createElement("span"), t2.firstChild.nextSibling); + assert_equals(internals.updateStyleAndReturnAffectedElementCount(), 1); + }, "Prepending an element sibling should not affect :nth-last-child of succeeding siblings."); + +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/css/outline-offset-large-expected.html b/third_party/WebKit/LayoutTests/fast/css/outline-offset-large-expected.html new file mode 100644 index 0000000..3dd5b7a --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css/outline-offset-large-expected.html
@@ -0,0 +1,5 @@ +<style> +body { + border: 1px solid red; +} +</style>
diff --git a/third_party/WebKit/LayoutTests/fast/css/outline-offset-large.html b/third_party/WebKit/LayoutTests/fast/css/outline-offset-large.html new file mode 100644 index 0000000..47b6eb73 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css/outline-offset-large.html
@@ -0,0 +1,9 @@ +<!-- Test for crbug.com/630524 --> +<!-- Ensures large outline-offset doesn't cause outline to be rendered incorrectly due to an integer overflow --> +<style> +body { + outline-offset: 2147483646px; + outline-style: outset; + border: 1px solid red; +} +</style>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/cross-frame-accessor-throw-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/cross-frame-accessor-throw-expected.txt index 4314ed43..2d76f84d 100644 --- a/third_party/WebKit/LayoutTests/fast/dom/cross-frame-accessor-throw-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/dom/cross-frame-accessor-throw-expected.txt
@@ -1,6 +1,6 @@ This is a testharness.js-based test. -FAIL Check that DOM exception is created in called function's context. assert_not_equals: got disallowed value [stringifying object threw TypeError: Illegal invocation with type object] -FAIL Check that DOM exception is created in setter's context. assert_not_equals: got disallowed value [stringifying object threw TypeError: Illegal invocation with type object] +PASS Check that DOM exception is created in called function's context. +FAIL Check that DOM exception is created in setter's context. assert_equals: expected [stringifying object threw TypeError: Illegal invocation with type object] but got [stringifying object threw TypeError: Illegal invocation with type object] PASS Check that native exception is created in setter's context. Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-capture.html b/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-capture.html index 1b971f4..9941140b 100644 --- a/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-capture.html +++ b/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-capture.html
@@ -172,6 +172,8 @@ } function runTests() { + // TODO(mustaq): Merge with mouse-pointer-haspointercapture.html for a single w3c test? + debug(" ======= Set pointer capture and release implicitly ======="); testScenario();
diff --git a/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-haspointercapture.html b/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-haspointercapture.html new file mode 100644 index 0000000..eaf301d2 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/events/pointerevents/mouse-pointer-haspointercapture.html
@@ -0,0 +1,97 @@ +<!DOCTYPE HTML> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> + +<style> +#target { + margin: 10px; + padding: 50px; +} +</style> +<h1>PointerEvent: Verifies that hasPointerCapture API works</h1> + +<div id="target" style="background-color:red"></div> + +<div id="log"></div> + +<script> +var changeCaptureInEH = false; +var mousePointerId = 1; + +var targetDiv = document.getElementById("target"); + +function testCaptureAtTarget(expected, testLabel) { + test(function() { + assert_equals(targetDiv.hasPointerCapture(mousePointerId), expected); + }, testLabel); +} + +function init() { + targetDiv.addEventListener("pointerdown", function(event) { + var testState = (changeCaptureInEH? "w" : "w/o") + " change within handler"; + + testCaptureAtTarget(false, "pointerdown: entered " + testState); + if (changeCaptureInEH) + targetDiv.setPointerCapture(mousePointerId); + testCaptureAtTarget(changeCaptureInEH, "pointerdown: exiting " + testState); + }); + + targetDiv.addEventListener("pointerup", function(event) { + var testState = (changeCaptureInEH? "w" : "w/o") + " change within handler"; + + testCaptureAtTarget(changeCaptureInEH, "pointerup: entered " + testState); + if (changeCaptureInEH) + targetDiv.releasePointerCapture(mousePointerId); + testCaptureAtTarget(false, "pointerup: exiting " + testState); + }); +} + +function runTests() { + // TODO(mustaq): Merge with mouse-pointer-capture.html for a single w3c test? + + testCaptureAtTarget(false, "Initial"); + + var rect = targetDiv.getBoundingClientRect(); + eventSender.mouseMoveTo(rect.left + 5, rect.top + 5); + + targetDiv.setPointerCapture(mousePointerId); + testCaptureAtTarget(false, "After set#1 w/o button"); + targetDiv.releasePointerCapture(mousePointerId); + testCaptureAtTarget(false, "After release#1 w/o button"); + + changeCaptureInEH = false; + eventSender.mouseDown(0); + + targetDiv.setPointerCapture(mousePointerId); + testCaptureAtTarget(true, "After set#1 w button"); + targetDiv.releasePointerCapture(mousePointerId); + testCaptureAtTarget(false, "After release#1 w button"); + + targetDiv.setPointerCapture(mousePointerId); + testCaptureAtTarget(true, "After set#2 w button"); + targetDiv.setPointerCapture(mousePointerId); + testCaptureAtTarget(true, "After set#3 w button"); + targetDiv.releasePointerCapture(mousePointerId); + testCaptureAtTarget(false, "After release#2 w button"); + targetDiv.releasePointerCapture(mousePointerId); + testCaptureAtTarget(false, "After release#3 w button"); + eventSender.mouseUp(0); + + changeCaptureInEH = true; + eventSender.mouseDown(0); + eventSender.mouseUp(0); +} + +test(function() { + if (!window.eventSender) + assert_true(true, "No eventSender, skipped tests"); + else if (!window.PointerEvent) + assert_true(true, "No PointerEvent, skipped tests"); + else { + init(); + runTests(); + } + + done(); +}, "PointerEvent: Verifies that hasPointerCapture API works"); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/gradients/css3-radial-gradients-zero-radius-crash.html b/third_party/WebKit/LayoutTests/fast/gradients/css3-radial-gradients-zero-radius-crash.html new file mode 100644 index 0000000..012883a --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/gradients/css3-radial-gradients-zero-radius-crash.html
@@ -0,0 +1,9 @@ +<!doctype html> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<div style="background-image: radial-gradient(ellipse closest-corner at 20px 0px, white, sandybrown);"></div> +<div style="background-image: radial-gradient(ellipse closest-corner at 0px 20px, white, sandybrown);"></div> +<div style="background-image: radial-gradient(ellipse closest-corner at 0px 0px, white, sandybrown);"></div> +<script> +test(function() {}, 'Radial-gradient does not crash when specified with a height or width of 0.'); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/balance-float-after-forced-break-expected.html b/third_party/WebKit/LayoutTests/fast/multicol/balance-float-after-forced-break-expected.html new file mode 100644 index 0000000..b032983 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/multicol/balance-float-after-forced-break-expected.html
@@ -0,0 +1,4 @@ +<!DOCTYPE html> +<p>Below there should be a blue square above a cyan square.</p> +<div style="width:100px; height:100px; background:blue;"></div> +<div style="width:100px; height:100px; background:cyan;"></div>
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/balance-float-after-forced-break.html b/third_party/WebKit/LayoutTests/fast/multicol/balance-float-after-forced-break.html new file mode 100644 index 0000000..9412c4af --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/multicol/balance-float-after-forced-break.html
@@ -0,0 +1,7 @@ +<!DOCTYPE html> +<p>Below there should be a blue square above a cyan square.</p> +<div style="columns:2; column-gap:0; width:100px; background:cyan;"> + <div style="break-after:column; height:100px; background:blue;"></div> + <div style="float:left; width:100%; height:100px; background:blue;"></div> + <div style="height:200px;"></div> +</div>
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/containing-block-position-change-expected.txt b/third_party/WebKit/LayoutTests/fast/repaint/containing-block-position-change-expected.txt index c54e5134..98146f9 100644 --- a/third_party/WebKit/LayoutTests/fast/repaint/containing-block-position-change-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/repaint/containing-block-position-change-expected.txt
@@ -11,7 +11,7 @@ { "object": "LayoutBlockFlow (positioned) DIV", "rect": [158, 70, 50, 50], - "reason": "bounds change" + "reason": "style change" }, { "object": "LayoutBlockFlow (positioned) DIV", @@ -32,7 +32,7 @@ }, { "object": "LayoutBlockFlow (positioned) DIV", - "reason": "bounds change" + "reason": "style change" } ] }
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/fixed-and-absolute-position-scrolled-expected.txt b/third_party/WebKit/LayoutTests/fast/repaint/fixed-and-absolute-position-scrolled-expected.txt index 2b17da2..0ca88e89 100644 --- a/third_party/WebKit/LayoutTests/fast/repaint/fixed-and-absolute-position-scrolled-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/repaint/fixed-and-absolute-position-scrolled-expected.txt
@@ -26,7 +26,7 @@ { "object": "LayoutBlockFlow (positioned) DIV id='absoluteDiv' class='absolute green'", "rect": [100, 700, 100, 100], - "reason": "bounds change" + "reason": "style change" } ] } @@ -46,7 +46,7 @@ }, { "object": "LayoutBlockFlow (positioned) DIV id='absoluteDiv' class='absolute green'", - "reason": "bounds change" + "reason": "style change" } ] }
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/stacking-context-lost-expected.txt b/third_party/WebKit/LayoutTests/fast/repaint/stacking-context-lost-expected.txt index a208f96..5ffecc5 100644 --- a/third_party/WebKit/LayoutTests/fast/repaint/stacking-context-lost-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/repaint/stacking-context-lost-expected.txt
@@ -25,7 +25,7 @@ { "object": "LayoutBlockFlow (relative positioned) DIV id='outer'", "rect": [0, 0, 100, 100], - "reason": "became visible" + "reason": "style change" }, { "object": "LayoutBlockFlow (relative positioned) DIV id='outer'", @@ -52,7 +52,7 @@ }, { "object": "LayoutBlockFlow (relative positioned) DIV id='outer'", - "reason": "became visible" + "reason": "style change" } ] }
diff --git a/third_party/WebKit/LayoutTests/fast/text/ellipsis-ltr-text-in-ltr-flow-underline.html b/third_party/WebKit/LayoutTests/fast/text/ellipsis-ltr-text-in-ltr-flow-underline.html new file mode 100644 index 0000000..bda1d94c --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/ellipsis-ltr-text-in-ltr-flow-underline.html
@@ -0,0 +1,14 @@ +<!DOCTYPE html> +<style> +div { + width: 125px; + font: 12px; + overflow: hidden; + text-overflow: ellipsis; + text-decoration: underline; +} +</style> +<p>crbug.com/634445: Ltr text in a ltr flow should truncate the text left-to-right.</p> +<p>You should see 01234567890123... below and text beneath the underline.</p> +<div>012345678901234567890123456789</div> +
diff --git a/third_party/WebKit/LayoutTests/fast/text/ellipsis-ltr-text-in-rtl-flow-underline.html b/third_party/WebKit/LayoutTests/fast/text/ellipsis-ltr-text-in-rtl-flow-underline.html new file mode 100644 index 0000000..9a60f421 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/ellipsis-ltr-text-in-rtl-flow-underline.html
@@ -0,0 +1,15 @@ +<!DOCTYPE html> +<style> +div { + width: 125px; + font: 12px; + overflow: hidden; + text-overflow: ellipsis; + direction: rtl; + text-decoration: underline; +} +</style> +<p>crbug.com/634445: Ltr text in a rtl flow should truncate the text right-to-left.</p> +<p>You should see ...32109876543210 below and an underline beneat the text.</p> +<div>0987654321098765432109876543210</div> +
diff --git a/third_party/WebKit/LayoutTests/fast/text/ellipsis-mixed-text-in-ltr-flow-underline.html b/third_party/WebKit/LayoutTests/fast/text/ellipsis-mixed-text-in-ltr-flow-underline.html new file mode 100644 index 0000000..174151a --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/ellipsis-mixed-text-in-ltr-flow-underline.html
@@ -0,0 +1,16 @@ +<!DOCTYPE html> +<meta charset='utf-8'> +<style> +div { + width: 125px; + font: 12px; + overflow: hidden; + text-overflow: ellipsis; + direction: ltr; + text-decoration: underline; +} +</style> +<p>crbug.com/634445: Rtl text in a ltr flow should truncate the text left-to-right.</p> +<p>You should see an underline beneath the text but not the ellipsis.</p> +<div>Loremאבגדהוזחטיכךלמםסעפףצץקרשת</div> +
diff --git a/third_party/WebKit/LayoutTests/fast/text/ellipsis-mixed-text-in-rtl-flow-underline.html b/third_party/WebKit/LayoutTests/fast/text/ellipsis-mixed-text-in-rtl-flow-underline.html new file mode 100644 index 0000000..24923ffd --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/ellipsis-mixed-text-in-rtl-flow-underline.html
@@ -0,0 +1,16 @@ +<!DOCTYPE html> +<meta charset='utf-8'> +<style> +div { + width: 125px; + font: 12px; + overflow: hidden; + text-overflow: ellipsis; + direction: rtl; + text-decoration: underline; +} +</style> +<p>crbug.com/634445: Rtl text in a rtl flow should truncate the text right-to-left.</p> +<p>You should see an underline beneath the text.</p> +<div>Loremאבגדהוזחטיכךלמםסעפףצץקרשת</div> +
diff --git a/third_party/WebKit/LayoutTests/fast/text/ellipsis-rtl-text-in-ltr-flow-underline.html b/third_party/WebKit/LayoutTests/fast/text/ellipsis-rtl-text-in-ltr-flow-underline.html new file mode 100644 index 0000000..afde6f64 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/ellipsis-rtl-text-in-ltr-flow-underline.html
@@ -0,0 +1,16 @@ +<!DOCTYPE html> +<meta charset='utf-8'> +<style> +div { + width: 125px; + font: 12px; + overflow: hidden; + text-overflow: ellipsis; + direction: ltr; + text-decoration: underline; +} +</style> +<p>crbug.com/634445: Rtl text in a ltr flow should truncate the text left-to-right.</p> +<p>You should see ךלמםסעפףצץקרשת... below with an underline beneath the text.</p> +<div>אבגדהוזחטיכךלמםסעפףצץקרשת</div> +
diff --git a/third_party/WebKit/LayoutTests/fast/text/ellipsis-rtl-text-in-rtl-flow-underline.html b/third_party/WebKit/LayoutTests/fast/text/ellipsis-rtl-text-in-rtl-flow-underline.html new file mode 100644 index 0000000..ef85864 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/ellipsis-rtl-text-in-rtl-flow-underline.html
@@ -0,0 +1,16 @@ +<!DOCTYPE html> +<meta charset='utf-8'> +<style> +div { + width: 125px; + font: 12px; + overflow: hidden; + text-overflow: ellipsis; + direction: rtl; + text-decoration: underline; +} +</style> +<p>crbug.com/634445: Rtl text in a rtl flow should truncate the text right-to-left.</p> +<p>You should see ...אבגדהוזחטיכךלמםס below with underline beneath the text.</p> +<div>אבגדהוזחטיכךלמםסעפףצץקרשת</div> +
diff --git a/third_party/WebKit/LayoutTests/fragmentation/repeating-thead-multiple-tables-expected.html b/third_party/WebKit/LayoutTests/fragmentation/repeating-thead-multiple-tables-expected.html new file mode 100644 index 0000000..8b820b1 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fragmentation/repeating-thead-multiple-tables-expected.html
@@ -0,0 +1,49 @@ +<!DOCTYPE html> +<style> +table { + border-collapse: collapse; +} +tr { + break-inside: avoid; +} +.header { + font-weight: bold; +} +</style> +<p>crbug.com/621258: Don't let repeating headers overlap on pages that contain two tables.</p> +<div style="-webkit-columns:3; line-height: 20px; column-fill: auto; height:190px;"> + <table> + <tr><td class="header" colspan=2>Col 1</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td class="header" colspan=2>Col 1</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + </table> + <br> + <br> + <table> + <tr><td class="header" colspan=2>Col 2</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td class="header" colspan=2>Col 2</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td class="header" colspan=2>Col 2</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + </table> +</div> +
diff --git a/third_party/WebKit/LayoutTests/fragmentation/repeating-thead-multiple-tables.html b/third_party/WebKit/LayoutTests/fragmentation/repeating-thead-multiple-tables.html new file mode 100644 index 0000000..c243702 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fragmentation/repeating-thead-multiple-tables.html
@@ -0,0 +1,51 @@ +<!DOCTYPE html> +<style> +table { + border-collapse: collapse; +} +thead, tr { + break-inside: avoid; +} +</style> +<p>crbug.com/621258: Don't let repeating headers overlap on pages that contain two tables.</p> +<div style="-webkit-columns:3; line-height: 20px; column-fill: auto; height:190px;"> + <table id="top"> + <thead id="top-thead"> + <tr> + <th colspan="2"><div>Col 1</div></th> + </tr> + </thead> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + </table> + <br> + <br> + <table id="second"> + <thead id="top-thead"> + <tr> + <th colspan="2"><div>Col 2</div></th> + </tr> + </thead> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + <tr><td>Te</td><td>xt</td></tr> + </table> +</div> +
diff --git a/third_party/WebKit/LayoutTests/http/tests/cachestorage/resources/test-helpers.js b/third_party/WebKit/LayoutTests/http/tests/cachestorage/resources/test-helpers.js index cb188730..3e8dd884 100644 --- a/third_party/WebKit/LayoutTests/http/tests/cachestorage/resources/test-helpers.js +++ b/third_party/WebKit/LayoutTests/http/tests/cachestorage/resources/test-helpers.js
@@ -235,3 +235,59 @@ } }), description); } + +// Helper for testing with Request objects. Compares simple +// attributes defined on the interfaces, as well as the headers. +function assert_request_equals(actual, expected, description) { + assert_class_string(actual, "Request", description); + ["url"].forEach(function(attribute) { + assert_equals(actual[attribute], expected[attribute], + description + " Attributes differ: " + attribute + "."); + }); + assert_header_equals(actual.headers, expected.headers, description); +} + +// TODO(zino): Should remove this function once keys() returns request +// keys in key insertion order. Please see http://crbug.com/627821. +// +// Assert that the two arrays |actual| and |expected| contain the same +// set of Requests as determined by assert_request_equals. The order +// is not significant. +// +// |expected| is assumed to not contain any duplicates. +function assert_request_array_equivalent(actual, expected, description) { + assert_true(Array.isArray(actual), description); + assert_equals(actual.length, expected.length, description); + expected.forEach(function(expected_element) { + // assert_request_in_array treats the first argument as being + // 'actual', and the second as being 'expected array'. We are + // switching them around because we want to be resilient + // against the |actual| array containing duplicates. + assert_request_in_array(expected_element, actual, description); + }); +} + +// Asserts that two arrays |actual| and |expected| contain the same +// set of Requests as determined by assert_request_equals(). The +// corresponding elements must occupy corresponding indices in their +// respective arrays. +function assert_request_array_equals(actual, expected, description) { + assert_true(Array.isArray(actual), description); + assert_equals(actual.length, expected.length, description); + actual.forEach(function(value, index) { + assert_request_equals(value, expected[index], + description + " : object[" + index + "]"); + }); +} + +// Equivalent to assert_in_array, but uses assert_request_equals. +function assert_request_in_array(actual, expected_array, description) { + assert_true(expected_array.some(function(element) { + try { + assert_request_equals(actual, element); + return true; + } catch (e) { + return false; + } + }), description); +}
diff --git a/third_party/WebKit/LayoutTests/http/tests/cachestorage/script-tests/cache-delete.js b/third_party/WebKit/LayoutTests/http/tests/cachestorage/script-tests/cache-delete.js index ad0d97c..0f847c3 100644 --- a/third_party/WebKit/LayoutTests/http/tests/cachestorage/script-tests/cache-delete.js +++ b/third_party/WebKit/LayoutTests/http/tests/cachestorage/script-tests/cache-delete.js
@@ -56,6 +56,26 @@ }, 'Cache.delete called with a Request object'); cache_test(function(cache) { + var request = new Request(test_url); + var response = new_test_response(); + return cache.put(request, response) + .then(function() { + return cache.delete(new Request(test_url, {method: 'HEAD'})); + }) + .then(function(result) { + assert_false(result, + 'Cache.delete should not match a non-GET request ' + + 'unless ignoreMethod option is set.'); + return cache.match(test_url); + }) + .then(function(result) { + assert_response_equals(result, response, + 'Cache.delete should leave non-matching response in the cache.'); + }); + }, 'Cache.delete called with a HEAD request'); + + +cache_test(function(cache) { return cache.delete(test_url) .then(function(result) { assert_false(result,
diff --git a/third_party/WebKit/LayoutTests/http/tests/cachestorage/script-tests/cache-keys.js b/third_party/WebKit/LayoutTests/http/tests/cachestorage/script-tests/cache-keys.js new file mode 100644 index 0000000..fad01507 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/cachestorage/script-tests/cache-keys.js
@@ -0,0 +1,145 @@ +if (self.importScripts) { + importScripts('/resources/testharness.js'); + importScripts('../resources/test-helpers.js'); +} + +cache_test(cache => { + return cache.keys() + .then(requests => { + assert_equals( + requests.length, 0, + 'Cache.keys should resolve to an empty array for an empty cache'); + }); + }, 'Cache.keys() called on an empty cache'); + +prepopulated_cache_test(simple_entries, function(cache, entries) { + return cache.keys('not-present-in-the-cache') + .then(function(result) { + assert_request_array_equals( + result, [], + 'Cache.keys should resolve with an empty array on failure.'); + }); + }, 'Cache.keys with no matching entries'); + +prepopulated_cache_test(simple_entries, function(cache, entries) { + return cache.keys(entries.a.request.url) + .then(function(result) { + assert_request_array_equals(result, [entries.a.request], + 'Cache.keys should match by URL.'); + }); + }, 'Cache.keys with URL'); + +prepopulated_cache_test(simple_entries, function(cache, entries) { + return cache.keys(entries.a.request) + .then(function(result) { + assert_request_array_equals( + result, [entries.a.request], + 'Cache.keys should match by Request.'); + }); + }, 'Cache.keys with Request'); + +prepopulated_cache_test(simple_entries, function(cache, entries) { + return cache.keys(new Request(entries.a.request.url)) + .then(function(result) { + assert_request_array_equals( + result, [entries.a.request], + 'Cache.keys should match by Request.'); + }); + }, 'Cache.keys with new Request'); + +prepopulated_cache_test(simple_entries, function(cache, entries) { + return cache.keys(entries.a.request, {ignoreSearch: true}) + .then(function(result) { + // TODO(zino): Should use assert_request_array_equals() instead of + // assert_request_array_equivalent() once keys() returns request + // keys in key insertion order. Please see http://crbug.com/627821. + assert_request_array_equivalent( + result, + [ + entries.a.request, + entries.a_with_query.request + ], + 'Cache.keys with ignoreSearch should ignore the ' + + 'search parameters of cached request.'); + }); + }, + 'Cache.keys with ignoreSearch option (request with no search ' + + 'parameters)'); + +prepopulated_cache_test(simple_entries, function(cache, entries) { + return cache.keys(entries.a_with_query.request, {ignoreSearch: true}) + .then(function(result) { + // TODO(zino): Should use assert_request_array_equals() instead of + // assert_request_array_equivalent() if once keys() returns request + // keys in key insertion order. Please see http://crbug.com/627821. + assert_request_array_equivalent( + result, + [ + entries.a.request, + entries.a_with_query.request + ], + 'Cache.keys with ignoreSearch should ignore the ' + + 'search parameters of request.'); + }); + }, + 'Cache.keys with ignoreSearch option (request with search parameters)'); + +prepopulated_cache_test(simple_entries, function(cache, entries) { + return cache.keys(entries.cat.request.url + '#mouse') + .then(function(result) { + assert_request_array_equals( + result, + [ + entries.cat.request, + ], + 'Cache.keys should ignore URL fragment.'); + }); + }, 'Cache.keys with URL containing fragment'); + +prepopulated_cache_test(simple_entries, function(cache, entries) { + return cache.keys('http') + .then(function(result) { + assert_request_array_equals( + result, [], + 'Cache.keys should treat query as a URL and not ' + + 'just a string fragment.'); + }); + }, 'Cache.keys with string fragment "http" as query'); + +prepopulated_cache_test(simple_entries, function(cache, entries) { + return cache.keys() + .then(function(result) { + // TODO(zino): Should use assert_request_array_equals() instead of + // assert_request_array_equivalent() once keys() returns request + // keys in key insertion order. Please see http://crbug.com/627821. + assert_request_array_equivalent( + result, + [ + entries.a.request, + entries.b.request, + entries.a_with_query.request, + entries.A.request, + entries.a_https.request, + entries.a_org.request, + entries.cat.request, + entries.catmandu.request, + entries.cat_num_lives.request, + entries.cat_in_the_hat.request, + entries.non_2xx_response.request, + entries.error_response.request + ], + 'Cache.keys without parameters should match all entries.'); + }); + }, 'Cache.keys without parameters'); + +prepopulated_cache_test(simple_entries, function(cache, entries) { + return cache.keys(new Request(entries.cat.request.url, {method: 'HEAD'})) + .then(function(result) { + assert_request_array_equals( + result, [], + 'Cache.keys should not match HEAD request unless ignoreMethod ' + + 'option is set.'); + }); + }, 'Cache.keys with a HEAD Request'); + +done();
diff --git a/third_party/WebKit/LayoutTests/http/tests/cachestorage/script-tests/cache-match.js b/third_party/WebKit/LayoutTests/http/tests/cachestorage/script-tests/cache-match.js index 8f1f288..7002fba 100644 --- a/third_party/WebKit/LayoutTests/http/tests/cachestorage/script-tests/cache-match.js +++ b/third_party/WebKit/LayoutTests/http/tests/cachestorage/script-tests/cache-match.js
@@ -53,6 +53,14 @@ }, 'Cache.match with new Request'); prepopulated_cache_test(simple_entries, function(cache, entries) { + return cache.match(new Request(entries.a.request.url, {method: 'HEAD'})) + .then(function(result) { + assert_equals(result, undefined, + 'Cache.match should not match HEAD Request.'); + }); + }, 'Cache.match with HEAD'); + +prepopulated_cache_test(simple_entries, function(cache, entries) { return cache.match(entries.a.request, {ignoreSearch: true}) .then(function(result) {
diff --git a/third_party/WebKit/LayoutTests/http/tests/cachestorage/script-tests/cache-matchAll.js b/third_party/WebKit/LayoutTests/http/tests/cachestorage/script-tests/cache-matchAll.js index 90450d8c..3a12045f 100644 --- a/third_party/WebKit/LayoutTests/http/tests/cachestorage/script-tests/cache-matchAll.js +++ b/third_party/WebKit/LayoutTests/http/tests/cachestorage/script-tests/cache-matchAll.js
@@ -39,6 +39,16 @@ }, 'Cache.matchAll with new Request'); prepopulated_cache_test(simple_entries, function(cache, entries) { + return cache.matchAll(new Request(entries.a.request.url, {method: 'HEAD'}), + {ignoreSearch: true}) + .then(function(result) { + assert_response_array_equals( + result, [], + 'Cache.matchAll should not match HEAD Request.'); + }); + }, 'Cache.matchAll with HEAD'); + +prepopulated_cache_test(simple_entries, function(cache, entries) { return cache.matchAll(entries.a.request, {ignoreSearch: true}) .then(function(result) {
diff --git a/third_party/WebKit/LayoutTests/http/tests/cachestorage/script-tests/cache-storage-match.js b/third_party/WebKit/LayoutTests/http/tests/cachestorage/script-tests/cache-storage-match.js index 2102d78..21517b1e 100644 --- a/third_party/WebKit/LayoutTests/http/tests/cachestorage/script-tests/cache-storage-match.js +++ b/third_party/WebKit/LayoutTests/http/tests/cachestorage/script-tests/cache-storage-match.js
@@ -60,7 +60,7 @@ return Promise.all(test_cache_list.map(function(key) { return self.caches.open(key); })) - .then(function() { return caches.open('x'); }) + .then(function() { return self.caches.open('x'); }) .then(function(cache) { return cache.put(transaction.request.clone(), transaction.response.clone()); @@ -93,13 +93,26 @@ }); }, 'CacheStorageMatch a string request'); +cache_test(function(cache) { + var transaction = create_unique_transaction(); + return cache.put(transaction.request.clone(), transaction.response.clone()) + .then(function() { + return self.caches.match(new Request(transaction.request.url, + {method: 'HEAD'})); + }) + .then(function(response) { + assert_equals(response, undefined, + 'A HEAD request should not be matched'); + }); +}, 'CacheStorageMatch a HEAD request'); + promise_test(function(test) { var transaction = create_unique_transaction(); return self.caches.match(transaction.request) .then(function(response) { assert_equals(response, undefined, 'The response should not be found.'); - }) + }); }, 'CacheStorageMatch with no cached entry'); promise_test(function(test) { @@ -117,7 +130,7 @@ }) .then(function(has_foo) { assert_false(has_foo, "The cache should still not exist."); - }) + }); }, 'CacheStorageMatch with no caches available but name provided'); done();
diff --git a/third_party/WebKit/LayoutTests/http/tests/cachestorage/serviceworker/cache-keys.html b/third_party/WebKit/LayoutTests/http/tests/cachestorage/serviceworker/cache-keys.html new file mode 100644 index 0000000..50361e617 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/cachestorage/serviceworker/cache-keys.html
@@ -0,0 +1,9 @@ +<!DOCTYPE html> +<title>Cache.keys</title> +<link rel="help" href="https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#cache-keys"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../../serviceworker/resources/test-helpers.js"></script> +<script> +service_worker_test('../script-tests/cache-keys.js'); +</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/cachestorage/serviceworker/cache-match-expected.txt b/third_party/WebKit/LayoutTests/http/tests/cachestorage/serviceworker/cache-match-expected.txt deleted file mode 100644 index 8d423f0b..0000000 --- a/third_party/WebKit/LayoutTests/http/tests/cachestorage/serviceworker/cache-match-expected.txt +++ /dev/null
@@ -1,20 +0,0 @@ -This is a testharness.js-based test. -PASS Cache.match -PASS Cache.match with no matching entries -PASS Cache.match with URL -PASS Cache.match with Request -PASS Cache.match with multiple cache hits -PASS Cache.match with new Request -PASS Cache.match with ignoreSearch option (request with no search parameters) -PASS Cache.match with ignoreSearch option (request with search parameter) -PASS Cache.match with URL containing fragment -PASS Cache.match with string fragment "http" as query -PASS Cache.match with responses containing "Vary" header -PASS Cache.match with Request and Response objects with different URLs -PASS Cache.match invoked multiple times for the same Request/Response -PASS Cache.match blob should be sliceable -FAIL Cache.match with POST Request assert_equals: Cache.match should not find a match expected (undefined) undefined but got (object) object "[object Response]" -PASS Cache.match with a non-2xx Response -PASS Cache.match with a network error Response -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/http/tests/cachestorage/serviceworker/cache-matchAll-expected.txt b/third_party/WebKit/LayoutTests/http/tests/cachestorage/serviceworker/cache-matchAll-expected.txt index 367876e..26076124 100644 --- a/third_party/WebKit/LayoutTests/http/tests/cachestorage/serviceworker/cache-matchAll-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/cachestorage/serviceworker/cache-matchAll-expected.txt
@@ -4,6 +4,7 @@ PASS Cache.matchAll with URL PASS Cache.matchAll with Request PASS Cache.matchAll with new Request +PASS Cache.matchAll with HEAD PASS Cache.matchAll with ignoreSearch option (request with no search parameters) PASS Cache.matchAll with ignoreSearch option (request with search parameters) PASS Cache.matchAll with URL containing fragment
diff --git a/third_party/WebKit/LayoutTests/http/tests/cachestorage/serviceworker/ignore-search-with-credentials.html b/third_party/WebKit/LayoutTests/http/tests/cachestorage/serviceworker/ignore-search-with-credentials.html index 82231d3..79efb80 100644 --- a/third_party/WebKit/LayoutTests/http/tests/cachestorage/serviceworker/ignore-search-with-credentials.html +++ b/third_party/WebKit/LayoutTests/http/tests/cachestorage/serviceworker/ignore-search-with-credentials.html
@@ -73,6 +73,13 @@ var expected = remove_query(request.url); assert_equals(remove_query(results[0].url), expected); assert_equals(remove_query(results[1].url), expected); + return cache.keys(request, { ignoreSearch : true }); + }) + .then(function(results) { + assert_equals(results.length, 2); + var expected = remove_query(request.url); + assert_equals(remove_query(results[0].url), expected); + assert_equals(remove_query(results[1].url), expected); return cache.delete(request, { ignoreSearch : true }); }) .then(function(result) {
diff --git a/third_party/WebKit/LayoutTests/http/tests/cachestorage/window/cache-keys.html b/third_party/WebKit/LayoutTests/http/tests/cachestorage/window/cache-keys.html new file mode 100644 index 0000000..fce29ab --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/cachestorage/window/cache-keys.html
@@ -0,0 +1,7 @@ +<!DOCTYPE html> +<title>Cache.keys</title> +<link rel="help" href="https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#cache-keys"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../resources/test-helpers.js"></script> +<script src="../script-tests/cache-keys.js"></script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/cachestorage/window/cache-match-expected.txt b/third_party/WebKit/LayoutTests/http/tests/cachestorage/window/cache-match-expected.txt deleted file mode 100644 index 046e5a4..0000000 --- a/third_party/WebKit/LayoutTests/http/tests/cachestorage/window/cache-match-expected.txt +++ /dev/null
@@ -1,19 +0,0 @@ -This is a testharness.js-based test. -PASS Cache.match with no matching entries -PASS Cache.match with URL -PASS Cache.match with Request -PASS Cache.match with multiple cache hits -PASS Cache.match with new Request -PASS Cache.match with ignoreSearch option (request with no search parameters) -PASS Cache.match with ignoreSearch option (request with search parameter) -PASS Cache.match with URL containing fragment -PASS Cache.match with string fragment "http" as query -PASS Cache.match with responses containing "Vary" header -PASS Cache.match with Request and Response objects with different URLs -PASS Cache.match invoked multiple times for the same Request/Response -PASS Cache.match blob should be sliceable -FAIL Cache.match with POST Request assert_equals: Cache.match should not find a match expected (undefined) undefined but got (object) object "[object Response]" -PASS Cache.match with a non-2xx Response -PASS Cache.match with a network error Response -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/http/tests/cachestorage/window/cache-matchAll-expected.txt b/third_party/WebKit/LayoutTests/http/tests/cachestorage/window/cache-matchAll-expected.txt index 0d4f4c7..cfed7e6 100644 --- a/third_party/WebKit/LayoutTests/http/tests/cachestorage/window/cache-matchAll-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/cachestorage/window/cache-matchAll-expected.txt
@@ -1,9 +1,10 @@ -CONSOLE WARNING: line 162: Cache.match() does not support 'ignoreVary' option yet. See http://crbug.com/499216 +CONSOLE WARNING: line 172: Cache.match() does not support 'ignoreVary' option yet. See http://crbug.com/499216 This is a testharness.js-based test. PASS Cache.matchAll with no matching entries PASS Cache.matchAll with URL PASS Cache.matchAll with Request PASS Cache.matchAll with new Request +PASS Cache.matchAll with HEAD PASS Cache.matchAll with ignoreSearch option (request with no search parameters) PASS Cache.matchAll with ignoreSearch option (request with search parameters) PASS Cache.matchAll with URL containing fragment
diff --git a/third_party/WebKit/LayoutTests/http/tests/cachestorage/worker/cache-keys.html b/third_party/WebKit/LayoutTests/http/tests/cachestorage/worker/cache-keys.html new file mode 100644 index 0000000..d8ea2b7 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/cachestorage/worker/cache-keys.html
@@ -0,0 +1,8 @@ +<!DOCTYPE html> +<title>Cache.keys</title> +<link rel="help" href="https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#cache-keys"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +fetch_tests_from_worker(new Worker('../script-tests/cache-keys.js')); +</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/cachestorage/worker/cache-match-expected.txt b/third_party/WebKit/LayoutTests/http/tests/cachestorage/worker/cache-match-expected.txt deleted file mode 100644 index 046e5a4..0000000 --- a/third_party/WebKit/LayoutTests/http/tests/cachestorage/worker/cache-match-expected.txt +++ /dev/null
@@ -1,19 +0,0 @@ -This is a testharness.js-based test. -PASS Cache.match with no matching entries -PASS Cache.match with URL -PASS Cache.match with Request -PASS Cache.match with multiple cache hits -PASS Cache.match with new Request -PASS Cache.match with ignoreSearch option (request with no search parameters) -PASS Cache.match with ignoreSearch option (request with search parameter) -PASS Cache.match with URL containing fragment -PASS Cache.match with string fragment "http" as query -PASS Cache.match with responses containing "Vary" header -PASS Cache.match with Request and Response objects with different URLs -PASS Cache.match invoked multiple times for the same Request/Response -PASS Cache.match blob should be sliceable -FAIL Cache.match with POST Request assert_equals: Cache.match should not find a match expected (undefined) undefined but got (object) object "[object Response]" -PASS Cache.match with a non-2xx Response -PASS Cache.match with a network error Response -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/http/tests/cachestorage/worker/cache-matchAll-expected.txt b/third_party/WebKit/LayoutTests/http/tests/cachestorage/worker/cache-matchAll-expected.txt index 0d4f4c7..cfed7e6 100644 --- a/third_party/WebKit/LayoutTests/http/tests/cachestorage/worker/cache-matchAll-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/cachestorage/worker/cache-matchAll-expected.txt
@@ -1,9 +1,10 @@ -CONSOLE WARNING: line 162: Cache.match() does not support 'ignoreVary' option yet. See http://crbug.com/499216 +CONSOLE WARNING: line 172: Cache.match() does not support 'ignoreVary' option yet. See http://crbug.com/499216 This is a testharness.js-based test. PASS Cache.matchAll with no matching entries PASS Cache.matchAll with URL PASS Cache.matchAll with Request PASS Cache.matchAll with new Request +PASS Cache.matchAll with HEAD PASS Cache.matchAll with ignoreSearch option (request with no search parameters) PASS Cache.matchAll with ignoreSearch option (request with search parameters) PASS Cache.matchAll with URL containing fragment
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/runtime-get-properties-doesnt-crash-on-window-frame-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/runtime-get-properties-doesnt-crash-on-window-frame-expected.txt new file mode 100644 index 0000000..b8d2add --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/runtime-get-properties-doesnt-crash-on-window-frame-expected.txt
@@ -0,0 +1 @@ +Tests that Runtime.getProperties doesn't crash on window.frames[0]. Should not crash.
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/runtime-get-properties-doesnt-crash-on-window-frame.html b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/runtime-get-properties-doesnt-crash-on-window-frame.html new file mode 100644 index 0000000..52975058 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/runtime-get-properties-doesnt-crash-on-window-frame.html
@@ -0,0 +1,18 @@ +<html> +<head> +<script type="text/javascript" src="./inspector-protocol-test.js"></script> +<script> +function test() +{ + InspectorTest.sendCommandPromise("Runtime.evaluate", { expression: "window.frames[0]" }) + .then((message) => InspectorTest.sendCommandPromise("Runtime.getProperties", { objectId: message.result.result.objectId })) + .then(() => InspectorTest.completeTest()); +} +</script> +</head> +<body> +Tests that Runtime.getProperties doesn't crash on window.frames[0]. Should not crash. +<iframe src="data:text/plain, <b>bold</b>" onload="runTest()"></iframe> +</body> +</html> +
diff --git a/third_party/WebKit/LayoutTests/http/tests/navigation/form-targets-cross-site-frame-get-expected.txt b/third_party/WebKit/LayoutTests/http/tests/navigation/form-targets-cross-site-frame-get-expected.txt index db658522..0942fb3 100644 --- a/third_party/WebKit/LayoutTests/http/tests/navigation/form-targets-cross-site-frame-get-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/navigation/form-targets-cross-site-frame-get-expected.txt
@@ -9,3 +9,9 @@ Parameters: test-field = test-value +Http headers: + +HTTP_CONNECTION = keep-alive +HTTP_HOST = localhost:8080 +HTTP_REFERER = http://127.0.0.1:8000/navigation/form-targets-cross-site-frame-get.html +HTTP_UPGRADE_INSECURE_REQUESTS = 1
diff --git a/third_party/WebKit/LayoutTests/http/tests/navigation/form-targets-cross-site-frame-get.html b/third_party/WebKit/LayoutTests/http/tests/navigation/form-targets-cross-site-frame-get.html index aab6d0a..c632ee83 100644 --- a/third_party/WebKit/LayoutTests/http/tests/navigation/form-targets-cross-site-frame-get.html +++ b/third_party/WebKit/LayoutTests/http/tests/navigation/form-targets-cross-site-frame-get.html
@@ -26,7 +26,7 @@ <body onload="onLoad();"> <form method="GET" - action="https://localhost:8443/navigation/resources/form-target.pl" + action="http://localhost:8080/navigation/resources/form-target.pl" target="cross-site-frame"> Test field: <input name="test-field" type="text" value="test-value"> @@ -34,6 +34,6 @@ </form> <iframe name="cross-site-frame" - src="https://localhost:8443/navigation/resources/form-target.pl"></iframe> + src="http://localhost:8080/navigation/resources/otherpage.html"></iframe> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/navigation/form-targets-cross-site-frame-post-expected.txt b/third_party/WebKit/LayoutTests/http/tests/navigation/form-targets-cross-site-frame-post-expected.txt index ca4d8e2a..4488d48 100644 --- a/third_party/WebKit/LayoutTests/http/tests/navigation/form-targets-cross-site-frame-post-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/navigation/form-targets-cross-site-frame-post-expected.txt
@@ -9,3 +9,11 @@ Parameters: test-field = test-value +Http headers: + +HTTP_CACHE_CONTROL = max-age=0 +HTTP_CONNECTION = keep-alive +HTTP_HOST = localhost:8080 +HTTP_ORIGIN = http://127.0.0.1:8000 +HTTP_REFERER = http://127.0.0.1:8000/navigation/form-targets-cross-site-frame-post.html +HTTP_UPGRADE_INSECURE_REQUESTS = 1
diff --git a/third_party/WebKit/LayoutTests/http/tests/navigation/form-targets-cross-site-frame-post.html b/third_party/WebKit/LayoutTests/http/tests/navigation/form-targets-cross-site-frame-post.html index f90afd84..7a737ae 100644 --- a/third_party/WebKit/LayoutTests/http/tests/navigation/form-targets-cross-site-frame-post.html +++ b/third_party/WebKit/LayoutTests/http/tests/navigation/form-targets-cross-site-frame-post.html
@@ -26,7 +26,7 @@ <body onload="onLoad();"> <form method="POST" - action="https://localhost:8443/navigation/resources/form-target.pl" + action="http://localhost:8080/navigation/resources/form-target.pl" target="cross-site-frame"> Test field: <input name="test-field" type="text" value="test-value"> @@ -34,6 +34,6 @@ </form> <iframe name="cross-site-frame" - src="https://localhost:8443/navigation/resources/form-target.pl"></iframe> + src="http://localhost:8080/navigation/resources/otherpage.html"></iframe> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/navigation/post-basic-expected.txt b/third_party/WebKit/LayoutTests/http/tests/navigation/post-basic-expected.txt index 0459fa7..430aa43 100644 --- a/third_party/WebKit/LayoutTests/http/tests/navigation/post-basic-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/navigation/post-basic-expected.txt
@@ -4,6 +4,14 @@ the-input = input value goes here submitwithpost = Submit with POST +Http headers: + +HTTP_CACHE_CONTROL = max-age=0 +HTTP_CONNECTION = keep-alive +HTTP_HOST = 127.0.0.1:8000 +HTTP_ORIGIN = http://127.0.0.1:8000 +HTTP_REFERER = http://127.0.0.1:8000/navigation/resources/page-that-posts.html +HTTP_UPGRADE_INSECURE_REQUESTS = 1 ============== Back Forward List ============== http://127.0.0.1:8000/navigation/resources/page-that-posts.html
diff --git a/third_party/WebKit/LayoutTests/http/tests/navigation/post-frames-expected.txt b/third_party/WebKit/LayoutTests/http/tests/navigation/post-frames-expected.txt index 8a7ec41..2c640e9 100644 --- a/third_party/WebKit/LayoutTests/http/tests/navigation/post-frames-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/navigation/post-frames-expected.txt
@@ -11,6 +11,14 @@ the-input = input value goes here submitwithpost = Submit with POST +Http headers: + +HTTP_CACHE_CONTROL = max-age=0 +HTTP_CONNECTION = keep-alive +HTTP_HOST = 127.0.0.1:8000 +HTTP_ORIGIN = http://127.0.0.1:8000 +HTTP_REFERER = http://127.0.0.1:8000/navigation/resources/page-that-posts.html +HTTP_UPGRADE_INSECURE_REQUESTS = 1 ============== Back Forward List ============== http://127.0.0.1:8000/navigation/post-frames.html
diff --git a/third_party/WebKit/LayoutTests/http/tests/navigation/post-frames-goback1-expected.txt b/third_party/WebKit/LayoutTests/http/tests/navigation/post-frames-goback1-expected.txt index dfdd3ae..47fb769 100644 --- a/third_party/WebKit/LayoutTests/http/tests/navigation/post-frames-goback1-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/navigation/post-frames-goback1-expected.txt
@@ -11,6 +11,14 @@ Parameters: the-input = input value goes here +Http headers: + +HTTP_CACHE_CONTROL = max-age=0 +HTTP_CONNECTION = keep-alive +HTTP_HOST = 127.0.0.1:8000 +HTTP_ORIGIN = http://127.0.0.1:8000 +HTTP_REFERER = http://127.0.0.1:8000/navigation/post-frames-goback1.html +HTTP_UPGRADE_INSECURE_REQUESTS = 1 ============== Back Forward List ============== curr-> http://127.0.0.1:8000/navigation/post-frames-goback1.html
diff --git a/third_party/WebKit/LayoutTests/http/tests/navigation/post-goback1-expected.txt b/third_party/WebKit/LayoutTests/http/tests/navigation/post-goback1-expected.txt index a79ced3..f844d6b 100644 --- a/third_party/WebKit/LayoutTests/http/tests/navigation/post-goback1-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/navigation/post-goback1-expected.txt
@@ -4,6 +4,14 @@ the-input = input value goes here submitwithpost = Submit with POST +Http headers: + +HTTP_CACHE_CONTROL = max-age=0 +HTTP_CONNECTION = keep-alive +HTTP_HOST = 127.0.0.1:8000 +HTTP_ORIGIN = http://127.0.0.1:8000 +HTTP_REFERER = http://127.0.0.1:8000/navigation/resources/page-that-posts.html +HTTP_UPGRADE_INSECURE_REQUESTS = 1 ============== Back Forward List ============== http://127.0.0.1:8000/navigation/resources/page-that-posts.html
diff --git a/third_party/WebKit/LayoutTests/http/tests/navigation/resources/form-target.pl b/third_party/WebKit/LayoutTests/http/tests/navigation/resources/form-target.pl index c07187d..17ccd01 100755 --- a/third_party/WebKit/LayoutTests/http/tests/navigation/resources/form-target.pl +++ b/third_party/WebKit/LayoutTests/http/tests/navigation/resources/form-target.pl
@@ -24,6 +24,22 @@ print "<li>" . $paramName . " = " . $query->param($paramName) . "</li>" } +print <<HEADER2; +</ul> +<p>Http headers:</p> +<ul> +HEADER2 + +my %headers = map { $_ => $query->http($_) } $query->http(); +for my $header ( sort (keys %headers) ) { + if (("$header" ne "HTTP_ACCEPT_ENCODING") && + ("$header" ne "HTTP_ACCEPT_LANGUAGE") && + ("$header" ne "HTTP_ACCEPT") && + ("$header" ne "HTTP_USER_AGENT")) { + print "<li>$header = $headers{$header}</li>\n"; + } +} + print <<FOOTER </ul> <script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/notifications/serviceworkerregistration-get-replacement.html b/third_party/WebKit/LayoutTests/http/tests/notifications/serviceworkerregistration-get-replacement.html new file mode 100644 index 0000000..94ca913 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/notifications/serviceworkerregistration-get-replacement.html
@@ -0,0 +1,48 @@ +<!doctype html> +<html> + <head> + <title>Notifications: ServiceWorkerRegistration.getNotifications() with a notification replacement.</title> + <script src="../resources/testharness.js"></script> + <script src="../resources/testharnessreport.js"></script> + <script src="../serviceworker/resources/test-helpers.js"></script> + <script src="resources/test-helpers.js"></script> + </head> + <body> + <script> + // Tests that the getNotifications() function when used in a document returns + // an array of the notifications which were previously displayed using a filter. + // Notifications replaced using the `tag` should not be included anymore. + async_test(function(test) { + var scope = 'resources/scope/' + location.pathname, + script = 'instrumentation-service-worker.js'; + + testRunner.setPermission('notifications', 'granted', location.origin, location.origin); + + var registration = null; + getActiveServiceWorkerWithMessagePort(test, script, scope).then(function(workerInfo) { + registration = workerInfo.registration; + + return registration.showNotification('Hello, world!', { + body: 'First notification', + tag: 'banana', + }); + }).then(function() { + return registration.showNotification('Hello again, world!', { + body: 'Second notification', + tag: 'banana', + }); + }).then(function() { + return registration.getNotifications({ tag: 'banana' }); + }).then(function(notifications) { + assert_equals(notifications.length, 1); + + assert_equals(notifications[0].title, 'Hello again, world!'); + assert_equals(notifications[0].body, 'Second notification'); + + test.done(); + }).catch(unreached_rejection(test)); + + }, 'ServiceWorkerRegistration.getNotifications() does not return replaced notifications.'); + </script> + </body> +</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-allowed-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-allowed-expected.txt index cde15a26..13590de 100644 --- a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-allowed-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-allowed-expected.txt
@@ -3,6 +3,14 @@ Parameters: fieldname = fieldvalue +Http headers: + +HTTP_CACHE_CONTROL = max-age=0 +HTTP_CONNECTION = keep-alive +HTTP_HOST = 127.0.0.1:8000 +HTTP_ORIGIN = http://127.0.0.1:8000 +HTTP_REFERER = http://127.0.0.1:8000/security/contentSecurityPolicy/1.1/form-action-src-allowed.html +HTTP_UPGRADE_INSECURE_REQUESTS = 1 ============== Back Forward List ============== http://127.0.0.1:8000/security/contentSecurityPolicy/1.1/form-action-src-allowed.html
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-default-ignored-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-default-ignored-expected.txt index 6fc2ca9..3b81410 100644 --- a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-default-ignored-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-default-ignored-expected.txt
@@ -3,6 +3,14 @@ Parameters: fieldname = fieldvalue +Http headers: + +HTTP_CACHE_CONTROL = max-age=0 +HTTP_CONNECTION = keep-alive +HTTP_HOST = 127.0.0.1:8000 +HTTP_ORIGIN = http://127.0.0.1:8000 +HTTP_REFERER = http://127.0.0.1:8000/security/contentSecurityPolicy/1.1/form-action-src-default-ignored.html +HTTP_UPGRADE_INSECURE_REQUESTS = 1 ============== Back Forward List ============== http://127.0.0.1:8000/security/contentSecurityPolicy/1.1/form-action-src-default-ignored.html
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-get-allowed-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-get-allowed-expected.txt index 35832f6a..182ba9d 100644 --- a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-get-allowed-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/form-action-src-get-allowed-expected.txt
@@ -3,6 +3,12 @@ Parameters: fieldname = fieldvalue +Http headers: + +HTTP_CONNECTION = keep-alive +HTTP_HOST = 127.0.0.1:8000 +HTTP_REFERER = http://127.0.0.1:8000/security/contentSecurityPolicy/1.1/form-action-src-get-allowed.html +HTTP_UPGRADE_INSECURE_REQUESTS = 1 ============== Back Forward List ============== http://127.0.0.1:8000/security/contentSecurityPolicy/1.1/form-action-src-get-allowed.html
diff --git a/third_party/WebKit/LayoutTests/http/tests/worklet/webexposed/global-interface-listing-paint-worklet-expected.txt b/third_party/WebKit/LayoutTests/http/tests/worklet/webexposed/global-interface-listing-paint-worklet-expected.txt index bb2a9c85..61bf12b 100644 --- a/third_party/WebKit/LayoutTests/http/tests/worklet/webexposed/global-interface-listing-paint-worklet-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/worklet/webexposed/global-interface-listing-paint-worklet-expected.txt
@@ -68,6 +68,9 @@ CONSOLE MESSAGE: line 137: getter x CONSOLE MESSAGE: line 137: getter y CONSOLE MESSAGE: line 137: method constructor +CONSOLE MESSAGE: line 137: interface CSSResourceValue : CSSStyleValue +CONSOLE MESSAGE: line 137: getter state +CONSOLE MESSAGE: line 137: method constructor CONSOLE MESSAGE: line 137: interface CSSRotation : CSSTransformComponent CONSOLE MESSAGE: line 137: getter angle CONSOLE MESSAGE: line 137: getter x
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/FileAPI/historical-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/FileAPI/historical-expected.txt deleted file mode 100644 index deac0092..0000000 --- a/third_party/WebKit/LayoutTests/imported/wpt/FileAPI/historical-expected.txt +++ /dev/null
@@ -1,9 +0,0 @@ -This is a testharness.js-based test. -PASS "toNativeLineEndings" should not be supported -PASS "FileError" should not be supported -PASS "FileException" should not be supported -PASS Blob should not support slice prefixed -PASS BlobBuilder should not be supported. -FAIL FileReader should not support readAsBinaryString assert_false: should not be in reader expected false got true -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/FileAPI/historical.html b/third_party/WebKit/LayoutTests/imported/wpt/FileAPI/historical.html index 3ff56a3..a9ae674 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/FileAPI/historical.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/FileAPI/historical.html
@@ -36,13 +36,6 @@ assert_false(prefixes[i]+'BlobBuilder' in window, prefixes[i]+'BlobBuilder'); } }, 'BlobBuilder should not be supported.'); - - test(function() { - var reader = new FileReader(); - assert_false('readAsBinaryString' in reader, 'should not be in reader'); - assert_equals(reader.readAsBinaryString, undefined, - 'should be undefined on getting') - }, 'FileReader should not support readAsBinaryString'); </script> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/IndexedDB/interfaces-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/IndexedDB/interfaces-expected.txt index 8bef3615..adc6cfa8 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/IndexedDB/interfaces-expected.txt +++ b/third_party/WebKit/LayoutTests/imported/wpt/IndexedDB/interfaces-expected.txt
@@ -86,6 +86,7 @@ PASS IDBDatabase interface: operation transaction([object Object],[object Object],IDBTransactionMode) PASS IDBDatabase interface: operation close() PASS IDBDatabase interface: attribute onabort +PASS IDBDatabase interface: attribute onclose PASS IDBDatabase interface: attribute onerror PASS IDBDatabase interface: attribute onversionchange PASS IDBObjectStore interface: existence and properties of interface object
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/IndexedDB/interfaces.idl b/third_party/WebKit/LayoutTests/imported/wpt/IndexedDB/interfaces.idl index 6eee5f4..353864d 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/IndexedDB/interfaces.idl +++ b/third_party/WebKit/LayoutTests/imported/wpt/IndexedDB/interfaces.idl
@@ -83,6 +83,7 @@ IDBTransaction transaction ((DOMString or sequence<DOMString>) storeNames, optional IDBTransactionMode mode = "readonly"); void close (); attribute EventHandler onabort; + attribute EventHandler onclose; attribute EventHandler onerror; attribute EventHandler onversionchange; };
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/custom-elements/custom-elements-registry/define-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/custom-elements/custom-elements-registry/define-expected.txt index 269a077..d383409 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/custom-elements/custom-elements-registry/define-expected.txt +++ b/third_party/WebKit/LayoutTests/imported/wpt/custom-elements/custom-elements-registry/define-expected.txt
@@ -8,6 +8,27 @@ PASS If constructor is string, should throw a TypeError PASS If constructor is arrow function, should throw a TypeError PASS If constructor is method, should throw a TypeError +FAIL If constructor is HTMLElement, should throw a TypeError assert_throws: function "() => { + customElements.define(`test-define-constructor-${t[0]}`, t[1]); + }" threw object "SyntaxError: Failed to execute 'define' on 'CustomElementsRegistry': "test-define-constructor-HTMLElement" is not a valid custom element name" ("SyntaxError") expected object "TypeError" ("TypeError") +FAIL If constructor is HTMLButtonElement, should throw a TypeError assert_throws: function "() => { + customElements.define(`test-define-constructor-${t[0]}`, t[1]); + }" threw object "SyntaxError: Failed to execute 'define' on 'CustomElementsRegistry': "test-define-constructor-HTMLButtonElement" is not a valid custom element name" ("SyntaxError") expected object "TypeError" ("TypeError") +FAIL If constructor is HTMLImageElement, should throw a TypeError assert_throws: function "() => { + customElements.define(`test-define-constructor-${t[0]}`, t[1]); + }" threw object "SyntaxError: Failed to execute 'define' on 'CustomElementsRegistry': "test-define-constructor-HTMLImageElement" is not a valid custom element name" ("SyntaxError") expected object "TypeError" ("TypeError") +FAIL If constructor is HTMLMediaElement, should throw a TypeError assert_throws: function "() => { + customElements.define(`test-define-constructor-${t[0]}`, t[1]); + }" threw object "SyntaxError: Failed to execute 'define' on 'CustomElementsRegistry': "test-define-constructor-HTMLMediaElement" is not a valid custom element name" ("SyntaxError") expected object "TypeError" ("TypeError") +FAIL If constructor is Image, should throw a TypeError assert_throws: function "() => { + customElements.define(`test-define-constructor-${t[0]}`, t[1]); + }" threw object "SyntaxError: Failed to execute 'define' on 'CustomElementsRegistry': "test-define-constructor-Image" is not a valid custom element name" ("SyntaxError") expected object "TypeError" ("TypeError") +FAIL If constructor is Audio, should throw a TypeError assert_throws: function "() => { + customElements.define(`test-define-constructor-${t[0]}`, t[1]); + }" threw object "SyntaxError: Failed to execute 'define' on 'CustomElementsRegistry': "test-define-constructor-Audio" is not a valid custom element name" ("SyntaxError") expected object "TypeError" ("TypeError") +FAIL If constructor is Option, should throw a TypeError assert_throws: function "() => { + customElements.define(`test-define-constructor-${t[0]}`, t[1]); + }" threw object "SyntaxError: Failed to execute 'define' on 'CustomElementsRegistry': "test-define-constructor-Option" is not a valid custom element name" ("SyntaxError") expected object "TypeError" ("TypeError") PASS Element names: defining an element named a- should succeed PASS Element names: defining an element named a-a should succeed PASS Element names: defining an element named aa- should succeed @@ -73,7 +94,6 @@ FAIL If extends is elementnametobeunknownelement, should throw a NotSupportedError assert_throws: function "() => { customElements.define('test-define-extend-' + name, class {}, { extends: name }); }" did not throw -PASS If constructor.observedAttributes throws, should rethrow PASS If constructor.prototype throws, should rethrow PASS If Type(constructor.prototype) is undefined, should throw a TypeError PASS If Type(constructor.prototype) is string, should throw a TypeError
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/custom-elements/custom-elements-registry/define.html b/third_party/WebKit/LayoutTests/imported/wpt/custom-elements/custom-elements-registry/define.html index 670c963..76ab2adf 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/custom-elements/custom-elements-registry/define.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/custom-elements/custom-elements-registry/define.html
@@ -56,7 +56,26 @@ }, `If constructor is ${t[0]}, should throw a TypeError`); }); - // 2. If name is not a valid custom element name, + // 2. If constructor is an interface object or named constructor whose corresponding + // interface either is HTMLElement or has HTMLElement in its set of inherited interfaces, + // throw a TypeError and abort these steps. + [ + [ 'HTMLElement', HTMLElement ], + [ 'HTMLButtonElement', HTMLButtonElement ], + [ 'HTMLImageElement', HTMLImageElement ], + [ 'HTMLMediaElement', HTMLMediaElement ], + [ 'Image' , Image ], + [ 'Audio' , Audio ], + [ 'Option', Option ], + ].forEach(t => { + test(() => { + assert_throws(expectTypeError, () => { + customElements.define(`test-define-constructor-${t[0]}`, t[1]); + }); + }, `If constructor is ${t[0]}, should throw a TypeError`); + }); + + // 3. If name is not a valid custom element name, // then throw a SyntaxError and abort these steps. let validCustomElementNames = [ // [a-z] (PCENChar)* '-' (PCENChar)* @@ -110,7 +129,7 @@ }, `Element names: defining an element named ${name} should throw a SyntaxError`); }); - // 3. If this CustomElementsRegistry contains an entry with name name, + // 4. If this CustomElementsRegistry contains an entry with name name, // then throw a NotSupportedError and abort these steps. test(() => { customElements.define('test-define-dup-name', class {}); @@ -119,7 +138,7 @@ }); }, 'If the name is already defined, should throw a NotSupportedError'); - // 4. If this CustomElementsRegistry contains an entry with constructor constructor, + // 6. If this CustomElementsRegistry contains an entry with constructor constructor, // then throw a NotSupportedError and abort these steps. test(() => { class TestDupConstructor {}; @@ -129,7 +148,7 @@ }); }, 'If the constructor is already defined, should throw a NotSupportedError'); - // 7.1. If extends is a valid custom element name, + // 10.1. If extends is a valid custom element name, // then throw a NotSupportedError. validCustomElementNames.forEach(name => { test(() => { @@ -139,7 +158,7 @@ }, `If extends is ${name}, should throw a NotSupportedError`); }); - // 7.2. If the element interface for extends and the HTML namespace is HTMLUnknownElement + // 10.2. If the element interface for extends and the HTML namespace is HTMLUnknownElement // (e.g., if extends does not indicate an element definition in this specification), // then throw a NotSupportedError. [ @@ -159,19 +178,7 @@ }, `If extends is ${name}, should throw a NotSupportedError`); }); - // 8. Let observedAttributesIterable be Get(constructor, "observedAttributes"). - // Rethrow any exceptions. - test(() => { - class C { - static get observedAttributes() { throw_rethrown_error(); } - attributeChangedCallback() {} - } - assert_rethrown(() => { - customElements.define('test-define-observedattributes-rethrow', C); - }); - }, 'If constructor.observedAttributes throws, should rethrow'); - - // 10. Let prototype be Get(constructor, "prototype"). Rethrow any exceptions. + // 13.1. Let prototype be Get(constructor, "prototype"). Rethrow any exceptions. function assert_rethrown(func, description) { assert_throws({ name: 'rethrown' }, func, description); } @@ -190,7 +197,8 @@ customElements.define('test-define-constructor-prototype-rethrow', BadConstructor); }); }, 'If constructor.prototype throws, should rethrow'); - // 11. If Type(prototype) is not Object, + + // 13.2. If Type(prototype) is not Object, // then throw a TypeError exception. test(() => { const c = (function () { }).bind({}); // prototype is undefined. @@ -206,15 +214,21 @@ }); }, 'If Type(constructor.prototype) is string, should throw a TypeError'); - // 12. Let connectedCallback be Get(prototype, "connectedCallback"). Rethrow any exceptions. - // 13. If connectedCallback is not undefined, and IsCallable(connectedCallback) is false, - // then throw a TypeError exception. - // 14. Let disconnectedCallback be Get(prototype, "disconnectedCallback"). Rethrow any exceptions. - // 15. If disconnectedCallback is not undefined, and IsCallable(disconnectedCallback) is false, - // then throw a TypeError exception. - // 16. Let attributeChangedCallback be Get(prototype, "attributeChangedCallback"). Rethrow any exceptions. - // 17. If attributeChangedCallback is not undefined, and IsCallable(attributeChangedCallback) is false, - // then throw a TypeError exception. + // 13.4. Let connectedCallbackValue be Get(prototype, "connectedCallback"). + // Rethrow any exceptions. + // 13.5. If connectedCallbackValue is not undefined, then set connectedCallback + // to the result of converting connectedCallbackValue to the Web IDL Function callback type. + // Rethrow any exceptions. + // 13.6. Let disconnectedCallbackValue be Get(prototype, "disconnectedCallback"). + // Rethrow any exceptions. + // 13.7. If disconnectedCallbackValue is not undefined, then set disconnectedCallback + // to the result of converting disconnectedCallbackValue to the Web IDL Function callback type. + // Rethrow any exceptions. + // 13.8. Let attributeChangedCallbackValue be Get(prototype, "attributeChangedCallback"). + // Rethrow any exceptions. + // 13.9. If attributeChangedCallbackValue is not undefined, then set attributeChangedCallback + // to the result of converting attributeChangedCallbackValue to the Web IDL Function callback type. + // Rethrow any exceptions. [ 'connectedCallback', 'disconnectedCallback',
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/dom/events/AddEventListenerOptions-once-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/dom/events/AddEventListenerOptions-once-expected.txt new file mode 100644 index 0000000..86cb1c1b --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/dom/events/AddEventListenerOptions-once-expected.txt
@@ -0,0 +1,6 @@ +This is a testharness.js-based test. +FAIL Once listener should be invoked only once assert_equals: Once handler shouldn't be invoked again expected false but got true +FAIL Once listener should be invoked only once even if the event is nested assert_equals: Once handler should only be invoked once expected 1 but got 2 +FAIL Once listener should be added / removed like normal listeners assert_equals: The handler was added as a once listener expected 0 but got 1 +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/dom/events/AddEventListenerOptions-once.html b/third_party/WebKit/LayoutTests/imported/wpt/dom/events/AddEventListenerOptions-once.html new file mode 100644 index 0000000..ae75070 --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/dom/events/AddEventListenerOptions-once.html
@@ -0,0 +1,81 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>AddEventListenerOptions.once</title> +<link rel="author" title="Xidorn Quan" href="https://www.upsuper.org"> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-addeventlisteneroptions-once"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> + +test(function() { + var invoked_once = false; + var invoked_normal = false; + function handler_once() { + invoked_once = true; + } + function handler_normal() { + invoked_normal = true; + } + + document.addEventListener('test', handler_once, {once: true}); + document.addEventListener('test', handler_normal); + document.dispatchEvent(new Event('test')); + assert_equals(invoked_once, true, "Once handler should be invoked"); + assert_equals(invoked_normal, true, "Normal handler should be invoked"); + + invoked_once = false; + invoked_normal = false; + document.dispatchEvent(new Event('test')); + assert_equals(invoked_once, false, "Once handler shouldn't be invoked again"); + assert_equals(invoked_normal, true, "Normal handler should be invoked again"); + document.removeEventListener('test', handler_normal); +}, "Once listener should be invoked only once"); + +test(function() { + var invoked_count = 0; + function handler() { + invoked_count++; + if (invoked_count == 1) + document.dispatchEvent(new Event('test')); + } + document.addEventListener('test', handler, {once: true}); + document.dispatchEvent(new Event('test')); + assert_equals(invoked_count, 1, "Once handler should only be invoked once"); + + invoked_count = 0; + function handler2() { + invoked_count++; + if (invoked_count == 1) + document.addEventListener('test', handler2, {once: true}); + if (invoked_count <= 2) + document.dispatchEvent(new Event('test')); + } + document.addEventListener('test', handler2, {once: true}); + document.dispatchEvent(new Event('test')); + assert_equals(invoked_count, 2, "Once handler should only be invoked once after each adding"); +}, "Once listener should be invoked only once even if the event is nested"); + +test(function() { + var invoked_count = 0; + function handler() { + invoked_count++; + } + + document.addEventListener('test', handler, {once: true}); + document.addEventListener('test', handler); + document.dispatchEvent(new Event('test')); + assert_equals(invoked_count, 1, "The handler should only be added once"); + + invoked_count = 0; + document.dispatchEvent(new Event('test')); + assert_equals(invoked_count, 0, "The handler was added as a once listener"); + + invoked_count = 0; + document.addEventListener('test', handler, {once: true}); + document.removeEventListener('test', handler); + document.dispatchEvent(new Event('test')); + assert_equals(invoked_count, 0, "The handler should have been removed"); +}, "Once listener should be added / removed like normal listeners"); + +</script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/dom/lists/DOMTokenList-iteration-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/dom/lists/DOMTokenList-iteration-expected.txt new file mode 100644 index 0000000..feff9d36 --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/dom/lists/DOMTokenList-iteration-expected.txt
@@ -0,0 +1,4 @@ +This is a testharness.js-based test. +FAIL DOMTokenList iteration: keys, values, etc. assert_equals: expected function "function values() { [native code] }" but got function "function () { [native code] }" +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/dom/lists/DOMTokenList-iteration.html b/third_party/WebKit/LayoutTests/imported/wpt/dom/lists/DOMTokenList-iteration.html new file mode 100644 index 0000000..1911f7bb --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/dom/lists/DOMTokenList-iteration.html
@@ -0,0 +1,48 @@ +<!doctype html> +<meta charset=utf-8> +<title>DOMTokenList iteration: keys, values, etc.</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<span class=" a a b "></span> +<script> + test(function() { + var list = document.querySelector("span").classList; + assert_array_equals([...list], ["a", "a", "b"]); + + var keys = list.keys(); + assert_false(keys instanceof Array); + keys = [...keys]; + assert_array_equals(keys, [0, 1, 2]); + + var values = list.values(); + assert_false(values instanceof Array); + values = [...values]; + assert_array_equals(values, ["a", "a", "b"]); + + var entries = list.entries(); + assert_false(entries instanceof Array); + entries = [...entries]; + assert_equals(entries.length, keys.length); + assert_equals(entries.length, values.length); + for (var i = 0; i < entries.length; ++i) { + assert_array_equals(entries[i], [keys[i], values[i]]); + } + + var cur = 0; + var thisObj = {}; + list.forEach(function(value, key, listObj) { + assert_equals(listObj, list); + assert_equals(this, thisObj); + assert_equals(value, values[cur]); + assert_equals(key, keys[cur]); + cur++; + }, thisObj); + assert_equals(cur, entries.length); + + assert_equals(list[Symbol.iterator], Array.prototype[Symbol.iterator]); + assert_equals(list.keys, Array.prototype.keys); + assert_equals(list.values, Array.prototype.values); + assert_equals(list.entries, Array.prototype.entries); + assert_equals(list.forEach, Array.prototype.forEach); + }); +</script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/dom/nodes/Node-childNodes-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/dom/nodes/Node-childNodes-expected.txt index 23d1b487..e178680 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/dom/nodes/Node-childNodes-expected.txt +++ b/third_party/WebKit/LayoutTests/imported/wpt/dom/nodes/Node-childNodes-expected.txt
@@ -3,5 +3,6 @@ PASS Node.childNodes on an Element. PASS Node.childNodes on a DocumentFragment. FAIL Node.childNodes on a Document. Illegal constructor +FAIL Iterator behavior of Node.childNodes assert_equals: expected function "function values() { [native code] }" but got function "function () { [native code] }" Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/dom/nodes/Node-childNodes.html b/third_party/WebKit/LayoutTests/imported/wpt/dom/nodes/Node-childNodes.html index d08dd2e1..8bd1f250 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/dom/nodes/Node-childNodes.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/dom/nodes/Node-childNodes.html
@@ -45,4 +45,53 @@ test(function() { check_parent_node(new Document()); }, "Node.childNodes on a Document."); + +test(function() { + var node = document.createElement("div"); + var kid1 = document.createElement("p"); + var kid2 = document.createTextNode("hey"); + var kid3 = document.createElement("span"); + node.appendChild(kid1); + node.appendChild(kid2); + node.appendChild(kid3); + + var list = node.childNodes; + assert_array_equals([...list], [kid1, kid2, kid3]); + + var keys = list.keys(); + assert_false(keys instanceof Array); + keys = [...keys]; + assert_array_equals(keys, [0, 1, 2]); + + var values = list.values(); + assert_false(values instanceof Array); + values = [...values]; + assert_array_equals(values, [kid1, kid2, kid3]); + + var entries = list.entries(); + assert_false(entries instanceof Array); + entries = [...entries]; + assert_equals(entries.length, keys.length); + assert_equals(entries.length, values.length); + for (var i = 0; i < entries.length; ++i) { + assert_array_equals(entries[i], [keys[i], values[i]]); + } + + var cur = 0; + var thisObj = {}; + list.forEach(function(value, key, listObj) { + assert_equals(listObj, list); + assert_equals(this, thisObj); + assert_equals(value, values[cur]); + assert_equals(key, keys[cur]); + cur++; + }, thisObj); + assert_equals(cur, entries.length); + + assert_equals(list[Symbol.iterator], Array.prototype[Symbol.iterator]); + assert_equals(list.keys, Array.prototype.keys); + assert_equals(list.values, Array.prototype.values); + assert_equals(list.entries, Array.prototype.entries); + assert_equals(list.forEach, Array.prototype.forEach); +}, "Iterator behavior of Node.childNodes"); </script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/grouping-content/the-li-element/grouping-li-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/grouping-content/the-li-element/grouping-li-expected.txt deleted file mode 100644 index 19aea0a..0000000 --- a/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/grouping-content/the-li-element/grouping-li-expected.txt +++ /dev/null
@@ -1,15 +0,0 @@ -This is a testharness.js-based test. -PASS The prototype for li is HTMLLIElement.prototype -FAIL li should have a 'value' attribute assert_own_property: li should have a 'value' attribute expected property "value" missing -PASS Default (unspecified) value of value is 0. -PASS .value property reflects content attribute - and both parse value of '2' correctly. -PASS IDL and content attribute parse value of '-10' correctly. -PASS IDL and content attribute parse value of '4.03' correctly. -PASS IDL and content attribute parse value of '-4.03' correctly. -PASS IDL and content attribute parse value of '4.9' correctly. -PASS IDL and content attribute parse value of '-4.9' correctly. -PASS IDL and content attribute parse value of '7e2' correctly. -PASS IDL and content attribute parse value of '.5' correctly. -PASS IDL and content attribute parse value of 'A' correctly. -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/grouping-content/the-li-element/grouping-li.html b/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/grouping-content/the-li-element/grouping-li.html index 9deb9b5..fa342b3e 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/grouping-content/the-li-element/grouping-li.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/grouping-content/the-li-element/grouping-li.html
@@ -37,7 +37,7 @@ <p>Unordered List</p> <ul id="unordered"> - <li id="test_li">list item</li> + <li>list item</li> <li>list item</li> <li>list item</li> </ul> @@ -116,23 +116,11 @@ <script> "use strict"; - var testLI = document.getElementById("test_li"), testList = [], i = 0; - - // check that prototype matches spec's DOM interface - test(function() { - assert_equals(Object.getPrototypeOf(testLI), HTMLLIElement.prototype, "HTMLLIElement.prototype should be used for li"); - }, "The prototype for li is HTMLLIElement.prototype"); - - // check that "own" property "value" is present - test(function() { - assert_own_property(testLI,"value", "li should have a 'value' attribute"); - }, "li should have a 'value' attribute"); - // "The [value] attribute has no default value" so, per https://html.spec.whatwg.org/multipage/#reflect, // the default when unspecified is 0 - testList = document.querySelectorAll("#unordered li, #basic li"); test(function() { - for(i = 0; i < testList.length; i++) { + var testList = document.querySelectorAll("#unordered li, #basic li"); + for (var i = 0; i < testList.length; i++) { assert_equals(testList[i].value, 0, "Default (unspecified) value of value is 0."); } }, "Default (unspecified) value of value is 0."); @@ -146,55 +134,55 @@ // start2's first element has value of 2 test(function() { - testLI = document.getElementById("start2").children[0]; + var testLI = document.getElementById("start2").children[0]; assert_equals(testLI.value, 2, "value of 2 -> value of 2"); }, ".value property reflects content attribute - and both parse value of '2' correctly."); // negative's first element has value of -10 test(function() { - testLI = document.getElementById("negative").children[0]; + var testLI = document.getElementById("negative").children[0]; assert_equals(testLI.value, -10, "value of -10 -> value of -10"); }, "IDL and content attribute parse value of '-10' correctly."); // posFloatDown's first element has value of 4.03 which should return 4 test(function() { - testLI = document.getElementById("posFloatDown").children[0]; + var testLI = document.getElementById("posFloatDown").children[0]; assert_equals(testLI.value, 4, "value of 4.03 -> 4"); }, "IDL and content attribute parse value of '4.03' correctly."); // negFloatDown's first element has value of -4.03 which should return -4 test(function() { - testLI = document.getElementById("negFloatDown").children[0]; + var testLI = document.getElementById("negFloatDown").children[0]; assert_equals(testLI.value, -4, "value of -4.03 -> -4"); }, "IDL and content attribute parse value of '-4.03' correctly."); // posFloatUp's first element has value of 4.9 which should return 4 test(function() { - testLI = document.getElementById("posFloatUp").children[0]; + var testLI = document.getElementById("posFloatUp").children[0]; assert_equals(testLI.value, 4, "value of 4.9 -> 4"); }, "IDL and content attribute parse value of '4.9' correctly."); // negFloatUp's first element has value of -4.9 which should return -4 test(function() { - testLI = document.getElementById("negFloatUp").children[0]; + var testLI = document.getElementById("negFloatUp").children[0]; assert_equals(testLI.value, -4, "value of -4.9 -> -4"); }, "IDL and content attribute parse value of '-4.9' correctly."); // exponent's first element has value of 7e2 which should return 7 test(function() { - testLI = document.getElementById("exponent").children[0]; + var testLI = document.getElementById("exponent").children[0]; assert_equals(testLI.value, 7, "value of 7e2 -> 7"); }, "IDL and content attribute parse value of '7e2' correctly."); // decimal's first element has value of .5 which should return 0 test(function() { - testLI = document.getElementById("decimal").children[0]; + var testLI = document.getElementById("decimal").children[0]; assert_equals(testLI.value, 0, "value of .5 -> 0 (default)"); }, "IDL and content attribute parse value of '.5' correctly."); // letter's first element has value of A which should return 0 test(function() { - testLI = document.getElementById("letter").children[0]; + var testLI = document.getElementById("letter").children[0]; assert_equals(testLI.value, 0, "value of A -> 0 (default)"); }, "IDL and content attribute parse value of 'A' correctly.");
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/interactive-elements/the-dialog-element/dialog-open.html b/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/interactive-elements/the-dialog-element/dialog-open.html new file mode 100644 index 0000000..4719f63 --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/interactive-elements/the-dialog-element/dialog-open.html
@@ -0,0 +1,30 @@ +<!doctype html> +<meta charset="utf-8"> +<title>dialog element: open</title> +<link rel=help href="https://html.spec.whatwg.org/multipage/forms.html#dom-dialog-open"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<dialog id="d1"> + <p>foobar</p> + <button>OK</button> +</dialog> +<dialog id="d2" open> + <p>foobar</p> + <button>OK</button> +</dialog> +<script> + var d1 = document.getElementById('d1'); + var d2 = document.getElementById('d2'); + + test(function(){ + assert_false(d1.open); + assert_true(d2.open); + }, "On getting, the IDL open attribute must return true if the content open attribute is set, and false if it is absent."); + + test(function(){ + d1.open = true; + assert_true(d1.hasAttribute("open")); + d2.open = false; + assert_false(d2.hasAttribute("open")); + }, "On setting, the content open attribute must be removed if the IDL open attribute is set to false, and must be present if the IDL open attribute is set to true."); +</script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/scripting-1/the-script-element/script-charset-03-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/scripting-1/the-script-element/script-charset-03-expected.txt new file mode 100644 index 0000000..62615fe --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/scripting-1/the-script-element/script-charset-03-expected.txt
@@ -0,0 +1,4 @@ +This is a testharness.js-based test. +FAIL Script changing @charset window.getSomeString is not a function +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/scripting-1/the-script-element/script-charset-03.html b/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/scripting-1/the-script-element/script-charset-03.html new file mode 100644 index 0000000..4ff4cc6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/scripting-1/the-script-element/script-charset-03.html
@@ -0,0 +1,20 @@ +<!DOCTYPE html> +<head> +<meta charset="utf-8"> +<title>Script changing @charset</title> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#scriptingLanguages"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +async_test(function() { + var s = document.createElement("script"); + s.src = "external-script-windows1250.js"; + s.charset = "windows-1250"; + document.body.appendChild(s); + s.charset = "utf-8"; + window.onload = this.step_func_done(function() { + assert_equals(window.getSomeString(), "\u015b\u0107\u0105\u017c\u017a"); + }); +}) +</script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/tabular-data/the-table-element/caption-methods.html b/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/tabular-data/the-table-element/caption-methods.html index 79546eb5..35ee9f4 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/tabular-data/the-table-element/caption-methods.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/tabular-data/the-table-element/caption-methods.html
@@ -36,6 +36,8 @@ </table> <table id="table4" style="display:none"> </table> + <table id="table5" style="display:none"> + </table> <script> test(function () { var table0 = document.getElementById('table0'); @@ -81,6 +83,18 @@ table4.deleteCaption(); assert_equals(caption.parentNode, table4); }, "deleteCaption method not remove caption that is not in html namespace") + test(function() { + var table5 = document.getElementById('table5'); + var caption = document.createElement('caption'); + caption.appendChild(table5) + + // Node cannot be inserted at the specified point in the hierarchy + assert_throws("HierarchyRequestError", function() { + table5.caption = caption; + }); + + assert_not_equals(table5.caption, caption); + }, "Setting caption rethrows exception"); </script> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/tabular-data/the-table-element/remove-row.html b/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/tabular-data/the-table-element/remove-row.html new file mode 100644 index 0000000..b0e529f9 --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/tabular-data/the-table-element/remove-row.html
@@ -0,0 +1,50 @@ +<!doctype html> +<meta charset="utf-8"> +<title>Delete Row tests</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<table id="element"> + <thead> + <th>First column</th> + <th>Second column</th> + </thead> + <tbody> + <tr> + <td>1.1</td> + <td>1.2</td> + </tr> + <tr> + <td>2.1</td> + <td>2.2</td> + </tr> + </tbody> +</table> + +<script> +var el = document.getElementById('element'); + +test(function() { + assert_throws("IndexSizeError", function() { + el.deleteRow(-2) + }) +}, 'deleteRow function invalid argument'); +test(function() { + assert_throws("IndexSizeError", function() { + el.deleteRow(el.rows.length) + }) +}, 'deleteRow function invalid argument bis'); + +test(function() { + var old_length = el.rows.length; + el.insertRow(-1); + el.deleteRow(-1); + assert_equals(old_length, el.rows.length); +}, "check normal deleteRow"); +test(function() { + while (el.rows.length > 1) { + el.deleteRow(-1); + } + assert_equals(1, el.rows.length); +}, "check normal deleteRow bis"); +</script>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/pointerevents/pointerevent_support.js b/third_party/WebKit/LayoutTests/imported/wpt/pointerevents/pointerevent_support.js index 6f399706..4067d53 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/pointerevents/pointerevent_support.js +++ b/third_party/WebKit/LayoutTests/imported/wpt/pointerevents/pointerevent_support.js
@@ -13,9 +13,10 @@ // Check for conformance to PointerEvent interface // TA: 1.1, 1.2, 1.6, 1.7, 1.8, 1.9, 1.10, 1.11, 1.12, 1.13 function check_PointerEvent(event) { + var pointerTestName = event.pointerType + ' ' + event.type; test(function () { assert_true(event instanceof PointerEvent, "event is a PointerEvent event"); - }, event.type + " event is a PointerEvent event"); + }, pointerTestName + " event is a PointerEvent event"); // Check attributes for conformance to WebIDL: @@ -37,31 +38,37 @@ ["readonly", "long", "tiltX"], ["readonly", "long", "tiltY"], ["readonly", "string", "pointerType"], - ["readonly", "boolean", "isPrimary"] + ["readonly", "boolean", "isPrimary"], + ["readonly", "long", "detail", 0] ].forEach(function (attr) { var readonly = attr[0]; var type = attr[1]; var name = attr[2]; - + var value = attr[3]; // existence check test(function () { assert_true(name in event, name + " attribute in " + event.type + " event"); - }, event.type + "." + name + " attribute exists"); - + }, pointerTestName + "." + name + " attribute exists"); // readonly check if (readonly === "readonly") { test(function () { assert_readonly(event.type, name, event.type + "." + name + " cannot be changed"); - }, event.type + "." + name + " is readonly"); + }, pointerTestName + "." + name + " is readonly"); } - // type check test(function () { assert_true(idl_type_check[type](event[name]), name + " attribute of type " + type); - }, event.type + "." + name + " IDL type " + type + " (JS type was " + typeof event[name] + ")"); + }, pointerTestName + "." + name + " IDL type " + type + " (JS type was " + typeof event[name] + ")"); + + // value check if defined + if (value != undefined) { + test(function () { + assert_equals(event[name], value, name + " attribute value"); + }, pointerTestName + "." + name + " value is " + value + "."); + } }); @@ -81,7 +88,7 @@ assert_equals(event.pressure, 0.5, "pressure is 0.5 for mouse with a button pressed"); } } - }, event.type + ".pressure value is valid"); + }, pointerTestName + ".pressure value is valid"); // Check mouse-specific properties @@ -91,7 +98,7 @@ assert_equals(event.tiltX, 0, event.type + ".tiltX is 0 for mouse"); assert_equals(event.tiltY, 0, event.type + ".tiltY is 0 for mouse"); assert_true(event.isPrimary, event.type + ".isPrimary is true for mouse"); - }, event.type + " properties for pointerType = mouse"); + }, pointerTestName + " properties for pointerType = mouse"); // Check properties for pointers other than mouse } }
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/pointerevents/pointerevent_touch-action-button-test_touch-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/pointerevents/pointerevent_touch-action-button-test_touch-manual.html index 01a1c88c..c57f869 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/pointerevents/pointerevent_touch-action-button-test_touch-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/pointerevents/pointerevent_touch-action-button-test_touch-manual.html
@@ -30,7 +30,7 @@ <h4 id="desc">Test Description: Try to scroll black element DOWN moving your touch outside of the red border. Wait for description update.</h4> <p>Note: this test is for touch only</p> <div id="target0"> - <button>Test Button</button> + <button id="testButton">Test Button</button> </div> <br> <input type="button" id="btnComplete" value="Complete test"> @@ -106,4 +106,4 @@ </div> <div id="log"></div> </body> -</html> \ No newline at end of file +</html>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/pointerevents/pointerevent_touch-action-svg-test_touch-manual.html b/third_party/WebKit/LayoutTests/imported/wpt/pointerevents/pointerevent_touch-action-svg-test_touch-manual.html index 6c9c0b3..e9dc9d78 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/pointerevents/pointerevent_touch-action-svg-test_touch-manual.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/pointerevents/pointerevent_touch-action-svg-test_touch-manual.html
@@ -23,7 +23,7 @@ <h4 id="desc">Test Description: Try to scroll black element DOWN moving your touch outside of the red border. Wait for description update.</h4> <p>Note: this test is for touch only</p> <div id="target0"> - <svg width="555" height="555" style="touch-action: none; border: 4px double red;"> + <svg id="testSvg" width="555" height="555" style="touch-action: none; border: 4px double red;"> <circle cx="305" cy="305" r="250" stroke="green" stroke-width="4" fill="yellow" /> Sorry, your browser does not support inline SVG. </svg> @@ -119,4 +119,4 @@ </div> <div id="log"></div> </body> -</html> \ No newline at end of file +</html>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/keyframe-effects/effect-value-context-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/keyframe-effects/effect-value-context-expected.txt new file mode 100644 index 0000000..9fddf1c --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/keyframe-effects/effect-value-context-expected.txt
@@ -0,0 +1,8 @@ +This is a testharness.js-based test. +PASS Effect values reflect changes to font-size on element +PASS Effect values reflect changes to font-size on parent element +PASS Effect values reflect changes to font-size when computed style is not immediately flushed +PASS Effect values reflect changes to font-size from reparenting +FAIL Effect values reflect changes to target element assert_equals: Effect value after updating target element expected "300px" but got "0px" +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/keyframe-effects/effect-value-context.html b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/keyframe-effects/effect-value-context.html index e2af80d..eeab40b 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/keyframe-effects/effect-value-context.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/animation-model/keyframe-effects/effect-value-context.html
@@ -82,5 +82,23 @@ }); }, 'Effect values reflect changes to font-size from reparenting'); +test(function(t) { + var divA = createDiv(t); + divA.style.fontSize = '10px'; + + var divB = createDiv(t); + divB.style.fontSize = '20px'; + + var animation = divA.animate([ { marginLeft: '10em' }, + { marginLeft: '20em' } ], 1000); + animation.currentTime = 500; + assert_equals(getComputedStyle(divA).marginLeft, '150px', + 'Effect value before updating target element'); + + animation.effect.target = divB; + assert_equals(getComputedStyle(divB).marginLeft, '300px', + 'Effect value after updating target element'); +}, 'Effect values reflect changes to target element'); + </script> </body>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/Animatable/animate-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/Animatable/animate-expected.txt index 5aedfec..4437e26 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/Animatable/animate-expected.txt +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/Animatable/animate-expected.txt
@@ -1,6 +1,9 @@ This is a testharness.js-based test. PASS Element.animate() creates an Animation object +FAIL Element.animate() creates an Animation object in the relevant realm of the target element Cannot read property 'prototype' of undefined PASS Element.animate() creates an Animation object with a KeyframeEffect +PASS Element.animate() creates an Animation object with a KeyframeEffect that is created in the relevant realm of the target element +PASS Element.animate() creates an Animation object with a KeyframeEffect whose AnimationEffectTiming object is created in the relevant realm of the target element FAIL Element.animate() accepts a one property two value property-indexed keyframes specification anim.effect.getKeyframes is not a function FAIL Element.animate() accepts a one shorthand property two value property-indexed keyframes specification anim.effect.getKeyframes is not a function FAIL Element.animate() accepts a two property (one shorthand and one of its longhand components) two value property-indexed keyframes specification anim.effect.getKeyframes is not a function @@ -23,6 +26,7 @@ FAIL Element.animate() accepts a keyframe sequence with duplicate values for offsets 0 and 1 anim.effect.getKeyframes is not a function FAIL Element.animate() accepts a two property four keyframe sequence anim.effect.getKeyframes is not a function FAIL Element.animate() accepts a single keyframe sequence with omitted offsets anim.effect.getKeyframes is not a function +FAIL Element.animate() accepts a single keyframe sequence with string offset anim.effect.getKeyframes is not a function FAIL Element.animate() accepts a one property keyframe sequence with some omitted offsets anim.effect.getKeyframes is not a function FAIL Element.animate() accepts a two property keyframe sequence with some omitted offsets anim.effect.getKeyframes is not a function FAIL Element.animate() accepts a one property keyframe sequence with all omitted offsets anim.effect.getKeyframes is not a function
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/Animatable/animate.html b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/Animatable/animate.html index ced7d1a5..a54298aa4 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/Animatable/animate.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/Animatable/animate.html
@@ -8,6 +8,7 @@ <script src="../../resources/keyframe-utils.js"></script> <body> <div id="log"></div> +<iframe width="10" height="10" id="iframe"></iframe> <script> 'use strict'; @@ -20,12 +21,56 @@ }, 'Element.animate() creates an Animation object'); test(function(t) { + var iframe = window.frames[0]; + var div = createDiv(t, iframe.document); + var anim = Element.prototype.animate.call(div, null); + assert_equals(Object.getPrototypeOf(anim), iframe.Animation.prototype, + 'The prototype of the created Animation is that defined on' + + ' the relevant global for the target element'); + assert_not_equals(Object.getPrototypeOf(anim), Animation.prototype, + 'The prototype of the created Animation is NOT that of' + + ' the current global'); +}, 'Element.animate() creates an Animation object in the relevant realm of' + + ' the target element'); + +test(function(t) { var div = createDiv(t); - var anim = div.animate(null); + var anim = Element.prototype.animate.call(div, null); assert_class_string(anim.effect, 'KeyframeEffect', 'Returned Animation has a KeyframeEffect'); }, 'Element.animate() creates an Animation object with a KeyframeEffect'); +test(function(t) { + var iframe = window.frames[0]; + var div = createDiv(t, iframe.document); + var anim = Element.prototype.animate.call(div, null); + assert_equals(Object.getPrototypeOf(anim.effect), + iframe.KeyframeEffect.prototype, + 'The prototype of the created KeyframeEffect is that defined on' + + ' the relevant global for the target element'); + assert_not_equals(Object.getPrototypeOf(anim.effect), + KeyframeEffect.prototype, + 'The prototype of the created KeyframeEffect is NOT that of' + + ' the current global'); +}, 'Element.animate() creates an Animation object with a KeyframeEffect' + + ' that is created in the relevant realm of the target element'); + +test(function(t) { + var iframe = window.frames[0]; + var div = createDiv(t, iframe.document); + var anim = div.animate(null); + assert_equals(Object.getPrototypeOf(anim.effect.timing), + iframe.AnimationEffectTiming.prototype, + 'The prototype of the created AnimationEffectTiming is that' + + ' defined on the relevant global for the target element'); + assert_not_equals(Object.getPrototypeOf(anim.effect.timing), + AnimationEffectTiming.prototype, + 'The prototype of the created AnimationEffectTiming is NOT' + + ' that of the current global'); +}, 'Element.animate() creates an Animation object with a KeyframeEffect' + + ' whose AnimationEffectTiming object is created in the relevant realm' + + ' of the target element'); + gPropertyIndexedKeyframesTests.forEach(function(subtest) { test(function(t) { var div = createDiv(t);
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/Animation/constructor.html b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/Animation/constructor.html index 1f75233..4f76194 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/Animation/constructor.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/Animation/constructor.html
@@ -13,45 +13,52 @@ "use strict"; var gTarget = document.getElementById("target"); -var gEffect = new KeyframeEffectReadOnly(gTarget, { opacity: [0, 1] }); + +function createEffect() { + return new KeyframeEffectReadOnly(gTarget, { opacity: [0, 1] }); +} + +function createNull() { + return null; +} var gTestArguments = [ { - effect: null, + createEffect: createNull, timeline: null, expectedTimeline: null, expectedTimelineDescription: "null", description: "with null effect and null timeline" }, { - effect: null, + createEffect: createNull, timeline: document.timeline, expectedTimeline: document.timeline, expectedTimelineDescription: "document.timeline", description: "with null effect and non-null timeline" }, { - effect: null, + createEffect: createNull, expectedTimeline: document.timeline, expectedTimelineDescription: "document.timeline", description: "with null effect and no timeline parameter" }, { - effect: gEffect, + createEffect: createEffect, timeline: null, expectedTimeline: null, expectedTimelineDescription: "null", description: "with non-null effect and null timeline" }, { - effect: gEffect, + createEffect: createEffect, timeline: document.timeline, expectedTimeline: document.timeline, expectedTimelineDescription: "document.timeline", description: "with non-null effect and non-null timeline" }, { - effect: gEffect, + createEffect: createEffect, expectedTimeline: document.timeline, expectedTimelineDescription: "document.timeline", description: "with non-null effect and no timeline parameter" @@ -60,11 +67,12 @@ gTestArguments.forEach(function(args) { test(function(t) { - var animation = new Animation(args.effect, args.timeline); + var effect = args.createEffect(); + var animation = new Animation(effect, args.timeline); assert_not_equals(animation, null, "An animation sohuld be created"); - assert_equals(animation.effect, args.effect, + assert_equals(animation.effect, effect, "Animation returns the same effect passed to " + "the Constructor"); assert_equals(animation.timeline, args.expectedTimeline,
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/AnimationEffectTiming/easing-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/AnimationEffectTiming/easing-expected.txt new file mode 100644 index 0000000..1d54d6dc --- /dev/null +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/AnimationEffectTiming/easing-expected.txt
@@ -0,0 +1,25 @@ +This is a testharness.js-based test. +FAIL step-start function assert_equals: expected "steps(1, start)" but got "step-start" +FAIL steps(1, start) function assert_equals: expected "steps(1, start)" but got "step-start" +PASS steps(2, start) function +FAIL step-end function assert_equals: expected "steps(1)" but got "step-end" +FAIL steps(1) function assert_equals: expected "steps(1)" but got "step-end" +FAIL steps(1, end) function assert_equals: expected "steps(1)" but got "step-end" +FAIL steps(2, end) function assert_equals: expected "steps(2)" but got "steps(2, end)" +PASS linear function +PASS ease function +PASS ease-in function +PASS ease-in-out function +PASS ease-out function +PASS easing function which produces values greater than 1 +PASS Invalid effect easing value test: '' +PASS Invalid effect easing value test: 'test' +PASS Invalid effect easing value test: 'cubic-bezier(1.1, 0, 1, 1)' +PASS Invalid effect easing value test: 'cubic-bezier(0, 0, 1.1, 1)' +PASS Invalid effect easing value test: 'cubic-bezier(-0.1, 0, 1, 1)' +PASS Invalid effect easing value test: 'cubic-bezier(0, 0, -0.1, 1)' +PASS Invalid effect easing value test: 'steps(-1, start)' +PASS Invalid effect easing value test: 'steps(0.1, start)' +PASS Change the easing while the animation is running +Harness: the test ran to completion. +
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/AnimationEffectTiming/easing.html b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/AnimationEffectTiming/easing.html index d7c99df..cedd7e6 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/AnimationEffectTiming/easing.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/AnimationEffectTiming/easing.html
@@ -28,7 +28,8 @@ { duration: 1000 * MS_PER_SEC, fill: 'forwards' }); anim.effect.timing.easing = options.easing; - assert_equals(anim.effect.timing.easing, options.easing); + assert_equals(anim.effect.timing.easing, + options.serialization || options.easing); var easing = options.easingFunction; assert_progress(anim, 0, easing); @@ -39,18 +40,16 @@ }, options.desc); }); -test(function(t) { - var div = createDiv(t); - var anim = div.animate({ opacity: [ 0, 1 ] }, 100 * MS_PER_SEC); - assert_throws({ name: 'TypeError' }, - function() { - anim.effect.timing.easing = ''; - }); - assert_throws({ name: 'TypeError' }, - function() { - anim.effect.timing.easing = 'test'; - }); -}, 'Test invalid easing value'); +gInvalidEasingTests.forEach(function(options) { + test(function(t) { + var div = createDiv(t); + var anim = div.animate({ opacity: [ 0, 1 ] }, 100 * MS_PER_SEC); + assert_throws({ name: 'TypeError' }, + function() { + anim.effect.timing.easing = options.easing; + }); + }, 'Invalid effect easing value test: \'' + options.easing + '\''); +}); test(function(t) { var delay = 1000 * MS_PER_SEC;
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/AnimationEffectTiming/getComputedStyle-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/AnimationEffectTiming/getComputedStyle-expected.txt deleted file mode 100644 index cce72c5d..0000000 --- a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/AnimationEffectTiming/getComputedStyle-expected.txt +++ /dev/null
@@ -1,13 +0,0 @@ -This is a testharness.js-based test. -PASS changed duration immediately updates its computed styles -PASS changed iterations immediately updates its computed styles -PASS change currentTime when fill is none and endDelay is positive -PASS change currentTime when fill forwards and endDelay is positive -PASS change currentTime when fill none and endDelay is negative -FAIL change currentTime when fill forwards and endDelay is negative assert_equals: set currentTime same as endTime expected "0" but got "0.5" -PASS change direction from "normal" to "reverse" -PASS change direction from "normal" to "alternate" -PASS change direction from "normal" to "alternate-reverse" -PASS change direction from "normal" to "reverse" -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/AnimationEffectTiming/getComputedStyle.html b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/AnimationEffectTiming/getComputedStyle.html index b4820024..6ab4f14d 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/AnimationEffectTiming/getComputedStyle.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/AnimationEffectTiming/getComputedStyle.html
@@ -104,15 +104,15 @@ 'set currentTime before endTime'); anim.currentTime = 5000; - assert_equals(getComputedStyle(div).opacity, '0', + assert_equals(getComputedStyle(div).opacity, '0.5', 'set currentTime same as endTime'); anim.currentTime = 9999; - assert_equals(getComputedStyle(div).opacity, '0', + assert_equals(getComputedStyle(div).opacity, '0.5', 'set currentTime during duration'); anim.currentTime = 10000; - assert_equals(getComputedStyle(div).opacity, '0', + assert_equals(getComputedStyle(div).opacity, '0.5', 'set currentTime after endTime'); }, 'change currentTime when fill forwards and endDelay is negative');
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/AnimationTimeline/idlharness-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/AnimationTimeline/idlharness-expected.txt index 5cb30a0..013f595 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/AnimationTimeline/idlharness-expected.txt +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/AnimationTimeline/idlharness-expected.txt
@@ -1,12 +1,12 @@ This is a testharness.js-based test. PASS Web Animations API: DocumentTimeline tests -FAIL DocumentTimeline interface: existence and properties of interface object assert_own_property: self does not have own property "DocumentTimeline" expected property "DocumentTimeline" missing -FAIL DocumentTimeline interface object length assert_own_property: self does not have own property "DocumentTimeline" expected property "DocumentTimeline" missing -FAIL DocumentTimeline interface object name assert_own_property: self does not have own property "DocumentTimeline" expected property "DocumentTimeline" missing -FAIL DocumentTimeline interface: existence and properties of interface prototype object assert_own_property: self does not have own property "DocumentTimeline" expected property "DocumentTimeline" missing -FAIL DocumentTimeline interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "DocumentTimeline" expected property "DocumentTimeline" missing -FAIL DocumentTimeline must be primary interface of document.timeline assert_own_property: self does not have own property "DocumentTimeline" expected property "DocumentTimeline" missing -FAIL Stringification of document.timeline assert_equals: class string of document.timeline expected "[object DocumentTimeline]" but got "[object AnimationTimeline]" +PASS DocumentTimeline interface: existence and properties of interface object +FAIL DocumentTimeline interface object length assert_equals: wrong value for DocumentTimeline.length expected 1 but got 0 +PASS DocumentTimeline interface object name +FAIL DocumentTimeline interface: existence and properties of interface prototype object assert_equals: class string of DocumentTimeline.prototype expected "[object DocumentTimelinePrototype]" but got "[object DocumentTimeline]" +PASS DocumentTimeline interface: existence and properties of interface prototype object's "constructor" property +PASS DocumentTimeline must be primary interface of document.timeline +PASS Stringification of document.timeline PASS AnimationTimeline interface: document.timeline must inherit property "currentTime" with the proper type (0) Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/DocumentTimeline/constructor-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/DocumentTimeline/constructor-expected.txt index e443eb4d..7011c3c 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/DocumentTimeline/constructor-expected.txt +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/DocumentTimeline/constructor-expected.txt
@@ -1,6 +1,6 @@ This is a testharness.js-based test. -FAIL zero origin time DocumentTimeline is not defined -FAIL positive origin time DocumentTimeline is not defined -FAIL negative origin time DocumentTimeline is not defined +FAIL zero origin time Illegal constructor +FAIL positive origin time Illegal constructor +FAIL negative origin time Illegal constructor Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/constructor-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/constructor-expected.txt index 0c18bef..a8b58c1 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/constructor-expected.txt +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/constructor-expected.txt
@@ -51,6 +51,8 @@ FAIL a KeyframeEffectReadOnly constructed with a two property four keyframe sequence roundtrips KeyframeEffectReadOnly is not defined FAIL a KeyframeEffectReadOnly can be constructed with a single keyframe sequence with omitted offsets KeyframeEffectReadOnly is not defined FAIL a KeyframeEffectReadOnly constructed with a single keyframe sequence with omitted offsets roundtrips KeyframeEffectReadOnly is not defined +FAIL a KeyframeEffectReadOnly can be constructed with a single keyframe sequence with string offset KeyframeEffectReadOnly is not defined +FAIL a KeyframeEffectReadOnly constructed with a single keyframe sequence with string offset roundtrips KeyframeEffectReadOnly is not defined FAIL a KeyframeEffectReadOnly can be constructed with a one property keyframe sequence with some omitted offsets KeyframeEffectReadOnly is not defined FAIL a KeyframeEffectReadOnly constructed with a one property keyframe sequence with some omitted offsets roundtrips KeyframeEffectReadOnly is not defined FAIL a KeyframeEffectReadOnly can be constructed with a two property keyframe sequence with some omitted offsets KeyframeEffectReadOnly is not defined
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/effect-easing-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/effect-easing-expected.txt index c8abac1..fdf8ff2 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/effect-easing-expected.txt +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/effect-easing-expected.txt
@@ -1,6 +1,11 @@ This is a testharness.js-based test. -FAIL steps(start) function Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'. -FAIL steps(end) function Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'. +FAIL step-start function Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'. +FAIL steps(1, start) function Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'. +FAIL steps(2, start) function Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'. +FAIL step-end function Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'. +FAIL steps(1) function Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'. +FAIL steps(1, end) function Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'. +FAIL steps(2, end) function Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'. FAIL linear function Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'. FAIL ease function Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'. FAIL ease-in function Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'. @@ -31,5 +36,13 @@ FAIL Test bounds point of step-start easing in keyframe assert_equals: Progress at 0ms expected "0px" but got "50px" FAIL Test bounds point of step-end easing with iterationStart and delay assert_equals: Progress at 0ms expected 0 but got 0.5 PASS Test bounds point of step-end easing with iterationStart not at a transition point +PASS Invalid keyframe easing value: '' +PASS Invalid keyframe easing value: 'test' +PASS Invalid keyframe easing value: 'cubic-bezier(1.1, 0, 1, 1)' +PASS Invalid keyframe easing value: 'cubic-bezier(0, 0, 1.1, 1)' +PASS Invalid keyframe easing value: 'cubic-bezier(-0.1, 0, 1, 1)' +PASS Invalid keyframe easing value: 'cubic-bezier(0, 0, -0.1, 1)' +PASS Invalid keyframe easing value: 'steps(-1, start)' +PASS Invalid keyframe easing value: 'steps(0.1, start)' Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/effect-easing.html b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/effect-easing.html index 5526eed..05019cdf 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/effect-easing.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/effect-easing.html
@@ -669,5 +669,15 @@ }, options.description); }); +gInvalidEasingTests.forEach(function(options) { + test(function(t) { + var div = createDiv(t); + assert_throws({ name: 'TypeError' }, + function() { + div.animate({ easing: options.easing }, 100 * MS_PER_SEC); + }); + }, 'Invalid keyframe easing value: \'' + options.easing + '\''); +}); + </script> </body>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-expected.txt index 70a2f00..fb0aa2c8 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-expected.txt +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument-expected.txt
@@ -31,5 +31,28 @@ FAIL non-animatable property 'transitionTimingFunction' is not accessed when using a keyframe sequence KeyframeEffectReadOnly is not defined FAIL non-animatable property 'display' is not accessed when using a keyframe sequence KeyframeEffectReadOnly is not defined FAIL non-animatable property 'unsupportedProperty' is not accessed when using a keyframe sequence KeyframeEffectReadOnly is not defined +FAIL Equivalent property indexed and sequenced keyframes: two properties with one value KeyframeEffectReadOnly is not defined +FAIL Equivalent property indexed and sequenced keyframes: two properties with three values KeyframeEffectReadOnly is not defined +FAIL Equivalent property indexed and sequenced keyframes: two properties with different numbers of values KeyframeEffectReadOnly is not defined +FAIL Equivalent property indexed and sequenced keyframes: same offset applied to all keyframes KeyframeEffectReadOnly is not defined +FAIL Equivalent property indexed and sequenced keyframes: same easing applied to all keyframes KeyframeEffectReadOnly is not defined +FAIL Equivalent property indexed and sequenced keyframes: same composite applied to all keyframes KeyframeEffectReadOnly is not defined +FAIL Custom iterator with basic keyframes. effect.getKeyframes is not a function +FAIL easing and offset are ignored on iterable objects. effect.getKeyframes is not a function +FAIL Custom iterator with multiple properties specified. effect.getKeyframes is not a function +FAIL Custom iterator with offset specified. effect.getKeyframes is not a function +FAIL Custom iterator with non object keyframe should throw. assert_throws: function "function () { + new KeyframeEffect(null, createIterable([ + {done: false, value: {left: '100px'}}, + {done: false, value: 1234}, + {done: false, value: {left: '200px'}}, + {done: true}, + ])); + }" did not throw +FAIL Custom iterator with value list in keyframe should give bizarre string representation of list. effect.getKeyframes is not a function +FAIL Only enumerable properties on keyframes are considered anim.effect.getKeyframes is not a function +FAIL Only properties defined directly on keyframes are considered anim.effect.getKeyframes is not a function +FAIL Only enumerable properties on property indexed keyframes are considered anim.effect.getKeyframes is not a function +FAIL Only properties defined directly on property indexed keyframes are considered anim.effect.getKeyframes is not a function Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument.html b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument.html index d0ee1bd..d1683128 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/processing-a-keyframes-argument.html
@@ -5,6 +5,7 @@ <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="../../testcommon.js"></script> +<script src="../../resources/keyframe-utils.js"></script> <body> <div id="log"></div> <div id="target"></div> @@ -79,7 +80,246 @@ + ' a keyframe sequence'); }); -// FIXME: Test that non-enumerable properties are not accessed +// Test equivalent forms of property indexed and sequenced keyframe syntax + +function assertEquivalentKeyframeSyntax(keyframesA, keyframesB) { + var processedKeyframesA = new KeyframeEffectReadOnly(null, keyframesA).getKeyframes(); + var processedKeyframesB = new KeyframeEffectReadOnly(null, keyframesB).getKeyframes(); + assert_frame_lists_equal(processedKeyframesA, processedKeyframesB); +} + +var gEquivalentSyntaxTests = [ + { + description: 'two properties with one value', + indexedKeyframes: { + left: '100px', + opacity: ['1'], + }, + sequencedKeyframes: [ + {left: '100px', opacity: '1'}, + ], + }, + { + description: 'two properties with three values', + indexedKeyframes: { + left: ['10px', '100px', '150px'], + opacity: ['1', '0', '1'], + }, + sequencedKeyframes: [ + {left: '10px', opacity: '1'}, + {left: '100px', opacity: '0'}, + {left: '150px', opacity: '1'}, + ], + }, + { + description: 'two properties with different numbers of values', + indexedKeyframes: { + left: ['0px', '100px', '200px'], + opacity: ['0', '1'] + }, + sequencedKeyframes: [ + {left: '0px', opacity: '0'}, + {left: '100px'}, + {left: '200px', opacity: '1'}, + ], + }, + { + description: 'same offset applied to all keyframes', + indexedKeyframes: { + left: ['0px', '100px'], + offset: 0.5, + }, + sequencedKeyframes: [ + {left: '0px', offset: 0.5}, + {left: '100px', offset: 0.5}, + ], + }, + { + description: 'same easing applied to all keyframes', + indexedKeyframes: { + left: ['10px', '100px', '150px'], + opacity: ['1', '0', '1'], + easing: 'ease', + }, + sequencedKeyframes: [ + {left: '10px', opacity: '1', easing: 'ease'}, + {left: '100px', opacity: '0', easing: 'ease'}, + {left: '150px', opacity: '1', easing: 'ease'}, + ], + }, + { + description: 'same composite applied to all keyframes', + indexedKeyframes: { + left: ['0px', '100px'], + composite: 'add', + }, + sequencedKeyframes: [ + {left: '0px', composite: 'add'}, + {left: '100px', composite: 'add'}, + ], + }, +]; + +gEquivalentSyntaxTests.forEach(function({description, indexedKeyframes, sequencedKeyframes}) { + test(function(t) { + assertEquivalentKeyframeSyntax(indexedKeyframes, sequencedKeyframes); + }, 'Equivalent property indexed and sequenced keyframes: ' + description); +}); + +// Test handling of custom iterable objects. + +function createIterable(iterations) { + return { + [Symbol.iterator]() { + var i = 0; + return { + next() { + return iterations[i++]; + }, + }; + }, + }; +} + +test(() => { + var effect = new KeyframeEffect(null, createIterable([ + {done: false, value: {left: '100px'}}, + {done: false, value: {left: '300px'}}, + {done: false, value: {left: '200px'}}, + {done: true}, + ])); + assert_frame_lists_equal(effect.getKeyframes(), [ + {offset: null, computedOffset: 0, easing: 'linear', left: '100px'}, + {offset: null, computedOffset: 0.5, easing: 'linear', left: '300px'}, + {offset: null, computedOffset: 1, easing: 'linear', left: '200px'}, + ]); +}, 'Custom iterator with basic keyframes.'); + +test(() => { + var keyframes = createIterable([ + {done: false, value: {left: '100px'}}, + {done: false, value: {left: '300px'}}, + {done: false, value: {left: '200px'}}, + {done: true}, + ]); + keyframes.easing = 'ease-in-out'; + keyframes.offset = '0.1'; + var effect = new KeyframeEffect(null, keyframes); + assert_frame_lists_equal(effect.getKeyframes(), [ + {offset: null, computedOffset: 0, easing: 'linear', left: '100px'}, + {offset: null, computedOffset: 0.5, easing: 'linear', left: '300px'}, + {offset: null, computedOffset: 1, easing: 'linear', left: '200px'}, + ]); +}, 'easing and offset are ignored on iterable objects.'); + +test(() => { + var effect = new KeyframeEffect(null, createIterable([ + {done: false, value: {left: '100px', top: '200px'}}, + {done: false, value: {left: '300px'}}, + {done: false, value: {left: '200px', top: '100px'}}, + {done: true}, + ])); + assert_frame_lists_equal(effect.getKeyframes(), [ + {offset: null, computedOffset: 0, easing: 'linear', left: '100px', top: '200px'}, + {offset: null, computedOffset: 0.5, easing: 'linear', left: '300px'}, + {offset: null, computedOffset: 1, easing: 'linear', left: '200px', top: '100px'}, + ]); +}, 'Custom iterator with multiple properties specified.'); + +test(() => { + var effect = new KeyframeEffect(null, createIterable([ + {done: false, value: {left: '100px'}}, + {done: false, value: {left: '250px', offset: 0.75}}, + {done: false, value: {left: '200px'}}, + {done: true}, + ])); + assert_frame_lists_equal(effect.getKeyframes(), [ + {offset: null, computedOffset: 0, easing: 'linear', left: '100px'}, + {offset: 0.75, computedOffset: 0.75, easing: 'linear', left: '250px'}, + {offset: null, computedOffset: 1, easing: 'linear', left: '200px'}, + ]); +}, 'Custom iterator with offset specified.'); + +test(() => { + assert_throws({name: 'TypeError'}, function() { + new KeyframeEffect(null, createIterable([ + {done: false, value: {left: '100px'}}, + {done: false, value: 1234}, + {done: false, value: {left: '200px'}}, + {done: true}, + ])); + }); +}, 'Custom iterator with non object keyframe should throw.'); + +test(() => { + var effect = new KeyframeEffect(null, createIterable([ + {done: false, value: {left: ['100px', '200px']}}, + {done: true}, + ])); + assert_frame_lists_equal(effect.getKeyframes(), [ + {offset: null, computedOffset: 1, easing: 'linear', left: '100px,200px'} + ]); +}, 'Custom iterator with value list in keyframe should give bizarre string representation of list.'); + +test(function(t) { + var keyframe = {}; + Object.defineProperty(keyframe, 'width', {value: '200px'}); + Object.defineProperty(keyframe, 'height', { + value: '100px', + enumerable: true}); + assert_equals(keyframe.width, '200px', 'width of keyframe is readable'); + assert_equals(keyframe.height, '100px', 'height of keyframe is readable'); + var anim = createDiv(t).animate([keyframe, {height: '200px'}], 1); + assert_frame_lists_equal(anim.effect.getKeyframes(), [ + {offset: null, computedOffset: 0, easing: 'linear', height: '100px'}, + {offset: null, computedOffset: 1, easing: 'linear', height: '200px'}, + ]); +}, 'Only enumerable properties on keyframes are considered'); + +test(function(t) { + var KeyframeParent = function() { this.width = '100px'; }; + KeyframeParent.prototype = { height: '100px' }; + var Keyframe = function() { this.top = '100px'; }; + Keyframe.prototype = Object.create(KeyframeParent.prototype); + Object.defineProperty(Keyframe.prototype, 'left', { + value: '100px', + enumerable: 'true'}); + var keyframe = new Keyframe(); + var anim = createDiv(t).animate([keyframe, {top: '200px'}], 1); + assert_frame_lists_equal(anim.effect.getKeyframes(), [ + {offset: null, computedOffset: 0, easing: 'linear', top: '100px'}, + {offset: null, computedOffset: 1, easing: 'linear', top: '200px'}, + ]); +}, 'Only properties defined directly on keyframes are considered'); + +test(function(t) { + var keyframes = {}; + Object.defineProperty(keyframes, 'width', ['100px', '200px']); + Object.defineProperty(keyframes, 'height', { + value: ['100px', '200px'], + enumerable: true}); + var anim = createDiv(t).animate(keyframes, 1); + assert_frame_lists_equal(anim.effect.getKeyframes(), [ + {offset: null, computedOffset: 0, easing: 'linear', height: '100px'}, + {offset: null, computedOffset: 1, easing: 'linear', height: '200px'}, + ]); +}, 'Only enumerable properties on property indexed keyframes are considered'); + +test(function(t) { + var KeyframesParent = function() { this.width = '100px'; }; + KeyframesParent.prototype = { height: '100px' }; + var Keyframes = function() { this.top = ['100px', '200px']; }; + Keyframes.prototype = Object.create(KeyframesParent.prototype); + Object.defineProperty(Keyframes.prototype, 'left', { + value: ['100px', '200px'], + enumerable: 'true'}); + var keyframes = new Keyframes(); + var anim = createDiv(t).animate(keyframes, 1); + assert_frame_lists_equal(anim.effect.getKeyframes(), [ + {offset: null, computedOffset: 0, easing: 'linear', top: '100px'}, + {offset: null, computedOffset: 1, easing: 'linear', top: '200px'}, + ]); +}, 'Only properties defined directly on property indexed keyframes are considered'); // FIXME: Test that properties are accessed in ascending order by Unicode // codepoint
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/setKeyframes-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/setKeyframes-expected.txt index c065f06..fc54b43e 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/setKeyframes-expected.txt +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/interfaces/KeyframeEffect/setKeyframes-expected.txt
@@ -22,6 +22,7 @@ FAIL Keyframes can be replaced with a keyframe sequence with duplicate values for offsets 0 and 1 effect.setKeyframes is not a function FAIL Keyframes can be replaced with a two property four keyframe sequence effect.setKeyframes is not a function FAIL Keyframes can be replaced with a single keyframe sequence with omitted offsets effect.setKeyframes is not a function +FAIL Keyframes can be replaced with a single keyframe sequence with string offset effect.setKeyframes is not a function FAIL Keyframes can be replaced with a one property keyframe sequence with some omitted offsets effect.setKeyframes is not a function FAIL Keyframes can be replaced with a two property keyframe sequence with some omitted offsets effect.setKeyframes is not a function FAIL Keyframes can be replaced with a one property keyframe sequence with all omitted offsets effect.setKeyframes is not a function
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/resources/effect-easing-tests.js b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/resources/effect-easing-tests.js index edce67e..49c4ff5b 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/resources/effect-easing-tests.js +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/resources/effect-easing-tests.js
@@ -1,13 +1,42 @@ var gEffectEasingTests = [ { - desc: 'steps(start) function', + desc: 'step-start function', + easing: 'step-start', + easingFunction: stepStart(1), + serialization: 'steps(1, start)' + }, + { + desc: 'steps(1, start) function', + easing: 'steps(1, start)', + easingFunction: stepStart(1) + }, + { + desc: 'steps(2, start) function', easing: 'steps(2, start)', easingFunction: stepStart(2) }, { - desc: 'steps(end) function', + desc: 'step-end function', + easing: 'step-end', + easingFunction: stepEnd(1), + serialization: 'steps(1)' + }, + { + desc: 'steps(1) function', + easing: 'steps(1)', + easingFunction: stepEnd(1) + }, + { + desc: 'steps(1, end) function', + easing: 'steps(1, end)', + easingFunction: stepEnd(1), + serialization: 'steps(1)' + }, + { + desc: 'steps(2, end) function', easing: 'steps(2, end)', - easingFunction: stepEnd(2) + easingFunction: stepEnd(2), + serialization: 'steps(2)' }, { desc: 'linear function', @@ -40,3 +69,30 @@ easingFunction: cubicBezier(0, 1.5, 1, 1.5) } ]; + +var gInvalidEasingTests = [ + { + easing: '' + }, + { + easing: 'test' + }, + { + easing: 'cubic-bezier(1.1, 0, 1, 1)' + }, + { + easing: 'cubic-bezier(0, 0, 1.1, 1)' + }, + { + easing: 'cubic-bezier(-0.1, 0, 1, 1)' + }, + { + easing: 'cubic-bezier(0, 0, -0.1, 1)' + }, + { + easing: 'steps(-1, start)' + }, + { + easing: 'steps(0.1, start)' + }, +];
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/resources/keyframe-utils.js b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/resources/keyframe-utils.js index 5278ad5..626f0bf 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/resources/keyframe-utils.js +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/resources/keyframe-utils.js
@@ -257,6 +257,10 @@ input: [{ left: "10px" }], output: [{ offset: null, computedOffset: 1, easing: "linear", left: "10px" }] }, + { desc: "a single keyframe sequence with string offset", + input: [{ offset: '0.5', left: "10px" }], + output: [{ offset: 0.5, computedOffset: 1, easing: "linear", + left: "10px" }] }, { desc: "a one property keyframe sequence with some omitted offsets", input: [{ offset: 0.00, left: "10px" }, { offset: 0.25, left: "20px" }, @@ -321,9 +325,9 @@ left: "30px" }, { offset: 0.5, computedOffset: 0.5, easing: "linear", top: "40px" }, - { offset: 1.0, computedOffset: 1.0, easing: "step-end", + { offset: 1.0, computedOffset: 1.0, easing: "steps(1)", left: "50px" }, - { offset: 1.0, computedOffset: 1.0, easing: "step-end", + { offset: 1.0, computedOffset: 1.0, easing: "steps(1)", top: "60px" }] }, { desc: "a keyframe sequence with different composite values, but the" + " same composite value for a given offset", @@ -432,7 +436,7 @@ left: "300px" }, { offset: 1.0, computedOffset: 1.0, easing: "ease-out", left: "400px" }, - { offset: 1.0, computedOffset: 1.0, easing: "step-end", + { offset: 1.0, computedOffset: 1.0, easing: "steps(1)", left: "500px" }] }, ];
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/timing-model/animation-effects/active-time.html b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/timing-model/animation-effects/active-time.html index 2fb028f..37b7f8ab 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/timing-model/animation-effects/active-time.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/timing-model/animation-effects/active-time.html
@@ -1,7 +1,7 @@ <!DOCTYPE html> <meta charset=utf-8> <title>Active time tests</title> -<link rel="help" href="https://w3c.github.io/web-animations/#active-time"> +<link rel="help" href="https://w3c.github.io/web-animations/#calculating-the-active-time"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="../../testcommon.js"></script> @@ -10,15 +10,133 @@ <script> 'use strict'; -async_test(function(t) { - var div = createDiv(t); - var anim = div.animate({ opacity: [ 0, 1 ] }, { delay: 1 }); +test(function(t) { + var tests = [ { fill: 'none', progress: null }, + { fill: 'backwards', progress: 0 }, + { fill: 'forwards', progress: null }, + { fill: 'both', progress: 0 } ]; + tests.forEach(function(test) { + var anim = createDiv(t).animate(null, { delay: 1, fill: test.fill }); + assert_equals(anim.effect.getComputedTiming().progress, test.progress, + 'Progress in before phase when using \'' + test.fill + + '\' fill'); + }); +}, 'Active time in before phase'); + +test(function(t) { + var anim = createDiv(t).animate(null, 1000); + anim.currentTime = 500; + assert_times_equal(anim.effect.getComputedTiming().progress, 0.5); +}, 'Active time in active phase and no start delay is the local time'); + +test(function(t) { + var anim = createDiv(t).animate(null, { duration: 1000, delay: 500 }); + anim.currentTime = 1000; + assert_times_equal(anim.effect.getComputedTiming().progress, 0.5); +}, 'Active time in active phase and positive start delay is the local time' + + ' minus the start delay'); + +test(function(t) { + var anim = createDiv(t).animate(null, { duration: 1000, delay: -500 }); + assert_times_equal(anim.effect.getComputedTiming().progress, 0.5); +}, 'Active time in active phase and negative start delay is the local time' + + ' minus the start delay'); + +test(function(t) { + var anim = createDiv(t).animate(null); assert_equals(anim.effect.getComputedTiming().progress, null); - anim.finished.then(t.step_func(function() { - assert_equals(anim.effect.getComputedTiming().progress, null); - t.done(); - })); -}, 'Test progress during before and after phase when fill is none'); +}, 'Active time in after phase with no fill is unresolved'); + +test(function(t) { + var anim = createDiv(t).animate(null, { fill: 'backwards' }); + assert_equals(anim.effect.getComputedTiming().progress, null); +}, 'Active time in after phase with backwards-only fill is unresolved'); + +test(function(t) { + var anim = createDiv(t).animate(null, { duration: 1000, + iterations: 2.3, + delay: 500, // Should have no effect + fill: 'forwards' }); + anim.finish(); + assert_equals(anim.effect.getComputedTiming().currentIteration, 2); + assert_times_equal(anim.effect.getComputedTiming().progress, 0.3); +}, 'Active time in after phase with forwards fill is the active duration'); + +test(function(t) { + var anim = createDiv(t).animate(null, { duration: 0, + iterations: Infinity, + fill: 'forwards' }); + anim.finish(); + assert_equals(anim.effect.getComputedTiming().currentIteration, Infinity); + assert_equals(anim.effect.getComputedTiming().progress, 1); +}, 'Active time in after phase with forwards fill, zero-duration, and ' + + ' infinite iteration count is the active duration'); + +test(function(t) { + var anim = createDiv(t).animate(null, { duration: 1000, + iterations: 2.3, + delay: 500, + endDelay: 4000, + fill: 'forwards' }); + anim.finish(); + assert_equals(anim.effect.getComputedTiming().currentIteration, 2); + assert_times_equal(anim.effect.getComputedTiming().progress, 0.3); +}, 'Active time in after phase with forwards fill and positive end delay' + + ' is the active duration'); + +test(function(t) { + var anim = createDiv(t).animate(null, { duration: 1000, + iterations: 2.3, + delay: 500, + endDelay: -800, + fill: 'forwards' }); + anim.finish(); + assert_equals(anim.effect.getComputedTiming().currentIteration, 1); + assert_times_equal(anim.effect.getComputedTiming().progress, 0.5); +}, 'Active time in after phase with forwards fill and negative end delay' + + ' is the active duration + end delay'); + +test(function(t) { + var anim = createDiv(t).animate(null, { duration: 1000, + iterations: 2.3, + delay: 500, + endDelay: -3000, + fill: 'forwards' }); + anim.finish(); + assert_equals(anim.effect.getComputedTiming().currentIteration, 0); + assert_equals(anim.effect.getComputedTiming().progress, 0); +}, 'Active time in after phase with forwards fill and negative end delay' + + ' greater in magnitude than the active duration is zero'); + +test(function(t) { + var anim = createDiv(t).animate(null, { duration: 1000, + iterations: 2.3, + delay: 500, + endDelay: -4000, + fill: 'forwards' }); + anim.finish(); + assert_equals(anim.effect.getComputedTiming().currentIteration, 0); + assert_equals(anim.effect.getComputedTiming().progress, 0); +}, 'Active time in after phase with forwards fill and negative end delay' + + ' greater in magnitude than the sum of the active duration and start delay' + + ' is zero'); + +test(function(t) { + var anim = createDiv(t).animate(null, { duration: 1000, + iterations: 2.3, + delay: 500, + fill: 'both' }); + anim.finish(); + assert_equals(anim.effect.getComputedTiming().currentIteration, 2); + assert_times_equal(anim.effect.getComputedTiming().progress, 0.3); +}, 'Active time in after phase with \'both\' fill is the active duration'); + +test(function(t) { + // Create an effect with a non-zero duration so we ensure we're not just + // testing the after-phase behavior. + var effect = new KeyframeEffect(null, null, 1); + assert_equals(effect.getComputedTiming().progress, null); +}, 'Active time when the local time is unresolved, is unresolved'); </script> </body>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/timing-model/animation-effects/current-iteration-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/timing-model/animation-effects/current-iteration-expected.txt index f3f8bfbc..1897d0b0 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/timing-model/animation-effects/current-iteration-expected.txt +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/timing-model/animation-effects/current-iteration-expected.txt
@@ -36,5 +36,15 @@ PASS Test infinity iterations: iterations:Infinity iterationStart:3 duration:0 delay:1 fill:both PASS Test infinity iterations: iterations:Infinity iterationStart:3 duration:100 delay:1 fill:both FAIL Test infinity iterations: iterations:Infinity iterationStart:3 duration:Infinity delay:1 fill:both assert_equals: expected 3 but got Infinity +PASS Test end delay: duration:100 delay:1 fill:both endDelay:50 +PASS Test end delay: duration:100 delay:1 fill:both endDelay:-50 +PASS Test end delay: duration:100 delay:1 fill:both endDelay:-100 +PASS Test end delay: duration:100 delay:1 fill:both endDelay:-200 +PASS Test end delay: iterationStart:0.5 duration:100 delay:1 fill:both endDelay:50 +FAIL Test end delay: iterationStart:0.5 duration:100 delay:1 fill:both endDelay:-50 assert_equals: expected 0 but got 0.5 +PASS Test end delay: iterationStart:0.5 duration:100 delay:1 fill:both endDelay:-100 +FAIL Test end delay: iterations:2 duration:100 delay:1 fill:both endDelay:-100 assert_equals: expected 0 but got 1 +PASS Test end delay: iterations:1 iterationStart:2 duration:100 delay:1 fill:both endDelay:-50 +PASS Test end delay: iterations:1 iterationStart:2 duration:100 delay:1 fill:both endDelay:-100 Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/timing-model/animation-effects/current-iteration.html b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/timing-model/animation-effects/current-iteration.html index 98d47fd..d249086 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/timing-model/animation-effects/current-iteration.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/timing-model/animation-effects/current-iteration.html
@@ -10,7 +10,7 @@ <script> 'use strict'; -function executeTests(tests, description) { +function runTests(tests, description) { tests.forEach(function(currentTest) { var testParams = ''; for (var attr in currentTest.input) { @@ -29,7 +29,7 @@ assert_equals(anim.effect.getComputedTiming().currentIteration, currentTest.after); } - }, description + testParams); + }, description + ':' + testParams); }); } @@ -43,7 +43,14 @@ })); }, 'Test currentIteration during before and after phase when fill is none'); -var gTests_zero_iterations = [ + +// -------------------------------------------------------------------- +// +// Zero iteration duration tests +// +// -------------------------------------------------------------------- + +runTests([ { input: { iterations: 0, iterationStart: 0, @@ -142,9 +149,16 @@ active: 3, after: 3 } -]; +], 'Test zero iterations'); -var gTests_integer_iterations = [ + +// -------------------------------------------------------------------- +// +// Tests where the iteration count is an integer +// +// -------------------------------------------------------------------- + +runTests([ { input: { iterations: 3, iterationStart: 0, @@ -240,9 +254,16 @@ before: 3, active: 3 } -]; +], 'Test integer iterations'); -var gTests_fractional_iterations = [ + +// -------------------------------------------------------------------- +// +// Tests where the iteration count is a fraction +// +// -------------------------------------------------------------------- + +runTests([ { input: { iterations: 3.5, iterationStart: 0, @@ -338,9 +359,16 @@ before: 3, active: 3 } -]; +], 'Test fractional iterations'); -var gTests_infinity_iterations = [ + +// -------------------------------------------------------------------- +// +// Tests where the iteration count is Infinity +// +// -------------------------------------------------------------------- + +runTests([ { input: { iterations: Infinity, iterationStart: 0, @@ -433,12 +461,124 @@ before: 3, active: 3 } -]; +], 'Test infinity iterations'); -executeTests(gTests_zero_iterations, "Test zero iterations:"); -executeTests(gTests_integer_iterations, "Test integer iterations:"); -executeTests(gTests_fractional_iterations, "Test fractional iterations:"); -executeTests(gTests_infinity_iterations, "Test infinity iterations:"); + +// -------------------------------------------------------------------- +// +// End delay tests +// +// -------------------------------------------------------------------- + +runTests([ + { + input: { duration: 100, + delay: 1, + fill: 'both', + endDelay: 50 }, + before: 0, + active: 0, + after: 0 + }, + + { + input: { duration: 100, + delay: 1, + fill: 'both', + endDelay: -50 }, + before: 0, + active: 0, + after: 0 + }, + + { + input: { duration: 100, + delay: 1, + fill: 'both', + endDelay: -100 }, + before: 0, + active: 0, + after: 0 + }, + + { + input: { duration: 100, + delay: 1, + fill: 'both', + endDelay: -200 }, + before: 0, + active: 0, + after: 0 + }, + + { + input: { iterationStart: 0.5, + duration: 100, + delay: 1, + fill: 'both', + endDelay: 50 }, + before: 0, + active: 0, + after: 1 + }, + + { + input: { iterationStart: 0.5, + duration: 100, + delay: 1, + fill: 'both', + endDelay: -50 }, + before: 0, + active: 0, + after: 0 + }, + + { + input: { iterationStart: 0.5, + duration: 100, + delay: 1, + fill: 'both', + endDelay: -100 }, + before: 0, + active: 0, + after: 0 + }, + + { + input: { iterations: 2, + duration: 100, + delay: 1, + fill: 'both', + endDelay: -100 }, + before: 0, + active: 0, + after: 0 + }, + + { + input: { iterations: 1, + iterationStart: 2, + duration: 100, + delay: 1, + fill: 'both', + endDelay: -50 }, + before: 2, + active: 2, + after: 2 + }, + + { + input: { iterations: 1, + iterationStart: 2, + duration: 100, + delay: 1, + fill: 'both', + endDelay: -100 }, + before: 2, + active: 2, + after: 2 + }, +], 'Test end delay'); </script> </body>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/timing-model/animation-effects/simple-iteration-progress-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/timing-model/animation-effects/simple-iteration-progress-expected.txt index a8d3eed..97ffe40 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/timing-model/animation-effects/simple-iteration-progress-expected.txt +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/timing-model/animation-effects/simple-iteration-progress-expected.txt
@@ -35,5 +35,15 @@ PASS Test infinity iterations: iterations:Infinity iterationStart:3 duration:0 delay:1 fill:both FAIL Test infinity iterations: iterations:Infinity iterationStart:3 duration:100 delay:1 fill:both assert_equals: expected 0 but got 2.7755575615628914e-16 PASS Test infinity iterations: iterations:Infinity iterationStart:3 duration:Infinity delay:1 fill:both +PASS Test end delay: duration:100 delay:1 fill:both endDelay:50 +PASS Test end delay: duration:100 delay:1 fill:both endDelay:-50 +PASS Test end delay: duration:100 delay:1 fill:both endDelay:-100 +PASS Test end delay: duration:100 delay:1 fill:both endDelay:-200 +FAIL Test end delay: iterationStart:0.5 duration:100 delay:1 fill:both endDelay:50 assert_equals: expected 0.5 but got 0.5000000000000001 +PASS Test end delay: iterationStart:0.5 duration:100 delay:1 fill:both endDelay:-50 +PASS Test end delay: iterationStart:0.5 duration:100 delay:1 fill:both endDelay:-100 +PASS Test end delay: iterations:2 duration:100 delay:1 fill:both endDelay:-100 +FAIL Test end delay: iterations:1 iterationStart:2 duration:100 delay:1 fill:both endDelay:-50 assert_equals: expected 0.5 but got 0.4999999999999999 +FAIL Test end delay: iterations:1 iterationStart:2 duration:100 delay:1 fill:both endDelay:-100 assert_equals: expected 0 but got 1 Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/timing-model/animation-effects/simple-iteration-progress.html b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/timing-model/animation-effects/simple-iteration-progress.html index a8fb33d..f6a3a51 100644 --- a/third_party/WebKit/LayoutTests/imported/wpt/web-animations/timing-model/animation-effects/simple-iteration-progress.html +++ b/third_party/WebKit/LayoutTests/imported/wpt/web-animations/timing-model/animation-effects/simple-iteration-progress.html
@@ -11,7 +11,7 @@ <script> 'use strict'; -function executeTests(tests, description) { +function runTests(tests, description) { tests.forEach(function(currentTest) { var testParams = ''; for (var attr in currentTest.input) { @@ -30,11 +30,18 @@ assert_equals(anim.effect.getComputedTiming().progress, currentTest.after); } - }, description + testParams); + }, description + ':' + testParams); }); } -var gTests_zero_iterations = [ + +// -------------------------------------------------------------------- +// +// Zero iteration duration tests +// +// -------------------------------------------------------------------- + +runTests([ { input: { iterations: 0, iterationStart: 0, @@ -133,9 +140,16 @@ active: 0, after: 0 } -]; +], 'Test zero iterations'); -var gTests_integer_iterations = [ + +// -------------------------------------------------------------------- +// +// Tests where the iteration count is an integer +// +// -------------------------------------------------------------------- + +runTests([ { input: { iterations: 3, iterationStart: 0, @@ -231,9 +245,16 @@ before: 0, active: 0 } -]; +], 'Test integer iterations'); -var gTests_fractional_iterations = [ + +// -------------------------------------------------------------------- +// +// Tests where the iteration count is a fraction +// +// -------------------------------------------------------------------- + +runTests([ { input: { iterations: 3.5, iterationStart: 0, @@ -329,9 +350,16 @@ before: 0, active: 0 } -]; +], 'Test fractional iterations'); -var gTests_infinity_iterations = [ + +// -------------------------------------------------------------------- +// +// Tests where the iteration count is Infinity +// +// -------------------------------------------------------------------- + +runTests([ { input: { iterations: Infinity, iterationStart: 0, @@ -424,12 +452,124 @@ before: 0, active: 0 } -]; +], 'Test infinity iterations'); -executeTests(gTests_zero_iterations, "Test zero iterations:"); -executeTests(gTests_integer_iterations, "Test integer iterations:"); -executeTests(gTests_fractional_iterations, "Test fractional iterations:"); -executeTests(gTests_infinity_iterations, "Test infinity iterations:"); + +// -------------------------------------------------------------------- +// +// End delay tests +// +// -------------------------------------------------------------------- + +runTests([ + { + input: { duration: 100, + delay: 1, + fill: 'both', + endDelay: 50 }, + before: 0, + active: 0, + after: 1 + }, + + { + input: { duration: 100, + delay: 1, + fill: 'both', + endDelay: -50 }, + before: 0, + active: 0, + after: 0.5 + }, + + { + input: { duration: 100, + delay: 1, + fill: 'both', + endDelay: -100 }, + before: 0, + active: 0, + after: 0 + }, + + { + input: { duration: 100, + delay: 1, + fill: 'both', + endDelay: -200 }, + before: 0, + active: 0, + after: 0 + }, + + { + input: { iterationStart: 0.5, + duration: 100, + delay: 1, + fill: 'both', + endDelay: 50 }, + before: 0.5, + active: 0.5, + after: 0.5 + }, + + { + input: { iterationStart: 0.5, + duration: 100, + delay: 1, + fill: 'both', + endDelay: -50 }, + before: 0.5, + active: 0.5, + after: 1 + }, + + { + input: { iterationStart: 0.5, + duration: 100, + delay: 1, + fill: 'both', + endDelay: -100 }, + before: 0.5, + active: 0.5, + after: 0.5 + }, + + { + input: { iterations: 2, + duration: 100, + delay: 1, + fill: 'both', + endDelay: -100 }, + before: 0, + active: 0, + after: 1 + }, + + { + input: { iterations: 1, + iterationStart: 2, + duration: 100, + delay: 1, + fill: 'both', + endDelay: -50 }, + before: 0, + active: 0, + after: 0.5 + }, + + { + input: { iterations: 1, + iterationStart: 2, + duration: 100, + delay: 1, + fill: 'both', + endDelay: -100 }, + before: 0, + active: 0, + after: 0 + }, +], 'Test end delay'); </script> </body>
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/continueToLocation-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/continueToLocation-expected.txt index 726c7373..d0c6ce7 100644 --- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/continueToLocation-expected.txt +++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/continueToLocation-expected.txt
@@ -1,30 +1,30 @@ Paused on debugger statement -Paused after continueToLocation (insterstatement=false) +Paused after continueToLocation Stopped on line 8, expected 8, requested 8, (0-based numbers). Control parameter 'step' calculation result: 1, expected: 1 SUCCESS Paused on debugger statement -Paused after continueToLocation (insterstatement=true) +Paused after continueToLocation Stopped on line 8, expected 8, requested 8, (0-based numbers). Control parameter 'step' calculation result: 1, expected: 1 SUCCESS Paused on debugger statement -Paused after continueToLocation (insterstatement=false) +Paused after continueToLocation Stopped on line 17, expected 17, requested 12, (0-based numbers). Control parameter 'step' calculation result: 6, expected: 6 SUCCESS Paused on debugger statement -Paused after continueToLocation (insterstatement=false) +Paused after continueToLocation Stopped on line 17, expected 17, requested 13, (0-based numbers). Control parameter 'step' calculation result: 6, expected: 6 SUCCESS Paused on debugger statement -Paused after continueToLocation (insterstatement=false) +Paused after continueToLocation Stopped on line 17, expected 17, requested 17, (0-based numbers). Control parameter 'step' calculation result: 6, expected: 6 SUCCESS Paused on debugger statement -Paused after continueToLocation (insterstatement=true) +Paused after continueToLocation Stopped on line 17, expected 17, requested 17, (0-based numbers). Control parameter 'step' calculation result: 6, expected: 6 SUCCESS
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/continueToLocation.html b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/continueToLocation.html index dec791a..ce8d20c 100644 --- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/continueToLocation.html +++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/continueToLocation.html
@@ -7,13 +7,13 @@ function test() { var scenario = [ - // requested line number, insterstatement location, expected control parameter 'step', expected line number - [ 8, false, 1, 8 ], - [ 8, true, 1, 8 ], - [ 12, false, 6, 17 ], - [ 13, false, 6, 17 ], - [ 17, false, 6, 17 ], - [ 17, true, 6, 17 ], + // requested line number, expected control parameter 'step', expected line number + [ 8, 1, 8 ], + [ 8, 1, 8 ], + [ 12, 6, 17 ], + [ 13, 6, 17 ], + [ 17, 6, 17 ], + [ 17, 6, 17 ], ]; InspectorTest.sendCommand("Debugger.enable", {}); @@ -40,13 +40,13 @@ function nextScenarioStep(pos) { if (pos < scenario.length) - gotoSinglePassChain(scriptId, scenario[pos][0], scenario[pos][1], scenario[pos][2], scenario[pos][3], nextScenarioStep.bind(this, pos + 1)); + gotoSinglePassChain(scriptId, scenario[pos][0], scenario[pos][1], scenario[pos][2], nextScenarioStep.bind(this, pos + 1)); else InspectorTest.completeTest(); } } - function gotoSinglePassChain(scriptId, lineNumber, interstatement, expectedResult, expectedLineNumber, next) + function gotoSinglePassChain(scriptId, lineNumber, expectedResult, expectedLineNumber, next) { InspectorTest.eventHandler["Debugger.paused"] = handleDebuggerPausedOne; @@ -58,7 +58,7 @@ InspectorTest.eventHandler["Debugger.paused"] = handleDebuggerPausedTwo; - InspectorTest.sendCommand("Debugger.continueToLocation", { location: { scriptId: scriptId, lineNumber: lineNumber, columnNumber: 0}, interstatementLocation: interstatement }, logContinueToLocation); + InspectorTest.sendCommand("Debugger.continueToLocation", { location: { scriptId: scriptId, lineNumber: lineNumber, columnNumber: 0} }, logContinueToLocation); function logContinueToLocation(response) { @@ -70,7 +70,7 @@ } function handleDebuggerPausedTwo(messageObject) { - InspectorTest.log("Paused after continueToLocation (insterstatement=" + interstatement + ")"); + InspectorTest.log("Paused after continueToLocation"); var actualLineNumber = messageObject.params.callFrames[0].location.lineNumber; InspectorTest.log("Stopped on line " + actualLineNumber + ", expected " + expectedLineNumber + ", requested " + lineNumber + ", (0-based numbers).");
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-compileScript-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-compileScript-expected.txt index 9904eb32..75cc0adf 100644 --- a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-compileScript-expected.txt +++ b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-compileScript-expected.txt
@@ -1,4 +1,6 @@ -{ +Compiling script: foo1.js + persist: false +compilation result: { exceptionDetails : { columnNumber : 2 lineNumber : 1 @@ -6,12 +8,22 @@ text : Uncaught SyntaxError: Unexpected end of input } } -{ +----- +Compiling script: foo2.js + persist: true +Debugger.scriptParsed: foo2.js +compilation result: { scriptId : 0 } -{ +----- +Compiling script: foo3.js + persist: false +compilation result: { } -{ +----- +Compiling script: foo4.js + persist: false +compilation result: { exceptionDetails : { columnNumber : 13 lineNumber : 0 @@ -19,4 +31,5 @@ text : Uncaught SyntaxError: Unexpected identifier } } +-----
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-compileScript.html b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-compileScript.html index 699e55b..da8e833 100644 --- a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-compileScript.html +++ b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-compileScript.html
@@ -6,37 +6,57 @@ { var executionContextId; - InspectorTest.sendCommand("Runtime.enable", {}); - InspectorTest.eventHandler["Runtime.executionContextCreated"] = function(messageObject) + InspectorTest.sendCommand("Debugger.enable", {}, onDebuggerEnabled); + + function onDebuggerEnabled() + { + InspectorTest.sendCommand("Runtime.enable", {}); + InspectorTest.eventHandler["Debugger.scriptParsed"] = onScriptParsed; + InspectorTest.eventHandler["Runtime.executionContextCreated"] = onExecutionContextCreated; + } + + function onScriptParsed(messageObject) + { + if (!messageObject.params.url) + return; + InspectorTest.log("Debugger.scriptParsed: " + messageObject.params.url); + } + + function onExecutionContextCreated(messageObject) { executionContextId = messageObject.params.context.id; - - compileScriptPromise("\n (", false, "foo1.js") - .then(dumpResult) - .then(() => compileScriptPromise("239", true, "foo2.js")) - .then(dumpResult) - .then(() => compileScriptPromise("239", false, "foo3.js")) - .then(dumpResult) - .then(() => compileScriptPromise("testfunction f()\n{\n return 0;\n}\n", false, "foo4.js")) - .then(dumpResult) + testCompileScript("\n (", false, "foo1.js") + .then(() => testCompileScript("239", true, "foo2.js")) + .then(() => testCompileScript("239", false, "foo3.js")) + .then(() => testCompileScript("testfunction f()\n{\n return 0;\n}\n", false, "foo4.js")) .then(() => InspectorTest.completeTest()); } - function dumpResult(messageObject) + function testCompileScript(expression, persistScript, sourceURL) { - if (messageObject.result.exceptionDetails) - messageObject.result.exceptionDetails.scriptId = 0; - if (messageObject.result.scriptId) - messageObject.result.scriptId = 0; - InspectorTest.logObject(messageObject.result); - } + InspectorTest.log("Compiling script: " + sourceURL); + InspectorTest.log(" persist: " + persistScript); + var callback; + var promise = new Promise(resolver => callback = resolver); + InspectorTest.sendCommand("Runtime.compileScript", { + expression: expression, + sourceURL: sourceURL, + persistScript: persistScript, + executionContextId: executionContextId + }, onCompiled); + return promise; - function compileScriptPromise(expression, persistScript, sourceURL) - { - var cb; - var p = new Promise((resolver) => cb = resolver); - InspectorTest.sendCommand("Runtime.compileScript", { expression: expression, sourceURL: sourceURL, persistScript: persistScript, executionContextId: executionContextId }, cb); - return p; + function onCompiled(messageObject) + { + var result = messageObject.result; + if (result.exceptionDetails) + result.exceptionDetails.scriptId = 0; + if (result.scriptId) + result.scriptId = 0; + InspectorTest.logObject(result, "compilation result: "); + InspectorTest.log("-----"); + callback(); + } } } </script>
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/autocomplete-general.html b/third_party/WebKit/LayoutTests/inspector/sources/autocomplete-general.html index 5113ef2..04b3b49 100644 --- a/third_party/WebKit/LayoutTests/inspector/sources/autocomplete-general.html +++ b/third_party/WebKit/LayoutTests/inspector/sources/autocomplete-general.html
@@ -69,7 +69,7 @@ ]; function dumpDictionary(next) { - var wordsInDictionary = textEditor._autocompleteController._delegate._dictionary.wordsWithPrefix(""); + var wordsInDictionary = textEditor._autocompleteController._dictionary.wordsWithPrefix(""); InspectorTest.addResult("========= Text in editor ========="); InspectorTest.dumpTextWithSelection(textEditor); InspectorTest.addResult("======= Words in dictionary =======");
diff --git a/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-generate-request-disallowed-input.html b/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-generate-request-disallowed-input.html index ff73eec3..a973ac6 100644 --- a/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-generate-request-disallowed-input.html +++ b/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-generate-request-disallowed-input.html
@@ -66,13 +66,13 @@ 0x00, 0x00, 0x00, 0x00 // datasize ]); return test_session('cenc', initData); - }, 'generateRequest() with invalid pssh data.'); + }, 'generateRequest() with invalid pssh box size.'); promise_test(function() { // Invalid data as type = 'psss'. var initData = new Uint8Array([ - 0x00, 0x00, 0x00, 0x00, // size = 0 + 0x00, 0x00, 0x00, 0x20, // size = 0 0x70, 0x73, 0x73, 0x73, // 'psss' 0x00, // version = 0 0x00, 0x00, 0x00, // flags
diff --git a/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-utils.js b/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-utils.js index d270037..dfccdfe 100644 --- a/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-utils.js +++ b/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-utils.js
@@ -32,7 +32,7 @@ if (initDataType == 'cenc') { return new Uint8Array([ - 0x00, 0x00, 0x00, 0x00, // size = 0 + 0x00, 0x00, 0x00, 0x34, // size = 52 0x70, 0x73, 0x73, 0x68, // 'pssh' 0x01, // version = 1 0x00, 0x00, 0x00, // flags
diff --git a/third_party/WebKit/LayoutTests/media/media-controls-fit-properly-while-zoomed.html b/third_party/WebKit/LayoutTests/media/media-controls-fit-properly-while-zoomed.html new file mode 100644 index 0000000..cae3e9d --- /dev/null +++ b/third_party/WebKit/LayoutTests/media/media-controls-fit-properly-while-zoomed.html
@@ -0,0 +1,31 @@ +<!DOCTYPE html> +<html> + <head> + <title>media controls adjust for zoom when filling the bar</title> + <script src="../resources/testharness.js"></script> + <script src="../resources/testharnessreport.js"></script> + <script src="media-controls.js"></script> + <script src=media-file.js></script> + <style> + body { zoom: 500%; } + </style> + </head> + <body onload="async_test(testTimelineVisible)"> + <div id="log"></div> + <video id="video" width="300px" controls></video> + <script> + var element = document.getElementById("video"); + element.src = findMediaFile("video", "content/counting"); + + function testTimelineVisible(test) { + // Check that the timeline is shown. If zoom is not accounted for, + // then it will be considered 500% bigger, and will be dropped. + var timeline = mediaControlsButton(element, "timeline"); + assert_true(getComputedStyle(timeline).display != "none", + "timeline should not be hidden while zoomed"); + test.done(); + } + </script> + </video> + </body> +</html>
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/update-visual-rects-after-compositing-change-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/update-visual-rects-after-compositing-change-expected.txt new file mode 100644 index 0000000..671e44c32 --- /dev/null +++ b/third_party/WebKit/LayoutTests/paint/invalidation/update-visual-rects-after-compositing-change-expected.txt
@@ -0,0 +1,12 @@ +gone! +Summary + +Harness status: OK + +Found 1 tests + +1 Pass +Details + +Result Test Name Message +Pass Untitled
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/update-visual-rects-after-compositing-change.html b/third_party/WebKit/LayoutTests/paint/invalidation/update-visual-rects-after-compositing-change.html new file mode 100644 index 0000000..faa4c0a --- /dev/null +++ b/third_party/WebKit/LayoutTests/paint/invalidation/update-visual-rects-after-compositing-change.html
@@ -0,0 +1,54 @@ +<!doctype HTML> +<style> +#child { + position: relative; +} +</style> +<div style="backface-visibility: hidden;"> + <div id="target"> + <div id="child"></div> + <div style="position: relative;"> + <span id="myspan">gone!</span> + </div> + </div> +</div> +<script src="../../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<script> + +function runTest() { + var content = document.createElement("span"); + var div = document.createElement("div"); + div.appendChild(content); + div.id = "child"; + target.replaceChild(div, child); + requestAnimationFrame(checkResult); +} + +function checkResult() { + if (window.internals) { + var clientRect = window.internals.visualRect(myspan.firstChild); + test(function() { + // Check that the visual rect for the child has been initialized + // to a non-zero (and hence presumably correct) size. + assert_true(clientRect.width > 0); + assert_true(clientRect.height > 0); + }); + } + if (window.testRunner) + testRunner.notifyDone(); +} + +if (window.testRunner) { + window.testRunner.waitUntilDone(); + window.testRunner.dumpAsText(); +} + +onload = function() { + requestAnimationFrame(function() { + requestAnimationFrame(function() { + runTest(); + }); + }); +} +</script>
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/text/ellipsis-rtl-text-in-ltr-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/text/ellipsis-rtl-text-in-ltr-flow-underline-expected.png new file mode 100644 index 0000000..14deca4 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/fast/text/ellipsis-rtl-text-in-ltr-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/text/ellipsis-rtl-text-in-rtl-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/text/ellipsis-rtl-text-in-rtl-flow-underline-expected.png new file mode 100644 index 0000000..6cd32f4 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/fast/text/ellipsis-rtl-text-in-rtl-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/webaudio/audiobuffersource-loop-points-expected.wav b/third_party/WebKit/LayoutTests/platform/android/webaudio/audiobuffersource-loop-points-expected.wav new file mode 100644 index 0000000..2ce8dcf --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/webaudio/audiobuffersource-loop-points-expected.wav Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux-precise/compositing/overflow/updating-scrolling-container-and-content-expected.png b/third_party/WebKit/LayoutTests/platform/linux-precise/compositing/overflow/updating-scrolling-container-and-content-expected.png deleted file mode 100644 index 27a6eca2..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux-precise/compositing/overflow/updating-scrolling-container-and-content-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux-precise/fast/forms/select-popup/popup-menu-appearance-long-expected.png b/third_party/WebKit/LayoutTests/platform/linux-precise/fast/forms/select-popup/popup-menu-appearance-long-expected.png deleted file mode 100644 index 920366d..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux-precise/fast/forms/select-popup/popup-menu-appearance-long-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux-precise/fast/forms/select-popup/popup-menu-appearance-many-expected.png b/third_party/WebKit/LayoutTests/platform/linux-precise/fast/forms/select-popup/popup-menu-appearance-many-expected.png deleted file mode 100644 index d669478..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux-precise/fast/forms/select-popup/popup-menu-appearance-many-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux-precise/fast/forms/select-popup/popup-menu-appearance-rtl-default-expected.png b/third_party/WebKit/LayoutTests/platform/linux-precise/fast/forms/select-popup/popup-menu-appearance-rtl-default-expected.png deleted file mode 100644 index 8b8cc5b..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux-precise/fast/forms/select-popup/popup-menu-appearance-rtl-default-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux-precise/fast/forms/select-popup/popup-menu-appearance-rtl-expected.png b/third_party/WebKit/LayoutTests/platform/linux-precise/fast/forms/select-popup/popup-menu-appearance-rtl-expected.png deleted file mode 100644 index 72a040c4..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux-precise/fast/forms/select-popup/popup-menu-appearance-rtl-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux-precise/fast/forms/select-popup/popup-menu-appearance-zoom-expected.png b/third_party/WebKit/LayoutTests/platform/linux-precise/fast/forms/select-popup/popup-menu-appearance-zoom-expected.png deleted file mode 100644 index 0c6c3a2..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux-precise/fast/forms/select-popup/popup-menu-appearance-zoom-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux-precise/fast/forms/select-popup/popup-menu-appearance-zoom090-expected.png b/third_party/WebKit/LayoutTests/platform/linux-precise/fast/forms/select-popup/popup-menu-appearance-zoom090-expected.png deleted file mode 100644 index 2396e59..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux-precise/fast/forms/select-popup/popup-menu-appearance-zoom090-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux-precise/fast/repaint/scrollbar-damage-and-full-viewport-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/linux-precise/fast/repaint/scrollbar-damage-and-full-viewport-repaint-expected.png deleted file mode 100644 index 284fa75e..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux-precise/fast/repaint/scrollbar-damage-and-full-viewport-repaint-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux-precise/svg/zoom/page/zoom-mask-with-percentages-expected.png b/third_party/WebKit/LayoutTests/platform/linux-precise/svg/zoom/page/zoom-mask-with-percentages-expected.png deleted file mode 100644 index 82b7365..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux-precise/svg/zoom/page/zoom-mask-with-percentages-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/css/text-overflow-ellipsis-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/css/text-overflow-ellipsis-expected.png index 522ce6becd..0ad6cd75 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/css/text-overflow-ellipsis-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/css/text-overflow-ellipsis-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/css/text-overflow-ellipsis-strict-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/css/text-overflow-ellipsis-strict-expected.png index 522ce6becd..0ad6cd75 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/css/text-overflow-ellipsis-strict-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/css/text-overflow-ellipsis-strict-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select-popup/popup-menu-appearance-long-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select-popup/popup-menu-appearance-long-expected.png index 5043463..920366d 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select-popup/popup-menu-appearance-long-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select-popup/popup-menu-appearance-long-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select-popup/popup-menu-appearance-many-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select-popup/popup-menu-appearance-many-expected.png index 9e62f67..d669478 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select-popup/popup-menu-appearance-many-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select-popup/popup-menu-appearance-many-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select-popup/popup-menu-appearance-rtl-default-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select-popup/popup-menu-appearance-rtl-default-expected.png index 373e358..8b8cc5b 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select-popup/popup-menu-appearance-rtl-default-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select-popup/popup-menu-appearance-rtl-default-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select-popup/popup-menu-appearance-rtl-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select-popup/popup-menu-appearance-rtl-expected.png index 085dfe4..72a040c4 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select-popup/popup-menu-appearance-rtl-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select-popup/popup-menu-appearance-rtl-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select-popup/popup-menu-appearance-zoom-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select-popup/popup-menu-appearance-zoom-expected.png index 00f90184..0c6c3a2 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select-popup/popup-menu-appearance-zoom-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select-popup/popup-menu-appearance-zoom-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select-popup/popup-menu-appearance-zoom090-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select-popup/popup-menu-appearance-zoom090-expected.png index 881a57b..2396e59 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select-popup/popup-menu-appearance-zoom090-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select-popup/popup-menu-appearance-zoom090-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/containing-block-position-change-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/containing-block-position-change-expected.txt index f8a78a6..7afae8e 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/containing-block-position-change-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/containing-block-position-change-expected.txt
@@ -11,7 +11,7 @@ { "object": "LayoutBlockFlow (positioned) DIV", "rect": [158, 74, 50, 50], - "reason": "bounds change" + "reason": "style change" }, { "object": "LayoutBlockFlow (positioned) DIV", @@ -32,7 +32,7 @@ }, { "object": "LayoutBlockFlow (positioned) DIV", - "reason": "bounds change" + "reason": "style change" } ] }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-ltr-text-in-ltr-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-ltr-text-in-ltr-flow-underline-expected.png new file mode 100644 index 0000000..4652fd9f --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-ltr-text-in-ltr-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-ltr-text-in-ltr-flow-underline-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-ltr-text-in-ltr-flow-underline-expected.txt new file mode 100644 index 0000000..1f78b1a --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-ltr-text-in-ltr-flow-underline-expected.txt
@@ -0,0 +1,15 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x116 + LayoutBlockFlow {HTML} at (0,0) size 800x116 + LayoutBlockFlow {BODY} at (8,16) size 784x92 + LayoutBlockFlow {P} at (0,0) size 784x20 + LayoutText {#text} at (0,0) size 457x19 + text run at (0,0) width 457: "crbug.com/634445: Ltr text in a ltr flow should truncate the text left-to-right." + LayoutBlockFlow {P} at (0,36) size 784x20 + LayoutText {#text} at (0,0) size 448x19 + text run at (0,0) width 448: "You should see 01234567890123... below and text beneath the underline." +layer at (8,88) size 125x20 scrollWidth 240 + LayoutBlockFlow {DIV} at (0,72) size 125x20 + LayoutText {#text} at (0,0) size 240x19 + text run at (0,0) width 240: "012345678901234567890123456789"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-ltr-text-in-rtl-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-ltr-text-in-rtl-flow-underline-expected.png new file mode 100644 index 0000000..28179b1 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-ltr-text-in-rtl-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-ltr-text-in-rtl-flow-underline-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-ltr-text-in-rtl-flow-underline-expected.txt new file mode 100644 index 0000000..a835082 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-ltr-text-in-rtl-flow-underline-expected.txt
@@ -0,0 +1,15 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x116 + LayoutBlockFlow {HTML} at (0,0) size 800x116 + LayoutBlockFlow {BODY} at (8,16) size 784x92 + LayoutBlockFlow {P} at (0,0) size 784x20 + LayoutText {#text} at (0,0) size 457x19 + text run at (0,0) width 457: "crbug.com/634445: Ltr text in a rtl flow should truncate the text right-to-left." + LayoutBlockFlow {P} at (0,36) size 784x20 + LayoutText {#text} at (0,0) size 459x19 + text run at (0,0) width 459: "You should see ...32109876543210 below and an underline beneat the text." +layer at (8,88) size 125x20 scrollX 123.00 scrollWidth 248 + LayoutBlockFlow {DIV} at (0,72) size 125x20 + LayoutText {#text} at (-123,0) size 248x19 + text run at (-123,0) width 248: "0987654321098765432109876543210"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-mixed-text-in-ltr-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-mixed-text-in-ltr-flow-underline-expected.png new file mode 100644 index 0000000..711fce20 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-mixed-text-in-ltr-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-mixed-text-in-ltr-flow-underline-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-mixed-text-in-ltr-flow-underline-expected.txt new file mode 100644 index 0000000..8406375 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-mixed-text-in-ltr-flow-underline-expected.txt
@@ -0,0 +1,16 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x116 + LayoutBlockFlow {HTML} at (0,0) size 800x116 + LayoutBlockFlow {BODY} at (8,16) size 784x92 + LayoutBlockFlow {P} at (0,0) size 784x20 + LayoutText {#text} at (0,0) size 456x19 + text run at (0,0) width 456: "crbug.com/634445: Rtl text in a ltr flow should truncate the text left-to-right." + LayoutBlockFlow {P} at (0,36) size 784x20 + LayoutText {#text} at (0,0) size 382x19 + text run at (0,0) width 382: "You should see an underline beneath the text but not the ellipsis." +layer at (8,88) size 125x20 scrollWidth 219 + LayoutBlockFlow {DIV} at (0,72) size 125x20 + LayoutText {#text} at (0,0) size 219x19 + text run at (0,0) width 40: "Lorem" + text run at (40,0) width 179 RTL: "\x{5D0}\x{5D1}\x{5D2}\x{5D3}\x{5D4}\x{5D5}\x{5D6}\x{5D7}\x{5D8}\x{5D9}\x{5DB}\x{5DA}\x{5DC}\x{5DE}\x{5DD}\x{5E1}\x{5E2}\x{5E4}\x{5E3}\x{5E6}\x{5E5}\x{5E7}\x{5E8}\x{5E9}\x{5EA}"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-mixed-text-in-rtl-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-mixed-text-in-rtl-flow-underline-expected.png new file mode 100644 index 0000000..98facbf7 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-mixed-text-in-rtl-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-mixed-text-in-rtl-flow-underline-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-mixed-text-in-rtl-flow-underline-expected.txt new file mode 100644 index 0000000..5909a7a --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-mixed-text-in-rtl-flow-underline-expected.txt
@@ -0,0 +1,16 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x116 + LayoutBlockFlow {HTML} at (0,0) size 800x116 + LayoutBlockFlow {BODY} at (8,16) size 784x92 + LayoutBlockFlow {P} at (0,0) size 784x20 + LayoutText {#text} at (0,0) size 456x19 + text run at (0,0) width 456: "crbug.com/634445: Rtl text in a rtl flow should truncate the text right-to-left." + LayoutBlockFlow {P} at (0,36) size 784x20 + LayoutText {#text} at (0,0) size 271x19 + text run at (0,0) width 271: "You should see an underline beneath the text." +layer at (8,88) size 125x20 scrollX 94.00 scrollWidth 219 + LayoutBlockFlow {DIV} at (0,72) size 125x20 + LayoutText {#text} at (-94,0) size 219x19 + text run at (-94,0) width 179 RTL: "\x{5D0}\x{5D1}\x{5D2}\x{5D3}\x{5D4}\x{5D5}\x{5D6}\x{5D7}\x{5D8}\x{5D9}\x{5DB}\x{5DA}\x{5DC}\x{5DE}\x{5DD}\x{5E1}\x{5E2}\x{5E4}\x{5E3}\x{5E6}\x{5E5}\x{5E7}\x{5E8}\x{5E9}\x{5EA}" + text run at (85,0) width 40: "Lorem"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-rtl-text-in-ltr-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-rtl-text-in-ltr-flow-underline-expected.png new file mode 100644 index 0000000..c230b5d --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-rtl-text-in-ltr-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-rtl-text-in-ltr-flow-underline-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-rtl-text-in-ltr-flow-underline-expected.txt new file mode 100644 index 0000000..882fc1f --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-rtl-text-in-ltr-flow-underline-expected.txt
@@ -0,0 +1,17 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x116 + LayoutBlockFlow {HTML} at (0,0) size 800x116 + LayoutBlockFlow {BODY} at (8,16) size 784x92 + LayoutBlockFlow {P} at (0,0) size 784x20 + LayoutText {#text} at (0,0) size 456x19 + text run at (0,0) width 456: "crbug.com/634445: Rtl text in a ltr flow should truncate the text left-to-right." + LayoutBlockFlow {P} at (0,36) size 784x20 + LayoutText {#text} at (0,0) size 465x19 + text run at (0,0) width 96: "You should see " + text run at (95,0) width 109 RTL: "\x{5DA}\x{5DC}\x{5DE}\x{5DD}\x{5E1}\x{5E2}\x{5E4}\x{5E3}\x{5E6}\x{5E5}\x{5E7}\x{5E8}\x{5E9}\x{5EA}" + text run at (203,0) width 262: "... below with an underline beneath the text." +layer at (8,88) size 125x20 scrollWidth 179 + LayoutBlockFlow {DIV} at (0,72) size 125x20 + LayoutText {#text} at (0,0) size 179x19 + text run at (0,0) width 179 RTL: "\x{5D0}\x{5D1}\x{5D2}\x{5D3}\x{5D4}\x{5D5}\x{5D6}\x{5D7}\x{5D8}\x{5D9}\x{5DB}\x{5DA}\x{5DC}\x{5DE}\x{5DD}\x{5E1}\x{5E2}\x{5E4}\x{5E3}\x{5E6}\x{5E5}\x{5E7}\x{5E8}\x{5E9}\x{5EA}"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-rtl-text-in-rtl-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-rtl-text-in-rtl-flow-underline-expected.png new file mode 100644 index 0000000..5f8349a --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-rtl-text-in-rtl-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-rtl-text-in-rtl-flow-underline-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-rtl-text-in-rtl-flow-underline-expected.txt new file mode 100644 index 0000000..98ce6fbc4 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-rtl-text-in-rtl-flow-underline-expected.txt
@@ -0,0 +1,17 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x116 + LayoutBlockFlow {HTML} at (0,0) size 800x116 + LayoutBlockFlow {BODY} at (8,16) size 784x92 + LayoutBlockFlow {P} at (0,0) size 784x20 + LayoutText {#text} at (0,0) size 456x19 + text run at (0,0) width 456: "crbug.com/634445: Rtl text in a rtl flow should truncate the text right-to-left." + LayoutBlockFlow {P} at (0,36) size 784x20 + LayoutText {#text} at (0,0) size 448x19 + text run at (0,0) width 108: "You should see ..." + text run at (107,0) width 110 RTL: "\x{5D0}\x{5D1}\x{5D2}\x{5D3}\x{5D4}\x{5D5}\x{5D6}\x{5D7}\x{5D8}\x{5D9}\x{5DB}\x{5DA}\x{5DC}\x{5DE}\x{5DD}\x{5E1}" + text run at (216,0) width 232: " below with underline beneath the text." +layer at (8,88) size 125x20 scrollX 54.00 scrollWidth 179 + LayoutBlockFlow {DIV} at (0,72) size 125x20 + LayoutText {#text} at (-54,0) size 179x19 + text run at (-54,0) width 179 RTL: "\x{5D0}\x{5D1}\x{5D2}\x{5D3}\x{5D4}\x{5D5}\x{5D6}\x{5D7}\x{5D8}\x{5D9}\x{5DB}\x{5DA}\x{5DC}\x{5DE}\x{5DD}\x{5E1}\x{5E2}\x{5E4}\x{5E3}\x{5E6}\x{5E5}\x{5E7}\x{5E8}\x{5E9}\x{5EA}"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/video-zoom-controls-expected.png index 80d0816..cf7063e6 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/video-zoom-controls-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/media/video-zoom-controls-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/video-zoom-controls-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/media/video-zoom-controls-expected.txt index 2a79cc8..861dd84 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/media/video-zoom-controls-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/media/video-zoom-controls-expected.txt
@@ -13,15 +13,23 @@ LayoutBlockFlow {DIV} at (0,132) size 240x48 layer at (57,85) size 240x117 LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x117 -layer at (57,217) size 240x48 scrollHeight 60 +layer at (57,217) size 240x48 scrollWidth 314 scrollHeight 60 LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x48 [bgcolor=#FAFAFA] LayoutButton {INPUT} at (0,0) size 48x48 - LayoutSlider {INPUT} at (75,22.50) size 90x3 - LayoutFlexibleBox {DIV} at (0,0) size 90x3 - LayoutBlockFlow {DIV} at (-27,-34.50) size 144x72 + LayoutFlexibleBox {DIV} at (48,0) size 35x48 [color=#5A5A5A] + LayoutBlockFlow (anonymous) at (0,0) size 35x48 + LayoutText {#text} at (0,13) size 35x21 + text run at (0,13) width 35: "0:00" + LayoutSlider {INPUT} at (110,22.50) size 37.50x3 + LayoutFlexibleBox {DIV} at (0,0) size 37.50x3 + LayoutBlockFlow {DIV} at (-27,-34.50) size 91.50x72 LayoutBlockFlow {DIV} at (0,0) size 54x72 -layer at (249,217) size 48x48 - LayoutButton {INPUT} at (192,0) size 48x48 + LayoutSlider {INPUT} at (201.50,22.50) size 37.50x3 + LayoutFlexibleBox {DIV} at (0,0) size 37.50x3 + LayoutBlockFlow {DIV} at (-27,-34.50) size 91.50x72 + LayoutBlockFlow {DIV} at (37.50,0) size 54x72 +layer at (323,217) size 48x48 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 + LayoutButton {INPUT} at (266,0) size 48x48 layer at (57,310) size 240x180 LayoutVideo {VIDEO} at (45,298) size 240x180 layer at (57,310) size 240x180 @@ -29,12 +37,20 @@ LayoutBlockFlow {DIV} at (0,132) size 240x48 layer at (57,310) size 240x117 LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x117 -layer at (57,442) size 240x48 scrollHeight 60 +layer at (57,442) size 240x48 scrollWidth 314 scrollHeight 60 LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x48 [bgcolor=#FAFAFA] LayoutButton {INPUT} at (0,0) size 48x48 - LayoutSlider {INPUT} at (75,22.50) size 90x3 - LayoutFlexibleBox {DIV} at (0,0) size 90x3 - LayoutBlockFlow {DIV} at (-27,-34.50) size 144x72 + LayoutFlexibleBox {DIV} at (48,0) size 35x48 [color=#5A5A5A] + LayoutBlockFlow (anonymous) at (0,0) size 35x48 + LayoutText {#text} at (0,13) size 35x21 + text run at (0,13) width 35: "0:00" + LayoutSlider {INPUT} at (110,22.50) size 37.50x3 + LayoutFlexibleBox {DIV} at (0,0) size 37.50x3 + LayoutBlockFlow {DIV} at (-27,-34.50) size 91.50x72 LayoutBlockFlow {DIV} at (0,0) size 54x72 -layer at (249,442) size 48x48 backgroundClip at (249,442) size 43x27 clip at (249,442) size 43x27 - LayoutButton {INPUT} at (192,0) size 48x48 + LayoutSlider {INPUT} at (201.50,22.50) size 37.50x3 + LayoutFlexibleBox {DIV} at (0,0) size 37.50x3 + LayoutBlockFlow {DIV} at (-27,-34.50) size 91.50x72 + LayoutBlockFlow {DIV} at (37.50,0) size 54x72 +layer at (323,442) size 48x48 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 + LayoutButton {INPUT} at (266,0) size 48x48
diff --git a/third_party/WebKit/LayoutTests/platform/linux/printing/thead-repeats-at-top-of-each-page-multiple-tables-expected.png b/third_party/WebKit/LayoutTests/platform/linux/printing/thead-repeats-at-top-of-each-page-multiple-tables-expected.png new file mode 100644 index 0000000..bbf6ba1 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/printing/thead-repeats-at-top-of-each-page-multiple-tables-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-clipped-hit-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-clipped-hit-expected.txt index 1be4d22..fba1cc3 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-clipped-hit-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-clipped-hit-expected.txt
@@ -22,21 +22,12 @@ "object": "LayoutSVGInlineText #text", "rect": [90, 115, 43, 19], "reason": "layoutObject insertion" - }, - { - "object": "LayoutSVGText text id='status'", - "rect": [89, 114, 3, 21], - "reason": "invalidate paint rectangle" } ] } ], "objectPaintInvalidations": [ { - "object": "LayoutSVGText text id='status'", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutSVGInlineText #text", "reason": "layoutObject removal" },
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-mask-with-percentages-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-mask-with-percentages-expected.png index 3d25b2e..82b7365 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-mask-with-percentages-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-mask-with-percentages-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/threaded/printing/thead-repeats-at-top-of-each-page-multiple-tables-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/threaded/printing/thead-repeats-at-top-of-each-page-multiple-tables-expected.png new file mode 100644 index 0000000..bbf6ba1 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/threaded/printing/thead-repeats-at-top-of-each-page-multiple-tables-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/compositing/overflow/updating-scrolling-container-and-content-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/compositing/overflow/updating-scrolling-container-and-content-expected.png deleted file mode 100644 index 3bed833..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/compositing/overflow/updating-scrolling-container-and-content-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/repaint/fixed-and-absolute-position-scrolled-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/repaint/fixed-and-absolute-position-scrolled-expected.png new file mode 100644 index 0000000..ea03162 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/repaint/fixed-and-absolute-position-scrolled-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/repaint/fixed-and-absolute-position-scrolled-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/repaint/fixed-and-absolute-position-scrolled-expected.txt new file mode 100644 index 0000000..f8b33619 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/repaint/fixed-and-absolute-position-scrolled-expected.txt
@@ -0,0 +1,11 @@ +layer at (0,0) size 800x600 scrollHeight 5808 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x2016 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600 + LayoutBlockFlow {HTML} at (0,0) size 800x2016 + LayoutBlockFlow {BODY} at (8,8) size 784x2000 +layer at (100,200) size 100x100 + LayoutBlockFlow (positioned) {DIV} at (100,200) size 100x100 [bgcolor=#FF0000] +layer at (8,5008) size 100x100 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600 + LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 100x100 +layer at (108,5708) size 100x100 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600 + LayoutBlockFlow (positioned) {DIV} at (100,700) size 100x100 [bgcolor=#008000]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/repaint/resize-iframe-text-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/repaint/resize-iframe-text-expected.png index 9ad77ec2..3ff17ff 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/repaint/resize-iframe-text-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/repaint/resize-iframe-text-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/repaint/resize-iframe-text-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/repaint/resize-iframe-text-expected.txt new file mode 100644 index 0000000..ba1bab2 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/repaint/resize-iframe-text-expected.txt
@@ -0,0 +1,110 @@ +{ + "name": "Content Root Layer", + "bounds": [800, 745], + "children": [ + { + "name": "LayoutView #document", + "bounds": [800, 745], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutIFrame (positioned) IFRAME", + "rect": [0, 0, 800, 745], + "reason": "forced by layout" + }, + { + "object": "LayoutView #document", + "rect": [0, 600, 800, 145], + "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 800, 34], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 785, 745], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow BODY", + "rect": [8, 8, 784, 18], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow H1", + "rect": [8, 700, 600, 37], + "reason": "bounds change" + }, + { + "object": "LayoutText #text", + "rect": [8, 8, 346, 18], + "reason": "forced by layout" + }, + { + "object": "LayoutView #document", + "rect": [785, 0, 15, 745], + "reason": "scroll" + }, + { + "object": "LayoutView #document", + "rect": [785, 0, 15, 600], + "reason": "scroll" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutView #document", + "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow BODY", + "reason": "forced by layout" + }, + { + "object": "RootInlineBox", + "reason": "forced by layout" + }, + { + "object": "LayoutText #text", + "reason": "forced by layout" + }, + { + "object": "InlineTextBox 'Test passes if you see \"Success\" after window resizes.'", + "reason": "forced by layout" + }, + { + "object": "LayoutIFrame (positioned) IFRAME", + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow H1", + "reason": "bounds change" + }, + { + "object": "RootInlineBox", + "reason": "bounds change" + }, + { + "object": "LayoutView #document", + "reason": "scroll" + }, + { + "object": "VerticalScrollbar", + "reason": "scroll" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/ellipsis-ltr-text-in-ltr-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/ellipsis-ltr-text-in-ltr-flow-underline-expected.png new file mode 100644 index 0000000..e8ed4252 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/ellipsis-ltr-text-in-ltr-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/ellipsis-ltr-text-in-rtl-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/ellipsis-ltr-text-in-rtl-flow-underline-expected.png new file mode 100644 index 0000000..8a143815 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/ellipsis-ltr-text-in-rtl-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/ellipsis-mixed-text-in-ltr-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/ellipsis-mixed-text-in-ltr-flow-underline-expected.png new file mode 100644 index 0000000..fbe4885 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/ellipsis-mixed-text-in-ltr-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/ellipsis-mixed-text-in-rtl-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/ellipsis-mixed-text-in-rtl-flow-underline-expected.png new file mode 100644 index 0000000..dbe8a52 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/ellipsis-mixed-text-in-rtl-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/ellipsis-rtl-text-in-ltr-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/ellipsis-rtl-text-in-ltr-flow-underline-expected.png new file mode 100644 index 0000000..b59d477d --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/ellipsis-rtl-text-in-ltr-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/ellipsis-rtl-text-in-rtl-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/ellipsis-rtl-text-in-rtl-flow-underline-expected.png new file mode 100644 index 0000000..3ed0e08 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/ellipsis-rtl-text-in-rtl-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/media/video-zoom-controls-expected.png new file mode 100644 index 0000000..cb93942f --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/media/video-zoom-controls-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/media/video-zoom-controls-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/media/video-zoom-controls-expected.txt new file mode 100644 index 0000000..8843bad --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/media/video-zoom-controls-expected.txt
@@ -0,0 +1,28 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x600 + LayoutBlockFlow {HTML} at (0,0) size 800x600 + LayoutBlockFlow {BODY} at (12,12) size 776x543 + LayoutBlockFlow {P} at (0,0) size 776x28 + LayoutText {#text} at (0,0) size 278x28 + text run at (0,0) width 278: "Zoomed video with controls." +layer at (57,85) size 240x180 + LayoutVideo {VIDEO} at (45,73) size 240x180 +layer at (57,85) size 240x180 + LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x180 + LayoutBlockFlow {DIV} at (0,132) size 240x48 +layer at (57,85) size 240x117 + LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x117 +layer at (57,217) size 240x48 + LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x48 [bgcolor=#FAFAFA] + LayoutButton {INPUT} at (0,0) size 48x48 +layer at (57,310) size 240x180 + LayoutVideo {VIDEO} at (45,298) size 240x180 +layer at (57,310) size 240x180 + LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x180 + LayoutBlockFlow {DIV} at (0,132) size 240x48 +layer at (57,310) size 240x117 + LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x117 +layer at (57,442) size 240x48 + LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x48 [bgcolor=#FAFAFA] + LayoutButton {INPUT} at (0,0) size 48x48
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/compositing/overflow/updating-scrolling-container-and-content-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/compositing/overflow/updating-scrolling-container-and-content-expected.png deleted file mode 100644 index 6081da932..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/compositing/overflow/updating-scrolling-container-and-content-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/repaint/fixed-and-absolute-position-scrolled-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/repaint/fixed-and-absolute-position-scrolled-expected.png new file mode 100644 index 0000000..8018f08c --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/repaint/fixed-and-absolute-position-scrolled-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/repaint/fixed-and-absolute-position-scrolled-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/repaint/fixed-and-absolute-position-scrolled-expected.txt new file mode 100644 index 0000000..0ca88e89 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/repaint/fixed-and-absolute-position-scrolled-expected.txt
@@ -0,0 +1,53 @@ +{ + "name": "Content Root Layer", + "bounds": [800, 2016], + "children": [ + { + "name": "LayoutView #document", + "bounds": [800, 2016], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutView #document", + "rect": [0, 2016, 800, 3792], + "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 800, 2016], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow (positioned) DIV id='absoluteDiv' class='absolute green'", + "rect": [108, 5708, 100, 100], + "reason": "subtree" + }, + { + "object": "LayoutBlockFlow (positioned) DIV id='absoluteDiv' class='absolute green'", + "rect": [100, 700, 100, 100], + "reason": "style change" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutBlockFlow (positioned) DIV id='absoluteDiv' class='absolute green'", + "reason": "subtree" + }, + { + "object": "LayoutView #document", + "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow (positioned) DIV id='absoluteDiv' class='absolute green'", + "reason": "style change" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/ellipsis-ltr-text-in-ltr-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/ellipsis-ltr-text-in-ltr-flow-underline-expected.png new file mode 100644 index 0000000..ae10431 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/ellipsis-ltr-text-in-ltr-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/ellipsis-ltr-text-in-rtl-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/ellipsis-ltr-text-in-rtl-flow-underline-expected.png new file mode 100644 index 0000000..1d454a2 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/ellipsis-ltr-text-in-rtl-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/ellipsis-mixed-text-in-ltr-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/ellipsis-mixed-text-in-ltr-flow-underline-expected.png new file mode 100644 index 0000000..14e74762 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/ellipsis-mixed-text-in-ltr-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/ellipsis-mixed-text-in-rtl-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/ellipsis-mixed-text-in-rtl-flow-underline-expected.png new file mode 100644 index 0000000..9041e10 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/ellipsis-mixed-text-in-rtl-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/ellipsis-rtl-text-in-ltr-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/ellipsis-rtl-text-in-ltr-flow-underline-expected.png new file mode 100644 index 0000000..e618598 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/ellipsis-rtl-text-in-ltr-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/ellipsis-rtl-text-in-rtl-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/ellipsis-rtl-text-in-rtl-flow-underline-expected.png new file mode 100644 index 0000000..5d81721c --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/ellipsis-rtl-text-in-rtl-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/media/video-zoom-controls-expected.png new file mode 100644 index 0000000..e91b1fdc --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/media/video-zoom-controls-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/media/video-zoom-controls-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/media/video-zoom-controls-expected.txt new file mode 100644 index 0000000..cbe004f --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/media/video-zoom-controls-expected.txt
@@ -0,0 +1,56 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x600 + LayoutBlockFlow {HTML} at (0,0) size 800x600 + LayoutBlockFlow {BODY} at (12,12) size 776x543 + LayoutBlockFlow {P} at (0,0) size 776x28 + LayoutText {#text} at (0,0) size 278x28 + text run at (0,0) width 278: "Zoomed video with controls." +layer at (57,85) size 240x180 + LayoutVideo {VIDEO} at (45,73) size 240x180 +layer at (57,85) size 240x180 + LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x180 + LayoutBlockFlow {DIV} at (0,132) size 240x48 +layer at (57,85) size 240x117 + LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x117 +layer at (57,217) size 240x48 scrollWidth 314 scrollHeight 60 + LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x48 [bgcolor=#FAFAFA] + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutFlexibleBox {DIV} at (48,0) size 35.03x48 [color=#5A5A5A] + LayoutBlockFlow (anonymous) at (0,0) size 35.03x48 + LayoutText {#text} at (0,13) size 36x21 + text run at (0,13) width 36: "0:00" + LayoutSlider {INPUT} at (110.03,22.50) size 37.50x3 + LayoutFlexibleBox {DIV} at (0,0) size 37.50x3 + LayoutBlockFlow {DIV} at (-27,-34.50) size 91.50x72 + LayoutBlockFlow {DIV} at (0,0) size 54x72 + LayoutSlider {INPUT} at (201.53,22.50) size 37.50x3 + LayoutFlexibleBox {DIV} at (0,0) size 37.50x3 + LayoutBlockFlow {DIV} at (-27,-34.50) size 91.50x72 + LayoutBlockFlow {DIV} at (37.50,0) size 54x72 +layer at (323,217) size 48x48 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 + LayoutButton {INPUT} at (266.03,0) size 48x48 +layer at (57,310) size 240x180 + LayoutVideo {VIDEO} at (45,298) size 240x180 +layer at (57,310) size 240x180 + LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x180 + LayoutBlockFlow {DIV} at (0,132) size 240x48 +layer at (57,310) size 240x117 + LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x117 +layer at (57,442) size 240x48 scrollWidth 314 scrollHeight 60 + LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x48 [bgcolor=#FAFAFA] + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutFlexibleBox {DIV} at (48,0) size 35.03x48 [color=#5A5A5A] + LayoutBlockFlow (anonymous) at (0,0) size 35.03x48 + LayoutText {#text} at (0,13) size 36x21 + text run at (0,13) width 36: "0:00" + LayoutSlider {INPUT} at (110.03,22.50) size 37.50x3 + LayoutFlexibleBox {DIV} at (0,0) size 37.50x3 + LayoutBlockFlow {DIV} at (-27,-34.50) size 91.50x72 + LayoutBlockFlow {DIV} at (0,0) size 54x72 + LayoutSlider {INPUT} at (201.53,22.50) size 37.50x3 + LayoutFlexibleBox {DIV} at (0,0) size 37.50x3 + LayoutBlockFlow {DIV} at (-27,-34.50) size 91.50x72 + LayoutBlockFlow {DIV} at (37.50,0) size 54x72 +layer at (323,442) size 48x48 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 + LayoutButton {INPUT} at (266.03,0) size 48x48
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/media/video-zoom-controls-expected.png new file mode 100644 index 0000000..cb93942f --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-retina/media/video-zoom-controls-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/media/video-zoom-controls-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/media/video-zoom-controls-expected.txt new file mode 100644 index 0000000..8843bad --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-retina/media/video-zoom-controls-expected.txt
@@ -0,0 +1,28 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x600 + LayoutBlockFlow {HTML} at (0,0) size 800x600 + LayoutBlockFlow {BODY} at (12,12) size 776x543 + LayoutBlockFlow {P} at (0,0) size 776x28 + LayoutText {#text} at (0,0) size 278x28 + text run at (0,0) width 278: "Zoomed video with controls." +layer at (57,85) size 240x180 + LayoutVideo {VIDEO} at (45,73) size 240x180 +layer at (57,85) size 240x180 + LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x180 + LayoutBlockFlow {DIV} at (0,132) size 240x48 +layer at (57,85) size 240x117 + LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x117 +layer at (57,217) size 240x48 + LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x48 [bgcolor=#FAFAFA] + LayoutButton {INPUT} at (0,0) size 48x48 +layer at (57,310) size 240x180 + LayoutVideo {VIDEO} at (45,298) size 240x180 +layer at (57,310) size 240x180 + LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x180 + LayoutBlockFlow {DIV} at (0,132) size 240x48 +layer at (57,310) size 240x117 + LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x117 +layer at (57,442) size 240x48 + LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x48 [bgcolor=#FAFAFA] + LayoutButton {INPUT} at (0,0) size 48x48
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/css/text-overflow-ellipsis-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/css/text-overflow-ellipsis-expected.png index b95d2693..8cb10826 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/css/text-overflow-ellipsis-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/css/text-overflow-ellipsis-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/css/text-overflow-ellipsis-strict-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/css/text-overflow-ellipsis-strict-expected.png index b95d2693..8cb10826 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/css/text-overflow-ellipsis-strict-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/css/text-overflow-ellipsis-strict-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-ltr-text-in-ltr-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-ltr-text-in-ltr-flow-underline-expected.png new file mode 100644 index 0000000..4f8287a9 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-ltr-text-in-ltr-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-ltr-text-in-ltr-flow-underline-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-ltr-text-in-ltr-flow-underline-expected.txt new file mode 100644 index 0000000..93e91c7 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-ltr-text-in-ltr-flow-underline-expected.txt
@@ -0,0 +1,15 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x110 + LayoutBlockFlow {HTML} at (0,0) size 800x110 + LayoutBlockFlow {BODY} at (8,16) size 784x86 + LayoutBlockFlow {P} at (0,0) size 784x18 + LayoutText {#text} at (0,0) size 491x18 + text run at (0,0) width 491: "crbug.com/634445: Ltr text in a ltr flow should truncate the text left-to-right." + LayoutBlockFlow {P} at (0,34) size 784x18 + LayoutText {#text} at (0,0) size 469x18 + text run at (0,0) width 469: "You should see 01234567890123... below and text beneath the underline." +layer at (8,84) size 125x18 scrollWidth 240 + LayoutBlockFlow {DIV} at (0,68) size 125x18 + LayoutText {#text} at (0,0) size 240x18 + text run at (0,0) width 240: "012345678901234567890123456789"
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-ltr-text-in-rtl-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-ltr-text-in-rtl-flow-underline-expected.png new file mode 100644 index 0000000..91cebb7 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-ltr-text-in-rtl-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-ltr-text-in-rtl-flow-underline-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-ltr-text-in-rtl-flow-underline-expected.txt new file mode 100644 index 0000000..3926bd9 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-ltr-text-in-rtl-flow-underline-expected.txt
@@ -0,0 +1,15 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x110 + LayoutBlockFlow {HTML} at (0,0) size 800x110 + LayoutBlockFlow {BODY} at (8,16) size 784x86 + LayoutBlockFlow {P} at (0,0) size 784x18 + LayoutText {#text} at (0,0) size 491x18 + text run at (0,0) width 491: "crbug.com/634445: Ltr text in a rtl flow should truncate the text right-to-left." + LayoutBlockFlow {P} at (0,34) size 784x18 + LayoutText {#text} at (0,0) size 481x18 + text run at (0,0) width 481: "You should see ...32109876543210 below and an underline beneat the text." +layer at (8,84) size 125x18 scrollX 123.00 scrollWidth 248 + LayoutBlockFlow {DIV} at (0,68) size 125x18 + LayoutText {#text} at (-123,0) size 248x18 + text run at (-123,0) width 248: "0987654321098765432109876543210"
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-mixed-text-in-ltr-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-mixed-text-in-ltr-flow-underline-expected.png new file mode 100644 index 0000000..3747ac48 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-mixed-text-in-ltr-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-mixed-text-in-ltr-flow-underline-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-mixed-text-in-ltr-flow-underline-expected.txt new file mode 100644 index 0000000..5bb731d --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-mixed-text-in-ltr-flow-underline-expected.txt
@@ -0,0 +1,16 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x111 + LayoutBlockFlow {HTML} at (0,0) size 800x111 + LayoutBlockFlow {BODY} at (8,16) size 784x87 + LayoutBlockFlow {P} at (0,0) size 784x18 + LayoutText {#text} at (0,0) size 492x18 + text run at (0,0) width 492: "crbug.com/634445: Rtl text in a ltr flow should truncate the text left-to-right." + LayoutBlockFlow {P} at (0,34) size 784x18 + LayoutText {#text} at (0,0) size 412x18 + text run at (0,0) width 412: "You should see an underline beneath the text but not the ellipsis." +layer at (8,84) size 125x19 scrollWidth 270 + LayoutBlockFlow {DIV} at (0,68) size 125x19 + LayoutText {#text} at (0,1) size 271x18 + text run at (0,1) width 43: "Lorem" + text run at (42,1) width 229 RTL: "\x{5D0}\x{5D1}\x{5D2}\x{5D3}\x{5D4}\x{5D5}\x{5D6}\x{5D7}\x{5D8}\x{5D9}\x{5DB}\x{5DA}\x{5DC}\x{5DE}\x{5DD}\x{5E1}\x{5E2}\x{5E4}\x{5E3}\x{5E6}\x{5E5}\x{5E7}\x{5E8}\x{5E9}\x{5EA}"
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-mixed-text-in-rtl-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-mixed-text-in-rtl-flow-underline-expected.png new file mode 100644 index 0000000..77aa7c4 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-mixed-text-in-rtl-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-mixed-text-in-rtl-flow-underline-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-mixed-text-in-rtl-flow-underline-expected.txt new file mode 100644 index 0000000..832f7f86 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-mixed-text-in-rtl-flow-underline-expected.txt
@@ -0,0 +1,16 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x111 + LayoutBlockFlow {HTML} at (0,0) size 800x111 + LayoutBlockFlow {BODY} at (8,16) size 784x87 + LayoutBlockFlow {P} at (0,0) size 784x18 + LayoutText {#text} at (0,0) size 492x18 + text run at (0,0) width 492: "crbug.com/634445: Rtl text in a rtl flow should truncate the text right-to-left." + LayoutBlockFlow {P} at (0,34) size 784x18 + LayoutText {#text} at (0,0) size 290x18 + text run at (0,0) width 290: "You should see an underline beneath the text." +layer at (8,84) size 125x19 scrollX 145.00 scrollWidth 270 + LayoutBlockFlow {DIV} at (0,68) size 125x19 + LayoutText {#text} at (-145,1) size 271x18 + text run at (-145,1) width 228 RTL: "\x{5D0}\x{5D1}\x{5D2}\x{5D3}\x{5D4}\x{5D5}\x{5D6}\x{5D7}\x{5D8}\x{5D9}\x{5DB}\x{5DA}\x{5DC}\x{5DE}\x{5DD}\x{5E1}\x{5E2}\x{5E4}\x{5E3}\x{5E6}\x{5E5}\x{5E7}\x{5E8}\x{5E9}\x{5EA}" + text run at (82,1) width 43: "Lorem"
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-rtl-text-in-ltr-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-rtl-text-in-ltr-flow-underline-expected.png new file mode 100644 index 0000000..7176fa2 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-rtl-text-in-ltr-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-rtl-text-in-ltr-flow-underline-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-rtl-text-in-ltr-flow-underline-expected.txt new file mode 100644 index 0000000..e2d39cf --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-rtl-text-in-ltr-flow-underline-expected.txt
@@ -0,0 +1,17 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x112 + LayoutBlockFlow {HTML} at (0,0) size 800x112 + LayoutBlockFlow {BODY} at (8,16) size 784x88 + LayoutBlockFlow {P} at (0,0) size 784x18 + LayoutText {#text} at (0,0) size 492x18 + text run at (0,0) width 492: "crbug.com/634445: Rtl text in a ltr flow should truncate the text left-to-right." + LayoutBlockFlow {P} at (0,34) size 784x19 + LayoutText {#text} at (0,1) size 517x18 + text run at (0,1) width 102: "You should see " + text run at (101,1) width 136 RTL: "\x{5DA}\x{5DC}\x{5DE}\x{5DD}\x{5E1}\x{5E2}\x{5E4}\x{5E3}\x{5E6}\x{5E5}\x{5E7}\x{5E8}\x{5E9}\x{5EA}" + text run at (236,1) width 281: "... below with an underline beneath the text." +layer at (8,85) size 125x19 scrollWidth 227 + LayoutBlockFlow {DIV} at (0,69) size 125x19 + LayoutText {#text} at (0,1) size 228x18 + text run at (0,1) width 228 RTL: "\x{5D0}\x{5D1}\x{5D2}\x{5D3}\x{5D4}\x{5D5}\x{5D6}\x{5D7}\x{5D8}\x{5D9}\x{5DB}\x{5DA}\x{5DC}\x{5DE}\x{5DD}\x{5E1}\x{5E2}\x{5E4}\x{5E3}\x{5E6}\x{5E5}\x{5E7}\x{5E8}\x{5E9}\x{5EA}"
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-rtl-text-in-rtl-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-rtl-text-in-rtl-flow-underline-expected.png new file mode 100644 index 0000000..d55b3e4b --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-rtl-text-in-rtl-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-rtl-text-in-rtl-flow-underline-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-rtl-text-in-rtl-flow-underline-expected.txt new file mode 100644 index 0000000..24a0fe6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-rtl-text-in-rtl-flow-underline-expected.txt
@@ -0,0 +1,17 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x112 + LayoutBlockFlow {HTML} at (0,0) size 800x112 + LayoutBlockFlow {BODY} at (8,16) size 784x88 + LayoutBlockFlow {P} at (0,0) size 784x18 + LayoutText {#text} at (0,0) size 492x18 + text run at (0,0) width 492: "crbug.com/634445: Rtl text in a rtl flow should truncate the text right-to-left." + LayoutBlockFlow {P} at (0,34) size 784x19 + LayoutText {#text} at (0,1) size 505x18 + text run at (0,1) width 114: "You should see ..." + text run at (113,1) width 142 RTL: "\x{5D0}\x{5D1}\x{5D2}\x{5D3}\x{5D4}\x{5D5}\x{5D6}\x{5D7}\x{5D8}\x{5D9}\x{5DB}\x{5DA}\x{5DC}\x{5DE}\x{5DD}\x{5E1}" + text run at (255,1) width 250: " below with underline beneath the text." +layer at (8,85) size 125x19 scrollX 102.00 scrollWidth 227 + LayoutBlockFlow {DIV} at (0,69) size 125x19 + LayoutText {#text} at (-102,1) size 228x18 + text run at (-102,1) width 227 RTL: "\x{5D0}\x{5D1}\x{5D2}\x{5D3}\x{5D4}\x{5D5}\x{5D6}\x{5D7}\x{5D8}\x{5D9}\x{5DB}\x{5DA}\x{5DC}\x{5DE}\x{5DD}\x{5E1}\x{5E2}\x{5E4}\x{5E3}\x{5E6}\x{5E5}\x{5E7}\x{5E8}\x{5E9}\x{5EA}"
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.png index 7689791..e91b1fdc 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.txt index d3b31d7f..cbe004f 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/media/video-zoom-controls-expected.txt
@@ -13,15 +13,23 @@ LayoutBlockFlow {DIV} at (0,132) size 240x48 layer at (57,85) size 240x117 LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x117 -layer at (57,217) size 240x48 scrollHeight 60 +layer at (57,217) size 240x48 scrollWidth 314 scrollHeight 60 LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x48 [bgcolor=#FAFAFA] LayoutButton {INPUT} at (0,0) size 48x48 - LayoutSlider {INPUT} at (75,22.50) size 90x3 - LayoutFlexibleBox {DIV} at (0,0) size 90x3 - LayoutBlockFlow {DIV} at (-27,-34.50) size 144x72 + LayoutFlexibleBox {DIV} at (48,0) size 35.03x48 [color=#5A5A5A] + LayoutBlockFlow (anonymous) at (0,0) size 35.03x48 + LayoutText {#text} at (0,13) size 36x21 + text run at (0,13) width 36: "0:00" + LayoutSlider {INPUT} at (110.03,22.50) size 37.50x3 + LayoutFlexibleBox {DIV} at (0,0) size 37.50x3 + LayoutBlockFlow {DIV} at (-27,-34.50) size 91.50x72 LayoutBlockFlow {DIV} at (0,0) size 54x72 -layer at (249,217) size 48x48 - LayoutButton {INPUT} at (192,0) size 48x48 + LayoutSlider {INPUT} at (201.53,22.50) size 37.50x3 + LayoutFlexibleBox {DIV} at (0,0) size 37.50x3 + LayoutBlockFlow {DIV} at (-27,-34.50) size 91.50x72 + LayoutBlockFlow {DIV} at (37.50,0) size 54x72 +layer at (323,217) size 48x48 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 + LayoutButton {INPUT} at (266.03,0) size 48x48 layer at (57,310) size 240x180 LayoutVideo {VIDEO} at (45,298) size 240x180 layer at (57,310) size 240x180 @@ -29,12 +37,20 @@ LayoutBlockFlow {DIV} at (0,132) size 240x48 layer at (57,310) size 240x117 LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x117 -layer at (57,442) size 240x48 scrollHeight 60 +layer at (57,442) size 240x48 scrollWidth 314 scrollHeight 60 LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x48 [bgcolor=#FAFAFA] LayoutButton {INPUT} at (0,0) size 48x48 - LayoutSlider {INPUT} at (75,22.50) size 90x3 - LayoutFlexibleBox {DIV} at (0,0) size 90x3 - LayoutBlockFlow {DIV} at (-27,-34.50) size 144x72 + LayoutFlexibleBox {DIV} at (48,0) size 35.03x48 [color=#5A5A5A] + LayoutBlockFlow (anonymous) at (0,0) size 35.03x48 + LayoutText {#text} at (0,13) size 36x21 + text run at (0,13) width 36: "0:00" + LayoutSlider {INPUT} at (110.03,22.50) size 37.50x3 + LayoutFlexibleBox {DIV} at (0,0) size 37.50x3 + LayoutBlockFlow {DIV} at (-27,-34.50) size 91.50x72 LayoutBlockFlow {DIV} at (0,0) size 54x72 -layer at (249,442) size 48x48 backgroundClip at (249,442) size 43x27 clip at (249,442) size 43x27 - LayoutButton {INPUT} at (192,0) size 48x48 + LayoutSlider {INPUT} at (201.53,22.50) size 37.50x3 + LayoutFlexibleBox {DIV} at (0,0) size 37.50x3 + LayoutBlockFlow {DIV} at (-27,-34.50) size 91.50x72 + LayoutBlockFlow {DIV} at (37.50,0) size 54x72 +layer at (323,442) size 48x48 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 + LayoutButton {INPUT} at (266.03,0) size 48x48
diff --git a/third_party/WebKit/LayoutTests/platform/mac/printing/thead-repeats-at-top-of-each-page-multiple-tables-expected.png b/third_party/WebKit/LayoutTests/platform/mac/printing/thead-repeats-at-top-of-each-page-multiple-tables-expected.png new file mode 100644 index 0000000..9f95644 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/printing/thead-repeats-at-top-of-each-page-multiple-tables-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-clipped-hit-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-clipped-hit-expected.txt index b8d0d00..f34e923 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-clipped-hit-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-clipped-hit-expected.txt
@@ -22,21 +22,12 @@ "object": "LayoutSVGInlineText #text", "rect": [90, 116, 44, 18], "reason": "layoutObject insertion" - }, - { - "object": "LayoutSVGText text id='status'", - "rect": [89, 115, 3, 20], - "reason": "invalidate paint rectangle" } ] } ], "objectPaintInvalidations": [ { - "object": "LayoutSVGText text id='status'", - "reason": "invalidate paint rectangle" - }, - { "object": "LayoutSVGInlineText #text", "reason": "layoutObject removal" },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/threaded/printing/thead-repeats-at-top-of-each-page-multiple-tables-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/threaded/printing/thead-repeats-at-top-of-each-page-multiple-tables-expected.png new file mode 100644 index 0000000..9f95644 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/threaded/printing/thead-repeats-at-top-of-each-page-multiple-tables-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/css/text-overflow-ellipsis-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/css/text-overflow-ellipsis-expected.png index 3b5ecc4..56f1a2e 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/css/text-overflow-ellipsis-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/fast/css/text-overflow-ellipsis-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/css/text-overflow-ellipsis-strict-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/css/text-overflow-ellipsis-strict-expected.png index 3b5ecc4..56f1a2e 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/css/text-overflow-ellipsis-strict-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/fast/css/text-overflow-ellipsis-strict-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/scrollbar-damage-and-full-viewport-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/scrollbar-damage-and-full-viewport-repaint-expected.png index 4b2df99..af3716c 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/scrollbar-damage-and-full-viewport-repaint-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/scrollbar-damage-and-full-viewport-repaint-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-ltr-text-in-ltr-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-ltr-text-in-ltr-flow-underline-expected.png new file mode 100644 index 0000000..69249d297b --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-ltr-text-in-ltr-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-ltr-text-in-ltr-flow-underline-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-ltr-text-in-ltr-flow-underline-expected.txt new file mode 100644 index 0000000..dceb1d43 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-ltr-text-in-ltr-flow-underline-expected.txt
@@ -0,0 +1,15 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x110 + LayoutBlockFlow {HTML} at (0,0) size 800x110 + LayoutBlockFlow {BODY} at (8,16) size 784x86 + LayoutBlockFlow {P} at (0,0) size 784x18 + LayoutText {#text} at (0,0) size 492x17 + text run at (0,0) width 492: "crbug.com/634445: Ltr text in a ltr flow should truncate the text left-to-right." + LayoutBlockFlow {P} at (0,34) size 784x18 + LayoutText {#text} at (0,0) size 469x17 + text run at (0,0) width 469: "You should see 01234567890123... below and text beneath the underline." +layer at (8,84) size 125x18 scrollWidth 240 + LayoutBlockFlow {DIV} at (0,68) size 125x18 + LayoutText {#text} at (0,0) size 240x17 + text run at (0,0) width 240: "012345678901234567890123456789"
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-ltr-text-in-rtl-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-ltr-text-in-rtl-flow-underline-expected.png new file mode 100644 index 0000000..8a2ba259 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-ltr-text-in-rtl-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-ltr-text-in-rtl-flow-underline-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-ltr-text-in-rtl-flow-underline-expected.txt new file mode 100644 index 0000000..7e2cf83 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-ltr-text-in-rtl-flow-underline-expected.txt
@@ -0,0 +1,15 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x110 + LayoutBlockFlow {HTML} at (0,0) size 800x110 + LayoutBlockFlow {BODY} at (8,16) size 784x86 + LayoutBlockFlow {P} at (0,0) size 784x18 + LayoutText {#text} at (0,0) size 492x17 + text run at (0,0) width 492: "crbug.com/634445: Ltr text in a rtl flow should truncate the text right-to-left." + LayoutBlockFlow {P} at (0,34) size 784x18 + LayoutText {#text} at (0,0) size 481x17 + text run at (0,0) width 481: "You should see ...32109876543210 below and an underline beneat the text." +layer at (8,84) size 125x18 scrollX 123.00 scrollWidth 248 + LayoutBlockFlow {DIV} at (0,68) size 125x18 + LayoutText {#text} at (-123,0) size 248x17 + text run at (-123,0) width 248: "0987654321098765432109876543210"
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-mixed-text-in-ltr-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-mixed-text-in-ltr-flow-underline-expected.png new file mode 100644 index 0000000..d9a97f6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-mixed-text-in-ltr-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-mixed-text-in-ltr-flow-underline-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-mixed-text-in-ltr-flow-underline-expected.txt new file mode 100644 index 0000000..40aed719 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-mixed-text-in-ltr-flow-underline-expected.txt
@@ -0,0 +1,16 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x110 + LayoutBlockFlow {HTML} at (0,0) size 800x110 + LayoutBlockFlow {BODY} at (8,16) size 784x86 + LayoutBlockFlow {P} at (0,0) size 784x18 + LayoutText {#text} at (0,0) size 492x17 + text run at (0,0) width 492: "crbug.com/634445: Rtl text in a ltr flow should truncate the text left-to-right." + LayoutBlockFlow {P} at (0,34) size 784x18 + LayoutText {#text} at (0,0) size 412x17 + text run at (0,0) width 412: "You should see an underline beneath the text but not the ellipsis." +layer at (8,84) size 125x18 scrollWidth 220 + LayoutBlockFlow {DIV} at (0,68) size 125x18 + LayoutText {#text} at (0,0) size 220x17 + text run at (0,0) width 43: "Lorem" + text run at (42,0) width 178 RTL: "\x{5D0}\x{5D1}\x{5D2}\x{5D3}\x{5D4}\x{5D5}\x{5D6}\x{5D7}\x{5D8}\x{5D9}\x{5DB}\x{5DA}\x{5DC}\x{5DE}\x{5DD}\x{5E1}\x{5E2}\x{5E4}\x{5E3}\x{5E6}\x{5E5}\x{5E7}\x{5E8}\x{5E9}\x{5EA}"
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-mixed-text-in-rtl-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-mixed-text-in-rtl-flow-underline-expected.png new file mode 100644 index 0000000..4695dbe --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-mixed-text-in-rtl-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-mixed-text-in-rtl-flow-underline-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-mixed-text-in-rtl-flow-underline-expected.txt new file mode 100644 index 0000000..45b8e8f --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-mixed-text-in-rtl-flow-underline-expected.txt
@@ -0,0 +1,16 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x110 + LayoutBlockFlow {HTML} at (0,0) size 800x110 + LayoutBlockFlow {BODY} at (8,16) size 784x86 + LayoutBlockFlow {P} at (0,0) size 784x18 + LayoutText {#text} at (0,0) size 492x17 + text run at (0,0) width 492: "crbug.com/634445: Rtl text in a rtl flow should truncate the text right-to-left." + LayoutBlockFlow {P} at (0,34) size 784x18 + LayoutText {#text} at (0,0) size 290x17 + text run at (0,0) width 290: "You should see an underline beneath the text." +layer at (8,84) size 125x18 scrollX 94.00 scrollWidth 220 + LayoutBlockFlow {DIV} at (0,68) size 125x18 + LayoutText {#text} at (-94,0) size 220x17 + text run at (-94,0) width 177 RTL: "\x{5D0}\x{5D1}\x{5D2}\x{5D3}\x{5D4}\x{5D5}\x{5D6}\x{5D7}\x{5D8}\x{5D9}\x{5DB}\x{5DA}\x{5DC}\x{5DE}\x{5DD}\x{5E1}\x{5E2}\x{5E4}\x{5E3}\x{5E6}\x{5E5}\x{5E7}\x{5E8}\x{5E9}\x{5EA}" + text run at (82,0) width 43: "Lorem"
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-rtl-text-in-ltr-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-rtl-text-in-ltr-flow-underline-expected.png new file mode 100644 index 0000000..e62d592 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-rtl-text-in-ltr-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-rtl-text-in-ltr-flow-underline-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-rtl-text-in-ltr-flow-underline-expected.txt new file mode 100644 index 0000000..a4709784 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-rtl-text-in-ltr-flow-underline-expected.txt
@@ -0,0 +1,17 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x110 + LayoutBlockFlow {HTML} at (0,0) size 800x110 + LayoutBlockFlow {BODY} at (8,16) size 784x86 + LayoutBlockFlow {P} at (0,0) size 784x18 + LayoutText {#text} at (0,0) size 492x17 + text run at (0,0) width 492: "crbug.com/634445: Rtl text in a ltr flow should truncate the text left-to-right." + LayoutBlockFlow {P} at (0,34) size 784x18 + LayoutText {#text} at (0,0) size 489x17 + text run at (0,0) width 102: "You should see " + text run at (101,0) width 108 RTL: "\x{5DA}\x{5DC}\x{5DE}\x{5DD}\x{5E1}\x{5E2}\x{5E4}\x{5E3}\x{5E6}\x{5E5}\x{5E7}\x{5E8}\x{5E9}\x{5EA}" + text run at (208,0) width 281: "... below with an underline beneath the text." +layer at (8,84) size 125x18 scrollWidth 177 + LayoutBlockFlow {DIV} at (0,68) size 125x18 + LayoutText {#text} at (0,0) size 178x17 + text run at (0,0) width 178 RTL: "\x{5D0}\x{5D1}\x{5D2}\x{5D3}\x{5D4}\x{5D5}\x{5D6}\x{5D7}\x{5D8}\x{5D9}\x{5DB}\x{5DA}\x{5DC}\x{5DE}\x{5DD}\x{5E1}\x{5E2}\x{5E4}\x{5E3}\x{5E6}\x{5E5}\x{5E7}\x{5E8}\x{5E9}\x{5EA}"
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-rtl-text-in-rtl-flow-underline-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-rtl-text-in-rtl-flow-underline-expected.png new file mode 100644 index 0000000..2075ed7 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-rtl-text-in-rtl-flow-underline-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-rtl-text-in-rtl-flow-underline-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-rtl-text-in-rtl-flow-underline-expected.txt new file mode 100644 index 0000000..8d546c89 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-rtl-text-in-rtl-flow-underline-expected.txt
@@ -0,0 +1,17 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x110 + LayoutBlockFlow {HTML} at (0,0) size 800x110 + LayoutBlockFlow {BODY} at (8,16) size 784x86 + LayoutBlockFlow {P} at (0,0) size 784x18 + LayoutText {#text} at (0,0) size 492x17 + text run at (0,0) width 492: "crbug.com/634445: Rtl text in a rtl flow should truncate the text right-to-left." + LayoutBlockFlow {P} at (0,34) size 784x18 + LayoutText {#text} at (0,0) size 470x17 + text run at (0,0) width 114: "You should see ..." + text run at (113,0) width 108 RTL: "\x{5D0}\x{5D1}\x{5D2}\x{5D3}\x{5D4}\x{5D5}\x{5D6}\x{5D7}\x{5D8}\x{5D9}\x{5DB}\x{5DA}\x{5DC}\x{5DE}\x{5DD}\x{5E1}" + text run at (220,0) width 250: " below with underline beneath the text." +layer at (8,84) size 125x18 scrollX 52.00 scrollWidth 177 + LayoutBlockFlow {DIV} at (0,68) size 125x18 + LayoutText {#text} at (-52,0) size 178x17 + text run at (-52,0) width 177 RTL: "\x{5D0}\x{5D1}\x{5D2}\x{5D3}\x{5D4}\x{5D5}\x{5D6}\x{5D7}\x{5D8}\x{5D9}\x{5DB}\x{5DA}\x{5DC}\x{5DE}\x{5DD}\x{5E1}\x{5E2}\x{5E4}\x{5E3}\x{5E6}\x{5E5}\x{5E7}\x{5E8}\x{5E9}\x{5EA}"
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/video-zoom-controls-expected.png index 68f6d69..39fe104 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/video-zoom-controls-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/media/video-zoom-controls-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/video-zoom-controls-expected.txt b/third_party/WebKit/LayoutTests/platform/win/media/video-zoom-controls-expected.txt index 1e5d86b..6109912 100644 --- a/third_party/WebKit/LayoutTests/platform/win/media/video-zoom-controls-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/media/video-zoom-controls-expected.txt
@@ -13,15 +13,23 @@ LayoutBlockFlow {DIV} at (0,132) size 240x48 layer at (57,84) size 240x117 LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x117 -layer at (57,216) size 240x48 scrollHeight 60 +layer at (57,216) size 240x48 scrollWidth 314 scrollHeight 60 LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x48 [bgcolor=#FAFAFA] LayoutButton {INPUT} at (0,0) size 48x48 - LayoutSlider {INPUT} at (75,22.50) size 90x3 - LayoutFlexibleBox {DIV} at (0,0) size 90x3 - LayoutBlockFlow {DIV} at (-27,-34.50) size 144x72 + LayoutFlexibleBox {DIV} at (48,0) size 35.05x48 [color=#5A5A5A] + LayoutBlockFlow (anonymous) at (0,0) size 35.05x48 + LayoutText {#text} at (0,14) size 36x20 + text run at (0,14) width 36: "0:00" + LayoutSlider {INPUT} at (110.05,22.50) size 37.50x3 + LayoutFlexibleBox {DIV} at (0,0) size 37.50x3 + LayoutBlockFlow {DIV} at (-27,-34.50) size 91.50x72 LayoutBlockFlow {DIV} at (0,0) size 54x72 -layer at (249,216) size 48x48 - LayoutButton {INPUT} at (192,0) size 48x48 + LayoutSlider {INPUT} at (201.55,22.50) size 37.50x3 + LayoutFlexibleBox {DIV} at (0,0) size 37.50x3 + LayoutBlockFlow {DIV} at (-27,-34.50) size 91.50x72 + LayoutBlockFlow {DIV} at (37.50,0) size 54x72 +layer at (323,216) size 48x48 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 + LayoutButton {INPUT} at (266.05,0) size 48x48 layer at (57,309) size 240x180 LayoutVideo {VIDEO} at (45,297) size 240x180 layer at (57,309) size 240x180 @@ -29,12 +37,20 @@ LayoutBlockFlow {DIV} at (0,132) size 240x48 layer at (57,309) size 240x117 LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x117 -layer at (57,441) size 240x48 scrollHeight 60 +layer at (57,441) size 240x48 scrollWidth 314 scrollHeight 60 LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x48 [bgcolor=#FAFAFA] LayoutButton {INPUT} at (0,0) size 48x48 - LayoutSlider {INPUT} at (75,22.50) size 90x3 - LayoutFlexibleBox {DIV} at (0,0) size 90x3 - LayoutBlockFlow {DIV} at (-27,-34.50) size 144x72 + LayoutFlexibleBox {DIV} at (48,0) size 35.05x48 [color=#5A5A5A] + LayoutBlockFlow (anonymous) at (0,0) size 35.05x48 + LayoutText {#text} at (0,14) size 36x20 + text run at (0,14) width 36: "0:00" + LayoutSlider {INPUT} at (110.05,22.50) size 37.50x3 + LayoutFlexibleBox {DIV} at (0,0) size 37.50x3 + LayoutBlockFlow {DIV} at (-27,-34.50) size 91.50x72 LayoutBlockFlow {DIV} at (0,0) size 54x72 -layer at (249,441) size 48x48 backgroundClip at (249,441) size 43x27 clip at (249,441) size 43x27 - LayoutButton {INPUT} at (192,0) size 48x48 + LayoutSlider {INPUT} at (201.55,22.50) size 37.50x3 + LayoutFlexibleBox {DIV} at (0,0) size 37.50x3 + LayoutBlockFlow {DIV} at (-27,-34.50) size 91.50x72 + LayoutBlockFlow {DIV} at (37.50,0) size 54x72 +layer at (323,441) size 48x48 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 + LayoutButton {INPUT} at (266.05,0) size 48x48
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-clipped-hit-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-clipped-hit-expected.png index 4f0c809..9639058 100644 --- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-clipped-hit-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-clipped-hit-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-clipped-hit-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-clipped-hit-expected.txt index adfabeed..d3df1f16 100644 --- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-clipped-hit-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-clipped-hit-expected.txt
@@ -1,61 +1,13 @@ -{ - "name": "Content Root Layer", - "bounds": [800, 600], - "children": [ - { - "name": "LayoutView #document", - "bounds": [800, 600], - "contentsOpaque": true, - "drawsContent": true, - "paintInvalidations": [ - { - "object": "LayoutSVGInlineText #text", - "rect": [90, 116, 64, 17], - "reason": "layoutObject removal" - }, - { - "object": "LayoutSVGText text id='status'", - "rect": [90, 116, 64, 17], - "reason": "full" - }, - { - "object": "LayoutSVGInlineText #text", - "rect": [90, 116, 44, 17], - "reason": "layoutObject insertion" - }, - { - "object": "LayoutSVGText text id='status'", - "rect": [89, 115, 3, 19], - "reason": "invalidate paint rectangle" - } - ] - } - ], - "objectPaintInvalidations": [ - { - "object": "LayoutSVGText text id='status'", - "reason": "invalidate paint rectangle" - }, - { - "object": "LayoutSVGInlineText #text", - "reason": "layoutObject removal" - }, - { - "object": "LayoutSVGText text id='status'", - "reason": "full" - }, - { - "object": "RootInlineBox", - "reason": "full" - }, - { - "object": "LayoutSVGInlineText #text", - "reason": "layoutObject insertion" - }, - { - "object": "InlineTextBox 'Passed'", - "reason": "layoutObject insertion" - } - ] -} - +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x600 + LayoutSVGRoot {svg} at (29,39) size 142x94 + LayoutSVGHiddenContainer {defs} at (0,0) size 0x0 + LayoutSVGHiddenContainer {symbol} at (0,0) size 0x0 + LayoutSVGRect {rect} at (0,0) size 71x11 [stroke={[type=SOLID] [color=#696969]}] [fill={[type=SOLID] [color=#DCDCDC]}] [x=-70.00] [y=-10.00] [width=140.00] [height=20.00] + LayoutSVGContainer {use} at (29,39) size 142x22 [transform={m=((1.00,0.00)(0.00,1.00)) t=(100.00,50.00)}] + LayoutSVGViewportContainer {svg} at (29,39) size 142x22 + LayoutSVGRect {rect} at (29,39) size 142x22 [stroke={[type=SOLID] [color=#696969]}] [fill={[type=SOLID] [color=#DCDCDC]}] [x=-70.00] [y=-10.00] [width=140.00] [height=20.00] + LayoutSVGText {text} at (90,116) size 64x17 contains 1 chunk(s) + LayoutSVGInlineText {#text} at (0,0) size 64x17 + chunk 1 text run 1 at (90.00,130.00) startOffset 0 endOffset 7 width 63.11: "Unknown"
diff --git a/third_party/WebKit/LayoutTests/platform/win7/compositing/overflow/updating-scrolling-container-and-content-expected.png b/third_party/WebKit/LayoutTests/platform/win7/compositing/overflow/updating-scrolling-container-and-content-expected.png deleted file mode 100644 index 9f5ccb320..0000000 --- a/third_party/WebKit/LayoutTests/platform/win7/compositing/overflow/updating-scrolling-container-and-content-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/repaint/resize-iframe-text-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/repaint/resize-iframe-text-expected.png deleted file mode 100644 index c9226f5..0000000 --- a/third_party/WebKit/LayoutTests/platform/win7/fast/repaint/resize-iframe-text-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/repaint/scrollbar-damage-and-full-viewport-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/repaint/scrollbar-damage-and-full-viewport-repaint-expected.png deleted file mode 100644 index af3716c..0000000 --- a/third_party/WebKit/LayoutTests/platform/win7/fast/repaint/scrollbar-damage-and-full-viewport-repaint-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/win7/media/video-zoom-controls-expected.png new file mode 100644 index 0000000..1760466 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win7/media/video-zoom-controls-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/media/video-zoom-controls-expected.txt b/third_party/WebKit/LayoutTests/platform/win7/media/video-zoom-controls-expected.txt new file mode 100644 index 0000000..b1670294 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win7/media/video-zoom-controls-expected.txt
@@ -0,0 +1,56 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x600 + LayoutBlockFlow {HTML} at (0,0) size 800x600 + LayoutBlockFlow {BODY} at (12,12) size 776x543 + LayoutBlockFlow {P} at (0,0) size 776x27 + LayoutText {#text} at (0,0) size 278x26 + text run at (0,0) width 278: "Zoomed video with controls." +layer at (57,84) size 240x180 + LayoutVideo {VIDEO} at (45,72) size 240x180 +layer at (57,84) size 240x180 + LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x180 + LayoutBlockFlow {DIV} at (0,132) size 240x48 +layer at (57,84) size 240x117 + LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x117 +layer at (57,216) size 240x48 scrollWidth 306 scrollHeight 60 + LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x48 [bgcolor=#FAFAFA] + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutFlexibleBox {DIV} at (48,0) size 26.59x48 [color=#5A5A5A] + LayoutBlockFlow (anonymous) at (0,0) size 26.59x48 + LayoutText {#text} at (0,13) size 27x21 + text run at (0,13) width 27: "0:00" + LayoutSlider {INPUT} at (101.59,22.50) size 37.50x3 + LayoutFlexibleBox {DIV} at (0,0) size 37.50x3 + LayoutBlockFlow {DIV} at (-27,-34.50) size 91.50x72 + LayoutBlockFlow {DIV} at (0,0) size 54x72 + LayoutSlider {INPUT} at (193.09,22.50) size 37.50x3 + LayoutFlexibleBox {DIV} at (0,0) size 37.50x3 + LayoutBlockFlow {DIV} at (-27,-34.50) size 91.50x72 + LayoutBlockFlow {DIV} at (37.50,0) size 54x72 +layer at (315,216) size 48x48 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 + LayoutButton {INPUT} at (257.59,0) size 48x48 +layer at (57,309) size 240x180 + LayoutVideo {VIDEO} at (45,297) size 240x180 +layer at (57,309) size 240x180 + LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x180 + LayoutBlockFlow {DIV} at (0,132) size 240x48 +layer at (57,309) size 240x117 + LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x117 +layer at (57,441) size 240x48 scrollWidth 306 scrollHeight 60 + LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 240x48 [bgcolor=#FAFAFA] + LayoutButton {INPUT} at (0,0) size 48x48 + LayoutFlexibleBox {DIV} at (48,0) size 26.59x48 [color=#5A5A5A] + LayoutBlockFlow (anonymous) at (0,0) size 26.59x48 + LayoutText {#text} at (0,13) size 27x21 + text run at (0,13) width 27: "0:00" + LayoutSlider {INPUT} at (101.59,22.50) size 37.50x3 + LayoutFlexibleBox {DIV} at (0,0) size 37.50x3 + LayoutBlockFlow {DIV} at (-27,-34.50) size 91.50x72 + LayoutBlockFlow {DIV} at (0,0) size 54x72 + LayoutSlider {INPUT} at (193.09,22.50) size 37.50x3 + LayoutFlexibleBox {DIV} at (0,0) size 37.50x3 + LayoutBlockFlow {DIV} at (-27,-34.50) size 91.50x72 + LayoutBlockFlow {DIV} at (37.50,0) size 54x72 +layer at (315,441) size 48x48 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 + LayoutButton {INPUT} at (257.59,0) size 48x48
diff --git a/third_party/WebKit/LayoutTests/platform/win7/printing/thead-repeats-at-top-of-each-page-multiple-tables-expected.png b/third_party/WebKit/LayoutTests/platform/win7/printing/thead-repeats-at-top-of-each-page-multiple-tables-expected.png new file mode 100644 index 0000000..174d6c9 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win7/printing/thead-repeats-at-top-of-each-page-multiple-tables-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/custom/use-clipped-hit-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/custom/use-clipped-hit-expected.png new file mode 100644 index 0000000..4f0c809 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win7/svg/custom/use-clipped-hit-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/custom/use-clipped-hit-expected.txt b/third_party/WebKit/LayoutTests/platform/win7/svg/custom/use-clipped-hit-expected.txt new file mode 100644 index 0000000..77f2b692 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win7/svg/custom/use-clipped-hit-expected.txt
@@ -0,0 +1,52 @@ +{ + "name": "Content Root Layer", + "bounds": [800, 600], + "children": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "paintInvalidations": [ + { + "object": "LayoutSVGInlineText #text", + "rect": [90, 116, 64, 17], + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGText text id='status'", + "rect": [90, 116, 64, 17], + "reason": "full" + }, + { + "object": "LayoutSVGInlineText #text", + "rect": [90, 116, 44, 17], + "reason": "layoutObject insertion" + } + ] + } + ], + "objectPaintInvalidations": [ + { + "object": "LayoutSVGInlineText #text", + "reason": "layoutObject removal" + }, + { + "object": "LayoutSVGText text id='status'", + "reason": "full" + }, + { + "object": "RootInlineBox", + "reason": "full" + }, + { + "object": "LayoutSVGInlineText #text", + "reason": "layoutObject insertion" + }, + { + "object": "InlineTextBox 'Passed'", + "reason": "layoutObject insertion" + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/win7/virtual/threaded/printing/thead-repeats-at-top-of-each-page-multiple-tables-expected.png b/third_party/WebKit/LayoutTests/platform/win7/virtual/threaded/printing/thead-repeats-at-top-of-each-page-multiple-tables-expected.png new file mode 100644 index 0000000..174d6c9 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win7/virtual/threaded/printing/thead-repeats-at-top-of-each-page-multiple-tables-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/printing/thead-repeats-at-top-of-each-page-multiple-tables-expected.txt b/third_party/WebKit/LayoutTests/printing/thead-repeats-at-top-of-each-page-multiple-tables-expected.txt new file mode 100644 index 0000000..464809b6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/printing/thead-repeats-at-top-of-each-page-multiple-tables-expected.txt
@@ -0,0 +1,691 @@ +layer at (0,0) size 1046x799 scrollHeight 2982 + LayoutView at (0,0) size 1046x799 +layer at (0,0) size 1046x2982 backgroundClip at (0,0) size 1046x799 clip at (0,0) size 1046x799 + LayoutBlockFlow {HTML} at (0,0) size 1046x2982 + LayoutBlockFlow {BODY} at (8,8) size 1030x2966 + LayoutTable {TABLE} at (0,0) size 449x1368 + LayoutTableSection {THEAD} at (0,0) size 449x44 + LayoutTableRow {TR} at (0,2) size 449x40 + LayoutTableCell {TH} at (2,2) size 147x40 [r=0 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 145x37 + text run at (1,1) width 145: "Column 1" + LayoutTableCell {TH} at (151,2) size 147x40 [r=0 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 145x37 + text run at (1,1) width 145: "Column 2" + LayoutTableCell {TH} at (300,2) size 147x40 [r=0 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 145x37 + text run at (1,1) width 145: "Column 3" + LayoutTableSection {TBODY} at (0,44) size 449x1324 + LayoutTableRow {TR} at (0,0) size 449x39 + LayoutTableCell {TD} at (2,0) size 147x39 [r=0 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "1-1" + LayoutTableCell {TD} at (151,0) size 147x39 [r=0 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "2-1" + LayoutTableCell {TD} at (300,0) size 147x39 [r=0 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "3-1" + LayoutTableRow {TR} at (0,41) size 449x39 + LayoutTableCell {TD} at (2,41) size 147x39 [r=1 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "1-2" + LayoutTableCell {TD} at (151,41) size 147x39 [r=1 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "2-2" + LayoutTableCell {TD} at (300,41) size 147x39 [r=1 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "3-2" + LayoutTableRow {TR} at (0,82) size 449x39 + LayoutTableCell {TD} at (2,82) size 147x39 [r=2 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "1-3" + LayoutTableCell {TD} at (151,82) size 147x39 [r=2 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "2-3" + LayoutTableCell {TD} at (300,82) size 147x39 [r=2 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "3-3" + LayoutTableRow {TR} at (0,123) size 449x39 + LayoutTableCell {TD} at (2,123) size 147x39 [r=3 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "1-4" + LayoutTableCell {TD} at (151,123) size 147x39 [r=3 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "2-4" + LayoutTableCell {TD} at (300,123) size 147x39 [r=3 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "3-4" + LayoutTableRow {TR} at (0,164) size 449x39 + LayoutTableCell {TD} at (2,164) size 147x39 [r=4 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "1-5" + LayoutTableCell {TD} at (151,164) size 147x39 [r=4 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "2-5" + LayoutTableCell {TD} at (300,164) size 147x39 [r=4 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "3-5" + LayoutTableRow {TR} at (0,205) size 449x39 + LayoutTableCell {TD} at (2,205) size 147x39 [r=5 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "1-6" + LayoutTableCell {TD} at (151,205) size 147x39 [r=5 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "2-6" + LayoutTableCell {TD} at (300,205) size 147x39 [r=5 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "3-6" + LayoutTableRow {TR} at (0,246) size 449x39 + LayoutTableCell {TD} at (2,246) size 147x39 [r=6 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "1-7" + LayoutTableCell {TD} at (151,246) size 147x39 [r=6 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "2-7" + LayoutTableCell {TD} at (300,246) size 147x39 [r=6 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "3-7" + LayoutTableRow {TR} at (0,287) size 449x39 + LayoutTableCell {TD} at (2,287) size 147x39 [r=7 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "1-8" + LayoutTableCell {TD} at (151,287) size 147x39 [r=7 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "2-8" + LayoutTableCell {TD} at (300,287) size 147x39 [r=7 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "3-8" + LayoutTableRow {TR} at (0,328) size 449x39 + LayoutTableCell {TD} at (2,328) size 147x39 [r=8 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "1-9" + LayoutTableCell {TD} at (151,328) size 147x39 [r=8 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "2-9" + LayoutTableCell {TD} at (300,328) size 147x39 [r=8 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "3-9" + LayoutTableRow {TR} at (0,369) size 449x39 + LayoutTableCell {TD} at (2,369) size 147x39 [r=9 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-10" + LayoutTableCell {TD} at (151,369) size 147x39 [r=9 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-10" + LayoutTableCell {TD} at (300,369) size 147x39 [r=9 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-10" + LayoutTableRow {TR} at (0,410) size 449x39 + LayoutTableCell {TD} at (2,410) size 147x39 [r=10 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 63x36 + text run at (1,1) width 63: "1-11" + LayoutTableCell {TD} at (151,410) size 147x39 [r=10 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 63x36 + text run at (1,1) width 63: "2-11" + LayoutTableCell {TD} at (300,410) size 147x39 [r=10 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 63x36 + text run at (1,1) width 63: "3-11" + LayoutTableRow {TR} at (0,451) size 449x39 + LayoutTableCell {TD} at (2,451) size 147x39 [r=11 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-12" + LayoutTableCell {TD} at (151,451) size 147x39 [r=11 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-12" + LayoutTableCell {TD} at (300,451) size 147x39 [r=11 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-12" + LayoutTableRow {TR} at (0,492) size 449x39 + LayoutTableCell {TD} at (2,492) size 147x39 [r=12 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-13" + LayoutTableCell {TD} at (151,492) size 147x39 [r=12 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-13" + LayoutTableCell {TD} at (300,492) size 147x39 [r=12 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-13" + LayoutTableRow {TR} at (0,533) size 449x39 + LayoutTableCell {TD} at (2,533) size 147x39 [r=13 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-14" + LayoutTableCell {TD} at (151,533) size 147x39 [r=13 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-14" + LayoutTableCell {TD} at (300,533) size 147x39 [r=13 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-14" + LayoutTableRow {TR} at (0,574) size 449x39 + LayoutTableCell {TD} at (2,574) size 147x39 [r=14 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-15" + LayoutTableCell {TD} at (151,574) size 147x39 [r=14 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-15" + LayoutTableCell {TD} at (300,574) size 147x39 [r=14 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-15" + LayoutTableRow {TR} at (0,615) size 449x39 + LayoutTableCell {TD} at (2,615) size 147x39 [r=15 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-16" + LayoutTableCell {TD} at (151,615) size 147x39 [r=15 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-16" + LayoutTableCell {TD} at (300,615) size 147x39 [r=15 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-16" + LayoutTableRow {TR} at (0,656) size 449x39 + LayoutTableCell {TD} at (2,656) size 147x39 [r=16 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-17" + LayoutTableCell {TD} at (151,656) size 147x39 [r=16 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-17" + LayoutTableCell {TD} at (300,656) size 147x39 [r=16 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-17" + LayoutTableRow {TR} at (0,697) size 449x39 + LayoutTableCell {TD} at (2,697) size 147x39 [r=17 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-18" + LayoutTableCell {TD} at (151,697) size 147x39 [r=17 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-18" + LayoutTableCell {TD} at (300,697) size 147x39 [r=17 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-18" + LayoutTableRow {TR} at (0,738) size 449x39 + LayoutTableCell {TD} at (2,791) size 147x39 [r=18 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-19" + LayoutTableCell {TD} at (151,791) size 147x39 [r=18 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-19" + LayoutTableCell {TD} at (300,791) size 147x39 [r=18 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-19" + LayoutTableRow {TR} at (0,832) size 449x39 + LayoutTableCell {TD} at (2,832) size 147x39 [r=19 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-20" + LayoutTableCell {TD} at (151,832) size 147x39 [r=19 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-20" + LayoutTableCell {TD} at (300,832) size 147x39 [r=19 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-20" + LayoutTableRow {TR} at (0,873) size 449x39 + LayoutTableCell {TD} at (2,873) size 147x39 [r=20 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-21" + LayoutTableCell {TD} at (151,873) size 147x39 [r=20 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-21" + LayoutTableCell {TD} at (300,873) size 147x39 [r=20 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-21" + LayoutTableRow {TR} at (0,914) size 449x39 + LayoutTableCell {TD} at (2,914) size 147x39 [r=21 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-22" + LayoutTableCell {TD} at (151,914) size 147x39 [r=21 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-22" + LayoutTableCell {TD} at (300,914) size 147x39 [r=21 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-22" + LayoutTableRow {TR} at (0,955) size 449x39 + LayoutTableCell {TD} at (2,955) size 147x39 [r=22 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-23" + LayoutTableCell {TD} at (151,955) size 147x39 [r=22 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-23" + LayoutTableCell {TD} at (300,955) size 147x39 [r=22 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-23" + LayoutTableRow {TR} at (0,996) size 449x39 + LayoutTableCell {TD} at (2,996) size 147x39 [r=23 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-24" + LayoutTableCell {TD} at (151,996) size 147x39 [r=23 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-24" + LayoutTableCell {TD} at (300,996) size 147x39 [r=23 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-24" + LayoutTableRow {TR} at (0,1037) size 449x39 + LayoutTableCell {TD} at (2,1037) size 147x39 [r=24 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-25" + LayoutTableCell {TD} at (151,1037) size 147x39 [r=24 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-25" + LayoutTableCell {TD} at (300,1037) size 147x39 [r=24 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-25" + LayoutTableRow {TR} at (0,1078) size 449x39 + LayoutTableCell {TD} at (2,1078) size 147x39 [r=25 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-26" + LayoutTableCell {TD} at (151,1078) size 147x39 [r=25 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-26" + LayoutTableCell {TD} at (300,1078) size 147x39 [r=25 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-26" + LayoutTableRow {TR} at (0,1119) size 449x39 + LayoutTableCell {TD} at (2,1119) size 147x39 [r=26 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-27" + LayoutTableCell {TD} at (151,1119) size 147x39 [r=26 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-27" + LayoutTableCell {TD} at (300,1119) size 147x39 [r=26 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-27" + LayoutTableRow {TR} at (0,1160) size 449x39 + LayoutTableCell {TD} at (2,1160) size 147x39 [r=27 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-28" + LayoutTableCell {TD} at (151,1160) size 147x39 [r=27 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-28" + LayoutTableCell {TD} at (300,1160) size 147x39 [r=27 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-28" + LayoutTableRow {TR} at (0,1201) size 449x39 + LayoutTableCell {TD} at (2,1201) size 147x39 [r=28 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-29" + LayoutTableCell {TD} at (151,1201) size 147x39 [r=28 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-29" + LayoutTableCell {TD} at (300,1201) size 147x39 [r=28 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-29" + LayoutTableRow {TR} at (0,1242) size 449x39 + LayoutTableCell {TD} at (2,1242) size 147x39 [r=29 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-30" + LayoutTableCell {TD} at (151,1242) size 147x39 [r=29 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-30" + LayoutTableCell {TD} at (300,1242) size 147x39 [r=29 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-30" + LayoutTableRow {TR} at (0,1283) size 449x39 + LayoutTableCell {TD} at (2,1283) size 147x39 [r=30 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-31" + LayoutTableCell {TD} at (151,1283) size 147x39 [r=30 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-31" + LayoutTableCell {TD} at (300,1283) size 147x39 [r=30 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-31" + LayoutTable {TABLE} at (0,1368) size 503x1598 + LayoutTableSection {THEAD} at (0,0) size 503x44 + LayoutTableRow {TR} at (0,2) size 503x40 + LayoutTableCell {TH} at (2,2) size 165x40 [r=0 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 163x37 + text run at (1,1) width 163: "Column2 1" + LayoutTableCell {TH} at (169,2) size 165x40 [r=0 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 163x37 + text run at (1,1) width 163: "Column2 2" + LayoutTableCell {TH} at (336,2) size 165x40 [r=0 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 163x37 + text run at (1,1) width 163: "Column2 3" + LayoutTableSection {TBODY} at (0,44) size 503x1554 + LayoutTableRow {TR} at (0,0) size 503x39 + LayoutTableCell {TD} at (2,0) size 165x39 [r=0 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "1-1" + LayoutTableCell {TD} at (169,0) size 165x39 [r=0 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "2-1" + LayoutTableCell {TD} at (336,0) size 165x39 [r=0 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "3-1" + LayoutTableRow {TR} at (0,41) size 503x39 + LayoutTableCell {TD} at (2,41) size 165x39 [r=1 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "1-2" + LayoutTableCell {TD} at (169,41) size 165x39 [r=1 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "2-2" + LayoutTableCell {TD} at (336,41) size 165x39 [r=1 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "3-2" + LayoutTableRow {TR} at (0,82) size 503x39 + LayoutTableCell {TD} at (2,82) size 165x39 [r=2 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "1-3" + LayoutTableCell {TD} at (169,82) size 165x39 [r=2 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "2-3" + LayoutTableCell {TD} at (336,82) size 165x39 [r=2 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "3-3" + LayoutTableRow {TR} at (0,123) size 503x39 + LayoutTableCell {TD} at (2,123) size 165x39 [r=3 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "1-4" + LayoutTableCell {TD} at (169,123) size 165x39 [r=3 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "2-4" + LayoutTableCell {TD} at (336,123) size 165x39 [r=3 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "3-4" + LayoutTableRow {TR} at (0,164) size 503x39 + LayoutTableCell {TD} at (2,222) size 165x39 [r=4 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "1-5" + LayoutTableCell {TD} at (169,222) size 165x39 [r=4 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "2-5" + LayoutTableCell {TD} at (336,222) size 165x39 [r=4 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "3-5" + LayoutTableRow {TR} at (0,263) size 503x39 + LayoutTableCell {TD} at (2,263) size 165x39 [r=5 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "1-6" + LayoutTableCell {TD} at (169,263) size 165x39 [r=5 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "2-6" + LayoutTableCell {TD} at (336,263) size 165x39 [r=5 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "3-6" + LayoutTableRow {TR} at (0,304) size 503x39 + LayoutTableCell {TD} at (2,304) size 165x39 [r=6 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "1-7" + LayoutTableCell {TD} at (169,304) size 165x39 [r=6 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "2-7" + LayoutTableCell {TD} at (336,304) size 165x39 [r=6 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "3-7" + LayoutTableRow {TR} at (0,345) size 503x39 + LayoutTableCell {TD} at (2,345) size 165x39 [r=7 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "1-8" + LayoutTableCell {TD} at (169,345) size 165x39 [r=7 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "2-8" + LayoutTableCell {TD} at (336,345) size 165x39 [r=7 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "3-8" + LayoutTableRow {TR} at (0,386) size 503x39 + LayoutTableCell {TD} at (2,386) size 165x39 [r=8 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "1-9" + LayoutTableCell {TD} at (169,386) size 165x39 [r=8 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "2-9" + LayoutTableCell {TD} at (336,386) size 165x39 [r=8 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 47x36 + text run at (1,1) width 47: "3-9" + LayoutTableRow {TR} at (0,427) size 503x39 + LayoutTableCell {TD} at (2,427) size 165x39 [r=9 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-10" + LayoutTableCell {TD} at (169,427) size 165x39 [r=9 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-10" + LayoutTableCell {TD} at (336,427) size 165x39 [r=9 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-10" + LayoutTableRow {TR} at (0,468) size 503x39 + LayoutTableCell {TD} at (2,468) size 165x39 [r=10 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 63x36 + text run at (1,1) width 63: "1-11" + LayoutTableCell {TD} at (169,468) size 165x39 [r=10 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 63x36 + text run at (1,1) width 63: "2-11" + LayoutTableCell {TD} at (336,468) size 165x39 [r=10 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 63x36 + text run at (1,1) width 63: "3-11" + LayoutTableRow {TR} at (0,509) size 503x39 + LayoutTableCell {TD} at (2,509) size 165x39 [r=11 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-12" + LayoutTableCell {TD} at (169,509) size 165x39 [r=11 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-12" + LayoutTableCell {TD} at (336,509) size 165x39 [r=11 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-12" + LayoutTableRow {TR} at (0,550) size 503x39 + LayoutTableCell {TD} at (2,550) size 165x39 [r=12 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-13" + LayoutTableCell {TD} at (169,550) size 165x39 [r=12 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-13" + LayoutTableCell {TD} at (336,550) size 165x39 [r=12 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-13" + LayoutTableRow {TR} at (0,591) size 503x39 + LayoutTableCell {TD} at (2,591) size 165x39 [r=13 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-14" + LayoutTableCell {TD} at (169,591) size 165x39 [r=13 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-14" + LayoutTableCell {TD} at (336,591) size 165x39 [r=13 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-14" + LayoutTableRow {TR} at (0,632) size 503x39 + LayoutTableCell {TD} at (2,632) size 165x39 [r=14 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-15" + LayoutTableCell {TD} at (169,632) size 165x39 [r=14 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-15" + LayoutTableCell {TD} at (336,632) size 165x39 [r=14 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-15" + LayoutTableRow {TR} at (0,673) size 503x39 + LayoutTableCell {TD} at (2,673) size 165x39 [r=15 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-16" + LayoutTableCell {TD} at (169,673) size 165x39 [r=15 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-16" + LayoutTableCell {TD} at (336,673) size 165x39 [r=15 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-16" + LayoutTableRow {TR} at (0,714) size 503x39 + LayoutTableCell {TD} at (2,714) size 165x39 [r=16 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-17" + LayoutTableCell {TD} at (169,714) size 165x39 [r=16 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-17" + LayoutTableCell {TD} at (336,714) size 165x39 [r=16 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-17" + LayoutTableRow {TR} at (0,755) size 503x39 + LayoutTableCell {TD} at (2,755) size 165x39 [r=17 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-18" + LayoutTableCell {TD} at (169,755) size 165x39 [r=17 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-18" + LayoutTableCell {TD} at (336,755) size 165x39 [r=17 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-18" + LayoutTableRow {TR} at (0,796) size 503x39 + LayoutTableCell {TD} at (2,796) size 165x39 [r=18 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-19" + LayoutTableCell {TD} at (169,796) size 165x39 [r=18 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-19" + LayoutTableCell {TD} at (336,796) size 165x39 [r=18 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-19" + LayoutTableRow {TR} at (0,837) size 503x39 + LayoutTableCell {TD} at (2,837) size 165x39 [r=19 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-20" + LayoutTableCell {TD} at (169,837) size 165x39 [r=19 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-20" + LayoutTableCell {TD} at (336,837) size 165x39 [r=19 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-20" + LayoutTableRow {TR} at (0,878) size 503x39 + LayoutTableCell {TD} at (2,878) size 165x39 [r=20 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-21" + LayoutTableCell {TD} at (169,878) size 165x39 [r=20 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-21" + LayoutTableCell {TD} at (336,878) size 165x39 [r=20 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-21" + LayoutTableRow {TR} at (0,919) size 503x39 + LayoutTableCell {TD} at (2,919) size 165x39 [r=21 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-22" + LayoutTableCell {TD} at (169,919) size 165x39 [r=21 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-22" + LayoutTableCell {TD} at (336,919) size 165x39 [r=21 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-22" + LayoutTableRow {TR} at (0,960) size 503x39 + LayoutTableCell {TD} at (2,1021) size 165x39 [r=22 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-23" + LayoutTableCell {TD} at (169,1021) size 165x39 [r=22 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-23" + LayoutTableCell {TD} at (336,1021) size 165x39 [r=22 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-23" + LayoutTableRow {TR} at (0,1062) size 503x39 + LayoutTableCell {TD} at (2,1062) size 165x39 [r=23 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-24" + LayoutTableCell {TD} at (169,1062) size 165x39 [r=23 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-24" + LayoutTableCell {TD} at (336,1062) size 165x39 [r=23 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-24" + LayoutTableRow {TR} at (0,1103) size 503x39 + LayoutTableCell {TD} at (2,1103) size 165x39 [r=24 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-25" + LayoutTableCell {TD} at (169,1103) size 165x39 [r=24 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-25" + LayoutTableCell {TD} at (336,1103) size 165x39 [r=24 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-25" + LayoutTableRow {TR} at (0,1144) size 503x39 + LayoutTableCell {TD} at (2,1144) size 165x39 [r=25 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-26" + LayoutTableCell {TD} at (169,1144) size 165x39 [r=25 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-26" + LayoutTableCell {TD} at (336,1144) size 165x39 [r=25 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-26" + LayoutTableRow {TR} at (0,1185) size 503x39 + LayoutTableCell {TD} at (2,1185) size 165x39 [r=26 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-27" + LayoutTableCell {TD} at (169,1185) size 165x39 [r=26 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-27" + LayoutTableCell {TD} at (336,1185) size 165x39 [r=26 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-27" + LayoutTableRow {TR} at (0,1226) size 503x39 + LayoutTableCell {TD} at (2,1226) size 165x39 [r=27 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-28" + LayoutTableCell {TD} at (169,1226) size 165x39 [r=27 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-28" + LayoutTableCell {TD} at (336,1226) size 165x39 [r=27 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-28" + LayoutTableRow {TR} at (0,1267) size 503x39 + LayoutTableCell {TD} at (2,1267) size 165x39 [r=28 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-29" + LayoutTableCell {TD} at (169,1267) size 165x39 [r=28 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-29" + LayoutTableCell {TD} at (336,1267) size 165x39 [r=28 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-29" + LayoutTableRow {TR} at (0,1308) size 503x39 + LayoutTableCell {TD} at (2,1308) size 165x39 [r=29 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-30" + LayoutTableCell {TD} at (169,1308) size 165x39 [r=29 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-30" + LayoutTableCell {TD} at (336,1308) size 165x39 [r=29 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-30" + LayoutTableRow {TR} at (0,1349) size 503x39 + LayoutTableCell {TD} at (2,1349) size 165x39 [r=30 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-31" + LayoutTableCell {TD} at (169,1349) size 165x39 [r=30 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-31" + LayoutTableCell {TD} at (336,1349) size 165x39 [r=30 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-31" + LayoutTableRow {TR} at (0,1390) size 503x39 + LayoutTableCell {TD} at (2,1390) size 165x39 [r=31 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-32" + LayoutTableCell {TD} at (169,1390) size 165x39 [r=31 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-32" + LayoutTableCell {TD} at (336,1390) size 165x39 [r=31 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-32" + LayoutTableRow {TR} at (0,1431) size 503x39 + LayoutTableCell {TD} at (2,1431) size 165x39 [r=32 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-33" + LayoutTableCell {TD} at (169,1431) size 165x39 [r=32 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-33" + LayoutTableCell {TD} at (336,1431) size 165x39 [r=32 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-33" + LayoutTableRow {TR} at (0,1472) size 503x39 + LayoutTableCell {TD} at (2,1472) size 165x39 [r=33 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-34" + LayoutTableCell {TD} at (169,1472) size 165x39 [r=33 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-34" + LayoutTableCell {TD} at (336,1472) size 165x39 [r=33 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-34" + LayoutTableRow {TR} at (0,1513) size 503x39 + LayoutTableCell {TD} at (2,1513) size 165x39 [r=34 c=0 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "1-35" + LayoutTableCell {TD} at (169,1513) size 165x39 [r=34 c=1 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "2-35" + LayoutTableCell {TD} at (336,1513) size 165x39 [r=34 c=2 rs=1 cs=1] + LayoutText {#text} at (1,1) size 65x36 + text run at (1,1) width 65: "3-35"
diff --git a/third_party/WebKit/LayoutTests/printing/thead-repeats-at-top-of-each-page-multiple-tables.html b/third_party/WebKit/LayoutTests/printing/thead-repeats-at-top-of-each-page-multiple-tables.html new file mode 100644 index 0000000..e567b69 --- /dev/null +++ b/third_party/WebKit/LayoutTests/printing/thead-repeats-at-top-of-each-page-multiple-tables.html
@@ -0,0 +1,365 @@ +<!DOCTYPE html> +<title>crbug.com/631222: When printing, table header groups repeat at the top of each page that the table continues on.</title> +<style> + table {font-family: Helvetica, Arial, Verdana; font-size: 24pt + } + @media print { + thead {display: table-header-group;} + } +</style> +<script> + if (window.testRunner) + testRunner.setPrinting(); +</script> +<table> +<thead> + <tr> + <th>Column 1</th> + <th>Column 2</th> + <th>Column 3</th> + </tr> +</thead> +<tbody> + <tr> + <td>1-1</td> + <td>2-1</td> + <td>3-1</td> + </tr> + <tr> + <td>1-2</td> + <td>2-2</td> + <td>3-2</td> + </tr> + <tr> + <td>1-3</td> + <td>2-3</td> + <td>3-3</td> + </tr> + <tr> + <td>1-4</td> + <td>2-4</td> + <td>3-4</td> + </tr> + <tr> + <td>1-5</td> + <td>2-5</td> + <td>3-5</td> + </tr> + <tr> + <td>1-6</td> + <td>2-6</td> + <td>3-6</td> + </tr> + <tr> + <td>1-7</td> + <td>2-7</td> + <td>3-7</td> + </tr> + <tr> + <td>1-8</td> + <td>2-8</td> + <td>3-8</td> + </tr> + <tr> + <td>1-9</td> + <td>2-9</td> + <td>3-9</td> + </tr> + <tr> + <td>1-10</td> + <td>2-10</td> + <td>3-10</td> + </tr> + <tr> + <td>1-11</td> + <td>2-11</td> + <td>3-11</td> + </tr> + <tr> + <td>1-12</td> + <td>2-12</td> + <td>3-12</td> + </tr> + <tr> + <td>1-13</td> + <td>2-13</td> + <td>3-13</td> + </tr> + <tr> + <td>1-14</td> + <td>2-14</td> + <td>3-14</td> + </tr> + <tr> + <td>1-15</td> + <td>2-15</td> + <td>3-15</td> + </tr> + <tr> + <td>1-16</td> + <td>2-16</td> + <td>3-16</td> + </tr> + <tr> + <td>1-17</td> + <td>2-17</td> + <td>3-17</td> + </tr> + <tr> + <td>1-18</td> + <td>2-18</td> + <td>3-18</td> + </tr> + <tr> + <td>1-19</td> + <td>2-19</td> + <td>3-19</td> + </tr> + <tr> + <td>1-20</td> + <td>2-20</td> + <td>3-20</td> + </tr> + <tr> + <td>1-21</td> + <td>2-21</td> + <td>3-21</td> + </tr> + <tr> + <td>1-22</td> + <td>2-22</td> + <td>3-22</td> + </tr> + <tr> + <td>1-23</td> + <td>2-23</td> + <td>3-23</td> + </tr> + <tr> + <td>1-24</td> + <td>2-24</td> + <td>3-24</td> + </tr> + <tr> + <td>1-25</td> + <td>2-25</td> + <td>3-25</td> + </tr> + <tr> + <td>1-26</td> + <td>2-26</td> + <td>3-26</td> + </tr> + <tr> + <td>1-27</td> + <td>2-27</td> + <td>3-27</td> + </tr> + <tr> + <td>1-28</td> + <td>2-28</td> + <td>3-28</td> + </tr> + <tr> + <td>1-29</td> + <td>2-29</td> + <td>3-29</td> + </tr> + <tr> + <td>1-30</td> + <td>2-30</td> + <td>3-30</td> + </tr> + <tr> + <td>1-31</td> + <td>2-31</td> + <td>3-31</td> + </tr> +</tbody> +</table> +<table> +<thead> + <tr> + <th>Column2 1</th> + <th>Column2 2</th> + <th>Column2 3</th> + </tr> +</thead> +<tbody> + <tr> + <td>1-1</td> + <td>2-1</td> + <td>3-1</td> + </tr> + <tr> + <td>1-2</td> + <td>2-2</td> + <td>3-2</td> + </tr> + <tr> + <td>1-3</td> + <td>2-3</td> + <td>3-3</td> + </tr> + <tr> + <td>1-4</td> + <td>2-4</td> + <td>3-4</td> + </tr> + <tr> + <td>1-5</td> + <td>2-5</td> + <td>3-5</td> + </tr> + <tr> + <td>1-6</td> + <td>2-6</td> + <td>3-6</td> + </tr> + <tr> + <td>1-7</td> + <td>2-7</td> + <td>3-7</td> + </tr> + <tr> + <td>1-8</td> + <td>2-8</td> + <td>3-8</td> + </tr> + <tr> + <td>1-9</td> + <td>2-9</td> + <td>3-9</td> + </tr> + <tr> + <td>1-10</td> + <td>2-10</td> + <td>3-10</td> + </tr> + <tr> + <td>1-11</td> + <td>2-11</td> + <td>3-11</td> + </tr> + <tr> + <td>1-12</td> + <td>2-12</td> + <td>3-12</td> + </tr> + <tr> + <td>1-13</td> + <td>2-13</td> + <td>3-13</td> + </tr> + <tr> + <td>1-14</td> + <td>2-14</td> + <td>3-14</td> + </tr> + <tr> + <td>1-15</td> + <td>2-15</td> + <td>3-15</td> + </tr> + <tr> + <td>1-16</td> + <td>2-16</td> + <td>3-16</td> + </tr> + <tr> + <td>1-17</td> + <td>2-17</td> + <td>3-17</td> + </tr> + <tr> + <td>1-18</td> + <td>2-18</td> + <td>3-18</td> + </tr> + <tr> + <td>1-19</td> + <td>2-19</td> + <td>3-19</td> + </tr> + <tr> + <td>1-20</td> + <td>2-20</td> + <td>3-20</td> + </tr> + <tr> + <td>1-21</td> + <td>2-21</td> + <td>3-21</td> + </tr> + <tr> + <td>1-22</td> + <td>2-22</td> + <td>3-22</td> + </tr> + <tr> + <td>1-23</td> + <td>2-23</td> + <td>3-23</td> + </tr> + <tr> + <td>1-24</td> + <td>2-24</td> + <td>3-24</td> + </tr> + <tr> + <td>1-25</td> + <td>2-25</td> + <td>3-25</td> + </tr> + <tr> + <td>1-26</td> + <td>2-26</td> + <td>3-26</td> + </tr> + <tr> + <td>1-27</td> + <td>2-27</td> + <td>3-27</td> + </tr> + <tr> + <td>1-28</td> + <td>2-28</td> + <td>3-28</td> + </tr> + <tr> + <td>1-29</td> + <td>2-29</td> + <td>3-29</td> + </tr> + <tr> + <td>1-30</td> + <td>2-30</td> + <td>3-30</td> + </tr> + <tr> + <td>1-31</td> + <td>2-31</td> + <td>3-31</td> + </tr> + <tr> + <td>1-32</td> + <td>2-32</td> + <td>3-32</td> + </tr> + <tr> + <td>1-33</td> + <td>2-33</td> + <td>3-33</td> + </tr> + <tr> + <td>1-34</td> + <td>2-34</td> + <td>3-34</td> + </tr> + <tr> + <td>1-35</td> + <td>2-35</td> + <td>3-35</td> + </tr> +</tbody> +</table>
diff --git a/third_party/WebKit/LayoutTests/resources/bluetooth/bluetooth-helpers.js b/third_party/WebKit/LayoutTests/resources/bluetooth/bluetooth-helpers.js index 184817f..fd9719a 100644 --- a/third_party/WebKit/LayoutTests/resources/bluetooth/bluetooth-helpers.js +++ b/third_party/WebKit/LayoutTests/resources/bluetooth/bluetooth-helpers.js
@@ -198,7 +198,7 @@ } assert_add_device_event(event, description) { let match = this._addDeviceRegex.exec(event); - assert_true(!!match, event + "isn't an add-device event: " + description); + assert_true(!!match, event + " isn't an add-device event: " + description); this._idsByName.set(match[1], match[2]); } has(name) {
diff --git a/third_party/WebKit/LayoutTests/typedcssom/inlinestyle/inlineStylePropertyMap_getProperties.html b/third_party/WebKit/LayoutTests/typedcssom/inlinestyle/inlineStylePropertyMap_getProperties.html index e8a834f89..fb72266 100644 --- a/third_party/WebKit/LayoutTests/typedcssom/inlinestyle/inlineStylePropertyMap_getProperties.html +++ b/third_party/WebKit/LayoutTests/typedcssom/inlinestyle/inlineStylePropertyMap_getProperties.html
@@ -40,9 +40,26 @@ testElement.styleMap.set('border-top-width', new CSSSimpleLength(10, 'px')); var result = testElement.styleMap.getProperties(); // TODO(meade): The spec should describe an order for this. - assert_equals(2, result.length, 2); + assert_equals(result.length, 2); assert_true(result.indexOf('width') >= 0); assert_true(result.indexOf('border-top-width') >= 0); }, "getProperties returns multiple properties if they are set."); +test(function() { + testElement.style = ''; + testElement.style.setProperty('--my-custom-property', '5px'); + + assert_array_equals(testElement.styleMap.getProperties(), ['--my-custom-property']); +}, "getProperties returns expected values for custom properties"); + +test(function() { + testElement.style.cssText = "@apply --foo"; + assert_array_equals(testElement.styleMap.getProperties(), ['@apply']); +}, "getProperties returns expected values when @apply is used"); + +test(function() { + testElement.style.cssText = "@apply --foo; @apply --bar;"; + assert_array_equals(testElement.styleMap.getProperties(), ['@apply']); +}, "getProperties returns only one @apply when multiple things are applied"); + </script>
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/animations/img-element-transform.html b/third_party/WebKit/LayoutTests/virtual/threaded/animations/img-element-transform.html new file mode 100644 index 0000000..2b26f8c --- /dev/null +++ b/third_party/WebKit/LayoutTests/virtual/threaded/animations/img-element-transform.html
@@ -0,0 +1,12 @@ +<!DOCTYPE html> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<img id="target"> +<script> +promise_test(function() { + var animation = target.animate({transform: ['rotate(0deg)', 'rotate(180deg)']}, 100000); + return animation.ready.then(() => { + assert_true(internals.isCompositedAnimation(animation)); + }); +}, '<img> elements should run compositor animations'); +</script>
diff --git a/third_party/WebKit/LayoutTests/web-animations-api/animation-set-timeline-expected.txt b/third_party/WebKit/LayoutTests/web-animations-api/animation-set-timeline-expected.txt index ffb4933..c368d02 100644 --- a/third_party/WebKit/LayoutTests/web-animations-api/animation-set-timeline-expected.txt +++ b/third_party/WebKit/LayoutTests/web-animations-api/animation-set-timeline-expected.txt
@@ -1,4 +1,4 @@ This is a testharness.js-based test. -FAIL Animations are retriggered if timeline time changes promise_test: Unhandled rejection with value: object "ReferenceError: DocumentTimeline is not defined" +FAIL Animations are retriggered if timeline time changes promise_test: Unhandled rejection with value: object "TypeError: Illegal constructor" Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiolistener-automation-position-expected.txt b/third_party/WebKit/LayoutTests/webaudio/audiolistener-automation-position-expected.txt index f9f0a53..d70dc0e 100644 --- a/third_party/WebKit/LayoutTests/webaudio/audiolistener-automation-position-expected.txt +++ b/third_party/WebKit/LayoutTests/webaudio/audiolistener-automation-position-expected.txt
@@ -3,16 +3,16 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". -PASS Distance model: "linear", rolloff: 1: left channel equals [6.123234262925839e-17,0.7070180177688599,0.7068585157394409,0.706699013710022,0.706539511680603,0.7063800096511841,0.7062205672264099,0.706061065196991,0.705901563167572,0.7057421207427979,0.7055826187133789,0.70542311668396,0.7052636742591858,0.7051041722297668,0.7049446105957031,0.704785168170929,...] with an element-wise tolerance of 0. -PASS Distance model: "linear", rolloff: 1: right channel equals [3,2.7067670822143555,2.7061564922332764,2.7055459022521973,2.704935073852539,2.70432448387146,2.703713893890381,2.7031033039093018,2.7024929523468018,2.7018823623657227,2.7012717723846436,2.7006611824035645,2.7000505924224854,2.6994400024414062,2.698829174041748,2.698218584060669,...] with an element-wise tolerance of 0. +PASS Distance model: "linear", rolloff: 1: left channel equals [6.1232e-17,0.70702,0.70686,0.70670,0.70654,0.70638,0.70622,0.70606,0.70590,0.70574,0.70558,0.70542,0.70526,0.70510,0.70494,0.70479,...] with an element-wise tolerance of 0. +PASS Distance model: "linear", rolloff: 1: right channel equals [3.0000,2.7068,2.7062,2.7055,2.7049,2.7043,2.7037,2.7031,2.7025,2.7019,2.7013,2.7007,2.7001,2.6994,2.6988,2.6982,...] with an element-wise tolerance of 0. PASS Moving AudioListener with distance model: "linear", rolloff: 1: passed. -PASS Distance model: "exponential", rolloff: 1.5: left channel equals [6.123234262925839e-17,0.20877854526042938,0.07381436228752136,0.040179457515478134,0.026097318157553673,0.018673719838261604,0.01420558150857687,0.011272982694208622,0.00922679528594017,0.007732539437711239,0.006602156907320023,0.00572264613583684,0.005022431258112192,0.004454211797565222,0.003985601011663675,0.0035937593784183264,...] with an element-wise tolerance of 0. -PASS Distance model: "exponential", rolloff: 1.5: right channel equals [3,0.7992934584617615,0.28259292244911194,0.153824120759964,0.09991168230772018,0.07149098068475723,0.05438503623008728,0.04315779730677605,0.03532411530613899,0.029603464528918266,0.025275876745581627,0.02190873585641384,0.01922801323235035,0.017052624374628067,0.01525858324021101,0.013758446089923382,...] with an element-wise tolerance of 0. +PASS Distance model: "exponential", rolloff: 1.5: left channel equals [6.1232e-17,0.20878,0.073814,0.040179,0.026097,0.018674,0.014206,0.011273,0.0092268,0.0077325,0.0066022,0.0057226,0.0050224,0.0044542,0.0039856,0.0035938,...] with an element-wise tolerance of 0. +PASS Distance model: "exponential", rolloff: 1.5: right channel equals [3.0000,0.79929,0.28259,0.15382,0.099912,0.071491,0.054385,0.043158,0.035324,0.029603,0.025276,0.021909,0.019228,0.017053,0.015259,0.013758,...] with an element-wise tolerance of 0. PASS Moving AudioListener with distance model: "exponential", rolloff: 1.5: passed. -PASS Distance model: "inverse", rolloff: 1: left channel equals [6.123234262925839e-17,0.313534677028656,0.156767338514328,0.1045115664601326,0.078383669257164,0.06270693242549896,0.052255779504776,0.04479067027568817,0.039191834628582,0.03483719006180763,0.03135346621274948,0.02850315533578396,0.026127889752388,0.024118050932884216,0.022395333275198936,0.02090231329202652,...] with an element-wise tolerance of 0. -PASS Distance model: "inverse", rolloff: 1: right channel equals [3,1.2003446817398071,0.6001723408699036,0.4001149535179138,0.3000861704349518,0.2400689274072647,0.20005744695663452,0.17147782444953918,0.1500430852174759,0.13337163627147675,0.12003446370363235,0.10912225395441055,0.10002872347831726,0.09233420342206955,0.085738904774189,0.08002298325300217,...] with an element-wise tolerance of 0. +PASS Distance model: "inverse", rolloff: 1: left channel equals [6.1232e-17,0.31353,0.15677,0.10451,0.078384,0.062707,0.052256,0.044791,0.039192,0.034837,0.031353,0.028503,0.026128,0.024118,0.022395,0.020902,...] with an element-wise tolerance of 0. +PASS Distance model: "inverse", rolloff: 1: right channel equals [3.0000,1.2003,0.60017,0.40011,0.30009,0.24007,0.20006,0.17148,0.15004,0.13337,0.12003,0.10912,0.10003,0.092334,0.085739,0.080023,...] with an element-wise tolerance of 0. PASS Moving AudioListener with distance model: "inverse", rolloff: 1: passed. PASS successfullyParsed is true
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiolistener-automation-position.html b/third_party/WebKit/LayoutTests/webaudio/audiolistener-automation-position.html index 40717ac..3aa3537 100644 --- a/third_party/WebKit/LayoutTests/webaudio/audiolistener-automation-position.html +++ b/third_party/WebKit/LayoutTests/webaudio/audiolistener-automation-position.html
@@ -180,9 +180,13 @@ var prefix = 'Distance model: "' + options.distanceModel.model + '"'; prefix += ', rolloff: ' + options.distanceModel.rolloff; - success = Should(prefix + ": left channel", actualLeft) + success = Should(prefix + ": left channel", actualLeft, { + precision: 5 + }) .beCloseToArray(expectedLeft, 0) && success; - success = Should(prefix + ": right channel", actualRight) + success = Should(prefix + ": right channel", actualRight, { + precision: 5 + }) .beCloseToArray(expectedRight, 0) && success; var message = 'Moving AudioListener with distance model: "';
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-continuous-expected.txt b/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-continuous-expected.txt index 3ceba5d..a388204 100644 --- a/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-continuous-expected.txt +++ b/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-continuous-expected.txt
@@ -10,20 +10,20 @@ PASS Linear ramp preceded by SetTarget is continuous. PASS Delayed linear ramp: Initial part equals [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,...] with an element-wise tolerance of 0. -PASS Delayed linear ramp: SetTarget part equals [1,0.9979188352992993,0.99584200184511,0.9937694906233947,0.991701292638876,0.9896373989149966,0.9875778004938814,0.9855224884362979,0.9834714538216175,0.981424687747777,0.9793821813312401,0.9773439257069583,0.9753099120283326,0.9732801314671757,0.9712545752136729,0.969233234476344,...] with an element-wise tolerance of 2.19417e-7. +PASS Delayed linear ramp: SetTarget part equals [1,0.9979188352992993,0.99584200184511,0.9937694906233947,0.991701292638876,0.9896373989149966,0.9875778004938814,0.9855224884362979,0.9834714538216175,0.981424687747777,0.9793821813312401,0.9773439257069583,0.9753099120283326,0.9732801314671757,0.9712545752136729,0.969233234476344,...] with an element-wise tolerance of 3.43632e-7. PASS Delayed linear ramp equals [0.44932896411722156,0.45015029411504087,0.4509716241128601,0.4517929541106794,0.45261428410849863,0.45343561410631794,0.4542569441041372,0.45507827410195645,0.45589960409977576,0.45672093409759495,0.4575422640954142,0.4583635940932335,0.45918492409105277,0.460006254088872,0.46082758408669133,0.4616489140845106,...] with an element-wise tolerance of 0.00000107972. PASS Delayed linear ramp: Tail part equals [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,...] with an element-wise tolerance of 0. PASS Delayed linear ramp preceded by SetTarget is continuous. PASS Exponential ramp: Initial part equals [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,...] with an element-wise tolerance of 0. PASS SetTarget part was correctly replaced by the ramp -PASS Exponential ramp equals [1,1.00030517578125,1.0006103515625,1.0009156465530396,1.0012210607528687,1.0015265941619873,1.001832127571106,1.0021378993988037,1.0024436712265015,1.0027495622634888,1.003055453300476,1.0033615827560425,1.0036677122116089,1.0039739608764648,1.0042803287506104,1.0045866966247559,...] with an element-wise tolerance of 0.0000113249. +PASS Exponential ramp equals [1,1.00030517578125,1.0006103515625,1.0009156465530396,1.0012210607528687,1.0015265941619873,1.001832127571106,1.0021378993988037,1.0024436712265015,1.0027495622634888,1.003055453300476,1.0033615827560425,1.0036677122116089,1.0039739608764648,1.0042803287506104,1.0045866966247559,...] with an element-wise tolerance of 0.0000114441. PASS Exponential ramp: Tail part equals [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,...] with an element-wise tolerance of 0. PASS Exponential ramp preceded by SetTarget is continuous. PASS Delayed exponential ramp: Initial part equals [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,...] with an element-wise tolerance of 0. -PASS Delayed exponential ramp: SetTarget part equals [1,0.9979188352992993,0.99584200184511,0.9937694906233947,0.991701292638876,0.9896373989149966,0.9875778004938814,0.9855224884362979,0.9834714538216175,0.981424687747777,0.9793821813312401,0.9773439257069583,0.9753099120283326,0.9732801314671757,0.9712545752136729,0.969233234476344,...] with an element-wise tolerance of 2.19417e-7. -PASS Delayed exponential ramp equals [0.4493289589881897,0.4496844708919525,0.45004022121429443,0.4503962993621826,0.4507526457309723,0.45110926032066345,0.4514661729335785,0.451823353767395,0.4521808326244354,0.4525385797023773,0.4528966248035431,0.45325493812561035,0.4536135494709015,0.4539724290370941,0.4543316066265106,0.4546910524368286,...] with an element-wise tolerance of 0.00000417233. +PASS Delayed exponential ramp: SetTarget part equals [1,0.9979188352992993,0.99584200184511,0.9937694906233947,0.991701292638876,0.9896373989149966,0.9875778004938814,0.9855224884362979,0.9834714538216175,0.981424687747777,0.9793821813312401,0.9773439257069583,0.9753099120283326,0.9732801314671757,0.9712545752136729,0.969233234476344,...] with an element-wise tolerance of 3.43632e-7. +PASS Delayed exponential ramp equals [0.4493289589881897,0.4496844708919525,0.45004022121429443,0.4503962993621826,0.4507526457309723,0.45110926032066345,0.4514661729335785,0.451823353767395,0.4521808326244354,0.4525385797023773,0.4528966248035431,0.45325493812561035,0.4536135494709015,0.4539724290370941,0.4543316066265106,0.4546910524368286,...] with an element-wise tolerance of 0.00000429154. PASS Delayed exponential ramp: Tail part equals [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,...] with an element-wise tolerance of 0. PASS Delayed exponential ramp preceded by SetTarget is continuous.
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-continuous.html b/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-continuous.html index 37efafef..00466d0f 100644 --- a/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-continuous.html +++ b/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-continuous.html
@@ -52,7 +52,7 @@ }, referenceFunction: linearResult, automationTime: 4 * renderQuantum / sampleRate, - thresholdSetTarget: 2.19417e-7, + thresholdSetTarget: 3.43632e-7, thresholdRamp: 1.07972e-6 }).then(done); }); @@ -66,7 +66,7 @@ referenceFunction: exponentialResult, automationTime: renderQuantum / sampleRate, thresholdSetTarget: 0, - thresholdRamp: 1.13249e-5 + thresholdRamp: 1.14441e-5 }).then(done); }); @@ -78,8 +78,8 @@ }, referenceFunction: exponentialResult, automationTime: 4 * renderQuantum / sampleRate, - thresholdSetTarget: 2.19417e-7, - thresholdRamp: 4.17233e-6 + thresholdSetTarget: 3.43632e-7, + thresholdRamp: 4.29154e-6 }).then(done); });
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-update-value-attribute-expected.txt b/third_party/WebKit/LayoutTests/webaudio/audioparam-update-value-attribute-expected.txt index c925e40..cc1c3fc 100644 --- a/third_party/WebKit/LayoutTests/webaudio/audioparam-update-value-attribute-expected.txt +++ b/third_party/WebKit/LayoutTests/webaudio/audioparam-update-value-attribute-expected.txt
@@ -48,25 +48,25 @@ PASS Gain .value attribute correctly updated during automation. PASS Initialize setTargetAtTime(0, 0, 0.1) with setValueAtTime(0.25, 0). -PASS setTargetAtTime(0, 0, 0.1) at frame 127 is 0.2404960 within a relative error of 0.0000012869. -PASS setTargetAtTime(0, 0, 0.1) at frame 255 is 0.2312828 within a relative error of 0.0000012869. -PASS setTargetAtTime(0, 0, 0.1) at frame 383 is 0.2224225 within a relative error of 0.0000012869. -PASS setTargetAtTime(0, 0, 0.1) at frame 511 is 0.2139016 within a relative error of 0.0000012869. -PASS setTargetAtTime(0, 0, 0.1) at frame 639 is 0.2057072 within a relative error of 0.0000012869. -PASS setTargetAtTime(0, 0, 0.1) at frame 767 is 0.1978266 within a relative error of 0.0000012869. -PASS setTargetAtTime(0, 0, 0.1) at frame 895 is 0.1902480 within a relative error of 0.0000012869. -PASS setTargetAtTime(0, 0, 0.1) at frame 1023 is 0.1829597 within a relative error of 0.0000012869. -PASS setTargetAtTime(0, 0, 0.1) at frame 1151 is 0.1759507 within a relative error of 0.0000012869. -PASS setTargetAtTime(0, 0, 0.1) at frame 1279 is 0.1692101 within a relative error of 0.0000012869. -PASS setTargetAtTime(0, 0, 0.1) at frame 1407 is 0.1627278 within a relative error of 0.0000012869. -PASS setTargetAtTime(0, 0, 0.1) at frame 1535 is 0.1564938 within a relative error of 0.0000012869. -PASS setTargetAtTime(0, 0, 0.1) at frame 1663 is 0.1504986 within a relative error of 0.0000012869. -PASS setTargetAtTime(0, 0, 0.1) at frame 1791 is 0.1447331 within a relative error of 0.0000012869. -PASS setTargetAtTime(0, 0, 0.1) at frame 1919 is 0.1391884 within a relative error of 0.0000012869. -PASS setTargetAtTime(0, 0, 0.1) at frame 2047 is 0.1338562 within a relative error of 0.0000012869. -PASS setTargetAtTime(0, 0, 0.1) at frame 2175 is 0.1287283 within a relative error of 0.0000012869. -PASS setTargetAtTime(0, 0, 0.1) at frame 2303 is 0.1237967 within a relative error of 0.0000012869. -PASS setTargetAtTime(0, 0, 0.1) at frame 2431 is 0.1190542 within a relative error of 0.0000012869. +PASS setTargetAtTime(0, 0, 0.1) at frame 127 is 0.2404960 within a relative error of 0.0000022599. +PASS setTargetAtTime(0, 0, 0.1) at frame 255 is 0.2312828 within a relative error of 0.0000022599. +PASS setTargetAtTime(0, 0, 0.1) at frame 383 is 0.2224225 within a relative error of 0.0000022599. +PASS setTargetAtTime(0, 0, 0.1) at frame 511 is 0.2139016 within a relative error of 0.0000022599. +PASS setTargetAtTime(0, 0, 0.1) at frame 639 is 0.2057072 within a relative error of 0.0000022599. +PASS setTargetAtTime(0, 0, 0.1) at frame 767 is 0.1978266 within a relative error of 0.0000022599. +PASS setTargetAtTime(0, 0, 0.1) at frame 895 is 0.1902480 within a relative error of 0.0000022599. +PASS setTargetAtTime(0, 0, 0.1) at frame 1023 is 0.1829597 within a relative error of 0.0000022599. +PASS setTargetAtTime(0, 0, 0.1) at frame 1151 is 0.1759507 within a relative error of 0.0000022599. +PASS setTargetAtTime(0, 0, 0.1) at frame 1279 is 0.1692101 within a relative error of 0.0000022599. +PASS setTargetAtTime(0, 0, 0.1) at frame 1407 is 0.1627278 within a relative error of 0.0000022599. +PASS setTargetAtTime(0, 0, 0.1) at frame 1535 is 0.1564938 within a relative error of 0.0000022599. +PASS setTargetAtTime(0, 0, 0.1) at frame 1663 is 0.1504986 within a relative error of 0.0000022599. +PASS setTargetAtTime(0, 0, 0.1) at frame 1791 is 0.1447331 within a relative error of 0.0000022599. +PASS setTargetAtTime(0, 0, 0.1) at frame 1919 is 0.1391884 within a relative error of 0.0000022599. +PASS setTargetAtTime(0, 0, 0.1) at frame 2047 is 0.1338562 within a relative error of 0.0000022599. +PASS setTargetAtTime(0, 0, 0.1) at frame 2175 is 0.1287283 within a relative error of 0.0000022599. +PASS setTargetAtTime(0, 0, 0.1) at frame 2303 is 0.1237967 within a relative error of 0.0000022599. +PASS setTargetAtTime(0, 0, 0.1) at frame 2431 is 0.1190542 within a relative error of 0.0000022599. PASS Gain .value attribute correctly updated during automation. PASS Initialize setValueCurveAtTime([1,1.5,4], 0, 0.05859375) with setValueAtTime(0.25, 0).
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-update-value-attribute.html b/third_party/WebKit/LayoutTests/webaudio/audioparam-update-value-attribute.html index 4824971..207768f 100644 --- a/third_party/WebKit/LayoutTests/webaudio/audioparam-update-value-attribute.html +++ b/third_party/WebKit/LayoutTests/webaudio/audioparam-update-value-attribute.html
@@ -62,7 +62,7 @@ return audioParamSetTarget(testTime, v0, t0, vFinal, timeConstant); }, message: "setTargetAtTime(" + vFinal + ", " + t0 + ", " + timeConstant + ")", - errorThreshold: 1.2869e-6 + errorThreshold: 2.2599e-6 }; }).then(done); });
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-automation-expected.txt b/third_party/WebKit/LayoutTests/webaudio/biquad-automation-expected.txt index 5a7af14..99087ff0 100644 --- a/third_party/WebKit/LayoutTests/webaudio/biquad-automation-expected.txt +++ b/third_party/WebKit/LayoutTests/webaudio/biquad-automation-expected.txt
@@ -7,7 +7,7 @@ PASS Output of bandpass filter with Q automation equals [0,0.013992002233862877,0.052294112741947174,0.1082303449511528,0.17509238421916962,0.24637210369110107,0.3159724175930023,0.3783925771713257,0.4288841784000397,0.4635751247406006,0.47955939173698425,0.47495153546333313,0.4489057660102844,0.40160006284713745,0.3341873586177826,0.2487161010503769,...] with an element-wise tolerance of 0.0000011062. PASS Output of lowshelf filter with gain automation equals [0,0.47850650548934937,1.554081916809082,3.0527422428131104,4.671957969665527,6.188648223876953,7.4877095222473145,8.524102210998535,9.282732963562012,9.756352424621582,9.939204216003418,9.828425407409668,9.427144050598145,8.746537208557129,7.806419372558594,6.634762763977051,...] with an element-wise tolerance of 0.000014306. PASS Output of bandpass filter with detune automation equals [0,0.0008340422064065933,0.0014052728656679392,0.0003835858660750091,0.0001248704647878185,0.0012254818575456738,0.0011344455415382981,0.000052847364713670686,0.0004774949047714472,0.0014240697491914034,0.0006955951685085893,-0.000031629722798243165,0.0009216234902851284,0.0013469421537593007,0.0002514156512916088,0.0001623158750589937,...] with an element-wise tolerance of 0.000029535. -PASS Output of peaking filter with automation of all parameters equals [0,0.9876883625984192,-0.30901700258255005,-0.8910065293312073,0.5877852439880371,0.7071067690849304,-0.80901700258255,-0.45399048924446106,0.9510565400123596,0.15643446147441864,-1,0.15643446147441864,0.9510565400123596,-0.45399048924446106,-0.80901700258255,0.7071067690849304,...] with an element-wise tolerance of 0.00031233. +PASS Output of peaking filter with automation of all parameters equals [0,0.9876883625984192,-0.30901700258255005,-0.8910065293312073,0.5877852439880371,0.7071067690849304,-0.80901700258255,-0.45399048924446106,0.9510565400123596,0.15643446147441864,-1,0.15643446147441864,0.9510565400123596,-0.45399048924446106,-0.80901700258255,0.7071067690849304,...] with an element-wise tolerance of 0.00062907. PASS Output of bandpass filter with sinusoidal modulation of bandpass center frequency equals [0,0.0018003738950937986,0.00716581242159009,0.015862563624978065,0.027496544644236565,0.04151911661028862,0.05723972246050835,0.07384545356035233,0.09042731672525406,0.10601259768009186,0.11960244923830032,0.13021349906921387,0.13692189753055573,0.13890819251537323,0.13550083339214325,0.12621651589870453,...] with an element-wise tolerance of 0.000039787. PASS successfullyParsed is true
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-automation.html b/third_party/WebKit/LayoutTests/webaudio/biquad-automation.html index b278f6c..33d41d9 100644 --- a/third_party/WebKit/LayoutTests/webaudio/biquad-automation.html +++ b/third_party/WebKit/LayoutTests/webaudio/biquad-automation.html
@@ -290,7 +290,7 @@ f.detune.linearRampToValueAtTime(parameters.detune[1], automationEndTime); context.startRendering() - .then(createFilterVerifier(createPeakingFilter, 3.1233e-4, parameters, b.getChannelData(0), + .then(createFilterVerifier(createPeakingFilter, 6.2907e-4, parameters, b.getChannelData(0), "Output of peaking filter with automation of all parameters")) .then(done); });
diff --git a/third_party/WebKit/LayoutTests/webaudio/panner-automation-position-expected.txt b/third_party/WebKit/LayoutTests/webaudio/panner-automation-position-expected.txt index 971fbdb..06e078cc 100644 --- a/third_party/WebKit/LayoutTests/webaudio/panner-automation-position-expected.txt +++ b/third_party/WebKit/LayoutTests/webaudio/panner-automation-position-expected.txt
@@ -3,22 +3,22 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". -PASS 1-channel [0, 0, 1] -> [0, 0, 10000]: distanceModel: inverse, rolloff: 1, left channel equals [0.7071067690849304,0.013321999460458755,0.0067243436351418495,0.00449715182185173,0.0033782348036766052,0.002705172635614872,0.0022557489573955536,0.0019343806197866797,0.0016931620193645358,0.0015054333489388227,0.0013551785377785563,0.0012321951799094677,0.0011296762386336923,0.00104290631134063,0.0009685150580480695,0.0009040298755280674,...] with an element-wise tolerance of 0. -PASS 1-channel [0, 0, 1] -> [0, 0, 10000]: distanceModel: inverse, rolloff: 1, right channel equals [0.7071067690849304,0.013321999460458755,0.0067243436351418495,0.00449715182185173,0.0033782348036766052,0.002705172635614872,0.0022557489573955536,0.0019343806197866797,0.0016931620193645358,0.0015054333489388227,0.0013551785377785563,0.0012321951799094677,0.0011296762386336923,0.00104290631134063,0.0009685150580480695,0.0009040298755280674,...] with an element-wise tolerance of 0. -PASS 2-channel [0, 0, 1] -> [0, 0, 10000]: distanceModel: inverse, rolloff: 1, left channel equals [1,0.018840152770280838,0.009509658440947533,0.006359932944178581,0.0047775455750525,0.003825691994279623,0.003190110670402646,0.0027356273494660854,0.0023944927379488945,0.0021290043368935585,0.0019165119156241417,0.0017425871919840574,0.0015976035501807928,0.0014748922549188137,0.0013696871465072036,0.001278491341508925,...] with an element-wise tolerance of 0. -PASS 2-channel [0, 0, 1] -> [0, 0, 10000]: distanceModel: inverse, rolloff: 1, right channel equals [2,0.037680305540561676,0.019019316881895065,0.012719865888357162,0.009555091150105,0.007651383988559246,0.006380221340805292,0.005471254698932171,0.004788985475897789,0.004258008673787117,0.0038330238312482834,0.003485174383968115,0.0031952071003615856,0.0029497845098376274,0.002739374293014407,0.00255698268301785,...] with an element-wise tolerance of 0. -PASS 1-channel [0, 0, 1] -> [20000, 30000, 10000]: distanceModel: inverse, rolloff: 1, left channel equals [0.7071067690849304,0.001196307479403913,0.0005938085960224271,0.0003949022793676704,0.0002958123222924769,0.00023647479247301817,0.00019696500385180116,0.00016876752488315105,0.00014763248327653855,0.0001312017993768677,0.00011806215479737148,0.00010731472139013931,0.00009836074605118483,0.00009078587027033791,0.00008429430454270914,0.00007866910891607404,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 4.8124e-7}. -PASS 1-channel [0, 0, 1] -> [20000, 30000, 10000]: distanceModel: inverse, rolloff: 1, right channel equals [0.7071067690849304,0.00498276436701417,0.002494250191375613,0.0016634686617180705,0.0012478390708565712,0.0009983853669837117,0.0008320511551573873,0.0007132254540920258,0.0006240977090783417,0.000554771046154201,0.0004993066540919244,0.00045392452739179134,0.00041610468178987503,0.00038410225533880293,0.000356670847395435,0.000332896423060447,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 4.8124e-7}. -PASS 2-channel [0, 0, 1] -> [20000, 30000, 10000]: distanceModel: inverse, rolloff: 1, left channel equals [1,0.002326501300558448,0.0011553276563063264,0.0007684475276619196,0.000575670157559216,0.0004602163680829108,0.0003833358350675553,0.0003284646081738174,0.00028733513318002224,0.00025535948225297034,0.0002297879836987704,0.00020887165737804025,0.00019144543330185115,0.00017670303350314498,0.00016406884242314845,0.00015312072355300188,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 4.3267e-7}. -PASS 2-channel [0, 0, 1] -> [20000, 30000, 10000]: distanceModel: inverse, rolloff: 1, right channel equals [2,0.014814520254731178,0.007416830863803625,0.004946674220263958,0.003710799152031541,0.002969020279124379,0.002474395092576742,0.0021210394334048033,0.001855994458310306,0.0016498314216732979,0.0014848907012492418,0.00134993193205446,0.0012374616926535964,0.001142291002906859,0.0010607137810438871,0.0009900116128847003,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 4.3267e-7}. -PASS 1-channel [0, 0, 1] -> [20000, 30000, 10000]: distanceModel: exponential, rolloff: 1.5, left channel equals [0.7071067690849304,0.00008563726441934705,0.000030067832994973287,0.000016328625861206092,0.000010593314073048532,0.000007574611117888708,0.000005759487976320088,0.0000045689607759413775,0.0000037386932945082663,0.0000031326046610047342,0.0000026742441150418017,0.0000023176937702373834,0.0000020338857211754657,0.0000018036150777334115,0.0000016137381635417114,0.0000014549860907209222,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 5.0783e-7}. -PASS 1-channel [0, 0, 1] -> [20000, 30000, 10000]: distanceModel: exponential, rolloff: 1.5, right channel equals [0.7071067690849304,0.00035668950295075774,0.00012629777484107763,0.00006878197018522769,0.000044686275941785425,0.000031979649065760896,0.00002433015288261231,0.00001930880534928292,0.000015804853319423273,0.000013245842637843452,0.000011309872206766158,0.00000980348249868257,0.00000860413729242282,0.00000763084153732052,0.0000068281406129244715,0.000006156923518574331,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 5.0783e-7}. -PASS 2-channel [0, 0, 1] -> [20000, 30000, 10000]: distanceModel: exponential, rolloff: 1.5, left channel equals [1,0.00016654180944897234,0.00005850067100254819,0.00003177416874677874,0.00002061528357444331,0.000014741360246262047,0.000011209189324290492,0.000008892362529877573,0.000007276568794623017,0.000006097022378526162,0.000005204963144933572,0.000004511035513132811,0.000003958673914894462,0.000003510504939185921,0.0000031409495022671763,0.0000028319695957179647,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 5.218e-7}. -PASS 2-channel [0, 0, 1] -> [20000, 30000, 10000]: distanceModel: exponential, rolloff: 1.5, right channel equals [2,0.0010604923591017723,0.0003755554498638958,0.0002045376895694062,0.00013288715854287148,0.00009510177915217355,0.00007235421799123287,0.00005742186840507202,0.00004700180943473242,0.00003939175803679973,0.00003363448922755197,0.00002915470213338267,0.000025588007702026516,0.000022693546270602383,0.0000203064064407954,0.000018310278392164037,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 5.218e-7}. -PASS 1-channel [0, 0, 1] -> [20000, 30000, 10000]: distanceModel: linear, rolloff: 1, left channel equals [0.7071067690849304,0.22892199456691742,0.22258761525154114,0.21748939156532288,0.21270129084587097,0.2080373466014862,0.2034355252981186,0.19886919856071472,0.19432516396045685,0.1897958517074585,0.18527695536613464,0.18076558411121368,0.1762598603963852,0.17175845801830292,0.1672605574131012,0.16276535391807556,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 0.0000065324}. -PASS 1-channel [0, 0, 1] -> [20000, 30000, 10000]: distanceModel: linear, rolloff: 1, right channel equals [0.7071067690849304,0.9534875750541687,0.9349632859230042,0.9161425232887268,0.8972479104995728,0.8783238530158997,0.8593849539756775,0.840437650680542,0.8214850425720215,0.8025290369987488,0.7835704684257507,0.7646101713180542,0.7456485629081726,0.7266858816146851,0.7077224254608154,0.6887583136558533,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 0.0000065324}. -PASS 2-channel [0, 0, 1] -> [20000, 30000, 10000]: distanceModel: linear, rolloff: 1, left channel equals [1,0.4451926648616791,0.4330716133117676,0.4232165515422821,0.41393065452575684,0.40487271547317505,0.39592882990837097,0.38705015182495117,0.37821245193481445,0.369401752948761,0.3606102168560028,0.35183247923851013,0.34306514263153076,0.3343057632446289,0.3255528211593628,0.31680476665496826,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 0.0000065756}. -PASS 2-channel [0, 0, 1] -> [20000, 30000, 10000]: distanceModel: linear, rolloff: 1, right channel equals [2,2.834864377975464,2.780179977416992,2.7243428230285645,2.6682181358337402,2.611978530883789,2.5556817054748535,2.499351978302002,2.4430017471313477,2.3866379261016846,2.3302643299102783,2.2738840579986572,2.217498540878296,2.16110897064209,2.1047163009643555,2.048321008682251,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 0.0000065756}. +PASS 1-channel [0, 0, 1] -> [0, 0, 10000]: distanceModel: inverse, rolloff: 1, left channel equals [0.70711,0.013322,0.0067243,0.0044972,0.0033782,0.0027052,0.0022557,0.0019344,0.0016932,0.0015054,0.0013552,0.0012322,0.0011297,0.0010429,0.00096852,0.00090403,...] with an element-wise tolerance of 0. +PASS 1-channel [0, 0, 1] -> [0, 0, 10000]: distanceModel: inverse, rolloff: 1, right channel equals [0.70711,0.013322,0.0067243,0.0044972,0.0033782,0.0027052,0.0022557,0.0019344,0.0016932,0.0015054,0.0013552,0.0012322,0.0011297,0.0010429,0.00096852,0.00090403,...] with an element-wise tolerance of 0. +PASS 2-channel [0, 0, 1] -> [0, 0, 10000]: distanceModel: inverse, rolloff: 1, left channel equals [1.0000,0.018840,0.0095097,0.0063599,0.0047775,0.0038257,0.0031901,0.0027356,0.0023945,0.0021290,0.0019165,0.0017426,0.0015976,0.0014749,0.0013697,0.0012785,...] with an element-wise tolerance of 0. +PASS 2-channel [0, 0, 1] -> [0, 0, 10000]: distanceModel: inverse, rolloff: 1, right channel equals [2.0000,0.037680,0.019019,0.012720,0.0095551,0.0076514,0.0063802,0.0054713,0.0047890,0.0042580,0.0038330,0.0034852,0.0031952,0.0029498,0.0027394,0.0025570,...] with an element-wise tolerance of 0. +PASS 1-channel [0, 0, 1] -> [20000, 30000, 10000]: distanceModel: inverse, rolloff: 1, left channel equals [0.70711,0.0011963,0.00059381,0.00039490,0.00029581,0.00023647,0.00019697,0.00016877,0.00014763,0.00013120,0.00011806,0.00010731,0.000098361,0.000090786,0.000084294,0.000078669,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 4.8124e-7}. +PASS 1-channel [0, 0, 1] -> [20000, 30000, 10000]: distanceModel: inverse, rolloff: 1, right channel equals [0.70711,0.0049828,0.0024943,0.0016635,0.0012478,0.00099839,0.00083205,0.00071323,0.00062410,0.00055477,0.00049931,0.00045392,0.00041610,0.00038410,0.00035667,0.00033290,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 4.8124e-7}. +PASS 2-channel [0, 0, 1] -> [20000, 30000, 10000]: distanceModel: inverse, rolloff: 1, left channel equals [1.0000,0.0023265,0.0011553,0.00076845,0.00057567,0.00046022,0.00038334,0.00032846,0.00028734,0.00025536,0.00022979,0.00020887,0.00019145,0.00017670,0.00016407,0.00015312,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 4.3267e-7}. +PASS 2-channel [0, 0, 1] -> [20000, 30000, 10000]: distanceModel: inverse, rolloff: 1, right channel equals [2.0000,0.014815,0.0074168,0.0049467,0.0037108,0.0029690,0.0024744,0.0021210,0.0018560,0.0016498,0.0014849,0.0013499,0.0012375,0.0011423,0.0010607,0.00099001,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 4.3267e-7}. +PASS 1-channel [0, 0, 1] -> [20000, 30000, 10000]: distanceModel: exponential, rolloff: 1.5, left channel equals [0.70711,0.000085637,0.000030068,0.000016329,0.000010593,0.0000075746,0.0000057595,0.0000045690,0.0000037387,0.0000031326,0.0000026742,0.0000023177,0.0000020339,0.0000018036,0.0000016137,0.0000014550,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 5.0783e-7}. +PASS 1-channel [0, 0, 1] -> [20000, 30000, 10000]: distanceModel: exponential, rolloff: 1.5, right channel equals [0.70711,0.00035669,0.00012630,0.000068782,0.000044686,0.000031980,0.000024330,0.000019309,0.000015805,0.000013246,0.000011310,0.0000098035,0.0000086041,0.0000076308,0.0000068281,0.0000061569,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 5.0783e-7}. +PASS 2-channel [0, 0, 1] -> [20000, 30000, 10000]: distanceModel: exponential, rolloff: 1.5, left channel equals [1.0000,0.00016654,0.000058501,0.000031774,0.000020615,0.000014741,0.000011209,0.0000088924,0.0000072766,0.0000060970,0.0000052050,0.0000045110,0.0000039587,0.0000035105,0.0000031409,0.0000028320,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 5.218e-7}. +PASS 2-channel [0, 0, 1] -> [20000, 30000, 10000]: distanceModel: exponential, rolloff: 1.5, right channel equals [2.0000,0.0010605,0.00037556,0.00020454,0.00013289,0.000095102,0.000072354,0.000057422,0.000047002,0.000039392,0.000033634,0.000029155,0.000025588,0.000022694,0.000020306,0.000018310,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 5.218e-7}. +PASS 1-channel [0, 0, 1] -> [20000, 30000, 10000]: distanceModel: linear, rolloff: 1, left channel equals [0.70711,0.22892,0.22259,0.21749,0.21270,0.20804,0.20344,0.19887,0.19433,0.18980,0.18528,0.18077,0.17626,0.17176,0.16726,0.16277,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 0.0000065324}. +PASS 1-channel [0, 0, 1] -> [20000, 30000, 10000]: distanceModel: linear, rolloff: 1, right channel equals [0.70711,0.95349,0.93496,0.91614,0.89725,0.87832,0.85938,0.84044,0.82149,0.80253,0.78357,0.76461,0.74565,0.72669,0.70772,0.68876,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 0.0000065324}. +PASS 2-channel [0, 0, 1] -> [20000, 30000, 10000]: distanceModel: linear, rolloff: 1, left channel equals [1.0000,0.44519,0.43307,0.42322,0.41393,0.40487,0.39593,0.38705,0.37821,0.36940,0.36061,0.35183,0.34307,0.33431,0.32555,0.31680,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 0.0000065756}. +PASS 2-channel [0, 0, 1] -> [20000, 30000, 10000]: distanceModel: linear, rolloff: 1, right channel equals [2.0000,2.8349,2.7802,2.7243,2.6682,2.6120,2.5557,2.4994,2.4430,2.3866,2.3303,2.2739,2.2175,2.1611,2.1047,2.0483,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 0.0000065756}. PASS successfullyParsed is true TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/webaudio/panner-automation-position.html b/third_party/WebKit/LayoutTests/webaudio/panner-automation-position.html index 56fad32..9a49373 100644 --- a/third_party/WebKit/LayoutTests/webaudio/panner-automation-position.html +++ b/third_party/WebKit/LayoutTests/webaudio/panner-automation-position.html
@@ -251,9 +251,13 @@ if (options.errorThreshold) errorThreshold = options.errorThreshold[channelCount - 1] - Should(prefix + "distanceModel: " + info + ", left channel", data0) + Should(prefix + "distanceModel: " + info + ", left channel", data0, { + precision: 5 + }) .beCloseToArray(expected0, errorThreshold); - Should(prefix + "distanceModel: " + info + ", right channel", data1) + Should(prefix + "distanceModel: " + info + ", right channel", data1, { + precision: 5 + }) .beCloseToArray(expected1, errorThreshold); }); }
diff --git a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data-expected.txt b/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data-expected.txt index 927d5e7e..9c929923 100644 --- a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data-expected.txt +++ b/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data-expected.txt
@@ -23,19 +23,19 @@ PASS Min FFT value is less than or equal to -100. PASS Max FFT value is greater than or equal to -30. PASS 512-point byte FFT equals [0,16,36,50,65,231,255,255,255,208,59,75,219,255,255,247,...] with an element-wise tolerance of 0. -PASS 1024-point float FFT equals [-100,-100,-100,-100,-99.4,-96.6,-93.6,-90.2,-86.4,-82.5,-79.7,-70.4,-33.9,-21.4,-19.2,-26.1,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 0.000012765}. +PASS 1024-point float FFT equals [-100,-100,-100,-100,-99.4,-96.6,-93.6,-90.2,-86.4,-82.5,-79.7,-70.4,-33.9,-21.4,-19.2,-26.1,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 0.000020483}. PASS Min FFT value is less than or equal to -100. PASS Max FFT value is greater than or equal to -30. PASS 1024-point byte FFT equals [0,0,0,0,2,12,23,35,49,63,74,107,240,255,255,255,...] with an element-wise tolerance of 0. -PASS 2048-point float FFT equals [-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 0.000008492}. +PASS 2048-point float FFT equals [-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 0.000013456}. PASS Min FFT value is less than or equal to -100. PASS Max FFT value is greater than or equal to -30. PASS 2048-point byte FFT equals [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,...] with an element-wise tolerance of 0. -PASS 4096-point float FFT equals [-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 4.3344e-7}. +PASS 4096-point float FFT equals [-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 4.6116e-7}. PASS Min FFT value is less than or equal to -100. PASS Max FFT value is greater than or equal to -30. PASS 4096-point byte FFT equals [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,...] with an element-wise tolerance of 0. -PASS 8192-point float FFT equals [-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 3.1314e-7}. +PASS 8192-point float FFT equals [-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 3.2106e-7}. PASS Min FFT value is less than or equal to -100. PASS Max FFT value is greater than or equal to -30. PASS 8192-point byte FFT equals [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,...] with an element-wise tolerance of 0.
diff --git a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data-smoothing-expected.txt b/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data-smoothing-expected.txt index 71a836a..48f4054 100644 --- a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data-smoothing-expected.txt +++ b/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data-smoothing-expected.txt
@@ -3,9 +3,9 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". -PASS First 512-point FFT at frame 512 equals [-100,-100,-96.1,-92.2,-88.1,-42.5,-28.3,-25.0,-30.7,-48.7,-89.7,-85.4,-45.9,-33.4,-31.2,-38.1,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 0.0000057607}. +PASS First 512-point FFT at frame 512 equals [-100,-100,-96.1,-92.2,-88.1,-42.5,-28.3,-25.0,-30.7,-48.7,-89.7,-85.4,-45.9,-33.4,-31.2,-38.1,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 0.0000059207}. PASS 512-point byte FFT equals [0,0,14,28,43,209,255,255,252,186,37,53,197,242,250,225,...] with an element-wise tolerance of 0. -PASS Smoothed 512-point FFT at frame 1536 equals [-94.6,-93.1,-90.1,-87.2,-85.6,-38.9,-24.8,-21.5,-27.2,-45.1,-87.5,-78.7,-42.4,-29.9,-27.7,-34.6,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 0.000015979}. +PASS Smoothed 512-point FFT at frame 1536 equals [-94.6,-93.1,-90.1,-87.2,-85.6,-38.9,-24.8,-21.5,-27.2,-45.1,-87.5,-78.7,-42.4,-29.9,-27.7,-34.6,...] with an element-wise tolerance of {absoluteThreshold: 0, relativeThreshold: 0.000025332}. PASS 512-point byte FFT equals [19,25,36,46,52,222,255,255,255,199,45,77,209,255,255,238,...] with an element-wise tolerance of 0. PASS FFT smoothing performed correctly with smoothing constant 0.5.
diff --git a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data-smoothing.html b/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data-smoothing.html index 10bbed3..bb1d72e 100644 --- a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data-smoothing.html +++ b/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data-smoothing.html
@@ -33,7 +33,7 @@ var options = { order: 9, smoothing: 0.5, - floatRelError: 5.7607e-6 + floatRelError: 5.9207e-6 }; var success = true; @@ -97,7 +97,7 @@ freqDataInDb, smoothedFloatResult.map(linearToDb), { order: options.order, smoothing: options.smoothing, - floatRelError: 1.5979e-5 + floatRelError: 2.5332e-5 }); success = success && comparison.success;
diff --git a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data.html b/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data.html index 030c8d2..119c5ee 100644 --- a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data.html +++ b/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data.html
@@ -48,16 +48,16 @@ floatRelError: 2.3906e-5 }, { order: 10, - floatRelError: 1.2765e-5 + floatRelError: 2.0483e-5 }, { order: 11, - floatRelError: 8.4920e-6, + floatRelError: 1.3456e-5 }, { order: 12, - floatRelError: 4.3344e-7 + floatRelError: 4.6116e-7 }, { order: 13, - floatRelError: 3.1314e-7 + floatRelError: 3.2106e-7 }, { order: 14, floatRelError: 1.1756e-7
diff --git a/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt index 9120a1a..6e09287 100644 --- a/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt
@@ -79,6 +79,7 @@ property hasAttributeNS property hasAttributes property hasChildNodes + property hasPointerCapture property hidden property id property innerHTML @@ -1187,6 +1188,7 @@ property hasAttributeNS property hasAttributes property hasChildNodes + property hasPointerCapture property hidden property id property innerHTML
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt index e777201..da55afb 100644 --- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -526,6 +526,10 @@ getter x getter y method constructor +interface CSSResourceValue : CSSStyleValue + attribute @@toStringTag + getter state + method constructor interface CSSRotation : CSSTransformComponent attribute @@toStringTag getter angle @@ -1500,6 +1504,9 @@ method prepend method querySelector method querySelectorAll +interface DocumentTimeline : AnimationTimeline + attribute @@toStringTag + method constructor interface DocumentType : Node attribute @@toStringTag attribute @@unscopables @@ -1591,6 +1598,7 @@ method hasAttribute method hasAttributeNS method hasAttributes + method hasPointerCapture method insertAdjacentElement method insertAdjacentHTML method insertAdjacentText
diff --git a/third_party/WebKit/PRESUBMIT.py b/third_party/WebKit/PRESUBMIT.py index cee4638e..c252d5e 100644 --- a/third_party/WebKit/PRESUBMIT.py +++ b/third_party/WebKit/PRESUBMIT.py
@@ -8,6 +8,7 @@ for more details about the presubmit API built into gcl. """ +import os import re import sys @@ -320,3 +321,55 @@ results.extend(input_api.canned_checks.CheckChangeHasDescription( input_api, output_api)) return results + + +def _ArePaintOrCompositingDirectoriesModified(change): # pylint: disable=C0103 + """Checks whether CL has changes to paint or compositing directories.""" + paint_or_compositing_paths = [ + os.path.join('third_party', 'WebKit', 'Source', 'platform', 'graphics', + 'compositing'), + os.path.join('third_party', 'WebKit', 'Source', 'platform', 'graphics', + 'paint'), + os.path.join('third_party', 'WebKit', 'Source', 'core', 'layout', + 'compositing'), + os.path.join('third_party', 'WebKit', 'Source', 'core', 'paint'), + ] + for affected_file in change.AffectedFiles(): + file_path = affected_file.LocalPath() + if any(x in file_path for x in paint_or_compositing_paths): + return True + return False + + +def PostUploadHook(cl, change, output_api): # pylint: disable=C0103 + """git cl upload will call this hook after the issue is created/modified. + + This hook adds extra try bots to the CL description in order to run slimming + paint v2 tests in addition to the CQ try bots if the change contains paint + or compositing changes (see: _ArePaintOrCompositingDirectoriesModified). For + more information about slimming-paint-v2 tests see https://crbug.com/601275. + """ + if not _ArePaintOrCompositingDirectoriesModified(change): + return [] + + rietveld_obj = cl.RpcServer() + issue = cl.issue + description = rietveld_obj.get_description(issue) + if re.search(r'^CQ_INCLUDE_TRYBOTS=.*', description, re.M | re.I): + return [] + + bots = [ + 'master.tryserver.chromium.linux:linux_layout_tests_slimming_paint_v2', + ] + + results = [] + new_description = description + new_description += '\nCQ_INCLUDE_TRYBOTS=%s' % ';'.join(bots) + results.append(output_api.PresubmitNotifyResult( + 'Automatically added slimming-paint-v2 tests to run on CQ due to ' + 'changes in paint or compositing directories.')) + + if new_description != description: + rietveld_obj.update_description(issue, new_description) + + return results
diff --git a/third_party/WebKit/PerformanceTests/DOM/inner_html_with_selection.html b/third_party/WebKit/PerformanceTests/DOM/inner_html_with_selection.html new file mode 100644 index 0000000..b8cf22c --- /dev/null +++ b/third_party/WebKit/PerformanceTests/DOM/inner_html_with_selection.html
@@ -0,0 +1,19 @@ +<!doctype html> +<script src="../resources/runner.js"></script> +<div id="target">target</div> +<div id="sample" style="display: none"></div> +<script> +var selection = window.getSelection(); +selection.selectAllChildren(document.getElementById('target')); +var sample = document.getElementById('sample'); +var sampleHTML = new Array(1000).join('<br>'); + +PerfTestRunner.measureTime({ + description: 'Measures performance of innerHTML setter with selection.', + + run: function() { + sample.innerHTML = sampleHTML; + sample.innerHTML = ''; + }, +}); +</script>
diff --git a/third_party/WebKit/Source/bindings/core/v8/ExceptionState.cpp b/third_party/WebKit/Source/bindings/core/v8/ExceptionState.cpp index 191f03d..a3106379 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ExceptionState.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/ExceptionState.cpp
@@ -68,7 +68,7 @@ m_code = ec; String processedMessage = addExceptionContext(message); m_message = processedMessage; - setException(V8ThrowException::createDOMException(m_isolate, ec, processedMessage, m_creationContext)); + setException(V8ThrowException::createDOMException(m_isolate, ec, processedMessage)); } void ExceptionState::throwSecurityError(const String& sanitizedMessage, const String& unsanitizedMessage) @@ -80,7 +80,7 @@ m_message = finalSanitized; String finalUnsanitized = addExceptionContext(unsanitizedMessage); - setException(V8ThrowException::createDOMException(m_isolate, SecurityError, finalSanitized, finalUnsanitized, m_creationContext)); + setException(V8ThrowException::createDOMException(m_isolate, SecurityError, finalSanitized, finalUnsanitized)); } void ExceptionState::setException(v8::Local<v8::Value> exception) @@ -97,7 +97,7 @@ void ExceptionState::throwException() { ASSERT(!m_exception.isEmpty()); - V8ThrowException::throwException(m_exception.newLocal(m_isolate), m_isolate); + V8ThrowException::throwException(m_isolate, m_exception.newLocal(m_isolate)); } void ExceptionState::throwTypeError(const String& message)
diff --git a/third_party/WebKit/Source/bindings/core/v8/GeneratedCodeHelper.cpp b/third_party/WebKit/Source/bindings/core/v8/GeneratedCodeHelper.cpp index 57ecd06..e449086 100644 --- a/third_party/WebKit/Source/bindings/core/v8/GeneratedCodeHelper.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/GeneratedCodeHelper.cpp
@@ -4,6 +4,7 @@ #include "bindings/core/v8/GeneratedCodeHelper.h" +#include "bindings/core/v8/SerializedScriptValue.h" #include "bindings/core/v8/V8Binding.h" namespace blink { @@ -18,4 +19,11 @@ v8SetReturnValue(info, perContextData->constructorForType(WrapperTypeInfo::unwrap(data))); } +v8::Local<v8::Value> v8Deserialize(v8::Isolate* isolate, PassRefPtr<SerializedScriptValue> value) +{ + if (value) + return value->deserialize(); + return v8::Null(isolate); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/bindings/core/v8/GeneratedCodeHelper.h b/third_party/WebKit/Source/bindings/core/v8/GeneratedCodeHelper.h index 1f09d19..2bb7093 100644 --- a/third_party/WebKit/Source/bindings/core/v8/GeneratedCodeHelper.h +++ b/third_party/WebKit/Source/bindings/core/v8/GeneratedCodeHelper.h
@@ -12,12 +12,17 @@ #define GeneratedCodeHelper_h #include "core/CoreExport.h" +#include "wtf/PassRefPtr.h" #include <v8.h> namespace blink { +class SerializedScriptValue; + CORE_EXPORT void v8ConstructorAttributeGetter(v8::Local<v8::Name> propertyName, const v8::PropertyCallbackInfo<v8::Value>&); +CORE_EXPORT v8::Local<v8::Value> v8Deserialize(v8::Isolate*, PassRefPtr<SerializedScriptValue>); + } // namespace blink #endif // GeneratedCodeHelper_h
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.cpp index f315c193..6c7b1e3 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.cpp
@@ -242,8 +242,7 @@ v8::Local<v8::Value> exception = V8ThrowException::createDOMException( m_scriptState->isolate(), InvalidStateError, - message, - constructor()); + message); fireErrorEvent(m_scriptState.get(), message, exception, std::move(location)); return false; }
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.cpp index be6b8d8..f7eb12a 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.cpp
@@ -12,11 +12,6 @@ } ScriptSourceCode::ScriptSourceCode(const String& source, const KURL& url, const TextPosition& startPosition) - : ScriptSourceCode(CompressibleString(source.impl()), url, startPosition) -{ -} - -ScriptSourceCode::ScriptSourceCode(const CompressibleString& source, const KURL& url, const TextPosition& startPosition) : m_source(source) , m_url(url) , m_startPosition(startPosition) @@ -86,7 +81,7 @@ // the empty script. Consequently, we need to disambiguate between such null string occurrences. // Do that by converting the latter case's null strings into empty ones. if (m_source.isNull()) - m_source = CompressibleString(); + m_source = ""; } } // namespace blink
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.h b/third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.h index 0347d2eb..8cc69e0 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.h +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.h
@@ -49,7 +49,6 @@ // Not sure if that matters. explicit ScriptSourceCode(ScriptResource*); ScriptSourceCode(const String&, const KURL& = KURL(), const TextPosition& startPosition = TextPosition::minimumPosition()); - ScriptSourceCode(const CompressibleString&, const KURL& = KURL(), const TextPosition& startPosition = TextPosition::minimumPosition()); ScriptSourceCode(ScriptStreamer*, ScriptResource*); ~ScriptSourceCode(); @@ -61,7 +60,7 @@ // constructor, and differs from the empty script. bool isNull() const { return m_source.isNull(); } - const CompressibleString& source() const { return m_source; } + const String& source() const { return m_source; } ScriptResource* resource() const { return m_resource.get(); } const KURL& url() const; int startLine() const { return m_startPosition.m_line.oneBasedInt(); } @@ -73,7 +72,7 @@ private: void treatNullSourceAsEmpty(); - CompressibleString m_source; + String m_source; Member<ScriptResource> m_resource; Member<ScriptStreamer> m_streamer; mutable KURL m_url;
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializer.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializer.cpp index 27d2d1ce..cbfc21c 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializer.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializer.cpp
@@ -23,6 +23,7 @@ #include "core/fileapi/Blob.h" #include "core/fileapi/File.h" #include "core/fileapi/FileList.h" +#include "platform/Histogram.h" #include "platform/RuntimeEnabledFeatures.h" #include "public/platform/Platform.h" #include "public/platform/WebBlobInfo.h" @@ -719,8 +720,23 @@ } } +static void recordValueCounts(int primitiveCount, int jsObjectCount, int domWrapperCount) +{ + struct ObjectCountHistograms { + CustomCountHistogram primitiveCount{"Blink.ScriptValueSerializer.PrimitiveCount", 0, 100000, 50}; + CustomCountHistogram jsObjectCount{"Blink.ScriptValueSerializer.JSObjectCount", 0, 100000, 50}; + CustomCountHistogram domWrapperCount{"Blink.ScriptValueSerializer.DOMWrapperCount", 0, 100000, 50}; + }; + DEFINE_THREAD_SAFE_STATIC_LOCAL(ObjectCountHistograms, histograms, new ObjectCountHistograms); + histograms.primitiveCount.count(primitiveCount); + histograms.jsObjectCount.count(jsObjectCount); + histograms.domWrapperCount.count(domWrapperCount); +} + PassRefPtr<SerializedScriptValue> ScriptValueSerializer::serialize(v8::Local<v8::Value> value, Transferables* transferables, ExceptionState& exceptionState) { + m_primitiveCount = m_jsObjectCount = m_domWrapperCount = 0; + DCHECK(!m_blobDataHandles); RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::create(); @@ -737,6 +753,7 @@ switch (m_status) { case Status::Success: + recordValueCounts(m_primitiveCount, m_jsObjectCount, m_domWrapperCount); transferData(transferables, exceptionState, serializedValue.get()); break; case Status::InputError: @@ -801,9 +818,15 @@ m_writer.writeObjectReference(objectReference); return nullptr; } - if (value->IsObject()) + if (value->IsObject()) { + if (V8DOMWrapper::isWrapper(isolate(), value)) + m_domWrapperCount++; + else + m_jsObjectCount++; return doSerializeObject(value.As<v8::Object>(), next); + } + m_primitiveCount++; if (value->IsUndefined()) { m_writer.writeUndefined(); } else if (value->IsNull()) {
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializer.h b/third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializer.h index 80c0bcb..8b1d6703 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializer.h +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializer.h
@@ -447,6 +447,11 @@ uint32_t m_nextObjectReference; WebBlobInfoArray* m_blobInfo; BlobDataHandleMap* m_blobDataHandles; + + // Counts of object types encountered while serializing the object graph. + int m_primitiveCount = 0; + int m_jsObjectCount = 0; + int m_domWrapperCount = 0; }; class ScriptValueDeserializer;
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializerTest.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializerTest.cpp new file mode 100644 index 0000000..932dae4 --- /dev/null +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptValueSerializerTest.cpp
@@ -0,0 +1,46 @@ +// 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 "bindings/core/v8/ScriptValueSerializer.h" + +#include "bindings/core/v8/ScriptController.h" +#include "core/layout/LayoutTestHelper.h" +#include "platform/testing/HistogramTester.h" + +namespace blink { + +class ScriptValueSerializerTest : public RenderingTest { +public: + FrameSettingOverrideFunction settingOverrider() const override + { + return &overrideSettings; + } + +private: + static void overrideSettings(Settings& settings) + { + settings.setScriptEnabled(true); + } +}; + +TEST_F(ScriptValueSerializerTest, ValueCountHistograms) +{ + HistogramTester histogramTester; + document().frame()->script().executeScriptInMainWorld( + "postMessage({ foo: 42, bar: [new Blob]}, '*')"); + + // Three primitives, "foo", 42 and "bar". + histogramTester.expectUniqueSample( + "Blink.ScriptValueSerializer.PrimitiveCount", 3, 1); + + // Two JS objects: the outer object and the array. + histogramTester.expectUniqueSample( + "Blink.ScriptValueSerializer.JSObjectCount", 2, 1); + + // One DOM wrapper: the blob. + histogramTester.expectUniqueSample( + "Blink.ScriptValueSerializer.DOMWrapperCount", 1, 1); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8Binding.h b/third_party/WebKit/Source/bindings/core/v8/V8Binding.h index 35a426b5..004d117 100644 --- a/third_party/WebKit/Source/bindings/core/v8/V8Binding.h +++ b/third_party/WebKit/Source/bindings/core/v8/V8Binding.h
@@ -48,7 +48,6 @@ #include "bindings/core/v8/V8ValueCache.h" #include "core/CoreExport.h" #include "platform/heap/Handle.h" -#include "platform/text/CompressibleString.h" #include "wtf/text/AtomicString.h" #include "wtf/text/StringView.h" #include <v8.h> @@ -415,13 +414,6 @@ return V8PerIsolateData::from(isolate)->getStringCache()->v8ExternalString(isolate, string.impl()); } -inline v8::Local<v8::String> v8String(v8::Isolate* isolate, const CompressibleString& string) -{ - if (string.isNull()) - return v8::String::Empty(isolate); - return V8PerIsolateData::from(isolate)->getStringCache()->v8ExternalString(isolate, string); -} - inline v8::Local<v8::String> v8AtomicString(v8::Isolate* isolate, const StringView& string) { DCHECK(isolate);
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8PrivateProperty.h b/third_party/WebKit/Source/bindings/core/v8/V8PrivateProperty.h index 49ee1a5..486aa74b 100644 --- a/third_party/WebKit/Source/bindings/core/v8/V8PrivateProperty.h +++ b/third_party/WebKit/Source/bindings/core/v8/V8PrivateProperty.h
@@ -25,11 +25,11 @@ X(CustomEvent, Detail) \ X(DOMException, Error) \ X(ErrorEvent, Error) \ - X(IDBObserver, Callback) \ - X(IntersectionObserver, Callback) \ + X(IDBObserver, Callback) \ + X(IntersectionObserver, Callback) \ X(MessageEvent, CachedData) \ - X(MutationObserver, Callback) \ - X(PerformanceObserver, Callback) \ + X(MutationObserver, Callback) \ + X(PerformanceObserver, Callback) \ X(PrivateScriptRunner, IsInitialized) \ X(SameObject, NotificationActions) \ X(SameObject, NotificationData) \
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp b/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp index 4be52d5..f7258b0 100644 --- a/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp
@@ -111,7 +111,7 @@ void throwScriptForbiddenException(v8::Isolate* isolate) { - V8ThrowException::throwGeneralError(isolate, "Script execution is forbidden."); + V8ThrowException::throwError(isolate, "Script execution is forbidden."); } v8::Local<v8::Value> throwStackOverflowExceptionIfNeeded(v8::Isolate* isolate) @@ -345,16 +345,16 @@ v8::MaybeLocal<v8::Script> V8ScriptRunner::compileScript(const ScriptSourceCode& source, v8::Isolate* isolate, AccessControlStatus accessControlStatus, V8CacheOptions cacheOptions) { if (source.source().length() >= v8::String::kMaxLength) { - V8ThrowException::throwGeneralError(isolate, "Source file too large."); + V8ThrowException::throwError(isolate, "Source file too large."); return v8::Local<v8::Script>(); } return compileScript(v8String(isolate, source.source()), source.url(), source.sourceMapUrl(), source.startPosition(), isolate, source.resource(), source.streamer(), source.resource() ? source.resource()->cacheHandler() : nullptr, accessControlStatus, cacheOptions); } -v8::MaybeLocal<v8::Script> V8ScriptRunner::compileScript(const CompressibleString& code, const String& fileName, const String& sourceMapUrl, const TextPosition& textPosition, v8::Isolate* isolate, CachedMetadataHandler* cacheMetadataHandler, AccessControlStatus accessControlStatus, V8CacheOptions v8CacheOptions) +v8::MaybeLocal<v8::Script> V8ScriptRunner::compileScript(const String& code, const String& fileName, const String& sourceMapUrl, const TextPosition& textPosition, v8::Isolate* isolate, CachedMetadataHandler* cacheMetadataHandler, AccessControlStatus accessControlStatus, V8CacheOptions v8CacheOptions) { if (code.length() >= v8::String::kMaxLength) { - V8ThrowException::throwGeneralError(isolate, "Source file too large."); + V8ThrowException::throwError(isolate, "Source file too large."); return v8::Local<v8::Script>(); } return compileScript(v8String(isolate, code), fileName, sourceMapUrl, textPosition, isolate, nullptr, nullptr, cacheMetadataHandler, accessControlStatus, v8CacheOptions);
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.h b/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.h index d984a14..7e3b532 100644 --- a/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.h +++ b/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.h
@@ -32,7 +32,6 @@ #include "bindings/core/v8/V8CacheOptions.h" #include "core/CoreExport.h" #include "core/fetch/AccessControlStatus.h" -#include "platform/text/CompressibleString.h" #include "wtf/Allocator.h" #include "wtf/text/TextPosition.h" #include "wtf/text/WTFString.h" @@ -53,7 +52,7 @@ // For the following methods, the caller sites have to hold // a HandleScope and a ContextScope. static v8::MaybeLocal<v8::Script> compileScript(const ScriptSourceCode&, v8::Isolate*, AccessControlStatus = SharableCrossOrigin, V8CacheOptions = V8CacheOptionsDefault); - static v8::MaybeLocal<v8::Script> compileScript(const CompressibleString&, const String& fileName, const String& sourceMapUrl, const TextPosition&, v8::Isolate*, CachedMetadataHandler* = nullptr, AccessControlStatus = SharableCrossOrigin, V8CacheOptions = V8CacheOptionsDefault); + static v8::MaybeLocal<v8::Script> compileScript(const String&, const String& fileName, const String& sourceMapUrl, const TextPosition&, v8::Isolate*, CachedMetadataHandler* = nullptr, AccessControlStatus = SharableCrossOrigin, V8CacheOptions = V8CacheOptionsDefault); // CachedMetadataHandler is set when metadata caching is supported. For // normal scripe resources, CachedMetadataHandler is from ScriptResource. // For worker script, ScriptResource is null but CachedMetadataHandler may be
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8StringResource.cpp b/third_party/WebKit/Source/bindings/core/v8/V8StringResource.cpp index f4a2085..7cbc56e 100644 --- a/third_party/WebKit/Source/bindings/core/v8/V8StringResource.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/V8StringResource.cpp
@@ -47,7 +47,7 @@ template<> struct StringTraits<AtomicString> { - static AtomicString fromStringResource(WebCoreStringResourceBase* resource) + static const AtomicString& fromStringResource(WebCoreStringResourceBase* resource) { return resource->getAtomicString(); } @@ -106,17 +106,10 @@ v8::String::ExternalStringResourceBase* resource = v8String->GetExternalStringResourceBase(&encoding); if (LIKELY(!!resource)) { WebCoreStringResourceBase* base; - if (UNLIKELY(resource->IsCompressible())) { - if (encoding == v8::String::ONE_BYTE_ENCODING) - base = static_cast<WebCoreCompressibleStringResource8*>(resource); - else - base = static_cast<WebCoreCompressibleStringResource16*>(resource); - } else { - if (encoding == v8::String::ONE_BYTE_ENCODING) - base = static_cast<WebCoreStringResource8*>(resource); - else - base = static_cast<WebCoreStringResource16*>(resource); - } + if (encoding == v8::String::ONE_BYTE_ENCODING) + base = static_cast<WebCoreStringResource8*>(resource); + else + base = static_cast<WebCoreStringResource16*>(resource); return StringTraits<StringType>::fromStringResource(base); } }
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8StringResource.h b/third_party/WebKit/Source/bindings/core/v8/V8StringResource.h index f7419ab..b65cfad 100644 --- a/third_party/WebKit/Source/bindings/core/v8/V8StringResource.h +++ b/third_party/WebKit/Source/bindings/core/v8/V8StringResource.h
@@ -28,7 +28,6 @@ #include "bindings/core/v8/ExceptionState.h" #include "core/CoreExport.h" -#include "platform/text/CompressibleString.h" #include "wtf/Allocator.h" #include "wtf/Threading.h" #include "wtf/text/AtomicString.h" @@ -63,52 +62,24 @@ v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(memoryConsumption(string)); } - explicit WebCoreStringResourceBase(const CompressibleString& string) - : m_compressibleString(string) - { -#if ENABLE(ASSERT) - m_threadId = WTF::currentThread(); -#endif - ASSERT(!string.isNull()); - v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(memoryConsumption(string)); - } - virtual ~WebCoreStringResourceBase() { #if ENABLE(ASSERT) ASSERT(m_threadId == WTF::currentThread()); #endif - int reducedExternalMemory = 0; - if (LIKELY(m_compressibleString.isNull())) { - reducedExternalMemory = -memoryConsumption(m_plainString); - if (m_plainString.impl() != m_atomicString.impl() && !m_atomicString.isNull()) - reducedExternalMemory -= memoryConsumption(m_atomicString.getString()); - } else { - reducedExternalMemory = -memoryConsumption(m_compressibleString); - } + int reducedExternalMemory = -memoryConsumption(m_plainString); + if (m_plainString.impl() != m_atomicString.impl() && !m_atomicString.isNull()) + reducedExternalMemory -= memoryConsumption(m_atomicString); v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(reducedExternalMemory); } - const String& webcoreString() - { - if (UNLIKELY(!m_compressibleString.isNull())) { - ASSERT(m_plainString.isNull()); - ASSERT(m_atomicString.isNull()); - return m_compressibleString.toString(); - } - return m_plainString; - } + const String& webcoreString() { return m_plainString; } - AtomicString getAtomicString() + const AtomicString& getAtomicString() { #if ENABLE(ASSERT) ASSERT(m_threadId == WTF::currentThread()); #endif - if (UNLIKELY(!m_compressibleString.isNull())) { - ASSERT(m_plainString.isNull()); - ASSERT(m_atomicString.isNull()); - return AtomicString(m_compressibleString.toString()); - } if (m_atomicString.isNull()) { m_atomicString = AtomicString(m_plainString); ASSERT(!m_atomicString.isNull()); @@ -118,8 +89,6 @@ return m_atomicString; } - const CompressibleString& getCompressibleString() { return m_compressibleString; } - protected: // A shallow copy of the string. Keeps the string buffer alive until the V8 engine garbage collects it. String m_plainString; @@ -130,19 +99,11 @@ // into that string. AtomicString m_atomicString; - CompressibleString m_compressibleString; - private: static int memoryConsumption(const String& string) { return string.length() * (string.is8Bit() ? sizeof(LChar) : sizeof(UChar)); } - - static int memoryConsumption(const CompressibleString& string) - { - return string.currentSizeInBytes(); - } - #if ENABLE(ASSERT) WTF::ThreadIdentifier m_threadId; #endif @@ -192,50 +153,6 @@ } }; -class WebCoreCompressibleStringResource16 final : public WebCoreStringResourceBase, public v8::String::ExternalStringResource { - WTF_MAKE_NONCOPYABLE(WebCoreCompressibleStringResource16); -public: - explicit WebCoreCompressibleStringResource16(const CompressibleString& string) - : WebCoreStringResourceBase(string) - { - ASSERT(!m_compressibleString.is8Bit()); - } - - bool IsCompressible() const override { return true; } - - size_t length() const override - { - return m_compressibleString.length(); - } - - const uint16_t* data() const override - { - return reinterpret_cast<const uint16_t*>(m_compressibleString.characters16()); - } -}; - -class WebCoreCompressibleStringResource8 final : public WebCoreStringResourceBase, public v8::String::ExternalOneByteStringResource { - WTF_MAKE_NONCOPYABLE(WebCoreCompressibleStringResource8); -public: - explicit WebCoreCompressibleStringResource8(const CompressibleString& string) - : WebCoreStringResourceBase(string) - { - ASSERT(m_compressibleString.is8Bit()); - } - - bool IsCompressible() const override { return true; } - - size_t length() const override - { - return m_compressibleString.length(); - } - - const char* data() const override - { - return reinterpret_cast<const char*>(m_compressibleString.characters8()); - } -}; - enum ExternalMode { Externalize, DoNotExternalize
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8ThrowException.cpp b/third_party/WebKit/Source/bindings/core/v8/V8ThrowException.cpp index 2a5afed..36cb08e 100644 --- a/third_party/WebKit/Source/bindings/core/v8/V8ThrowException.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/V8ThrowException.cpp
@@ -33,7 +33,9 @@ namespace blink { -static void domExceptionStackGetter(v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) +namespace { + +void domExceptionStackGetter(v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { v8::Isolate* isolate = info.GetIsolate(); v8::Local<v8::Value> value; @@ -41,123 +43,65 @@ v8SetReturnValue(info, value); } -static void domExceptionStackSetter(v8::Local<v8::Name> name, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<void>& info) +void domExceptionStackSetter(v8::Local<v8::Name> name, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<void>& info) { v8::Maybe<bool> unused = info.Data().As<v8::Object>()->Set(info.GetIsolate()->GetCurrentContext(), v8AtomicString(info.GetIsolate(), "stack"), value); ALLOW_UNUSED_LOCAL(unused); } -v8::Local<v8::Value> V8ThrowException::createDOMException(v8::Isolate* isolate, int ec, const String& sanitizedMessage, const String& unsanitizedMessage, const v8::Local<v8::Object>& creationContext) +} // namespace + +v8::Local<v8::Value> V8ThrowException::createDOMException(v8::Isolate* isolate, ExceptionCode exceptionCode, const String& sanitizedMessage, const String& unsanitizedMessage) { - if (ec <= 0 || isolate->IsExecutionTerminating()) - return v8Undefined(); + DCHECK_GT(exceptionCode, 0); + DCHECK(exceptionCode == SecurityError || unsanitizedMessage.isNull()); - ASSERT(ec == SecurityError || unsanitizedMessage.isEmpty()); + if (isolate->IsExecutionTerminating()) + return v8::Local<v8::Value>(); - if (ec == V8GeneralError) - return V8ThrowException::createGeneralError(isolate, sanitizedMessage); - if (ec == V8TypeError) - return V8ThrowException::createTypeError(isolate, sanitizedMessage); - if (ec == V8RangeError) - return V8ThrowException::createRangeError(isolate, sanitizedMessage); - if (ec == V8SyntaxError) - return V8ThrowException::createSyntaxError(isolate, sanitizedMessage); - if (ec == V8ReferenceError) - return V8ThrowException::createReferenceError(isolate, sanitizedMessage); - - v8::Local<v8::Object> sanitizedCreationContext = creationContext; - - // FIXME: Is the current context always the right choice? - ScriptState* scriptState = ScriptState::from(creationContext->CreationContext()); - Frame* frame = toFrameIfNotDetached(scriptState->context()); - if (!frame || !BindingSecurity::shouldAllowAccessToFrame(isolate, currentDOMWindow(isolate), frame, DoNotReportSecurityError)) { - scriptState = ScriptState::current(isolate); - sanitizedCreationContext = scriptState->context()->Global(); + switch (exceptionCode) { + case V8Error: + return createError(isolate, sanitizedMessage); + case V8TypeError: + return createTypeError(isolate, sanitizedMessage); + case V8RangeError: + return createRangeError(isolate, sanitizedMessage); + case V8SyntaxError: + return createSyntaxError(isolate, sanitizedMessage); + case V8ReferenceError: + return createReferenceError(isolate, sanitizedMessage); } - v8::TryCatch tryCatch(isolate); - - DOMException* domException = DOMException::create(ec, sanitizedMessage, unsanitizedMessage); - v8::Local<v8::Value> exception = toV8(domException, sanitizedCreationContext, isolate); - - if (tryCatch.HasCaught()) { - ASSERT(exception.IsEmpty()); - return tryCatch.Exception(); - } - ASSERT(!exception.IsEmpty()); - - // Attach an Error object to the DOMException. This is then lazily used to get the stack value. + DOMException* domException = DOMException::create(exceptionCode, sanitizedMessage, unsanitizedMessage); + v8::Local<v8::Object> exceptionObj = toV8(domException, isolate->GetCurrentContext()->Global(), isolate).As<v8::Object>(); + // Attach an Error object to the DOMException. This is then lazily used to + // get the stack value. v8::Local<v8::Value> error = v8::Exception::Error(v8String(isolate, domException->message())); - ASSERT(!error.IsEmpty()); - v8::Local<v8::Object> exceptionObject = exception.As<v8::Object>(); - exceptionObject->SetAccessor(isolate->GetCurrentContext(), v8AtomicString(isolate, "stack"), domExceptionStackGetter, domExceptionStackSetter, error).ToChecked(); + exceptionObj->SetAccessor(isolate->GetCurrentContext(), v8AtomicString(isolate, "stack"), domExceptionStackGetter, domExceptionStackSetter, error).ToChecked(); auto privateError = V8PrivateProperty::getDOMExceptionError(isolate); - privateError.set(scriptState->context(), exceptionObject, error); + privateError.set(isolate->GetCurrentContext(), exceptionObj, error); - return exception; + return exceptionObj; } -v8::Local<v8::Value> V8ThrowException::createGeneralError(v8::Isolate* isolate, const String& message) -{ - return v8::Exception::Error(v8String(isolate, message.isNull() ? "Error" : message)); +#define DEFINE_CREATE_AND_THROW_ERROR_FUNC(blinkErrorType, v8ErrorType, defaultMessage) \ +v8::Local<v8::Value> V8ThrowException::create##blinkErrorType(v8::Isolate* isolate, const String& message) \ +{ \ + return v8::Exception::v8ErrorType(v8String(isolate, message.isNull() ? defaultMessage : message)); \ +} \ +\ +void V8ThrowException::throw##blinkErrorType(v8::Isolate* isolate, const String& message) \ +{ \ + throwException(isolate, create##blinkErrorType(isolate, message)); \ } -v8::Local<v8::Value> V8ThrowException::throwGeneralError(v8::Isolate* isolate, const String& message) -{ - v8::Local<v8::Value> exception = V8ThrowException::createGeneralError(isolate, message); - return V8ThrowException::throwException(exception, isolate); -} +DEFINE_CREATE_AND_THROW_ERROR_FUNC(Error, Error, "Error") +DEFINE_CREATE_AND_THROW_ERROR_FUNC(RangeError, RangeError, "Range error") +DEFINE_CREATE_AND_THROW_ERROR_FUNC(ReferenceError, ReferenceError, "Reference error") +DEFINE_CREATE_AND_THROW_ERROR_FUNC(SyntaxError, SyntaxError, "Syntax error") +DEFINE_CREATE_AND_THROW_ERROR_FUNC(TypeError, TypeError, "Type error") -v8::Local<v8::Value> V8ThrowException::createTypeError(v8::Isolate* isolate, const String& message) -{ - return v8::Exception::TypeError(v8String(isolate, message.isNull() ? "Type error" : message)); -} - -v8::Local<v8::Value> V8ThrowException::throwTypeError(v8::Isolate* isolate, const String& message) -{ - v8::Local<v8::Value> exception = V8ThrowException::createTypeError(isolate, message); - return V8ThrowException::throwException(exception, isolate); -} - -v8::Local<v8::Value> V8ThrowException::createRangeError(v8::Isolate* isolate, const String& message) -{ - return v8::Exception::RangeError(v8String(isolate, message.isNull() ? "Range error" : message)); -} - -v8::Local<v8::Value> V8ThrowException::throwRangeError(v8::Isolate* isolate, const String& message) -{ - v8::Local<v8::Value> exception = V8ThrowException::createRangeError(isolate, message); - return V8ThrowException::throwException(exception, isolate); -} - -v8::Local<v8::Value> V8ThrowException::createSyntaxError(v8::Isolate* isolate, const String& message) -{ - return v8::Exception::SyntaxError(v8String(isolate, message.isNull() ? "Syntax error" : message)); -} - -v8::Local<v8::Value> V8ThrowException::throwSyntaxError(v8::Isolate* isolate, const String& message) -{ - v8::Local<v8::Value> exception = V8ThrowException::createSyntaxError(isolate, message); - return V8ThrowException::throwException(exception, isolate); -} - -v8::Local<v8::Value> V8ThrowException::createReferenceError(v8::Isolate* isolate, const String& message) -{ - return v8::Exception::ReferenceError(v8String(isolate, message.isNull() ? "Reference error" : message)); -} - -v8::Local<v8::Value> V8ThrowException::throwReferenceError(v8::Isolate* isolate, const String& message) -{ - v8::Local<v8::Value> exception = V8ThrowException::createReferenceError(isolate, message); - return V8ThrowException::throwException(exception, isolate); -} - -v8::Local<v8::Value> V8ThrowException::throwException(v8::Local<v8::Value> exception, v8::Isolate* isolate) -{ - if (!isolate->IsExecutionTerminating()) - isolate->ThrowException(exception); - return v8::Undefined(isolate); -} +#undef DEFINE_CREATE_AND_THROW_ERROR_FUNC } // namespace blink
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8ThrowException.h b/third_party/WebKit/Source/bindings/core/v8/V8ThrowException.h index 2eaaa25d..dae1a56 100644 --- a/third_party/WebKit/Source/bindings/core/v8/V8ThrowException.h +++ b/third_party/WebKit/Source/bindings/core/v8/V8ThrowException.h
@@ -26,34 +26,40 @@ #define V8ThrowException_h #include "core/CoreExport.h" +#include "core/dom/ExceptionCode.h" #include "wtf/Allocator.h" #include "wtf/text/WTFString.h" #include <v8.h> namespace blink { +// Provides utility functions to create and/or throw a V8 exception. +// Mostly a set of wrapper functions for v8::Exception class. class CORE_EXPORT V8ThrowException { STATIC_ONLY(V8ThrowException); public: + // Creates and returns an exception object, or returns an empty handle if + // failed. |unsanitizedMessage| should not be specified unless it's + // SecurityError. + static v8::Local<v8::Value> createDOMException(v8::Isolate*, ExceptionCode, const String& sanitizedMessage, const String& unsanitizedMessage = String()); - static v8::Local<v8::Value> createDOMException(v8::Isolate* isolate, int ec, const String& message, const v8::Local<v8::Object>& creationContext) + static void throwException(v8::Isolate* isolate, v8::Local<v8::Value> exception) { - return createDOMException(isolate, ec, message, String(), creationContext); + if (!isolate->IsExecutionTerminating()) + isolate->ThrowException(exception); } - static v8::Local<v8::Value> createDOMException(v8::Isolate*, int, const String& sanitizedMessage, const String& unsanitizedMessage, const v8::Local<v8::Object>& creationContext); - static v8::Local<v8::Value> throwException(v8::Local<v8::Value>, v8::Isolate*); + static v8::Local<v8::Value> createError(v8::Isolate*, const String& message); + static v8::Local<v8::Value> createRangeError(v8::Isolate*, const String& message); + static v8::Local<v8::Value> createReferenceError(v8::Isolate*, const String& message); + static v8::Local<v8::Value> createSyntaxError(v8::Isolate*, const String& message); + static v8::Local<v8::Value> createTypeError(v8::Isolate*, const String& message); - static v8::Local<v8::Value> createGeneralError(v8::Isolate*, const String&); - static v8::Local<v8::Value> throwGeneralError(v8::Isolate*, const String&); - static v8::Local<v8::Value> createTypeError(v8::Isolate*, const String&); - static v8::Local<v8::Value> throwTypeError(v8::Isolate*, const String&); - static v8::Local<v8::Value> createRangeError(v8::Isolate*, const String&); - static v8::Local<v8::Value> throwRangeError(v8::Isolate*, const String&); - static v8::Local<v8::Value> createSyntaxError(v8::Isolate*, const String&); - static v8::Local<v8::Value> throwSyntaxError(v8::Isolate*, const String&); - static v8::Local<v8::Value> createReferenceError(v8::Isolate*, const String&); - static v8::Local<v8::Value> throwReferenceError(v8::Isolate*, const String&); + static void throwError(v8::Isolate*, const String& message); + static void throwRangeError(v8::Isolate*, const String& message); + static void throwReferenceError(v8::Isolate*, const String& message); + static void throwSyntaxError(v8::Isolate*, const String& message); + static void throwTypeError(v8::Isolate*, const String& message); }; } // namespace blink
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8ValueCache.cpp b/third_party/WebKit/Source/bindings/core/v8/V8ValueCache.cpp index 605dbed..5dfb241 100644 --- a/third_party/WebKit/Source/bindings/core/v8/V8ValueCache.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/V8ValueCache.cpp
@@ -55,29 +55,6 @@ V8PerIsolateData::from(data.GetIsolate())->getStringCache()->InvalidateLastString(); } - -CompressibleStringCacheMapTraits::MapType* CompressibleStringCacheMapTraits::MapFromWeakCallbackInfo( - const v8::WeakCallbackInfo<WeakCallbackDataType>& data) -{ - return &(V8PerIsolateData::from(data.GetIsolate())->getStringCache()->m_compressibleStringCache); -} - -void CompressibleStringCacheMapTraits::Dispose( - v8::Isolate* isolate, v8::Global<v8::String> value, CompressibleStringImpl* key) -{ - key->deref(); -} - -void CompressibleStringCacheMapTraits::DisposeWeak(const v8::WeakCallbackInfo<WeakCallbackDataType>& data) -{ - data.GetParameter()->deref(); -} - -void CompressibleStringCacheMapTraits::OnWeakCallback(const v8::WeakCallbackInfo<WeakCallbackDataType>& data) -{ -} - - void StringCache::dispose() { // The MapType::Dispose callback calls StringCache::InvalidateLastString, @@ -107,27 +84,6 @@ return newString; } -static v8::Local<v8::String> makeExternalString(v8::Isolate* isolate, const CompressibleString& string) -{ - if (string.is8Bit()) { - WebCoreCompressibleStringResource8* stringResource = new WebCoreCompressibleStringResource8(string); - v8::Local<v8::String> newString; - if (!v8::String::NewExternalOneByte(isolate, stringResource).ToLocal(&newString)) { - delete stringResource; - return v8::String::Empty(isolate); - } - return newString; - } - - WebCoreCompressibleStringResource16* stringResource = new WebCoreCompressibleStringResource16(string); - v8::Local<v8::String> newString; - if (!v8::String::NewExternalTwoByte(isolate, stringResource).ToLocal(&newString)) { - delete stringResource; - return v8::String::Empty(isolate); - } - return newString; -} - v8::Local<v8::String> StringCache::v8ExternalStringSlow(v8::Isolate* isolate, StringImpl* stringImpl) { if (!stringImpl->length()) @@ -143,18 +99,6 @@ return createStringAndInsertIntoCache(isolate, stringImpl); } -v8::Local<v8::String> StringCache::v8ExternalStringSlow(v8::Isolate* isolate, const CompressibleString& string) -{ - if (!string.length()) - return v8::String::Empty(isolate); - - CompressibleStringCacheMapTraits::MapType::PersistentValueReference cachedV8String = m_compressibleStringCache.GetReference(string.impl()); - if (!cachedV8String.IsEmpty()) - return cachedV8String.NewLocal(isolate); - - return createStringAndInsertIntoCache(isolate, string); -} - void StringCache::setReturnValueFromStringSlow(v8::ReturnValue<v8::Value> returnValue, StringImpl* stringImpl) { if (!stringImpl->length()) { @@ -192,31 +136,6 @@ return newString; } -v8::Local<v8::String> StringCache::createStringAndInsertIntoCache(v8::Isolate* isolate, const CompressibleString& string) -{ - CompressibleStringImpl* stringImpl = string.impl(); - - ASSERT(!m_compressibleStringCache.Contains(stringImpl)); - ASSERT(stringImpl->originalLength()); - - v8::Local<v8::String> newString = makeExternalString(isolate, string); - ASSERT(!newString.IsEmpty()); - ASSERT(newString->Length()); - - v8::UniquePersistent<v8::String> wrapper(isolate, newString); - - stringImpl->ref(); - wrapper.MarkIndependent(); - // CompressibleStringImpl objects are NOT cached on |m_stringCache| or - // |m_lastStringImpl|. It's because if even one objects holds a StringImpl - // object in a CompressibleStringImpl, uncompressed string will exists even - // when compressing the string. - CompressibleStringCacheMapTraits::MapType::PersistentValueReference unused; - m_compressibleStringCache.Set(stringImpl, std::move(wrapper), &unused); - - return newString; -} - void StringCache::InvalidateLastString() { m_lastStringImpl = nullptr;
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8ValueCache.h b/third_party/WebKit/Source/bindings/core/v8/V8ValueCache.h index ca513420..3bc2e00 100644 --- a/third_party/WebKit/Source/bindings/core/v8/V8ValueCache.h +++ b/third_party/WebKit/Source/bindings/core/v8/V8ValueCache.h
@@ -28,7 +28,6 @@ #include "bindings/core/v8/V8GlobalValueMap.h" #include "core/CoreExport.h" -#include "platform/text/CompressibleString.h" #include "wtf/Allocator.h" #include "wtf/HashMap.h" #include "wtf/Noncopyable.h" @@ -65,41 +64,12 @@ static void DisposeWeak(const v8::WeakCallbackInfo<WeakCallbackDataType>&); }; -class CompressibleStringCacheMapTraits : public V8GlobalValueMapTraits<CompressibleStringImpl*, v8::String, v8::kWeakWithParameter> { - STATIC_ONLY(CompressibleStringCacheMapTraits); -public: - // Weak traits: - typedef CompressibleStringImpl WeakCallbackDataType; - typedef v8::GlobalValueMap<CompressibleStringImpl*, v8::String, CompressibleStringCacheMapTraits> MapType; - - static WeakCallbackDataType* WeakCallbackParameter( - MapType* map, CompressibleStringImpl* key, v8::Local<v8::String>& value) { return key; } - static void DisposeCallbackData(WeakCallbackDataType* callbackData) { } - - static MapType* MapFromWeakCallbackInfo( - const v8::WeakCallbackInfo<WeakCallbackDataType>&); - - static CompressibleStringImpl* KeyFromWeakCallbackInfo( - const v8::WeakCallbackInfo<WeakCallbackDataType>& data) - { - return data.GetParameter(); - } - - static void OnWeakCallback(const v8::WeakCallbackInfo<WeakCallbackDataType>&); - - static void Dispose(v8::Isolate*, v8::Global<v8::String> value, CompressibleStringImpl* key); - static void DisposeWeak(const v8::WeakCallbackInfo<WeakCallbackDataType>&); -}; class CORE_EXPORT StringCache { USING_FAST_MALLOC(StringCache); WTF_MAKE_NONCOPYABLE(StringCache); public: - explicit StringCache(v8::Isolate* isolate) - : m_stringCache(isolate) - , m_compressibleStringCache(isolate) - { - } + explicit StringCache(v8::Isolate* isolate) : m_stringCache(isolate) { } v8::Local<v8::String> v8ExternalString(v8::Isolate* isolate, StringImpl* stringImpl) { @@ -109,13 +79,6 @@ return v8ExternalStringSlow(isolate, stringImpl); } - v8::Local<v8::String> v8ExternalString(v8::Isolate* isolate, const CompressibleString& string) - { - // Note that the last CompressibleString is not cached. - ASSERT(!string.isNull()); - return v8ExternalStringSlow(isolate, string); - } - void setReturnValueFromString(v8::ReturnValue<v8::Value> returnValue, StringImpl* stringImpl) { ASSERT(stringImpl); @@ -128,21 +91,16 @@ void dispose(); friend class StringCacheMapTraits; - friend class CompressibleStringCacheMapTraits; private: v8::Local<v8::String> v8ExternalStringSlow(v8::Isolate*, StringImpl*); - v8::Local<v8::String> v8ExternalStringSlow(v8::Isolate*, const CompressibleString&); void setReturnValueFromStringSlow(v8::ReturnValue<v8::Value>, StringImpl*); v8::Local<v8::String> createStringAndInsertIntoCache(v8::Isolate*, StringImpl*); - v8::Local<v8::String> createStringAndInsertIntoCache(v8::Isolate*, const CompressibleString&); void InvalidateLastString(); StringCacheMapTraits::MapType m_stringCache; StringCacheMapTraits::MapType::PersistentValueReference m_lastV8String; - CompressibleStringCacheMapTraits::MapType m_compressibleStringCache; - // Note: RefPtr is a must as we cache by StringImpl* equality, not identity // hence lastStringImpl might be not a key of the cache (in sense of identity) // and hence it's not refed on addition.
diff --git a/third_party/WebKit/Source/bindings/core/v8/WorkerOrWorkletScriptController.cpp b/third_party/WebKit/Source/bindings/core/v8/WorkerOrWorkletScriptController.cpp index af04d355..3b1d9d9 100644 --- a/third_party/WebKit/Source/bindings/core/v8/WorkerOrWorkletScriptController.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/WorkerOrWorkletScriptController.cpp
@@ -200,7 +200,7 @@ return true; } -ScriptValue WorkerOrWorkletScriptController::evaluate(const CompressibleString& script, const String& fileName, const TextPosition& scriptStartPosition, CachedMetadataHandler* cacheHandler, V8CacheOptions v8CacheOptions) +ScriptValue WorkerOrWorkletScriptController::evaluate(const String& script, const String& fileName, const TextPosition& scriptStartPosition, CachedMetadataHandler* cacheHandler, V8CacheOptions v8CacheOptions) { if (!initializeContextIfNeeded()) return ScriptValue(); @@ -316,7 +316,7 @@ const String& errorMessage = errorEvent->message(); if (m_executionState) m_executionState->m_errorEventFromImportedScript = errorEvent; - exceptionState.rethrowV8Exception(V8ThrowException::createGeneralError(m_isolate, errorMessage)); + exceptionState.rethrowV8Exception(V8ThrowException::createError(m_isolate, errorMessage)); } DEFINE_TRACE(WorkerOrWorkletScriptController)
diff --git a/third_party/WebKit/Source/bindings/core/v8/WorkerOrWorkletScriptController.h b/third_party/WebKit/Source/bindings/core/v8/WorkerOrWorkletScriptController.h index e2c8914..1c6d97a 100644 --- a/third_party/WebKit/Source/bindings/core/v8/WorkerOrWorkletScriptController.h +++ b/third_party/WebKit/Source/bindings/core/v8/WorkerOrWorkletScriptController.h
@@ -36,7 +36,6 @@ #include "bindings/core/v8/V8Binding.h" #include "bindings/core/v8/V8CacheOptions.h" #include "core/CoreExport.h" -#include "platform/text/CompressibleString.h" #include "wtf/Allocator.h" #include "wtf/ThreadingPrimitives.h" #include "wtf/text/TextPosition.h" @@ -97,7 +96,7 @@ class ExecutionState; // Evaluate a script file in the current execution environment. - ScriptValue evaluate(const CompressibleString& script, const String& fileName, const TextPosition& scriptStartPosition, CachedMetadataHandler*, V8CacheOptions); + ScriptValue evaluate(const String& script, const String& fileName, const TextPosition& scriptStartPosition, CachedMetadataHandler*, V8CacheOptions); void disposeContextIfNeeded(); Member<WorkerOrWorkletGlobalScope> m_globalScope;
diff --git a/third_party/WebKit/Source/bindings/core/v8/custom/V8IntersectionObserverCustom.cpp b/third_party/WebKit/Source/bindings/core/v8/custom/V8IntersectionObserverCustom.cpp index 623aef1..38cd3bb4 100644 --- a/third_party/WebKit/Source/bindings/core/v8/custom/V8IntersectionObserverCustom.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/custom/V8IntersectionObserverCustom.cpp
@@ -17,7 +17,7 @@ void V8IntersectionObserver::constructorCustom(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "createIntersectionObserver", "Intersection", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "createIntersectionObserver", "Intersection", 1, info.Length())); return; }
diff --git a/third_party/WebKit/Source/bindings/core/v8/custom/V8PerformanceObserverCustom.cpp b/third_party/WebKit/Source/bindings/core/v8/custom/V8PerformanceObserverCustom.cpp index 770b19ce..0c1824b6 100644 --- a/third_party/WebKit/Source/bindings/core/v8/custom/V8PerformanceObserverCustom.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/custom/V8PerformanceObserverCustom.cpp
@@ -19,7 +19,7 @@ void V8PerformanceObserver::constructorCustom(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "createPerformanceObserver", "Performance", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "createPerformanceObserver", "Performance", 1, info.Length())); return; }
diff --git a/third_party/WebKit/Source/bindings/core/v8/v8.gypi b/third_party/WebKit/Source/bindings/core/v8/v8.gypi index 4dd67ec2..b66a211 100644 --- a/third_party/WebKit/Source/bindings/core/v8/v8.gypi +++ b/third_party/WebKit/Source/bindings/core/v8/v8.gypi
@@ -198,6 +198,7 @@ 'ScriptPromiseResolverTest.cpp', 'ScriptPromiseTest.cpp', 'ScriptStreamerTest.cpp', + 'ScriptValueSerializerTest.cpp', 'SerializedScriptValueTest.cpp', 'ToV8Test.cpp', 'V8BindingForTesting.cpp',
diff --git a/third_party/WebKit/Source/bindings/modules/v8/custom/V8IDBObserverCustom.cpp b/third_party/WebKit/Source/bindings/modules/v8/custom/V8IDBObserverCustom.cpp index b8286a4a..3cfc2a6 100644 --- a/third_party/WebKit/Source/bindings/modules/v8/custom/V8IDBObserverCustom.cpp +++ b/third_party/WebKit/Source/bindings/modules/v8/custom/V8IDBObserverCustom.cpp
@@ -16,7 +16,7 @@ void V8IDBObserver::constructorCustom(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForConstructor(info.GetIsolate(), "IDBObserver", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForConstructor(info.GetIsolate(), "IDBObserver", 1, info.Length())); return; }
diff --git a/third_party/WebKit/Source/bindings/scripts/v8_types.py b/third_party/WebKit/Source/bindings/scripts/v8_types.py index 51f595d..87d6ef20 100644 --- a/third_party/WebKit/Source/bindings/scripts/v8_types.py +++ b/third_party/WebKit/Source/bindings/scripts/v8_types.py
@@ -870,7 +870,7 @@ '{isolate}, impl->getExecutionContext()) : ' + 'v8::Null({isolate}).As<v8::Value>()'), 'ScriptValue': '{cpp_value}.v8Value()', - 'SerializedScriptValue': '{cpp_value} ? {cpp_value}->deserialize() : v8::Local<v8::Value>(v8::Null({isolate}))', + 'SerializedScriptValue': 'v8Deserialize({isolate}, {cpp_value})', # General 'array': 'toV8({cpp_value}, {creation_context}, {isolate})', 'FrozenArray': 'freezeV8Object(toV8({cpp_value}, {creation_context}, {isolate}), {isolate})',
diff --git a/third_party/WebKit/Source/bindings/templates/methods.cpp b/third_party/WebKit/Source/bindings/templates/methods.cpp index fb7c401a..33d2559 100644 --- a/third_party/WebKit/Source/bindings/templates/methods.cpp +++ b/third_party/WebKit/Source/bindings/templates/methods.cpp
@@ -342,7 +342,7 @@ v8SetReturnValue(info, ScriptPromise::rejectRaw(ScriptState::current(info.GetIsolate()), {{create_minimum_arity_type_error_without_exception_state(method, number_of_required_arguments)}})); return; {%- else %} -V8ThrowException::throwException({{create_minimum_arity_type_error_without_exception_state(method, number_of_required_arguments)}}, info.GetIsolate()); +V8ThrowException::throwException(info.GetIsolate(), {{create_minimum_arity_type_error_without_exception_state(method, number_of_required_arguments)}}); return; {%- endif %} {%- endmacro %}
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestIntegerIndexed.cpp b/third_party/WebKit/Source/bindings/tests/results/core/V8TestIntegerIndexed.cpp index 582e0033..fd0f00d 100644 --- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestIntegerIndexed.cpp +++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestIntegerIndexed.cpp
@@ -67,7 +67,7 @@ static void voidMethodDocumentMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodDocument", "TestIntegerIndexed", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodDocument", "TestIntegerIndexed", 1, info.Length())); return; } TestIntegerIndexed* impl = V8TestIntegerIndexed::toImpl(info.Holder());
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestIntegerIndexedGlobal.cpp b/third_party/WebKit/Source/bindings/tests/results/core/V8TestIntegerIndexedGlobal.cpp index e7eb0e1..6d2b067 100644 --- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestIntegerIndexedGlobal.cpp +++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestIntegerIndexedGlobal.cpp
@@ -67,7 +67,7 @@ static void voidMethodDocumentMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodDocument", "TestIntegerIndexedGlobal", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodDocument", "TestIntegerIndexedGlobal", 1, info.Length())); return; } TestIntegerIndexedGlobal* impl = V8TestIntegerIndexedGlobal::toImpl(info.Holder());
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestIntegerIndexedPrimaryGlobal.cpp b/third_party/WebKit/Source/bindings/tests/results/core/V8TestIntegerIndexedPrimaryGlobal.cpp index d8896ab..28399b2 100644 --- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestIntegerIndexedPrimaryGlobal.cpp +++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestIntegerIndexedPrimaryGlobal.cpp
@@ -67,7 +67,7 @@ static void voidMethodDocumentMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodDocument", "TestIntegerIndexedPrimaryGlobal", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodDocument", "TestIntegerIndexedPrimaryGlobal", 1, info.Length())); return; } TestIntegerIndexedPrimaryGlobal* impl = V8TestIntegerIndexedPrimaryGlobal::toImpl(info.Holder());
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface.cpp b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface.cpp index 63990819..e21e857 100644 --- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface.cpp +++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface.cpp
@@ -1454,7 +1454,7 @@ static void voidMethodTestInterfaceEmptyArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodTestInterfaceEmptyArg", "TestInterface", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodTestInterfaceEmptyArg", "TestInterface", 1, info.Length())); return; } TestInterfaceImplementation* impl = V8TestInterface::toImpl(info.Holder()); @@ -1824,7 +1824,7 @@ static void legacyInterfaceTypeCheckingMethodMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "legacyInterfaceTypeCheckingMethod", "TestInterface", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "legacyInterfaceTypeCheckingMethod", "TestInterface", 1, info.Length())); return; } TestInterfaceImplementation* impl = V8TestInterface::toImpl(info.Holder()); @@ -2064,7 +2064,7 @@ static void partialVoidMethodPartialCallbackTypeArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "partialVoidMethodPartialCallbackTypeArg", "TestInterface", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "partialVoidMethodPartialCallbackTypeArg", "TestInterface", 1, info.Length())); return; } TestInterfaceImplementation* impl = V8TestInterface::toImpl(info.Holder());
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface3.cpp b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface3.cpp index 74a35cee..80e82356 100644 --- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface3.cpp +++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface3.cpp
@@ -54,7 +54,7 @@ static void voidMethodDocumentMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodDocument", "TestInterface3", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodDocument", "TestInterface3", 1, info.Length())); return; } TestInterface3* impl = V8TestInterface3::toImpl(info.Holder());
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceConstructor3.cpp b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceConstructor3.cpp index 3b754994..966f956 100644 --- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceConstructor3.cpp +++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceConstructor3.cpp
@@ -37,7 +37,7 @@ static void constructor(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForConstructor(info.GetIsolate(), "TestInterfaceConstructor3", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForConstructor(info.GetIsolate(), "TestInterfaceConstructor3", 1, info.Length())); return; } V8StringResource<> stringArg;
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceGarbageCollected.cpp b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceGarbageCollected.cpp index fbc89c8..1a4bff5e 100644 --- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceGarbageCollected.cpp +++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceGarbageCollected.cpp
@@ -73,7 +73,7 @@ static void funcMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "func", "TestInterfaceGarbageCollected", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "func", "TestInterfaceGarbageCollected", 1, info.Length())); return; } TestInterfaceGarbageCollected* impl = V8TestInterfaceGarbageCollected::toImpl(info.Holder()); @@ -305,7 +305,7 @@ static void constructor(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForConstructor(info.GetIsolate(), "TestInterfaceGarbageCollected", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForConstructor(info.GetIsolate(), "TestInterfaceGarbageCollected", 1, info.Length())); return; } V8StringResource<> str;
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceNamedConstructor2.cpp b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceNamedConstructor2.cpp index 775b112..c3af817 100644 --- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceNamedConstructor2.cpp +++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceNamedConstructor2.cpp
@@ -59,7 +59,7 @@ return; } if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForConstructor(info.GetIsolate(), "TestInterfaceNamedConstructor2", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForConstructor(info.GetIsolate(), "TestInterfaceNamedConstructor2", 1, info.Length())); return; } V8StringResource<> stringArg;
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp b/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp index 6614c73..bb843143 100644 --- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp +++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp
@@ -964,7 +964,7 @@ { v8::Local<v8::Object> holder = info.Holder(); TestObject* impl = V8TestObject::toImpl(holder); - v8SetReturnValue(info, WTF::getPtr(impl->serializedScriptValueAttribute()) ? WTF::getPtr(impl->serializedScriptValueAttribute())->deserialize() : v8::Local<v8::Value>(v8::Null(info.GetIsolate()))); + v8SetReturnValue(info, v8Deserialize(info.GetIsolate(), WTF::getPtr(impl->serializedScriptValueAttribute()))); } static void serializedScriptValueAttributeAttributeGetterCallback(const v8::FunctionCallbackInfo<v8::Value>& info) @@ -5070,7 +5070,7 @@ static void voidMethodDateArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodDateArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodDateArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -5089,7 +5089,7 @@ static void voidMethodStringArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodStringArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodStringArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -5443,7 +5443,7 @@ static void voidMethodTestInterfaceEmptyArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodTestInterfaceEmptyArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodTestInterfaceEmptyArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -5518,7 +5518,7 @@ static void voidMethodVoidCallbackFunctionArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodVoidCallbackFunctionArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodVoidCallbackFunctionArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -5570,7 +5570,7 @@ static void voidMethodNullableVoidCallbackFunctionArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodNullableVoidCallbackFunctionArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodNullableVoidCallbackFunctionArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -5593,7 +5593,7 @@ static void voidMethodAnyCallbackFunctionOptionalAnyArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodAnyCallbackFunctionOptionalAnyArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodAnyCallbackFunctionOptionalAnyArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -5627,7 +5627,7 @@ static void voidMethodEventTargetArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodEventTargetArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodEventTargetArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -5650,7 +5650,7 @@ static void voidMethodAnyArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodAnyArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodAnyArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -5669,7 +5669,7 @@ static void voidMethodAttrArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodAttrArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodAttrArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -5692,7 +5692,7 @@ static void voidMethodDocumentArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodDocumentArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodDocumentArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -5715,7 +5715,7 @@ static void voidMethodDocumentTypeArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodDocumentTypeArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodDocumentTypeArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -5738,7 +5738,7 @@ static void voidMethodElementArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodElementArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodElementArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -5761,7 +5761,7 @@ static void voidMethodNodeArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodNodeArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodNodeArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -5839,7 +5839,7 @@ static void voidMethodArrayBufferArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodArrayBufferArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodArrayBufferArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -5862,7 +5862,7 @@ static void voidMethodArrayBufferOrNullArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodArrayBufferOrNullArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodArrayBufferOrNullArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -5885,7 +5885,7 @@ static void voidMethodArrayBufferViewArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodArrayBufferViewArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodArrayBufferViewArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -5908,7 +5908,7 @@ static void voidMethodFlexibleArrayBufferViewArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodFlexibleArrayBufferViewArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodFlexibleArrayBufferViewArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -5931,7 +5931,7 @@ static void voidMethodFlexibleArrayBufferViewTypedArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodFlexibleArrayBufferViewTypedArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodFlexibleArrayBufferViewTypedArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -5954,7 +5954,7 @@ static void voidMethodFloat32ArrayArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodFloat32ArrayArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodFloat32ArrayArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -5977,7 +5977,7 @@ static void voidMethodInt32ArrayArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodInt32ArrayArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodInt32ArrayArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -6000,7 +6000,7 @@ static void voidMethodUint8ArrayArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodUint8ArrayArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodUint8ArrayArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -6581,7 +6581,7 @@ static void voidMethodTestInterfaceEmptyOrNullArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodTestInterfaceEmptyOrNullArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodTestInterfaceEmptyOrNullArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -6604,7 +6604,7 @@ static void voidMethodTestCallbackInterfaceArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodTestCallbackInterfaceArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodTestCallbackInterfaceArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -6650,7 +6650,7 @@ static void voidMethodTestCallbackInterfaceOrNullArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodTestCallbackInterfaceOrNullArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodTestCallbackInterfaceOrNullArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -6864,7 +6864,7 @@ static void serializedScriptValueMethodMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { TestObject* impl = V8TestObject::toImpl(info.Holder()); - v8SetReturnValue(info, impl->serializedScriptValueMethod() ? impl->serializedScriptValueMethod()->deserialize() : v8::Local<v8::Value>(v8::Null(info.GetIsolate()))); + v8SetReturnValue(info, v8Deserialize(info.GetIsolate(), impl->serializedScriptValueMethod())); } static void serializedScriptValueMethodMethodCallback(const v8::FunctionCallbackInfo<v8::Value>& info) @@ -6914,7 +6914,7 @@ static void voidMethodNodeFilterArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodNodeFilterArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodNodeFilterArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -6933,7 +6933,7 @@ static void voidMethodPromiseArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodPromiseArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodPromiseArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -6979,7 +6979,7 @@ static void voidMethodXPathNSResolverArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodXPathNSResolverArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodXPathNSResolverArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -9094,7 +9094,7 @@ static void voidMethodTreatNullAsEmptyStringStringArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodTreatNullAsEmptyStringStringArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodTreatNullAsEmptyStringStringArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -9115,7 +9115,7 @@ static void voidMethodTreatNullAsNullStringStringArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodTreatNullAsNullStringStringArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodTreatNullAsNullStringStringArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -9136,7 +9136,7 @@ static void voidMethodTreatNullAsNullStringTreatUndefinedAsNullStringStringArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodTreatNullAsNullStringTreatUndefinedAsNullStringStringArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodTreatNullAsNullStringTreatUndefinedAsNullStringStringArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -9877,7 +9877,7 @@ static void perWorldBindingsVoidMethodTestInterfaceEmptyArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "perWorldBindingsVoidMethodTestInterfaceEmptyArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "perWorldBindingsVoidMethodTestInterfaceEmptyArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -9900,7 +9900,7 @@ static void perWorldBindingsVoidMethodTestInterfaceEmptyArgMethodForMainWorld(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "perWorldBindingsVoidMethodTestInterfaceEmptyArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "perWorldBindingsVoidMethodTestInterfaceEmptyArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -10438,7 +10438,7 @@ static void legacyInterfaceTypeCheckingVoidMethodTestInterfaceEmptyArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "legacyInterfaceTypeCheckingVoidMethodTestInterfaceEmptyArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "legacyInterfaceTypeCheckingVoidMethodTestInterfaceEmptyArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -10480,7 +10480,7 @@ static void useToImpl4ArgumentsCheckingIfPossibleWithOptionalArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "useToImpl4ArgumentsCheckingIfPossibleWithOptionalArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "useToImpl4ArgumentsCheckingIfPossibleWithOptionalArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -10519,7 +10519,7 @@ static void useToImpl4ArgumentsCheckingIfPossibleWithNullableArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 2)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "useToImpl4ArgumentsCheckingIfPossibleWithNullableArg", "TestObject", 2, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "useToImpl4ArgumentsCheckingIfPossibleWithNullableArg", "TestObject", 2, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -10548,7 +10548,7 @@ static void useToImpl4ArgumentsCheckingIfPossibleWithUndefinedArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "useToImpl4ArgumentsCheckingIfPossibleWithUndefinedArg", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "useToImpl4ArgumentsCheckingIfPossibleWithUndefinedArg", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -10711,7 +10711,7 @@ static void stringMethodWithStringArgumentImplementedInPrivateScriptMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "stringMethodWithStringArgumentImplementedInPrivateScript", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "stringMethodWithStringArgumentImplementedInPrivateScript", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder()); @@ -10735,7 +10735,7 @@ static void nodeMethodWithNodeArgumentImplementedInPrivateScriptMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "nodeMethodWithNodeArgumentImplementedInPrivateScript", "TestObject", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "nodeMethodWithNodeArgumentImplementedInPrivateScript", "TestObject", 1, info.Length())); return; } TestObject* impl = V8TestObject::toImpl(info.Holder());
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestSpecialOperations.cpp b/third_party/WebKit/Source/bindings/tests/results/core/V8TestSpecialOperations.cpp index b50d7f6..95cea91 100644 --- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestSpecialOperations.cpp +++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestSpecialOperations.cpp
@@ -43,7 +43,7 @@ static void namedItemMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "namedItem", "TestSpecialOperations", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "namedItem", "TestSpecialOperations", 1, info.Length())); return; } TestSpecialOperations* impl = V8TestSpecialOperations::toImpl(info.Holder());
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestTypedefs.cpp b/third_party/WebKit/Source/bindings/tests/results/core/V8TestTypedefs.cpp index b4fcd14..6f65152a 100644 --- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestTypedefs.cpp +++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestTypedefs.cpp
@@ -158,7 +158,7 @@ static void voidMethodTestCallbackInterfaceTypeArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodTestCallbackInterfaceTypeArg", "TestTypedefs", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodTestCallbackInterfaceTypeArg", "TestTypedefs", 1, info.Length())); return; } TestTypedefs* impl = V8TestTypedefs::toImpl(info.Holder()); @@ -276,7 +276,7 @@ static void constructor(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForConstructor(info.GetIsolate(), "TestTypedefs", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForConstructor(info.GetIsolate(), "TestTypedefs", 1, info.Length())); return; } V8StringResource<> stringArg;
diff --git a/third_party/WebKit/Source/bindings/tests/results/modules/V8TestInterface2Partial.cpp b/third_party/WebKit/Source/bindings/tests/results/modules/V8TestInterface2Partial.cpp index 3ecaefd6..45ac5b2 100644 --- a/third_party/WebKit/Source/bindings/tests/results/modules/V8TestInterface2Partial.cpp +++ b/third_party/WebKit/Source/bindings/tests/results/modules/V8TestInterface2Partial.cpp
@@ -26,7 +26,7 @@ static void voidMethodPartial1Method(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodPartial1", "TestInterface2", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodPartial1", "TestInterface2", 1, info.Length())); return; } TestInterface2* impl = V8TestInterface2::toImpl(info.Holder()); @@ -47,7 +47,7 @@ static void voidMethodPartial2Method(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodPartial2", "TestInterface2", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodPartial2", "TestInterface2", 1, info.Length())); return; } TestInterface2* impl = V8TestInterface2::toImpl(info.Holder());
diff --git a/third_party/WebKit/Source/bindings/tests/results/modules/V8TestInterface5.cpp b/third_party/WebKit/Source/bindings/tests/results/modules/V8TestInterface5.cpp index 2dfe203..b64d49e 100644 --- a/third_party/WebKit/Source/bindings/tests/results/modules/V8TestInterface5.cpp +++ b/third_party/WebKit/Source/bindings/tests/results/modules/V8TestInterface5.cpp
@@ -303,7 +303,7 @@ static void voidMethodTestInterfaceEmptyArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info) { if (UNLIKELY(info.Length() < 1)) { - V8ThrowException::throwException(createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodTestInterfaceEmptyArg", "TestInterface5", 1, info.Length()), info.GetIsolate()); + V8ThrowException::throwException(info.GetIsolate(), createMinimumArityTypeErrorForMethod(info.GetIsolate(), "voidMethodTestInterfaceEmptyArg", "TestInterface5", 1, info.Length())); return; } TestInterface5Implementation* impl = V8TestInterface5::toImpl(info.Holder());
diff --git a/third_party/WebKit/Source/core/OWNERS b/third_party/WebKit/Source/core/OWNERS index cef3f99f..3002824 100644 --- a/third_party/WebKit/Source/core/OWNERS +++ b/third_party/WebKit/Source/core/OWNERS
@@ -55,6 +55,7 @@ senorblanco@chromium.org sigbjornf@opera.com skobes@chromium.org +svillar@igalia.com thakis@chromium.org timloh@chromium.org tkent@chromium.org
diff --git a/third_party/WebKit/Source/core/animation/AnimationStackTest.cpp b/third_party/WebKit/Source/core/animation/AnimationStackTest.cpp index c7ddd8b..9082448 100644 --- a/third_party/WebKit/Source/core/animation/AnimationStackTest.cpp +++ b/third_party/WebKit/Source/core/animation/AnimationStackTest.cpp
@@ -5,8 +5,8 @@ #include "core/animation/AnimationStack.h" #include "core/animation/AnimationClock.h" -#include "core/animation/AnimationTimeline.h" #include "core/animation/CompositorPendingAnimations.h" +#include "core/animation/DocumentTimeline.h" #include "core/animation/ElementAnimations.h" #include "core/animation/KeyframeEffectModel.h" #include "core/animation/LegacyStyleInterpolation.h" @@ -24,7 +24,7 @@ pageHolder = DummyPageHolder::create(); document = &pageHolder->document(); document->animationClock().resetTimeForTesting(); - timeline = AnimationTimeline::create(document.get()); + timeline = DocumentTimeline::create(document.get()); element = document->createElement("foo", ASSERT_NO_EXCEPTION); } @@ -82,7 +82,7 @@ std::unique_ptr<DummyPageHolder> pageHolder; Persistent<Document> document; - Persistent<AnimationTimeline> timeline; + Persistent<DocumentTimeline> timeline; Persistent<Element> element; };
diff --git a/third_party/WebKit/Source/core/animation/AnimationTimeline.h b/third_party/WebKit/Source/core/animation/AnimationTimeline.h index 382aacd0..9d3b34cd 100644 --- a/third_party/WebKit/Source/core/animation/AnimationTimeline.h +++ b/third_party/WebKit/Source/core/animation/AnimationTimeline.h
@@ -49,7 +49,7 @@ class AnimationEffect; // AnimationTimeline is constructed and owned by Document, and tied to its lifecycle. -class CORE_EXPORT AnimationTimeline final : public GarbageCollectedFinalized<AnimationTimeline>, public ScriptWrappable { +class CORE_EXPORT AnimationTimeline : public GarbageCollectedFinalized<AnimationTimeline>, public ScriptWrappable { DEFINE_WRAPPERTYPEINFO(); public: class PlatformTiming : public GarbageCollectedFinalized<PlatformTiming> { @@ -63,6 +63,8 @@ static AnimationTimeline* create(Document*, PlatformTiming* = nullptr); + virtual ~AnimationTimeline() {} + void serviceAnimations(TimingUpdateReason); void scheduleNextService();
diff --git a/third_party/WebKit/Source/core/animation/AnimationTimelineTest.cpp b/third_party/WebKit/Source/core/animation/AnimationTimelineTest.cpp index e3912b3..976c1d8 100644 --- a/third_party/WebKit/Source/core/animation/AnimationTimelineTest.cpp +++ b/third_party/WebKit/Source/core/animation/AnimationTimelineTest.cpp
@@ -339,20 +339,6 @@ updateClockAndService(4.98); } -TEST_F(AnimationAnimationTimelineTest, PlayAfterDocumentDeref) -{ - timing.iterationDuration = 2; - timing.startDelay = 5; - - timeline = &document->timeline(); - element = nullptr; - document = nullptr; - - KeyframeEffect* keyframeEffect = KeyframeEffect::create(0, nullptr, timing); - // Test passes if this does not crash. - timeline->play(keyframeEffect); -} - TEST_F(AnimationAnimationTimelineTest, UseAnimationAfterTimelineDeref) { Animation* animation = timeline->play(0);
diff --git a/third_party/WebKit/Source/core/animation/CSSVisibilityInterpolationType.cpp b/third_party/WebKit/Source/core/animation/CSSVisibilityInterpolationType.cpp index d0c5772..caf4773 100644 --- a/third_party/WebKit/Source/core/animation/CSSVisibilityInterpolationType.cpp +++ b/third_party/WebKit/Source/core/animation/CSSVisibilityInterpolationType.cpp
@@ -32,8 +32,8 @@ return m_start; if (fraction >= 1) return m_end; - if (m_start == VISIBLE || m_end == VISIBLE) - return VISIBLE; + if (m_start == EVisibility::Visible || m_end == EVisibility::Visible) + return EVisibility::Visible; return fraction < 0.5 ? m_start : m_end; } @@ -113,7 +113,7 @@ InterpolationValue CSSVisibilityInterpolationType::maybeConvertInitial(const StyleResolverState&, ConversionCheckers&) const { - return createVisibilityValue(VISIBLE); + return createVisibilityValue(EVisibility::Visible); } InterpolationValue CSSVisibilityInterpolationType::maybeConvertInherit(const StyleResolverState& state, ConversionCheckers& conversionCheckers) const
diff --git a/third_party/WebKit/Source/core/animation/CompositorAnimations.cpp b/third_party/WebKit/Source/core/animation/CompositorAnimations.cpp index 18afe756..a4083d93 100644 --- a/third_party/WebKit/Source/core/animation/CompositorAnimations.cpp +++ b/third_party/WebKit/Source/core/animation/CompositorAnimations.cpp
@@ -223,10 +223,6 @@ return true; } -// ----------------------------------------------------------------------- -// CompositorAnimations public API -// ----------------------------------------------------------------------- - bool CompositorAnimations::isCandidateForAnimationOnCompositor(const Timing& timing, const Element& targetElement, const Animation* animationToAdd, const EffectModel& effect, double animationPlaybackRate) { const KeyframeEffectModelBase& keyframeEffect = toKeyframeEffectModelBase(effect); @@ -241,7 +237,7 @@ return false; if (isTransformRelatedCSSProperty(property)) { - if (targetElement.layoutObject() && targetElement.layoutObject()->isInline() && !targetElement.layoutObject()->isInlineBlockOrInlineTable()) { + if (targetElement.layoutObject() && !targetElement.layoutObject()->isTransformApplicable()) { return false; } transformPropertyCount++; @@ -430,91 +426,31 @@ namespace { -template<typename PlatformAnimationCurveType, typename PlatformAnimationKeyframeType> -void addCompositorKeyframeWithTimingFunction(PlatformAnimationCurveType& curve, const PlatformAnimationKeyframeType& keyframe, const TimingFunction* timingFunction) -{ - if (!timingFunction) { - curve.addCubicBezierKeyframe(keyframe, *CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseType::EASE)); - return; - } - - switch (timingFunction->getType()) { - case TimingFunction::Type::LINEAR: - curve.addLinearKeyframe(keyframe); - break; - - case TimingFunction::Type::CUBIC_BEZIER: { - const CubicBezierTimingFunction& cubic = toCubicBezierTimingFunction(*timingFunction); - curve.addCubicBezierKeyframe(keyframe, cubic); - break; - } - - case TimingFunction::Type::STEPS: { - const StepsTimingFunction& steps = toStepsTimingFunction(*timingFunction); - curve.addStepsKeyframe(keyframe, steps); - break; - } - - default: - NOTREACHED(); - } -} - -template <typename PlatformAnimationCurveType> -void setTimingFunctionOnCurve(PlatformAnimationCurveType& curve, TimingFunction* timingFunction) -{ - if (!timingFunction) { - curve.setLinearTimingFunction(); - return; - } - - switch (timingFunction->getType()) { - case TimingFunction::Type::LINEAR: - curve.setLinearTimingFunction(); - break; - - case TimingFunction::Type::CUBIC_BEZIER: { - const CubicBezierTimingFunction& cubic = toCubicBezierTimingFunction(*timingFunction); - curve.setCubicBezierTimingFunction(cubic); - break; - } - - case TimingFunction::Type::STEPS: { - const StepsTimingFunction& steps = toStepsTimingFunction(*timingFunction); - curve.setStepsTimingFunction(steps); - break; - } - - default: - NOTREACHED(); - } -} - void addKeyframeToCurve(CompositorFilterAnimationCurve& curve, Keyframe::PropertySpecificKeyframe* keyframe, - const AnimatableValue* value, const TimingFunction* keyframeTimingFunction) + const AnimatableValue* value, const TimingFunction& keyframeTimingFunction) { std::unique_ptr<CompositorFilterOperations> ops = CompositorFilterOperations::create(); toCompositorFilterOperations(toAnimatableFilterOperations(value)->operations(), ops.get()); CompositorFilterKeyframe filterKeyframe(keyframe->offset(), std::move(ops)); - addCompositorKeyframeWithTimingFunction(curve, filterKeyframe, keyframeTimingFunction); + curve.addKeyframe(filterKeyframe, keyframeTimingFunction); } void addKeyframeToCurve(CompositorFloatAnimationCurve& curve, Keyframe::PropertySpecificKeyframe* keyframe, - const AnimatableValue* value, const TimingFunction* keyframeTimingFunction) + const AnimatableValue* value, const TimingFunction& keyframeTimingFunction) { CompositorFloatKeyframe floatKeyframe(keyframe->offset(), toAnimatableDouble(value)->toDouble()); - addCompositorKeyframeWithTimingFunction(curve, floatKeyframe, keyframeTimingFunction); + curve.addKeyframe(floatKeyframe, keyframeTimingFunction); } void addKeyframeToCurve(CompositorTransformAnimationCurve& curve, Keyframe::PropertySpecificKeyframe* keyframe, - const AnimatableValue* value, const TimingFunction* keyframeTimingFunction) + const AnimatableValue* value, const TimingFunction& keyframeTimingFunction) { std::unique_ptr<CompositorTransformOperations> ops = CompositorTransformOperations::create(); toCompositorTransformOperations(toAnimatableTransform(value)->transformOperations(), ops.get()); CompositorTransformKeyframe transformKeyframe(keyframe->offset(), std::move(ops)); - addCompositorKeyframeWithTimingFunction(curve, transformKeyframe, keyframeTimingFunction); + curve.addKeyframe(transformKeyframe, keyframeTimingFunction); } template <typename PlatformAnimationCurveType> @@ -523,16 +459,18 @@ auto* lastKeyframe = keyframes.last().get(); for (const auto& keyframe : keyframes) { const TimingFunction* keyframeTimingFunction = 0; - if (keyframe != lastKeyframe) { // Ignore timing function of last frame. + // Ignore timing function of last frame. + if (keyframe == lastKeyframe) + keyframeTimingFunction = LinearTimingFunction::shared(); + else keyframeTimingFunction = &keyframe->easing(); - } // FIXME: This relies on StringKeyframes being eagerly evaluated, which will // not happen eventually. Instead we should extract the CSSValue here // and convert using another set of toAnimatableXXXOperations functions. const AnimatableValue* value = keyframe->getAnimatableValue().get(); - addKeyframeToCurve(curve, keyframe.get(), value, keyframeTimingFunction); + addKeyframeToCurve(curve, keyframe.get(), value, *keyframeTimingFunction); } } @@ -560,12 +498,13 @@ CompositorTargetProperty::Type targetProperty; std::unique_ptr<CompositorAnimationCurve> curve; + DCHECK(timing.timingFunction); switch (property.cssProperty()) { case CSSPropertyOpacity: { targetProperty = CompositorTargetProperty::OPACITY; std::unique_ptr<CompositorFloatAnimationCurve> floatCurve = CompositorFloatAnimationCurve::create(); addKeyframesToCurve(*floatCurve, values); - setTimingFunctionOnCurve(*floatCurve, timing.timingFunction.get()); + floatCurve->setTimingFunction(*timing.timingFunction); curve = std::move(floatCurve); break; } @@ -574,7 +513,7 @@ targetProperty = CompositorTargetProperty::FILTER; std::unique_ptr<CompositorFilterAnimationCurve> filterCurve = CompositorFilterAnimationCurve::create(); addKeyframesToCurve(*filterCurve, values); - setTimingFunctionOnCurve(*filterCurve, timing.timingFunction.get()); + filterCurve->setTimingFunction(*timing.timingFunction); curve = std::move(filterCurve); break; } @@ -585,7 +524,7 @@ targetProperty = CompositorTargetProperty::TRANSFORM; std::unique_ptr<CompositorTransformAnimationCurve> transformCurve = CompositorTransformAnimationCurve::create(); addKeyframesToCurve(*transformCurve, values); - setTimingFunctionOnCurve(*transformCurve, timing.timingFunction.get()); + transformCurve->setTimingFunction(*timing.timingFunction); curve = std::move(transformCurve); break; }
diff --git a/third_party/WebKit/Source/core/animation/CompositorAnimationsTest.cpp b/third_party/WebKit/Source/core/animation/CompositorAnimationsTest.cpp index 7feb055..f4eb231 100644 --- a/third_party/WebKit/Source/core/animation/CompositorAnimationsTest.cpp +++ b/third_party/WebKit/Source/core/animation/CompositorAnimationsTest.cpp
@@ -658,7 +658,7 @@ EXPECT_EQ(1.0, keyframes[1].time); EXPECT_EQ(5.0f, keyframes[1].value); - EXPECT_EQ(CubicBezierTimingFunction::EaseType::EASE, keyframedFloatCurve->getKeyframeEaseTypeForTesting(1)); + EXPECT_TRUE(keyframedFloatCurve->keyframeHasLinearTimingFunctionForTesting(1)); } TEST_F(AnimationCompositorAnimationsTest, createSimpleOpacityAnimationDuration) @@ -719,7 +719,7 @@ EXPECT_EQ(1.0, keyframes[3].time); EXPECT_EQ(5.0f, keyframes[3].value); - EXPECT_EQ(CubicBezierTimingFunction::EaseType::EASE, keyframedFloatCurve->getKeyframeEaseTypeForTesting(3)); + EXPECT_TRUE(keyframedFloatCurve->keyframeHasLinearTimingFunctionForTesting(3)); } TEST_F(AnimationCompositorAnimationsTest, createSimpleOpacityAnimationStartDelay) @@ -794,7 +794,7 @@ EXPECT_EQ(2.0, keyframes[3].time); EXPECT_EQ(5.0f, keyframes[3].value); - EXPECT_EQ(CubicBezierTimingFunction::EaseType::EASE, keyframedFloatCurve->getKeyframeEaseTypeForTesting(3)); + EXPECT_TRUE(keyframedFloatCurve->keyframeHasLinearTimingFunctionForTesting(3)); } TEST_F(AnimationCompositorAnimationsTest, createReversedOpacityAnimation) @@ -844,7 +844,7 @@ EXPECT_EQ(1.0, keyframes[3].time); EXPECT_EQ(5.0f, keyframes[3].value); - EXPECT_EQ(CubicBezierTimingFunction::EaseType::EASE, keyframedFloatCurve->getKeyframeEaseTypeForTesting(3)); + EXPECT_TRUE(keyframedFloatCurve->keyframeHasLinearTimingFunctionForTesting(3)); } TEST_F(AnimationCompositorAnimationsTest, createReversedOpacityAnimationNegativeStartDelay) @@ -954,7 +954,7 @@ EXPECT_EQ(1.0, keyframes[1].time); EXPECT_EQ(5.0f, keyframes[1].value); - EXPECT_EQ(CubicBezierTimingFunction::EaseType::EASE, keyframedFloatCurve->getKeyframeEaseTypeForTesting(1)); + EXPECT_TRUE(keyframedFloatCurve->keyframeHasLinearTimingFunctionForTesting(1)); } TEST_F(AnimationCompositorAnimationsTest, cancelIncompatibleCompositorAnimations)
diff --git a/third_party/WebKit/Source/core/animation/CustomCompositorAnimations.cpp b/third_party/WebKit/Source/core/animation/CustomCompositorAnimations.cpp index 00aac40..c93db2da 100644 --- a/third_party/WebKit/Source/core/animation/CustomCompositorAnimations.cpp +++ b/third_party/WebKit/Source/core/animation/CustomCompositorAnimations.cpp
@@ -5,7 +5,7 @@ #include "CustomCompositorAnimations.h" #include "core/animation/Animation.h" -#include "core/animation/AnimationTimeline.h" +#include "core/animation/DocumentTimeline.h" #include "core/animation/KeyframeEffect.h" #include "core/animation/KeyframeEffectModel.h" #include "core/animation/animatable/AnimatableDouble.h"
diff --git a/third_party/WebKit/Source/core/animation/DocumentAnimation.h b/third_party/WebKit/Source/core/animation/DocumentAnimation.h index 7d6ab3f2..612b0f6e 100644 --- a/third_party/WebKit/Source/core/animation/DocumentAnimation.h +++ b/third_party/WebKit/Source/core/animation/DocumentAnimation.h
@@ -13,7 +13,7 @@ class DocumentAnimation { STATIC_ONLY(DocumentAnimation); public: - static AnimationTimeline* timeline(Document& document) { return &document.timeline(); } + static DocumentTimeline* timeline(Document& document) { return &document.timeline(); } }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/animation/DocumentAnimation.idl b/third_party/WebKit/Source/core/animation/DocumentAnimation.idl index 7e02888d..197e1b0 100644 --- a/third_party/WebKit/Source/core/animation/DocumentAnimation.idl +++ b/third_party/WebKit/Source/core/animation/DocumentAnimation.idl
@@ -7,6 +7,5 @@ [ RuntimeEnabled=WebAnimationsAPI, ] partial interface Document { - // TODO(dstockwell): This should be a DocumentTimeline. - readonly attribute AnimationTimeline timeline; + readonly attribute DocumentTimeline timeline; };
diff --git a/third_party/WebKit/Source/core/animation/DocumentAnimations.cpp b/third_party/WebKit/Source/core/animation/DocumentAnimations.cpp index 30b6208..4d47f10 100644 --- a/third_party/WebKit/Source/core/animation/DocumentAnimations.cpp +++ b/third_party/WebKit/Source/core/animation/DocumentAnimations.cpp
@@ -31,8 +31,8 @@ #include "core/animation/DocumentAnimations.h" #include "core/animation/AnimationClock.h" -#include "core/animation/AnimationTimeline.h" #include "core/animation/CompositorPendingAnimations.h" +#include "core/animation/DocumentTimeline.h" #include "core/dom/Document.h" #include "core/dom/Element.h" #include "core/dom/Node.h"
diff --git a/third_party/WebKit/Source/core/animation/DocumentTimeline.h b/third_party/WebKit/Source/core/animation/DocumentTimeline.h new file mode 100644 index 0000000..1d06ec4 --- /dev/null +++ b/third_party/WebKit/Source/core/animation/DocumentTimeline.h
@@ -0,0 +1,59 @@ +/* + * Copyright (C) 2013 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 DocumentTimeline_h +#define DocumentTimeline_h + +#include "bindings/core/v8/ScriptWrappable.h" +#include "core/CoreExport.h" +#include "core/animation/AnimationTimeline.h" + +namespace blink { + +class Document; + +class CORE_EXPORT DocumentTimeline final : public AnimationTimeline { + DEFINE_WRAPPERTYPEINFO(); +public: + static DocumentTimeline* create(Document* document) + { + return new DocumentTimeline(document); + } + +private: + DocumentTimeline(Document* document) + : AnimationTimeline(document, nullptr) {} + + friend class AnimationDocumentTimelineTest; +}; + +} // namespace blink + +#endif
diff --git a/third_party/WebKit/Source/core/animation/DocumentTimeline.idl b/third_party/WebKit/Source/core/animation/DocumentTimeline.idl new file mode 100644 index 0000000..62d7b8b8 --- /dev/null +++ b/third_party/WebKit/Source/core/animation/DocumentTimeline.idl
@@ -0,0 +1,10 @@ +// 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. + +// http://www.w3.org/TR/web-animations/#the-documenttimeline-interface + +[ + RuntimeEnabled=WebAnimationsAPI, +] interface DocumentTimeline : AnimationTimeline { +};
diff --git a/third_party/WebKit/Source/core/animation/DocumentTimelineTest.cpp b/third_party/WebKit/Source/core/animation/DocumentTimelineTest.cpp new file mode 100644 index 0000000..6fbdc6c --- /dev/null +++ b/third_party/WebKit/Source/core/animation/DocumentTimelineTest.cpp
@@ -0,0 +1,74 @@ +/* + * Copyright (c) 2013, 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 "core/animation/DocumentTimeline.h" + +#include "core/animation/KeyframeEffect.h" +#include "core/dom/Document.h" +#include "core/testing/DummyPageHolder.h" +#include "testing/gtest/include/gtest/gtest.h" +#include <memory> + +namespace blink { + +class AnimationDocumentTimelineTest : public ::testing::Test { +protected: + virtual void SetUp() + { + pageHolder = DummyPageHolder::create(); + document = &pageHolder->document(); + } + + virtual void TearDown() + { + document.release(); + ThreadHeap::collectAllGarbage(); + } + + std::unique_ptr<DummyPageHolder> pageHolder; + Persistent<Document> document; + Persistent<DocumentTimeline> timeline; + Timing timing; +}; + +TEST_F(AnimationDocumentTimelineTest, PlayAfterDocumentDeref) +{ + timing.iterationDuration = 2; + timing.startDelay = 5; + + timeline = &document->timeline(); + document = nullptr; + + KeyframeEffect* keyframeEffect = KeyframeEffect::create(0, nullptr, timing); + // Test passes if this does not crash. + timeline->play(keyframeEffect); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/animation/ElementAnimation.h b/third_party/WebKit/Source/core/animation/ElementAnimation.h index a21eb7b5..ce647b91 100644 --- a/third_party/WebKit/Source/core/animation/ElementAnimation.h +++ b/third_party/WebKit/Source/core/animation/ElementAnimation.h
@@ -32,7 +32,7 @@ #define ElementAnimation_h #include "bindings/core/v8/EffectModelOrDictionarySequenceOrDictionary.h" -#include "core/animation/AnimationTimeline.h" +#include "core/animation/DocumentTimeline.h" #include "core/animation/EffectInput.h" #include "core/animation/ElementAnimations.h" #include "core/animation/KeyframeEffect.h"
diff --git a/third_party/WebKit/Source/core/animation/KeyframeEffectTest.cpp b/third_party/WebKit/Source/core/animation/KeyframeEffectTest.cpp index 8f7ae0c..c38f847 100644 --- a/third_party/WebKit/Source/core/animation/KeyframeEffectTest.cpp +++ b/third_party/WebKit/Source/core/animation/KeyframeEffectTest.cpp
@@ -11,7 +11,7 @@ #include "core/animation/AnimationClock.h" #include "core/animation/AnimationEffectTiming.h" #include "core/animation/AnimationTestHelper.h" -#include "core/animation/AnimationTimeline.h" +#include "core/animation/DocumentTimeline.h" #include "core/animation/KeyframeEffectModel.h" #include "core/animation/Timing.h" #include "core/dom/Document.h"
diff --git a/third_party/WebKit/Source/core/animation/animatable/AnimatableValueTestHelper.cpp b/third_party/WebKit/Source/core/animation/animatable/AnimatableValueTestHelper.cpp index eef1bd1..ace2b8c3 100644 --- a/third_party/WebKit/Source/core/animation/animatable/AnimatableValueTestHelper.cpp +++ b/third_party/WebKit/Source/core/animation/animatable/AnimatableValueTestHelper.cpp
@@ -159,17 +159,17 @@ { *os << "AnimatableVisibility("; switch (animVisibility.visibility()) { - case VISIBLE: - *os << "VISIBLE"; + case EVisibility::Visible: + *os << "EVisibility::Visible"; break; - case HIDDEN: - *os << "HIDDEN"; + case EVisibility::Hidden: + *os << "EVisibility::Hidden"; break; - case COLLAPSE: - *os << "COLLAPSE"; + case EVisibility::Collapse: + *os << "EVisibility::Collapse"; break; default: - *os << "Unknown Visbilility - update switch in AnimatableValueTestHelper.h"; + *os << "Unknown Visibility - update switch in AnimatableValueTestHelper.h"; } *os << ")"; }
diff --git a/third_party/WebKit/Source/core/animation/animatable/AnimatableValueTestHelperTest.cpp b/third_party/WebKit/Source/core/animation/animatable/AnimatableValueTestHelperTest.cpp index 575e0c5..909370e 100644 --- a/third_party/WebKit/Source/core/animation/animatable/AnimatableValueTestHelperTest.cpp +++ b/third_party/WebKit/Source/core/animation/animatable/AnimatableValueTestHelperTest.cpp
@@ -81,8 +81,8 @@ PrintToString(AnimatableUnknown::create(CSSPrimitiveValue::createIdentifier(CSSValueNone)))); EXPECT_EQ( - ::std::string("AnimatableVisibility(VISIBLE)"), - PrintToString(AnimatableVisibility::create(VISIBLE))); + ::std::string("AnimatableVisibility(EVisibility::Visible)"), + PrintToString(AnimatableVisibility::create(EVisibility::Visible))); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/animation/animatable/AnimatableVisibility.cpp b/third_party/WebKit/Source/core/animation/animatable/AnimatableVisibility.cpp index f0bb4860..399130b 100644 --- a/third_party/WebKit/Source/core/animation/animatable/AnimatableVisibility.cpp +++ b/third_party/WebKit/Source/core/animation/animatable/AnimatableVisibility.cpp
@@ -36,20 +36,20 @@ { EVisibility from = m_visibility; EVisibility to = toAnimatableVisibility(value)->m_visibility; - return from != VISIBLE && to != VISIBLE; + return from != EVisibility::Visible && to != EVisibility::Visible; } PassRefPtr<AnimatableValue> AnimatableVisibility::interpolateTo(const AnimatableValue* value, double fraction) const { EVisibility from = m_visibility; EVisibility to = toAnimatableVisibility(value)->m_visibility; - if (from != VISIBLE && to != VISIBLE) + if (from != EVisibility::Visible && to != EVisibility::Visible) return defaultInterpolateTo(this, value, fraction); if (fraction <= 0) return takeConstRef(this); if (fraction >= 1) return takeConstRef(value); - return takeConstRef(from == VISIBLE ? this : value); + return takeConstRef(from == EVisibility::Visible ? this : value); } bool AnimatableVisibility::equalTo(const AnimatableValue* value) const
diff --git a/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp b/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp index 78a1c61..992284d 100644 --- a/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp +++ b/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp
@@ -32,8 +32,8 @@ #include "core/StylePropertyShorthand.h" #include "core/animation/Animation.h" -#include "core/animation/AnimationTimeline.h" #include "core/animation/CompositorAnimations.h" +#include "core/animation/DocumentTimeline.h" #include "core/animation/ElementAnimations.h" #include "core/animation/InertEffect.h" #include "core/animation/Interpolation.h"
diff --git a/third_party/WebKit/Source/core/core.gypi b/third_party/WebKit/Source/core/core.gypi index ea144c1..83cbac15 100644 --- a/third_party/WebKit/Source/core/core.gypi +++ b/third_party/WebKit/Source/core/core.gypi
@@ -11,6 +11,7 @@ 'animation/AnimationEffectTiming.idl', 'animation/Animation.idl', 'animation/AnimationTimeline.idl', + 'animation/DocumentTimeline.idl', 'clipboard/DataTransfer.idl', 'clipboard/DataTransferItemList.idl', 'css/CSS.idl', @@ -47,6 +48,7 @@ 'css/cssom/CSSNumberValue.idl', 'css/cssom/CSSPerspective.idl', 'css/cssom/CSSPositionValue.idl', + 'css/cssom/CSSResourceValue.idl', 'css/cssom/CSSRotation.idl', 'css/cssom/CSSScale.idl', 'css/cssom/CSSSimpleLength.idl', @@ -267,9 +269,6 @@ 'page/PagePopupController.idl', 'page/scrolling/ScrollState.idl', 'page/scrolling/ScrollStateCallback.idl', - 'streams/ReadableByteStream.idl', - 'streams/ReadableByteStreamReader.idl', - 'streams/ReadableStreamReader.idl', 'streams/Stream.idl', 'streams/UnderlyingSourceBase.idl', 'svg/SVGAElement.idl', @@ -541,14 +540,24 @@ 'layout/api/LineLayoutText.h', 'layout/api/LineLayoutTextCombine.h', 'layout/api/SelectionState.h', - 'layout/ng/LayoutNGBlockFlow.cpp', - 'layout/ng/LayoutNGBlockFlow.h', - 'layout/ng/NGBlockLayoutAlgorithm.cpp', - 'layout/ng/NGBlockLayoutAlgorithm.h', - 'layout/ng/NGConstraintSpace.cpp', - 'layout/ng/NGConstraintSpace.h', - 'layout/ng/NGFragment.cpp', - 'layout/ng/NGFragment.h', + 'layout/ng/layout_ng_block_flow.cc', + 'layout/ng/layout_ng_block_flow.h', + 'layout/ng/ng_block_layout_algorithm.cc', + 'layout/ng/ng_block_layout_algorithm.h', + 'layout/ng/ng_box.cc', + 'layout/ng/ng_box.h', + 'layout/ng/ng_constraint_space.cc', + 'layout/ng/ng_constraint_space.h', + 'layout/ng/ng_fragment_base.cc', + 'layout/ng/ng_fragment_base.h', + 'layout/ng/ng_fragment.cc', + 'layout/ng/ng_fragment.h', + 'layout/ng/ng_length_utils.cc', + 'layout/ng/ng_length_utils.h', + 'layout/ng/ng_margin_strut.h', + 'layout/ng/ng_text.cc', + 'layout/ng/ng_text.h', + 'layout/ng/ng_units.h', 'layout/BidiRun.h', 'layout/BidiRunForLine.cpp', 'layout/BidiRunForLine.h', @@ -960,6 +969,7 @@ 'animation/DocumentAnimation.h', 'animation/DocumentAnimations.cpp', 'animation/DocumentAnimations.h', + 'animation/DocumentTimeline.h', 'animation/EffectInput.cpp', 'animation/EffectInput.h', 'animation/ElementAnimation.h', @@ -1360,6 +1370,7 @@ 'css/cssom/CSSPerspective.h', 'css/cssom/CSSPositionValue.cpp', 'css/cssom/CSSPositionValue.h', + 'css/cssom/CSSResourceValue.h', 'css/cssom/CSSRotation.cpp', 'css/cssom/CSSRotation.h', 'css/cssom/CSSScale.cpp', @@ -2201,20 +2212,11 @@ 'paint/ViewPainter.cpp', 'paint/ViewPainter.h', 'plugins/PluginView.h', - 'streams/ReadableByteStream.cpp', - 'streams/ReadableByteStream.h', - 'streams/ReadableByteStreamReader.h', - 'streams/ReadableStream.cpp', - 'streams/ReadableStream.h', 'streams/ReadableStreamController.h', - 'streams/ReadableStreamImpl.h', 'streams/ReadableStreamOperations.cpp', 'streams/ReadableStreamOperations.h', - 'streams/ReadableStreamReader.cpp', - 'streams/ReadableStreamReader.h', 'streams/Stream.cpp', 'streams/Stream.h', - 'streams/UnderlyingSource.h', 'streams/UnderlyingSourceBase.h', 'streams/UnderlyingSourceBase.cpp', 'timing/DOMWindowPerformance.cpp', @@ -3997,6 +3999,7 @@ 'animation/AnimationTestHelper.h', 'animation/AnimationTimelineTest.cpp', 'animation/CompositorAnimationsTest.cpp', + 'animation/DocumentTimelineTest.cpp', 'animation/EffectInputTest.cpp', 'animation/InterpolableValueTest.cpp', 'animation/InterpolationEffectTest.cpp', @@ -4034,6 +4037,7 @@ 'css/RuleFeatureSetTest.cpp', 'css/RuleSetTest.cpp', 'css/StyleSheetContentsTest.cpp', + 'css/cssom/CSSResourceValueTest.cpp', 'css/cssom/CSSTokenStreamValueTest.cpp', 'css/cssom/CSSVariableReferenceValueTest.cpp', 'css/cssom/FilteredComputedStylePropertyMapTest.cpp', @@ -4203,6 +4207,7 @@ 'layout/TextAutosizerTest.cpp', 'layout/VisualRectMappingTest.cpp', 'layout/compositing/CompositedLayerMappingTest.cpp', + 'layout/ng/ng_block_layout_algorithm_test.cc', 'layout/shapes/BoxShapeTest.cpp', 'layout/svg/LayoutSVGRootTest.cpp', 'loader/DocumentLoadTimingTest.cpp', @@ -4230,6 +4235,7 @@ 'paint/PaintControllerPaintTest.h', 'paint/PaintInfoTest.cpp', 'paint/PaintLayerPainterTest.cpp', + 'paint/PaintLayerScrollableAreaTest.cpp', 'paint/PaintPropertyTreeBuilderTest.cpp', 'paint/StubChromeClientForSPv2.h', 'paint/SVGInlineTextBoxPainterTest.cpp', @@ -4237,8 +4243,6 @@ 'paint/TextPainterTest.cpp', 'paint/VideoPainterTest.cpp', 'streams/ReadableStreamOperationsTest.cpp', - 'streams/ReadableStreamReaderTest.cpp', - 'streams/ReadableStreamTest.cpp', 'style/ComputedStyleTest.cpp', 'style/OutlineValueTest.cpp', 'style/SVGComputedStyleTest.cpp',
diff --git a/third_party/WebKit/Source/core/css/CSSGradientValue.cpp b/third_party/WebKit/Source/core/css/CSSGradientValue.cpp index 462ce6b..0987781 100644 --- a/third_party/WebKit/Source/core/css/CSSGradientValue.cpp +++ b/third_party/WebKit/Source/core/css/CSSGradientValue.cpp
@@ -1053,6 +1053,11 @@ // width/height given by aspectRatio. inline FloatSize ellipseRadius(const FloatPoint& p, float aspectRatio) { + // If the aspectRatio is 0 or infinite, the ellipse is completely flat. + // TODO(sashab): Implement Degenerate Radial Gradients, see crbug.com/635727. + if (aspectRatio == 0 || std::isinf(aspectRatio)) + return FloatSize(0, 0); + // x^2/a^2 + y^2/b^2 = 1 // a/b = aspectRatio, b = a/aspectRatio // a = sqrt(x^2 + y^2/(1/r^2))
diff --git a/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h b/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h index 574b331..dd8e963 100644 --- a/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h +++ b/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h
@@ -2509,13 +2509,13 @@ { init(UnitType::ValueID); switch (e) { - case VISIBLE: + case EVisibility::Visible: m_value.valueID = CSSValueVisible; break; - case HIDDEN: + case EVisibility::Hidden: m_value.valueID = CSSValueHidden; break; - case COLLAPSE: + case EVisibility::Collapse: m_value.valueID = CSSValueCollapse; break; } @@ -2526,17 +2526,17 @@ ASSERT(isValueID()); switch (m_value.valueID) { case CSSValueHidden: - return HIDDEN; + return EVisibility::Hidden; case CSSValueVisible: - return VISIBLE; + return EVisibility::Visible; case CSSValueCollapse: - return COLLAPSE; + return EVisibility::Collapse; default: break; } ASSERT_NOT_REACHED(); - return VISIBLE; + return EVisibility::Visible; } template<> inline CSSPrimitiveValue::CSSPrimitiveValue(EWhiteSpace e)
diff --git a/third_party/WebKit/Source/core/css/cssom/CSSResourceValue.h b/third_party/WebKit/Source/core/css/cssom/CSSResourceValue.h new file mode 100644 index 0000000..50d0993 --- /dev/null +++ b/third_party/WebKit/Source/core/css/cssom/CSSResourceValue.h
@@ -0,0 +1,53 @@ +// 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 CSSResourceValue_h +#define CSSResourceValue_h + +#include "core/css/cssom/CSSStyleValue.h" + +#include "core/fetch/Resource.h" + +namespace blink { + +class CORE_EXPORT CSSResourceValue : public CSSStyleValue { + WTF_MAKE_NONCOPYABLE(CSSResourceValue); + DEFINE_WRAPPERTYPEINFO(); +public: + virtual ~CSSResourceValue() { } + + StyleValueType type() const override { return ResourceType; } + + const String state() const + { + switch (status()) { + case Resource::Status::NotStarted: + return "unloaded"; + case Resource::Status::Pending: + return "loading"; + case Resource::Status::Cached: + return "loaded"; + case Resource::Status::LoadError: + case Resource::Status::DecodeError: + return "error"; + default: + NOTREACHED(); + return ""; + } + } + + DEFINE_INLINE_VIRTUAL_TRACE() + { + CSSStyleValue::trace(visitor); + } + +protected: + CSSResourceValue() { } + + virtual Resource::Status status() const = 0; +}; + +} // namespace blink + +#endif // CSSResourceValue_h
diff --git a/third_party/WebKit/Source/core/css/cssom/CSSResourceValue.idl b/third_party/WebKit/Source/core/css/cssom/CSSResourceValue.idl new file mode 100644 index 0000000..05f927e --- /dev/null +++ b/third_party/WebKit/Source/core/css/cssom/CSSResourceValue.idl
@@ -0,0 +1,14 @@ +// 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. + +enum CSSResourceState { + "unloaded", "loading", "loaded", "error" +}; + +[ + Exposed=(Window,PaintWorklet), + RuntimeEnabled=CSSTypedOM, +] interface CSSResourceValue : CSSStyleValue { + readonly attribute CSSResourceState state; +};
diff --git a/third_party/WebKit/Source/core/css/cssom/CSSResourceValueTest.cpp b/third_party/WebKit/Source/core/css/cssom/CSSResourceValueTest.cpp new file mode 100644 index 0000000..c31c88a --- /dev/null +++ b/third_party/WebKit/Source/core/css/cssom/CSSResourceValueTest.cpp
@@ -0,0 +1,40 @@ +// 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 "core/css/cssom/CSSResourceValue.h" + +#include "testing/gtest/include/gtest/gtest.h" + +namespace blink { + +namespace { + +class FakeCSSResourceValue : public CSSResourceValue { +public: + FakeCSSResourceValue(Resource::Status status) + : m_status(status) + { + } + + CSSValue* toCSSValue() const override { return nullptr; } + + Resource::Status status() const override { return m_status; } + +private: + Resource::Status m_status; +}; + + +TEST(CSSResourceValueTest, TestStatus) +{ + EXPECT_EQ((new FakeCSSResourceValue(Resource::NotStarted))->state(), "unloaded"); + EXPECT_EQ((new FakeCSSResourceValue(Resource::Pending))->state(), "loading"); + EXPECT_EQ((new FakeCSSResourceValue(Resource::Cached))->state(), "loaded"); + EXPECT_EQ((new FakeCSSResourceValue(Resource::LoadError))->state(), "error"); + EXPECT_EQ((new FakeCSSResourceValue(Resource::DecodeError))->state(), "error"); +} + +} // namespace + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/css/cssom/CSSStyleValue.h b/third_party/WebKit/Source/core/css/cssom/CSSStyleValue.h index 5e2c3cdd..8e919d7 100644 --- a/third_party/WebKit/Source/core/css/cssom/CSSStyleValue.h +++ b/third_party/WebKit/Source/core/css/cssom/CSSStyleValue.h
@@ -27,6 +27,7 @@ KeywordType, NumberType, PositionType, + ResourceType, SimpleLengthType, TokenStreamType, TransformType,
diff --git a/third_party/WebKit/Source/core/css/cssom/InlineStylePropertyMap.cpp b/third_party/WebKit/Source/core/css/cssom/InlineStylePropertyMap.cpp index 4329990..06b39b2 100644 --- a/third_party/WebKit/Source/core/css/cssom/InlineStylePropertyMap.cpp +++ b/third_party/WebKit/Source/core/css/cssom/InlineStylePropertyMap.cpp
@@ -50,11 +50,24 @@ Vector<String> InlineStylePropertyMap::getProperties() { + DEFINE_STATIC_LOCAL(const String, kAtApply, ("@apply")); Vector<String> result; + bool containsAtApply = false; StylePropertySet& inlineStyleSet = m_ownerElement->ensureMutableInlineStyle(); for (unsigned i = 0; i < inlineStyleSet.propertyCount(); i++) { CSSPropertyID propertyID = inlineStyleSet.propertyAt(i).id(); - result.append(getPropertyNameString(propertyID)); + if (propertyID == CSSPropertyVariable) { + StylePropertySet::PropertyReference propertyReference = inlineStyleSet.propertyAt(i); + const CSSCustomPropertyDeclaration& customDeclaration = toCSSCustomPropertyDeclaration(propertyReference.value()); + result.append(customDeclaration.name()); + } else if (propertyID == CSSPropertyApplyAtRule) { + if (!containsAtApply) { + result.append(kAtApply); + containsAtApply = true; + } + } else { + result.append(getPropertyNameString(propertyID)); + } } return result; } @@ -146,6 +159,7 @@ HeapVector<StylePropertyMap::StylePropertyMapEntry> InlineStylePropertyMap::getIterationEntries() { + DEFINE_STATIC_LOCAL(const String, kAtApply, ("@apply")); HeapVector<StylePropertyMap::StylePropertyMapEntry> result; StylePropertySet& inlineStyleSet = m_ownerElement->ensureMutableInlineStyle(); for (unsigned i = 0; i < inlineStyleSet.propertyCount(); i++) { @@ -159,7 +173,7 @@ // TODO(meade): Eventually custom properties will support other types, so actually return them instead of always returning a CSSUnsupportedStyleValue. value.setCSSStyleValue(CSSUnsupportedStyleValue::create(customDeclaration.customCSSText())); } else if (propertyID == CSSPropertyApplyAtRule) { - name = "@apply"; + name = kAtApply; value.setCSSStyleValue(CSSUnsupportedStyleValue::create(toCSSCustomIdentValue(propertyReference.value()).value())); } else { name = getPropertyNameString(propertyID);
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleAdjuster.cpp b/third_party/WebKit/Source/core/css/resolver/StyleAdjuster.cpp index 90e4221c..0b4bbc53 100644 --- a/third_party/WebKit/Source/core/css/resolver/StyleAdjuster.cpp +++ b/third_party/WebKit/Source/core/css/resolver/StyleAdjuster.cpp
@@ -382,7 +382,8 @@ if (doesNotInheritTextDecoration(style, element)) style.clearAppliedTextDecorations(); - + else + style.restoreParentTextDecorations(parentStyle); style.applyTextDecorations(); // Cull out any useless layers and also repeat patterns into additional layers.
diff --git a/third_party/WebKit/Source/core/dom/ContainerNode.cpp b/third_party/WebKit/Source/core/dom/ContainerNode.cpp index d79ca295..56e6d7f 100644 --- a/third_party/WebKit/Source/core/dom/ContainerNode.cpp +++ b/third_party/WebKit/Source/core/dom/ContainerNode.cpp
@@ -1229,6 +1229,9 @@ if (!hasRestyleFlag(ChildrenAffectedByStructuralRules)) return; + Element* elementAfterChange = !nodeAfterChange || nodeAfterChange->isElementNode() ? toElement(nodeAfterChange) : ElementTraversal::nextSibling(*nodeAfterChange); + Element* elementBeforeChange = !nodeBeforeChange || nodeBeforeChange->isElementNode() ? toElement(nodeBeforeChange) : ElementTraversal::previousSibling(*nodeBeforeChange); + // Forward positional selectors include :nth-child, :nth-of-type, // :first-of-type, and only-of-type. The indirect adjacent selector is the ~ // selector. Backward positional selectors include :nth-last-child, @@ -1241,15 +1244,12 @@ // don't want to make childrenChanged O(n^2) by crawling all our kids here. // recalcStyle will then force a walk of the children when it sees that this // has happened. - if ((childrenAffectedByForwardPositionalRules() && nodeAfterChange) - || (childrenAffectedByBackwardPositionalRules() && nodeBeforeChange)) { + if ((childrenAffectedByForwardPositionalRules() && elementAfterChange) + || (childrenAffectedByBackwardPositionalRules() && elementBeforeChange)) { setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::SiblingSelector)); return; } - Element* elementAfterChange = !nodeAfterChange || nodeAfterChange->isElementNode() ? toElement(nodeAfterChange) : ElementTraversal::nextSibling(*nodeAfterChange); - Element* elementBeforeChange = !nodeBeforeChange || nodeBeforeChange->isElementNode() ? toElement(nodeBeforeChange) : ElementTraversal::previousSibling(*nodeBeforeChange); - if (childrenAffectedByFirstChildRules() && !elementBeforeChange && elementAfterChange && elementAfterChange->affectedByFirstChildRules()) { DCHECK_NE(changeType, FinishedParsingChildren); elementAfterChange->pseudoStateChanged(CSSSelector::PseudoFirstChild);
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp index f520860..749d9d1 100644 --- a/third_party/WebKit/Source/core/dom/Document.cpp +++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -45,9 +45,9 @@ #include "core/SVGNames.h" #include "core/XMLNSNames.h" #include "core/XMLNames.h" -#include "core/animation/AnimationTimeline.h" #include "core/animation/CompositorPendingAnimations.h" #include "core/animation/DocumentAnimations.h" +#include "core/animation/DocumentTimeline.h" #include "core/css/CSSFontSelector.h" #include "core/css/CSSStyleDeclaration.h" #include "core/css/CSSStyleSheet.h" @@ -446,7 +446,7 @@ , m_taskRunner(MainThreadTaskRunner::create(this)) , m_registrationContext(initializer.registrationContext(this)) , m_elementDataCacheClearTimer(this, &Document::elementDataCacheClearTimerFired) - , m_timeline(AnimationTimeline::create(this)) + , m_timeline(DocumentTimeline::create(this)) , m_compositorPendingAnimations(new CompositorPendingAnimations()) , m_templateDocumentHost(nullptr) , m_didAssociateFormControlsTimer(this, &Document::didAssociateFormControlsTimerFired) @@ -1996,7 +1996,7 @@ bool Document::isPageBoxVisible(int pageIndex) { - return styleForPage(pageIndex)->visibility() != HIDDEN; // display property doesn't apply to @page. + return styleForPage(pageIndex)->visibility() != EVisibility::Hidden; // display property doesn't apply to @page. } void Document::pageSizeAndMarginsInPixels(int pageIndex, DoubleSize& pageSize, int& marginTop, int& marginRight, int& marginBottom, int& marginLeft) @@ -3795,9 +3795,9 @@ } if (LocalFrame* frame = this->frame()) { + frame->selection().nodeChildrenWillBeRemoved(container); for (Node& n : NodeTraversal::childrenOf(container)) { frame->eventHandler().nodeWillBeRemoved(n); - frame->selection().nodeWillBeRemoved(n); frame->page()->dragCaretController().nodeWillBeRemoved(n); } }
diff --git a/third_party/WebKit/Source/core/dom/Document.h b/third_party/WebKit/Source/core/dom/Document.h index 2d874b3..a987a54 100644 --- a/third_party/WebKit/Source/core/dom/Document.h +++ b/third_party/WebKit/Source/core/dom/Document.h
@@ -61,7 +61,7 @@ namespace blink { class AnimationClock; -class AnimationTimeline; +class DocumentTimeline; class AXObjectCache; class Attr; class CDATASection; @@ -993,7 +993,7 @@ Locale& getCachedLocale(const AtomicString& locale = nullAtom); AnimationClock& animationClock(); - AnimationTimeline& timeline() const { return *m_timeline; } + DocumentTimeline& timeline() const { return *m_timeline; } CompositorPendingAnimations& compositorPendingAnimations() { return *m_compositorPendingAnimations; } void addToTopLayer(Element*, const Element* before = nullptr); @@ -1385,7 +1385,7 @@ using LocaleIdentifierToLocaleMap = HashMap<AtomicString, std::unique_ptr<Locale>>; LocaleIdentifierToLocaleMap m_localeCache; - Member<AnimationTimeline> m_timeline; + Member<DocumentTimeline> m_timeline; Member<CompositorPendingAnimations> m_compositorPendingAnimations; Member<Document> m_templateDocument;
diff --git a/third_party/WebKit/Source/core/dom/DocumentStatisticsCollector.cpp b/third_party/WebKit/Source/core/dom/DocumentStatisticsCollector.cpp index 62515ecb..e2f6ae00 100644 --- a/third_party/WebKit/Source/core/dom/DocumentStatisticsCollector.cpp +++ b/third_party/WebKit/Source/core/dom/DocumentStatisticsCollector.cpp
@@ -64,7 +64,7 @@ return false; return ( style->display() != NONE - && style->visibility() != HIDDEN + && style->visibility() != EVisibility::Hidden && style->opacity() != 0 ); }
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp index 499b9ea..66d497b9 100644 --- a/third_party/WebKit/Source/core/dom/Element.cpp +++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -241,12 +241,12 @@ if (isInCanvasSubtree()) { const HTMLCanvasElement* canvas = Traversal<HTMLCanvasElement>::firstAncestorOrSelf(*this); DCHECK(canvas); - return canvas->layoutObject() && canvas->layoutObject()->style()->visibility() == VISIBLE; + return canvas->layoutObject() && canvas->layoutObject()->style()->visibility() == EVisibility::Visible; } // FIXME: Even if we are not visible, we might have a child that is visible. // Hyatt wants to fix that some day with a "has visible content" flag or the like. - return layoutObject() && layoutObject()->style()->visibility() == VISIBLE; + return layoutObject() && layoutObject()->style()->visibility() == EVisibility::Visible; } Node* Element::cloneNode(bool deep) @@ -2755,6 +2755,11 @@ } } +bool Element::hasPointerCapture(int pointerId) +{ + return document().frame() && document().frame()->eventHandler().hasPointerCapture(pointerId, this); +} + String Element::innerText() { // We need to update layout, since plainText uses line boxes in the layout tree.
diff --git a/third_party/WebKit/Source/core/dom/Element.h b/third_party/WebKit/Source/core/dom/Element.h index b35cb50..bf54f522 100644 --- a/third_party/WebKit/Source/core/dom/Element.h +++ b/third_party/WebKit/Source/core/dom/Element.h
@@ -452,6 +452,7 @@ void setPointerCapture(int pointerId, ExceptionState&); void releasePointerCapture(int pointerId, ExceptionState&); + bool hasPointerCapture(int pointerId); String textFromChildren();
diff --git a/third_party/WebKit/Source/core/dom/Element.idl b/third_party/WebKit/Source/core/dom/Element.idl index c8a7b62..488dae9e 100644 --- a/third_party/WebKit/Source/core/dom/Element.idl +++ b/third_party/WebKit/Source/core/dom/Element.idl
@@ -38,6 +38,11 @@ // PointerEvent (http://www.w3.org/TR/pointerevents/#extensions-to-the-element-interface) [RuntimeEnabled=PointerEvent, RaisesException] void setPointerCapture (long pointerId); [RuntimeEnabled=PointerEvent, RaisesException] void releasePointerCapture (long pointerId); + [RuntimeEnabled=PointerEvent] attribute EventHandler ongotpointercapture; + [RuntimeEnabled=PointerEvent] attribute EventHandler onlostpointercapture; + + // PointerEvent v2 (https://w3c.github.io/pointerevents/#extensions-to-the-element-interface) + [RuntimeEnabled=PointerEvent] boolean hasPointerCapture (long pointerId); boolean hasAttributes(); [SameObject, PerWorldBindings, ImplementedAs=attributesForBindings] readonly attribute NamedNodeMap attributes; @@ -130,11 +135,6 @@ attribute EventHandler onsearch; attribute EventHandler onselectstart; attribute EventHandler onwheel; - - // Pointerevent attributes (http://www.w3.org/TR/pointerevents/#extensions-to-the-element-interface) - [RuntimeEnabled=PointerEvent] attribute EventHandler ongotpointercapture; - [RuntimeEnabled=PointerEvent] attribute EventHandler onlostpointercapture; - }; Element implements ParentNode;
diff --git a/third_party/WebKit/Source/core/dom/ExceptionCode.h b/third_party/WebKit/Source/core/dom/ExceptionCode.h index 5bda96b..68c7410 100644 --- a/third_party/WebKit/Source/core/dom/ExceptionCode.h +++ b/third_party/WebKit/Source/core/dom/ExceptionCode.h
@@ -92,7 +92,7 @@ }; enum V8ErrorType { - V8GeneralError = 1000, + V8Error = 1000, V8TypeError, V8RangeError, V8SyntaxError,
diff --git a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp index ea786f0..471a724 100644 --- a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp +++ b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
@@ -370,10 +370,10 @@ const ContentSecurityPolicy* csp = elementDocument->contentSecurityPolicy(); bool shouldBypassMainWorldCSP = (frame && frame->script().shouldBypassMainWorldCSP()) - || csp->allowScriptWithHash(sourceCode.source().toString(), ContentSecurityPolicy::InlineType::Block) + || csp->allowScriptWithHash(sourceCode.source(), ContentSecurityPolicy::InlineType::Block) || (!isParserInserted() && csp->allowDynamic()); - if (!m_isExternalScript && (!shouldBypassMainWorldCSP && !csp->allowInlineScript(elementDocument->url(), m_element->fastGetAttribute(HTMLNames::nonceAttr), m_startLineNumber, sourceCode.source().toString()))) { + if (!m_isExternalScript && (!shouldBypassMainWorldCSP && !csp->allowInlineScript(elementDocument->url(), m_element->fastGetAttribute(HTMLNames::nonceAttr), m_startLineNumber, sourceCode.source()))) { return false; }
diff --git a/third_party/WebKit/Source/core/dom/StyleEngine.cpp b/third_party/WebKit/Source/core/dom/StyleEngine.cpp index a15af6c..cb6e0a484 100644 --- a/third_party/WebKit/Source/core/dom/StyleEngine.cpp +++ b/third_party/WebKit/Source/core/dom/StyleEngine.cpp
@@ -28,7 +28,7 @@ #include "core/dom/StyleEngine.h" #include "core/HTMLNames.h" -#include "core/animation/AnimationTimeline.h" +#include "core/animation/DocumentTimeline.h" #include "core/css/CSSDefaultStyleSheets.h" #include "core/css/CSSFontSelector.h" #include "core/css/CSSStyleSheet.h"
diff --git a/third_party/WebKit/Source/core/editing/EditingUtilities.cpp b/third_party/WebKit/Source/core/editing/EditingUtilities.cpp index f3f043b..05f2fd0 100644 --- a/third_party/WebKit/Source/core/editing/EditingUtilities.cpp +++ b/third_party/WebKit/Source/core/editing/EditingUtilities.cpp
@@ -1462,7 +1462,7 @@ if (!layoutObject) return false; - return layoutObject->style()->visibility() == VISIBLE; + return layoutObject->style()->visibility() == EVisibility::Visible; } // return first preceding DOM position rendered at a different location, or "this"
diff --git a/third_party/WebKit/Source/core/editing/FrameSelection.cpp b/third_party/WebKit/Source/core/editing/FrameSelection.cpp index e8f1728..ba33e45 100644 --- a/third_party/WebKit/Source/core/editing/FrameSelection.cpp +++ b/third_party/WebKit/Source/core/editing/FrameSelection.cpp
@@ -243,19 +243,17 @@ m_originalBase = createVisiblePosition(toPositionInDOMTree(newBase.deepEquivalent())); } -template <typename Strategy> -void FrameSelection::setNonDirectionalSelectionIfNeededAlgorithm(const VisibleSelectionTemplate<Strategy>& passedNewSelection, TextGranularity granularity, - EndPointsAdjustmentMode endpointsAdjustmentMode) +void FrameSelection::setNonDirectionalSelectionIfNeeded(const VisibleSelectionInFlatTree& passedNewSelection, TextGranularity granularity, EndPointsAdjustmentMode endpointsAdjustmentMode) { - VisibleSelectionTemplate<Strategy> newSelection = passedNewSelection; + VisibleSelectionInFlatTree newSelection = passedNewSelection; bool isDirectional = shouldAlwaysUseDirectionalSelection(m_frame) || newSelection.isDirectional(); - const PositionTemplate<Strategy> basePosition = this->originalBase<Strategy>().deepEquivalent(); - const VisiblePositionTemplate<Strategy> originalBase = basePosition.isConnected() ? createVisiblePosition(basePosition) : VisiblePositionTemplate<Strategy>(); - const VisiblePositionTemplate<Strategy> base = originalBase.isNotNull() ? originalBase : createVisiblePosition(newSelection.base()); - VisiblePositionTemplate<Strategy> newBase = base; - const VisiblePositionTemplate<Strategy> extent = createVisiblePosition(newSelection.extent()); - VisiblePositionTemplate<Strategy> newExtent = extent; + const PositionInFlatTree basePosition = m_originalBaseInFlatTree.deepEquivalent(); + const VisiblePositionInFlatTree originalBase = basePosition.isConnected() ? createVisiblePosition(basePosition) : VisiblePositionInFlatTree(); + const VisiblePositionInFlatTree base = originalBase.isNotNull() ? originalBase : createVisiblePosition(newSelection.base()); + VisiblePositionInFlatTree newBase = base; + const VisiblePositionInFlatTree extent = createVisiblePosition(newSelection.extent()); + VisiblePositionInFlatTree newExtent = extent; if (endpointsAdjustmentMode == AdjustEndpointsAtBidiBoundary) adjustEndpointsAtBidiBoundary(newBase, newExtent); @@ -264,25 +262,20 @@ newSelection.setBase(newBase); newSelection.setExtent(newExtent); } else if (originalBase.isNotNull()) { - if (visibleSelection<Strategy>().base() == newSelection.base()) + if (visibleSelection<EditingInFlatTreeStrategy>().base() == newSelection.base()) newSelection.setBase(originalBase); - setOriginalBase(VisiblePositionTemplate<Strategy>()); + setOriginalBase(VisiblePositionInFlatTree()); } // Adjusting base and extent will make newSelection always directional newSelection.setIsDirectional(isDirectional); - if (visibleSelection<Strategy>() == newSelection) + if (visibleSelection<EditingInFlatTreeStrategy>() == newSelection) return; const SetSelectionOptions options = CloseTyping | ClearTypingStyle; setSelection(newSelection, options, CursorAlignOnScroll::IfNeeded, granularity); } -void FrameSelection::setNonDirectionalSelectionIfNeeded(const VisibleSelectionInFlatTree& passedNewSelection, TextGranularity granularity, EndPointsAdjustmentMode endpointsAdjustmentMode) -{ - setNonDirectionalSelectionIfNeededAlgorithm<EditingInFlatTreeStrategy>(passedNewSelection, granularity, endpointsAdjustmentMode); -} - template <typename Strategy> void FrameSelection::setSelectionAlgorithm(const VisibleSelectionTemplate<Strategy>& newSelection, SetSelectionOptions options, CursorAlignOnScroll align, TextGranularity granularity) { @@ -406,6 +399,38 @@ return element.isShadowIncludingInclusiveAncestorOf(position.anchorNode()); } +static Position computePositionForChildrenRemoval(const Position& position, ContainerNode& container) +{ + Node* node = position.computeContainerNode(); + if (container.containsIncludingHostElements(*node)) + return Position::firstPositionInNode(&container); + return position; +} + +void FrameSelection::nodeChildrenWillBeRemoved(ContainerNode& container) +{ + if (isNone() || !container.inActiveDocument()) + return; + const Position& oldStart = selection().start(); + const Position& newStart = computePositionForChildrenRemoval(oldStart, container); + const Position& oldEnd = selection().end(); + const Position& newEnd = computePositionForChildrenRemoval(oldEnd, container); + const Position& oldBase = selection().base(); + const Position& newBase = computePositionForChildrenRemoval(oldBase, container); + const Position& oldExtent = selection().extent(); + const Position& newExtent = computePositionForChildrenRemoval(oldExtent, container); + if (newStart == oldStart && newEnd == oldEnd && newBase == oldBase && newExtent == oldExtent) + return; + if (selection().isBaseFirst()) + m_selectionEditor->setWithoutValidation(newStart, newEnd); + else + m_selectionEditor->setWithoutValidation(newEnd, newStart); + m_frameCaret->setCaretRectNeedsUpdate(); + if (document().isRunningExecCommand()) + return; + TypingCommand::closeTyping(m_frame); +} + void FrameSelection::nodeWillBeRemoved(Node& node) { // There can't be a selection inside a fragment, so if a fragment's node is being removed,
diff --git a/third_party/WebKit/Source/core/editing/FrameSelection.h b/third_party/WebKit/Source/core/editing/FrameSelection.h index f50aa62..f009984c 100644 --- a/third_party/WebKit/Source/core/editing/FrameSelection.h +++ b/third_party/WebKit/Source/core/editing/FrameSelection.h
@@ -174,6 +174,7 @@ void documentAttached(Document*); void documentDetached(const Document&); + void nodeChildrenWillBeRemoved(ContainerNode&); void nodeWillBeRemoved(Node&); void dataWillChange(const CharacterData& node); void didUpdateCharacterData(CharacterData*, unsigned offset, unsigned oldLength, unsigned newLength); @@ -260,9 +261,6 @@ void setOriginalBase(const VisiblePositionInFlatTree&); template <typename Strategy> - void setNonDirectionalSelectionIfNeededAlgorithm(const VisibleSelectionTemplate<Strategy>&, TextGranularity, EndPointsAdjustmentMode); - - template <typename Strategy> void setSelectionAlgorithm(const VisibleSelectionTemplate<Strategy>&, SetSelectionOptions, CursorAlignOnScroll, TextGranularity); void respondToNodeModification(Node&, bool baseRemoved, bool extentRemoved, bool startRemoved, bool endRemoved);
diff --git a/third_party/WebKit/Source/core/editing/InputMethodController.cpp b/third_party/WebKit/Source/core/editing/InputMethodController.cpp index c093057..fd9f11c 100644 --- a/third_party/WebKit/Source/core/editing/InputMethodController.cpp +++ b/third_party/WebKit/Source/core/editing/InputMethodController.cpp
@@ -321,11 +321,6 @@ if (!target) return; - int selectionOffsetsStart = static_cast<int>(getSelectionOffsets().start()); - int start = selectionOffsetsStart + selectionStart; - int end = selectionOffsetsStart + selectionEnd; - PlainTextRange selectedRange = createRangeForSelection(start, end, text.length()); - // Dispatch an appropriate composition event to the focused node. // We check the composition status and choose an appropriate composition event since this // function is used for three purposes: @@ -344,13 +339,11 @@ if (text.isEmpty()) { if (hasComposition()) { confirmComposition(emptyString()); - } else { - // It's weird to call |setComposition()| with empty text outside composition, however some IME - // (e.g. Japanese IBus-Anthy) did this, so we simply delete selection without sending extra events. - TypingCommand::deleteSelection(*frame().document(), TypingCommand::PreventSpellChecking); + return; } - - setEditableSelectionOffsets(selectedRange); + // It's weird to call |setComposition()| with empty text outside composition, however some IME + // (e.g. Japanese IBus-Anthy) did this, so we simply delete selection without sending extra events. + TypingCommand::deleteSelection(*frame().document(), TypingCommand::PreventSpellChecking); return; } @@ -401,7 +394,31 @@ if (baseNode->layoutObject()) baseNode->layoutObject()->setShouldDoFullPaintInvalidation(); - setEditableSelectionOffsets(selectedRange); + // In case of exceeding the left boundary. + int selectionOffsetsStart = static_cast<int>(getSelectionOffsets().start()); + int start = std::max(selectionOffsetsStart + selectionStart, 0); + int end = std::max(selectionOffsetsStart + selectionEnd, start); + + Element* rootEditableElement = frame().selection().rootEditableElement(); + if (!rootEditableElement) + return; + + // In case of exceeding the right boundary. + // If both |value1| and |value2| exceed right boundary, + // PlainTextRange(value1, value2)::createRange() will return a default + // value, which is [0,0]. In order to get the correct Position in that case, + // we should make sure |value1| is within range at least. + const EphemeralRange& startRange = PlainTextRange(0, start).createRange(*rootEditableElement); + const EphemeralRange& endRange = PlainTextRange(0, end).createRange(*rootEditableElement); + + // TODO(yabinh): There should be a better way to create |startPosition| and + // |endPosition|. But for now, since we can't get |anchorNode| and |offset|, + // we can't create the 2 Position objects directly. So we use + // PlainTextRange::createRange as a workaround. + const Position& startPosition = startRange.endPosition(); + const Position& endPosition = endRange.endPosition(); + const EphemeralRange selectedRange(startPosition, endPosition); + frame().selection().setSelectedRange(selectedRange, TextAffinity::Downstream, SelectionDirectionalMode::NonDirectional, NotUserTriggered); if (underlines.isEmpty()) { frame().document()->markers().addCompositionMarker(m_compositionRange->startPosition(), m_compositionRange->endPosition(), Color::black, false, LayoutTheme::theme().platformDefaultCompositionBackgroundColor()); @@ -500,7 +517,7 @@ if (range.isNull()) return false; - return frame().selection().setSelectedRange(range, VP_DEFAULT_AFFINITY, SelectionDirectionalMode::NonDirectional, NotUserTriggered); + return frame().selection().setSelectedRange(range, VP_DEFAULT_AFFINITY, SelectionDirectionalMode::NonDirectional, FrameSelection::CloseTyping); } bool InputMethodController::setEditableSelectionOffsets(const PlainTextRange& selectionOffsets) @@ -510,38 +527,6 @@ return setSelectionOffsets(selectionOffsets); } -PlainTextRange InputMethodController::createRangeForSelection(int start, int end, size_t textLength) const -{ - // In case of exceeding the left boundary. - start = std::max(start, 0); - end = std::max(end, start); - - // In case of exceeding the right boundary. - Element* rootEditableElement = frame().selection().rootEditableElement(); - if (!rootEditableElement) - return PlainTextRange(); - const EphemeralRange& range = EphemeralRange::rangeOfContents(*rootEditableElement); - if (range.isNull()) - return PlainTextRange(); - - const TextIteratorBehaviorFlags behaviorFlags = TextIteratorEmitsObjectReplacementCharacter | TextIteratorEmitsCharactersBetweenAllVisiblePositions; - TextIterator it(range.startPosition(), range.endPosition(), behaviorFlags); - - int rightBoundary = 0; - for (; !it.atEnd(); it.advance()) - rightBoundary += it.length(); - - if (hasComposition()) - rightBoundary -= compositionRange()->text().length(); - - rightBoundary += textLength; - - start = std::min(start, rightBoundary); - end = std::min(end, rightBoundary); - - return PlainTextRange(start, end); -} - void InputMethodController::extendSelectionAndDelete(int before, int after) { if (!editor().canEdit())
diff --git a/third_party/WebKit/Source/core/editing/InputMethodController.h b/third_party/WebKit/Source/core/editing/InputMethodController.h index 2d4ade7c..bf7e152c 100644 --- a/third_party/WebKit/Source/core/editing/InputMethodController.h +++ b/third_party/WebKit/Source/core/editing/InputMethodController.h
@@ -78,7 +78,6 @@ // Returns true if setting selection to specified offsets, otherwise false. bool setEditableSelectionOffsets(const PlainTextRange&); void extendSelectionAndDelete(int before, int after); - PlainTextRange createRangeForSelection(int start, int end, size_t textLength) const; private: class SelectionOffsetsScope {
diff --git a/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp b/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp index 8f50a34..e4d8b52 100644 --- a/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp +++ b/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp
@@ -7,7 +7,6 @@ #include "core/dom/Document.h" #include "core/dom/Element.h" #include "core/dom/Range.h" -#include "core/editing/Editor.h" #include "core/editing/FrameSelection.h" #include "core/events/MouseEvent.h" #include "core/frame/FrameView.h" @@ -350,55 +349,6 @@ EXPECT_EQ(24u, controller().getSelectionOffsets().end()); } -TEST_F(InputMethodControllerTest, SetCompositionWithEmptyText) -{ - Element* div = insertHTMLElement( - "<div id='sample' contenteditable='true'>hello</div>", - "sample"); - - controller().setEditableSelectionOffsets(PlainTextRange(2, 2)); - EXPECT_STREQ("hello", div->innerText().utf8().data()); - EXPECT_EQ(2u, controller().getSelectionOffsets().start()); - EXPECT_EQ(2u, controller().getSelectionOffsets().end()); - - Vector<CompositionUnderline> underlines0; - underlines0.append(CompositionUnderline(0, 0, Color(255, 0, 0), false, 0)); - Vector<CompositionUnderline> underlines2; - underlines2.append(CompositionUnderline(0, 2, Color(255, 0, 0), false, 0)); - - controller().setComposition("AB", underlines2, 2, 2); - // With previous composition. - controller().setComposition("", underlines0, 2, 2); - EXPECT_STREQ("hello", div->innerText().utf8().data()); - EXPECT_EQ(4u, controller().getSelectionOffsets().start()); - EXPECT_EQ(4u, controller().getSelectionOffsets().end()); - - // Without previous composition. - controller().setComposition("", underlines0, -1, -1); - EXPECT_STREQ("hello", div->innerText().utf8().data()); - EXPECT_EQ(3u, controller().getSelectionOffsets().start()); - EXPECT_EQ(3u, controller().getSelectionOffsets().end()); -} - -TEST_F(InputMethodControllerTest, InsertLineBreakWhileComposingText) -{ - Element* div = insertHTMLElement( - "<div id='sample' contenteditable='true'></div>", - "sample"); - - Vector<CompositionUnderline> underlines; - underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); - controller().setComposition("hello", underlines, 5, 5); - EXPECT_STREQ("hello", div->innerText().utf8().data()); - EXPECT_EQ(5u, controller().getSelectionOffsets().start()); - EXPECT_EQ(5u, controller().getSelectionOffsets().end()); - - frame().editor().insertLineBreak(); - EXPECT_STREQ("\n\n", div->innerText().utf8().data()); - EXPECT_EQ(1u, controller().getSelectionOffsets().start()); - EXPECT_EQ(1u, controller().getSelectionOffsets().end()); -} - TEST_F(InputMethodControllerTest, CompositionInputEventIsComposing) { document().settings()->setScriptEnabled(true);
diff --git a/third_party/WebKit/Source/core/editing/Position.cpp b/third_party/WebKit/Source/core/editing/Position.cpp index 01f0364..9d488dc4 100644 --- a/third_party/WebKit/Source/core/editing/Position.cpp +++ b/third_party/WebKit/Source/core/editing/Position.cpp
@@ -35,10 +35,20 @@ namespace blink { #if DCHECK_IS_ON() -static bool canBeAnchorNode(Node* node) +template <typename Strategy> +static bool canBeAnchorNode(Node*); + +template <> +bool canBeAnchorNode<EditingStrategy>(Node* node) { return !node || !node->isPseudoElement(); } + +template <> +bool canBeAnchorNode<EditingInFlatTreeStrategy>(Node* node) +{ + return canBeAnchorNode<EditingStrategy>(node) && node->canParticipateInFlatTree(); +} #endif template <typename Strategy> @@ -89,7 +99,7 @@ return; } #if DCHECK_IS_ON() - DCHECK(canBeAnchorNode(m_anchorNode.get())); + DCHECK(canBeAnchorNode<Strategy>(m_anchorNode.get())) << m_anchorNode; #endif DCHECK_NE(m_anchorType, PositionAnchorType::OffsetInAnchor); } @@ -105,7 +115,7 @@ else DCHECK_EQ(offset, 0); #if DCHECK_IS_ON() - DCHECK(canBeAnchorNode(m_anchorNode.get())); + DCHECK(canBeAnchorNode<Strategy>(m_anchorNode.get())) << m_anchorNode; #endif } @@ -513,8 +523,8 @@ if (pos.isNull()) return PositionInFlatTree(); + Node* const anchor = pos.anchorNode(); if (pos.isOffsetInAnchor()) { - Node* anchor = pos.anchorNode(); if (anchor->isCharacterDataNode()) return PositionInFlatTree(anchor, pos.computeOffsetInContainerNode()); DCHECK(!anchor->isSlotOrActiveInsertionPoint()); @@ -541,7 +551,11 @@ return PositionInFlatTree(anchor, PositionAnchorType::AfterChildren); } - return PositionInFlatTree(pos.anchorNode(), pos.anchorType()); + if (anchor->isShadowRoot()) + return PositionInFlatTree(anchor->shadowHost(), pos.anchorType()); + // TODO(yosin): Once we have a test case for SLOT or active insertion point, + // this function should handle it. + return PositionInFlatTree(anchor, pos.anchorType()); } Position toPositionInDOMTree(const Position& position)
diff --git a/third_party/WebKit/Source/core/editing/PositionTest.cpp b/third_party/WebKit/Source/core/editing/PositionTest.cpp index 97c036fe..1c775ca 100644 --- a/third_party/WebKit/Source/core/editing/PositionTest.cpp +++ b/third_party/WebKit/Source/core/editing/PositionTest.cpp
@@ -139,6 +139,14 @@ EXPECT_EQ(PositionInFlatTree(host, 0), toPositionInFlatTree(Position(shadowRoot, 0))); EXPECT_EQ(PositionInFlatTree(host, PositionAnchorType::AfterChildren), toPositionInFlatTree(Position(shadowRoot, 1))); + EXPECT_EQ(PositionInFlatTree(host, PositionAnchorType::AfterChildren), + toPositionInFlatTree(Position(shadowRoot, PositionAnchorType::AfterChildren))); + EXPECT_EQ(PositionInFlatTree(host, PositionAnchorType::BeforeChildren), + toPositionInFlatTree(Position(shadowRoot, PositionAnchorType::BeforeChildren))); + EXPECT_EQ(PositionInFlatTree(host, PositionAnchorType::AfterAnchor), + toPositionInFlatTree(Position(shadowRoot, PositionAnchorType::AfterAnchor))); + EXPECT_EQ(PositionInFlatTree(host, PositionAnchorType::BeforeAnchor), + toPositionInFlatTree(Position(shadowRoot, PositionAnchorType::BeforeAnchor))); } TEST_F(PositionTest, ToPositionInFlatTreeWithShadowRootContainingSingleContent)
diff --git a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp index 30dc1f5..ce8de63 100644 --- a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp +++ b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
@@ -1558,7 +1558,7 @@ continue; } const ComputedStyle& style = layoutItem.styleRef(); - if (style.visibility() != VISIBLE) { + if (style.visibility() != EVisibility::Visible) { prevousNodeIterator = Strategy::previousPostOrder(*prevousNodeIterator, startBlock); continue; } @@ -1649,7 +1649,7 @@ continue; } const ComputedStyle& style = layoutObject->styleRef(); - if (style.visibility() != VISIBLE) { + if (style.visibility() != EVisibility::Visible) { nextNodeItreator = Strategy::next(*nextNodeItreator, startBlock); continue; } @@ -2457,7 +2457,7 @@ // skip position in non-laid out or invisible node LayoutObject* layoutObject = associatedLayoutObjectOf(*currentNode, currentPos.offsetInLeafNode()); - if (!layoutObject || layoutObject->style()->visibility() != VISIBLE) + if (!layoutObject || layoutObject->style()->visibility() != EVisibility::Visible) continue; if (rule == CanCrossEditingBoundary && boundaryCrossed) { @@ -2505,7 +2505,7 @@ // |Text| node with :first-letter. DCHECK_GE(currentPos.offsetInLeafNode(), 1); LayoutObject* firstLetterLayoutObject = toLayoutTextFragment(layoutObject)->firstLetterPseudoElement()->layoutObject(); - if (firstLetterLayoutObject && firstLetterLayoutObject->style()->visibility() == VISIBLE) + if (firstLetterLayoutObject && firstLetterLayoutObject->style()->visibility() == EVisibility::Visible) return currentPos.computePosition(); } continue; @@ -2608,7 +2608,7 @@ // skip position in non-laid out or invisible node LayoutObject* layoutObject = associatedLayoutObjectOf(*currentNode, currentPos.offsetInLeafNode()); - if (!layoutObject || layoutObject->style()->visibility() != VISIBLE) + if (!layoutObject || layoutObject->style()->visibility() != EVisibility::Visible) continue; if (rule == CanCrossEditingBoundary && boundaryCrossed) { @@ -2726,7 +2726,7 @@ if (!layoutObject) return false; - if (layoutObject->style()->visibility() != VISIBLE) + if (layoutObject->style()->visibility() != EVisibility::Visible) return false; if (layoutObject->isBR()) {
diff --git a/third_party/WebKit/Source/core/editing/iterators/SimplifiedBackwardsTextIterator.cpp b/third_party/WebKit/Source/core/editing/iterators/SimplifiedBackwardsTextIterator.cpp index e5941fb8..b7711886 100644 --- a/third_party/WebKit/Source/core/editing/iterators/SimplifiedBackwardsTextIterator.cpp +++ b/third_party/WebKit/Source/core/editing/iterators/SimplifiedBackwardsTextIterator.cpp
@@ -156,10 +156,10 @@ LayoutObject* layoutObject = m_node->layoutObject(); if (layoutObject && layoutObject->isText() && m_node->getNodeType() == Node::kTextNode) { // FIXME: What about kCdataSectionNode? - if (layoutObject->style()->visibility() == VISIBLE && m_offset > 0) + if (layoutObject->style()->visibility() == EVisibility::Visible && m_offset > 0) m_handledNode = handleTextNode(); } else if (layoutObject && (layoutObject->isLayoutPart() || TextIterator::supportsAltText(m_node))) { - if (layoutObject->style()->visibility() == VISIBLE && m_offset > 0) + if (layoutObject->style()->visibility() == EVisibility::Visible && m_offset > 0) m_handledNode = handleReplacedElement(); } else { m_handledNode = handleNonTextNode();
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp b/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp index 3d0909b..aeff18e0 100644 --- a/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp +++ b/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
@@ -441,7 +441,7 @@ static bool hasVisibleTextNode(LayoutText* layoutObject) { - if (layoutObject->style()->visibility() == VISIBLE) + if (layoutObject->style()->visibility() == EVisibility::Visible) return true; if (!layoutObject->isTextFragment()) @@ -453,7 +453,7 @@ DCHECK(fragment->firstLetterPseudoElement()); LayoutObject* pseudoElementLayoutObject = fragment->firstLetterPseudoElement()->layoutObject(); - return pseudoElementLayoutObject && pseudoElementLayoutObject->style()->visibility() == VISIBLE; + return pseudoElementLayoutObject && pseudoElementLayoutObject->style()->visibility() == EVisibility::Visible; } template<typename Strategy> @@ -497,7 +497,7 @@ return false; } } - if (layoutObject->style()->visibility() != VISIBLE && !ignoresStyleVisibility()) + if (layoutObject->style()->visibility() != EVisibility::Visible && !ignoresStyleVisibility()) return false; int strLength = str.length(); int end = (textNode == m_endContainer) ? m_endOffset : INT_MAX; @@ -518,7 +518,7 @@ handleTextNodeFirstLetter(toLayoutTextFragment(layoutObject)); if (!layoutObject->firstTextBox() && str.length() > 0 && !shouldHandleFirstLetter) { - if (layoutObject->style()->visibility() != VISIBLE && !ignoresStyleVisibility()) + if (layoutObject->style()->visibility() != EVisibility::Visible && !ignoresStyleVisibility()) return false; m_lastTextNodeEndedWithCollapsedSpace = true; // entire block is collapsed space return true; @@ -547,7 +547,7 @@ { LayoutText* layoutObject = m_firstLetterText ? m_firstLetterText : toLayoutText(m_node->layoutObject()); - if (layoutObject->style()->visibility() != VISIBLE && !ignoresStyleVisibility()) { + if (layoutObject->style()->visibility() != EVisibility::Visible && !ignoresStyleVisibility()) { m_textBox = nullptr; } else { String str = layoutObject->text(); @@ -660,7 +660,7 @@ return; LayoutObject* pseudoLayoutObject = firstLetterElement->layoutObject(); - if (pseudoLayoutObject->style()->visibility() != VISIBLE && !ignoresStyleVisibility()) + if (pseudoLayoutObject->style()->visibility() != EVisibility::Visible && !ignoresStyleVisibility()) return; LayoutObject* firstLetter = pseudoLayoutObject->slowFirstChild(); @@ -694,7 +694,7 @@ return false; LayoutObject* layoutObject = m_node->layoutObject(); - if (layoutObject->style()->visibility() != VISIBLE && !ignoresStyleVisibility()) + if (layoutObject->style()->visibility() != EVisibility::Visible && !ignoresStyleVisibility()) return false; if (emitsObjectReplacementCharacter()) { @@ -912,7 +912,7 @@ // If this node is unrendered or invisible the VisiblePosition checks below won't have much meaning. // Additionally, if the range we are iterating over contains huge sections of unrendered content, // we would create VisiblePositions on every call to this function without this check. - if (!m_node->layoutObject() || m_node->layoutObject()->style()->visibility() != VISIBLE + if (!m_node->layoutObject() || m_node->layoutObject()->style()->visibility() != EVisibility::Visible || (m_node->layoutObject()->isLayoutBlockFlow() && !toLayoutBlock(m_node->layoutObject())->size().height() && !isHTMLBodyElement(*m_node))) return false;
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckRequester.cpp b/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckRequester.cpp index 7261ec8..addf7ba3 100644 --- a/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckRequester.cpp +++ b/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckRequester.cpp
@@ -40,7 +40,6 @@ Range* checkingRange, Range* paragraphRange, const String& text, - TextCheckingTypeMask mask, TextCheckingProcessType processType, const Vector<uint32_t>& documentMarkersInRange, const Vector<unsigned>& documentMarkerOffsets, @@ -49,7 +48,7 @@ , m_checkingRange(checkingRange) , m_paragraphRange(paragraphRange) , m_rootEditableElement(blink::rootEditableElement(*m_checkingRange->startContainer())) - , m_requestData(unrequestedTextCheckingSequence, text, mask, processType, documentMarkersInRange, documentMarkerOffsets) + , m_requestData(unrequestedTextCheckingSequence, text, processType, documentMarkersInRange, documentMarkerOffsets) , m_requestNumber(requestNumber) { DCHECK(m_checkingRange); @@ -81,7 +80,7 @@ } // static -SpellCheckRequest* SpellCheckRequest::create(TextCheckingTypeMask textCheckingOptions, TextCheckingProcessType processType, const EphemeralRange& checkingRange, const EphemeralRange& paragraphRange, int requestNumber) +SpellCheckRequest* SpellCheckRequest::create(TextCheckingProcessType processType, const EphemeralRange& checkingRange, const EphemeralRange& paragraphRange, int requestNumber) { if (checkingRange.isNull()) return nullptr; @@ -108,7 +107,7 @@ offsets[i] = markers[i]->startOffset(); } - return new SpellCheckRequest(checkingRangeObject, paragraphRangeObject, text, textCheckingOptions, processType, hashes, offsets, requestNumber); + return new SpellCheckRequest(checkingRangeObject, paragraphRangeObject, text, processType, hashes, offsets, requestNumber); } const TextCheckingRequestData& SpellCheckRequest::data() const @@ -220,6 +219,10 @@ // the leak detector, they're all cancelled to prevent flaky leaks being // reported. m_requestQueue.clear(); + // WebSpellCheckClient stores a set of WebTextCheckingCompletion objects, + // which may store references to already invoked requests. We should clear + // these references to prevent them from being a leak source. + client().cancelAllPendingRequests(); } void SpellCheckRequester::invokeRequest(SpellCheckRequest* request) @@ -288,10 +291,6 @@ TextCheckingRequestData requestData = m_processingRequest->data(); if (requestData.sequence() == sequence) { DocumentMarker::MarkerTypes markers = DocumentMarker::SpellCheckClientMarkers(); - if (!requestData.maskContains(TextCheckingTypeSpelling)) - markers.remove(DocumentMarker::Spelling); - if (!requestData.maskContains(TextCheckingTypeGrammar)) - markers.remove(DocumentMarker::Grammar); if (m_processingRequest->isValid()) { Range* checkingRange = m_processingRequest->checkingRange(); frame().document()->markers().removeMarkers(EphemeralRange(checkingRange), markers);
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckRequester.h b/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckRequester.h index 44a6a2f..b93c670 100644 --- a/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckRequester.h +++ b/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckRequester.h
@@ -45,7 +45,7 @@ class SpellCheckRequest final : public TextCheckingRequest { public: - static SpellCheckRequest* create(TextCheckingTypeMask, TextCheckingProcessType, const EphemeralRange& checkingRange, const EphemeralRange& paragraphRange, int requestNumber = 0); + static SpellCheckRequest* create(TextCheckingProcessType, const EphemeralRange& checkingRange, const EphemeralRange& paragraphRange, int requestNumber = 0); ~SpellCheckRequest() override; void dispose(); @@ -66,7 +66,7 @@ DECLARE_VIRTUAL_TRACE(); private: - SpellCheckRequest(Range* checkingRange, Range* paragraphRange, const String&, TextCheckingTypeMask, TextCheckingProcessType, const Vector<uint32_t>& documentMarkersInRange, const Vector<unsigned>& documentMarkerOffsets, int requestNumber); + SpellCheckRequest(Range* checkingRange, Range* paragraphRange, const String&, TextCheckingProcessType, const Vector<uint32_t>& documentMarkersInRange, const Vector<unsigned>& documentMarkerOffsets, int requestNumber); Member<SpellCheckRequester> m_requester; Member<Range> m_checkingRange;
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp index 0fa676f..3304bc2 100644 --- a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp +++ b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp
@@ -517,7 +517,7 @@ // Check the full paragraph instead if the paragraph is short, which saves // the cost on sentence boundary finding. if (fullParagraphToCheck.rangeLength() <= kChunkSize) { - SpellCheckRequest* request = SpellCheckRequest::create(TextCheckingTypeSpelling | TextCheckingTypeGrammar, TextCheckingProcessBatch, paragraphRange, paragraphRange, 0); + SpellCheckRequest* request = SpellCheckRequest::create(TextCheckingProcessBatch, paragraphRange, paragraphRange, 0); if (request) m_spellCheckRequester->requestCheckingFor(request); return; @@ -528,7 +528,7 @@ EphemeralRange chunkRange = checkRangeIterator.calculateCharacterSubrange(0, kChunkSize); EphemeralRange checkRange = requestNum ? expandEndToSentenceBoundary(chunkRange) : expandRangeToSentenceBoundary(chunkRange); - SpellCheckRequest* request = SpellCheckRequest::create(TextCheckingTypeSpelling | TextCheckingTypeGrammar, TextCheckingProcessBatch, checkRange, paragraphRange, requestNum); + SpellCheckRequest* request = SpellCheckRequest::create(TextCheckingProcessBatch, checkRange, paragraphRange, requestNum); if (request) m_spellCheckRequester->requestCheckingFor(request); @@ -558,12 +558,8 @@ return; } - TextCheckingTypeMask textCheckingOptions = request->data().mask(); TextCheckingParagraph paragraph(request->checkingRange(), request->paragraphRange()); - bool shouldMarkSpelling = textCheckingOptions & TextCheckingTypeSpelling; - bool shouldMarkGrammar = textCheckingOptions & TextCheckingTypeGrammar; - // Expand the range to encompass entire paragraphs, since text checking needs that much context. int selectionOffset = 0; int ambiguousBoundaryOffset = -1; @@ -571,17 +567,15 @@ bool restoreSelectionAfterChange = false; bool adjustSelectionForParagraphBoundaries = false; - if (shouldMarkSpelling) { - if (frame().selection().isCaret()) { - // Attempt to save the caret position so we can restore it later if needed - Position caretPosition = frame().selection().end(); - selectionOffset = paragraph.offsetTo(caretPosition); - restoreSelectionAfterChange = true; - if (selectionOffset > 0 && (static_cast<unsigned>(selectionOffset) > paragraph.text().length() || paragraph.textCharAt(selectionOffset - 1) == newlineCharacter)) - adjustSelectionForParagraphBoundaries = true; - if (selectionOffset > 0 && static_cast<unsigned>(selectionOffset) <= paragraph.text().length() && isAmbiguousBoundaryCharacter(paragraph.textCharAt(selectionOffset - 1))) - ambiguousBoundaryOffset = selectionOffset - 1; - } + if (frame().selection().isCaret()) { + // Attempt to save the caret position so we can restore it later if needed + Position caretPosition = frame().selection().end(); + selectionOffset = paragraph.offsetTo(caretPosition); + restoreSelectionAfterChange = true; + if (selectionOffset > 0 && (static_cast<unsigned>(selectionOffset) > paragraph.text().length() || paragraph.textCharAt(selectionOffset - 1) == newlineCharacter)) + adjustSelectionForParagraphBoundaries = true; + if (selectionOffset > 0 && static_cast<unsigned>(selectionOffset) <= paragraph.text().length() && isAmbiguousBoundaryCharacter(paragraph.textCharAt(selectionOffset - 1))) + ambiguousBoundaryOffset = selectionOffset - 1; } // TODO(dglazkov): The use of updateStyleAndLayoutIgnorePendingStylesheets needs to be audited. @@ -599,16 +593,16 @@ bool resultEndsAtAmbiguousBoundary = ambiguousBoundaryOffset >= 0 && resultLocation + resultLength == ambiguousBoundaryOffset; // Only mark misspelling if: - // 1. Current text checking isn't done for autocorrection, in which case shouldMarkSpelling is false. + // 1. Current text checking isn't done for autocorrection. // 2. Result falls within spellingRange. // 3. The word in question doesn't end at an ambiguous boundary. For instance, we would not mark // "wouldn'" as misspelled right after apostrophe is typed. - if (shouldMarkSpelling && result->decoration == TextDecorationTypeSpelling && resultLocation >= paragraph.checkingStart() && resultLocation + resultLength <= spellingRangeEndOffset && !resultEndsAtAmbiguousBoundary) { + if (result->decoration == TextDecorationTypeSpelling && resultLocation >= paragraph.checkingStart() && resultLocation + resultLength <= spellingRangeEndOffset && !resultEndsAtAmbiguousBoundary) { DCHECK_GT(resultLength, 0); DCHECK_GE(resultLocation, 0); const EphemeralRange misspellingRange = calculateCharacterSubrange(paragraph.paragraphRange(), resultLocation, resultLength); frame().document()->markers().addMarker(misspellingRange.startPosition(), misspellingRange.endPosition(), DocumentMarker::Spelling, result->replacement, result->hash); - } else if (shouldMarkGrammar && result->decoration == TextDecorationTypeGrammar && paragraph.checkingRangeCovers(resultLocation, resultLength)) { + } else if (result->decoration == TextDecorationTypeGrammar && paragraph.checkingRangeCovers(resultLocation, resultLength)) { DCHECK_GT(resultLength, 0); DCHECK_GE(resultLocation, 0); for (unsigned j = 0; j < result->details.size(); j++) { @@ -933,7 +927,7 @@ void SpellChecker::requestTextChecking(const Element& element) { const EphemeralRange rangeToCheck = EphemeralRange::rangeOfContents(element); - m_spellCheckRequester->requestCheckingFor(SpellCheckRequest::create(TextCheckingTypeSpelling | TextCheckingTypeGrammar, TextCheckingProcessBatch, rangeToCheck, rangeToCheck)); + m_spellCheckRequester->requestCheckingFor(SpellCheckRequest::create(TextCheckingProcessBatch, rangeToCheck, rangeToCheck)); } DEFINE_TRACE(SpellChecker)
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.cpp b/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.cpp index 7ba54bf..975ef0a 100644 --- a/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.cpp +++ b/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.cpp
@@ -365,8 +365,7 @@ unsigned grammarDetailIndex = 0; Vector<TextCheckingResult> results; - TextCheckingTypeMask checkingTypes = TextCheckingTypeSpelling | TextCheckingTypeGrammar; - checkTextOfParagraph(m_client->textChecker(), paragraphString, checkingTypes, results); + checkTextOfParagraph(m_client->textChecker(), paragraphString, results); for (unsigned i = 0; i < results.size(); i++) { const TextCheckingResult* result = &results[i]; @@ -554,27 +553,24 @@ return blink::unifiedTextCheckerEnabled(doc.frame()); } -void checkTextOfParagraph(TextCheckerClient& client, const String& text, TextCheckingTypeMask checkingTypes, Vector<TextCheckingResult>& results) +void checkTextOfParagraph(TextCheckerClient& client, const String& text, Vector<TextCheckingResult>& results) { Vector<UChar> characters; text.appendTo(characters); unsigned length = text.length(); Vector<TextCheckingResult> spellingResult; - if (checkingTypes & TextCheckingTypeSpelling) - findMisspellings(client, characters.data(), 0, length, spellingResult); + findMisspellings(client, characters.data(), 0, length, spellingResult); + + // Only checks grammartical error before the first misspellings + int grammarCheckLength = length; + for (const auto& spelling : spellingResult) { + if (spelling.location < grammarCheckLength) + grammarCheckLength = spelling.location; + } Vector<TextCheckingResult> grammarResult; - if (checkingTypes & TextCheckingTypeGrammar) { - // Only checks grammartical error before the first misspellings - int grammarCheckLength = length; - for (const auto& spelling : spellingResult) { - if (spelling.location < grammarCheckLength) - grammarCheckLength = spelling.location; - } - - findBadGrammars(client, characters.data(), 0, grammarCheckLength, grammarResult); - } + findBadGrammars(client, characters.data(), 0, grammarCheckLength, grammarResult); if (grammarResult.size()) results.swap(grammarResult);
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.h b/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.h index a7c9a204..42334f3 100644 --- a/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.h +++ b/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.h
@@ -103,7 +103,7 @@ bool unifiedTextCheckerEnabled() const; }; -void checkTextOfParagraph(TextCheckerClient&, const String&, TextCheckingTypeMask, Vector<TextCheckingResult>&); +void checkTextOfParagraph(TextCheckerClient&, const String&, Vector<TextCheckingResult>&); bool unifiedTextCheckerEnabled(const LocalFrame*); } // namespace blink
diff --git a/third_party/WebKit/Source/core/events/EventTarget.cpp b/third_party/WebKit/Source/core/events/EventTarget.cpp index b1aea0a..19d5091f 100644 --- a/third_party/WebKit/Source/core/events/EventTarget.cpp +++ b/third_party/WebKit/Source/core/events/EventTarget.cpp
@@ -579,7 +579,7 @@ } else if (checkTypeThenUseCount(event, EventTypeNames::mousedown, UseCounter::MouseDownFired)) { } else if (checkTypeThenUseCount(event, EventTypeNames::pointerdown, UseCounter::PointerDownFired)) { if (LocalDOMWindow* executingWindow = this->executingWindow()) { - if (static_cast<PointerEvent*>(event)->pointerType() == "touch") + if (event->isPointerEvent() && static_cast<PointerEvent*>(event)->pointerType() == "touch") UseCounter::count(executingWindow->document(), UseCounter::PointerDownFiredForTouch); } }
diff --git a/third_party/WebKit/Source/core/events/WheelEvent.cpp b/third_party/WebKit/Source/core/events/WheelEvent.cpp index 5f45e07a1..2d23921 100644 --- a/third_party/WebKit/Source/core/events/WheelEvent.cpp +++ b/third_party/WebKit/Source/core/events/WheelEvent.cpp
@@ -42,7 +42,11 @@ MouseEvent::platformModifiersToButtons(event.getModifiers()), event.timestamp(), event.resendingPluginId(), event.hasPreciseScrollingDeltas(), static_cast<Event::RailsMode>(event.getRailsMode()), - event.cancelable()); + event.cancelable() +#if OS(MACOSX) + , static_cast<WheelEventPhase>(event.phase()), static_cast<WheelEventPhase>(event.momentumPhase()) +#endif + ); } WheelEvent::WheelEvent() @@ -66,6 +70,10 @@ , m_resendingPluginId(-1) , m_hasPreciseScrollingDeltas(false) , m_railsMode(RailsModeFree) +#if OS(MACOSX) + , m_phase(WheelEventPhaseNone) + , m_momentumPhase(WheelEventPhaseNone) +#endif { } @@ -87,9 +95,39 @@ , m_resendingPluginId(resendingPluginId) , m_hasPreciseScrollingDeltas(hasPreciseScrollingDeltas) , m_railsMode(railsMode) +#if OS(MACOSX) + , m_phase(WheelEventPhaseNone) + , m_momentumPhase(WheelEventPhaseNone) +#endif { } +#if OS(MACOSX) +WheelEvent::WheelEvent(const FloatPoint& wheelTicks, const FloatPoint& rawDelta, unsigned deltaMode, + AbstractView* view, const IntPoint& screenLocation, const IntPoint& windowLocation, + PlatformEvent::Modifiers modifiers, unsigned short buttons, double platformTimeStamp, + int resendingPluginId, bool hasPreciseScrollingDeltas, RailsMode railsMode, bool cancelable, + WheelEventPhase phase, WheelEventPhase momentumPhase) + : MouseEvent(EventTypeNames::wheel, true, cancelable, view, 0, screenLocation.x(), screenLocation.y(), + windowLocation.x(), windowLocation.y(), 0, 0, modifiers, 0, buttons, + nullptr, platformTimeStamp, PlatformMouseEvent::RealOrIndistinguishable, + // TODO(zino): Should support canvas hit region because the wheel event + // is a kind of mouse event. Please see http://crbug.com/594075 + String()) + , m_wheelDelta(wheelTicks.x() * TickMultiplier, wheelTicks.y() * TickMultiplier) + , m_deltaX(-rawDelta.x()) + , m_deltaY(-rawDelta.y()) + , m_deltaZ(0) + , m_deltaMode(deltaMode) + , m_resendingPluginId(resendingPluginId) + , m_hasPreciseScrollingDeltas(hasPreciseScrollingDeltas) + , m_railsMode(railsMode) + , m_phase(phase) + , m_momentumPhase(momentumPhase) +{ +} +#endif + const AtomicString& WheelEvent::interfaceName() const { return EventNames::WheelEvent;
diff --git a/third_party/WebKit/Source/core/events/WheelEvent.h b/third_party/WebKit/Source/core/events/WheelEvent.h index 522073c..568ea24 100644 --- a/third_party/WebKit/Source/core/events/WheelEvent.h +++ b/third_party/WebKit/Source/core/events/WheelEvent.h
@@ -34,6 +34,18 @@ class PlatformWheelEvent; +#if OS(MACOSX) +enum WheelEventPhase { + WheelEventPhaseNone = 0, + WheelEventPhaseBegan = 1 << 0, + WheelEventPhaseStationary = 1 << 1, + WheelEventPhaseChanged = 1 << 2, + WheelEventPhaseEnded = 1 << 3, + WheelEventPhaseCancelled = 1 << 4, + WheelEventPhaseMayBegin = 1 << 5, +}; +#endif + class CORE_EXPORT WheelEvent final : public MouseEvent { DEFINE_WRAPPERTYPEINFO(); public: @@ -61,11 +73,19 @@ const FloatPoint& rawDelta, unsigned deltaMode, AbstractView* view, const IntPoint& screenLocation, const IntPoint& windowLocation, PlatformEvent::Modifiers modifiers, unsigned short buttons, double platformTimeStamp, - int resendingPluginId, bool hasPreciseScrollingDeltas, RailsMode railsMode, bool cancelable) + int resendingPluginId, bool hasPreciseScrollingDeltas, RailsMode railsMode, bool cancelable +#if OS(MACOSX) + , WheelEventPhase phase, WheelEventPhase momentumPhase +#endif + ) { return new WheelEvent(wheelTicks, rawDelta, deltaMode, view, screenLocation, windowLocation, modifiers, buttons, platformTimeStamp, - resendingPluginId, hasPreciseScrollingDeltas, railsMode, cancelable); + resendingPluginId, hasPreciseScrollingDeltas, railsMode, cancelable +#if OS(MACOSX) + , phase, momentumPhase +#endif + ); } double deltaX() const { return m_deltaX; } // Positive when scrolling right. @@ -87,6 +107,11 @@ EventDispatchMediator* createMediator() override; +#if OS(MACOSX) + WheelEventPhase phase() const { return m_phase; } + WheelEventPhase momentumPhase() const { return m_momentumPhase; } +#endif + DECLARE_VIRTUAL_TRACE(); private: @@ -96,6 +121,14 @@ unsigned, AbstractView*, const IntPoint& screenLocation, const IntPoint& windowLocation, PlatformEvent::Modifiers, unsigned short buttons, double platformTimeStamp, int resendingPluginId, bool hasPreciseScrollingDeltas, RailsMode, bool cancelable); +#if OS(MACOSX) + WheelEvent(const FloatPoint& wheelTicks, const FloatPoint& rawDelta, + unsigned, AbstractView*, const IntPoint& screenLocation, const IntPoint& windowLocation, + PlatformEvent::Modifiers, unsigned short buttons, double platformTimeStamp, + int resendingPluginId, bool hasPreciseScrollingDeltas, RailsMode, bool cancelable, + WheelEventPhase phase, WheelEventPhase momentumPhase + ); +#endif IntPoint m_wheelDelta; double m_deltaX; @@ -105,6 +138,10 @@ int m_resendingPluginId; bool m_hasPreciseScrollingDeltas; RailsMode m_railsMode; +#if OS(MACOSX) + WheelEventPhase m_phase; + WheelEventPhase m_momentumPhase; +#endif }; DEFINE_EVENT_TYPE_CASTS(WheelEvent);
diff --git a/third_party/WebKit/Source/core/fetch/ImageResourceTest.cpp b/third_party/WebKit/Source/core/fetch/ImageResourceTest.cpp index fc422248..ea18343 100644 --- a/third_party/WebKit/Source/core/fetch/ImageResourceTest.cpp +++ b/third_party/WebKit/Source/core/fetch/ImageResourceTest.cpp
@@ -159,6 +159,7 @@ std::unique_ptr<WebTaskRunner> clone() override { return nullptr; } double virtualTimeSeconds() const override { return 0.0; } double monotonicallyIncreasingVirtualTimeSeconds() const override { return 0.0; } + SingleThreadTaskRunner* taskRunner() override { return nullptr; } }; }
diff --git a/third_party/WebKit/Source/core/fetch/ResourceFetcherTest.cpp b/third_party/WebKit/Source/core/fetch/ResourceFetcherTest.cpp index e74ea5b..c9e2c16 100644 --- a/third_party/WebKit/Source/core/fetch/ResourceFetcherTest.cpp +++ b/third_party/WebKit/Source/core/fetch/ResourceFetcherTest.cpp
@@ -69,6 +69,7 @@ std::unique_ptr<WebTaskRunner> clone() override { return nullptr; } double virtualTimeSeconds() const override { return 0.0; } double monotonicallyIncreasingVirtualTimeSeconds() const override { return 0.0; } + SingleThreadTaskRunner* taskRunner() override { return nullptr; } }; }
diff --git a/third_party/WebKit/Source/core/fetch/ScriptResource.cpp b/third_party/WebKit/Source/core/fetch/ScriptResource.cpp index 167017b..b5a1aeb0 100644 --- a/third_party/WebKit/Source/core/fetch/ScriptResource.cpp +++ b/third_party/WebKit/Source/core/fetch/ScriptResource.cpp
@@ -76,11 +76,11 @@ Resource::onMemoryDump(levelOfDetail, memoryDump); const String name = getMemoryDumpName() + "/decoded_script"; auto dump = memoryDump->createMemoryAllocatorDump(name); - dump->addScalar("size", "bytes", m_script.currentSizeInBytes()); + dump->addScalar("size", "bytes", m_script.getString().sizeInBytes()); memoryDump->addSuballocation(dump->guid(), String(WTF::Partitions::kAllocatedObjectPoolName)); } -const CompressibleString& ScriptResource::script() +const String& ScriptResource::script() { ASSERT(!isPurgeable()); ASSERT(isLoaded()); @@ -92,7 +92,7 @@ // That's because the MemoryCache thinks that it can clear out decoded data by calling destroyDecodedData(), // but we can't destroy script in destroyDecodedData because that's our only copy of the data! setEncodedSize(script.sizeInBytes()); - m_script = CompressibleString(script.impl()); + m_script = AtomicString(script); } return m_script; @@ -100,7 +100,7 @@ void ScriptResource::destroyDecodedDataForFailedRevalidation() { - m_script = CompressibleString(); + m_script = AtomicString(); } bool ScriptResource::mimeTypeAllowedByNosniff() const
diff --git a/third_party/WebKit/Source/core/fetch/ScriptResource.h b/third_party/WebKit/Source/core/fetch/ScriptResource.h index 254d5569..036e26b 100644 --- a/third_party/WebKit/Source/core/fetch/ScriptResource.h +++ b/third_party/WebKit/Source/core/fetch/ScriptResource.h
@@ -30,8 +30,6 @@ #include "core/fetch/IntegrityMetadata.h" #include "core/fetch/ResourceClient.h" #include "core/fetch/TextResource.h" -#include "platform/heap/Handle.h" -#include "platform/text/CompressibleString.h" namespace blink { @@ -76,7 +74,7 @@ void destroyDecodedDataForFailedRevalidation() override; - const CompressibleString& script(); + const String& script(); bool mimeTypeAllowedByNosniff() const; @@ -104,7 +102,7 @@ ScriptIntegrityDisposition m_integrityDisposition; IntegrityMetadataSet m_integrityMetadata; - CompressibleString m_script; + AtomicString m_script; }; DEFINE_RESOURCE_TYPE_CASTS(Script);
diff --git a/third_party/WebKit/Source/core/frame/Frame.cpp b/third_party/WebKit/Source/core/frame/Frame.cpp index 1c763fe..6fc666a0 100644 --- a/third_party/WebKit/Source/core/frame/Frame.cpp +++ b/third_party/WebKit/Source/core/frame/Frame.cpp
@@ -278,14 +278,6 @@ return nullptr; } -bool Frame::isCrossOrigin() const -{ - // Check to see if the frame can script into the top level document. - const SecurityOrigin* securityOrigin = securityContext()->getSecurityOrigin(); - Frame* top = tree().top(); - return top && !securityOrigin->canAccess(top->securityContext()->getSecurityOrigin()); -} - void Frame::didChangeVisibilityState() { HeapVector<Member<Frame>> childFrames;
diff --git a/third_party/WebKit/Source/core/frame/Frame.h b/third_party/WebKit/Source/core/frame/Frame.h index 50be7e5..a855dc5 100644 --- a/third_party/WebKit/Source/core/frame/Frame.h +++ b/third_party/WebKit/Source/core/frame/Frame.h
@@ -127,10 +127,6 @@ Settings* settings() const; // can be null - // Return true if and only if this frame is a cross-origin frame with - // respect to the top-level frame. - bool isCrossOrigin() const; - // isLoading() is true when the embedder should think a load is in progress. // In the case of LocalFrames, it means that the frame has sent a didStartLoading() // callback, but not the matching didStopLoading(). Inside blink, you probably
diff --git a/third_party/WebKit/Source/core/frame/FrameView.cpp b/third_party/WebKit/Source/core/frame/FrameView.cpp index 44f2446..15cff79b 100644 --- a/third_party/WebKit/Source/core/frame/FrameView.cpp +++ b/third_party/WebKit/Source/core/frame/FrameView.cpp
@@ -4161,7 +4161,8 @@ void FrameView::updateThrottlingStatus() { // Only offscreen frames can be throttled. - m_hiddenForThrottling = m_viewportIntersectionValid && m_viewportIntersection.isEmpty(); + DCHECK(m_viewportIntersectionValid); + m_hiddenForThrottling = m_viewportIntersection.isEmpty(); // We only throttle the rendering pipeline in cross-origin frames. This is // to avoid a situation where an ancestor frame directly depends on the
diff --git a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp index 1fb4ffe..7379a49a1 100644 --- a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp +++ b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
@@ -706,7 +706,7 @@ if (!isCurrentlyDisplayedInFrame()) return nullptr; - return frame()->document()->getSelection(); + return document()->getSelection(); } Element* LocalDOMWindow::frameElement() const @@ -730,8 +730,8 @@ if (!host) return; - if (frame()->document()->isSandboxed(SandboxModals)) { - UseCounter::count(frame()->document(), UseCounter::DialogInSandboxedContext); + if (document()->isSandboxed(SandboxModals)) { + UseCounter::count(document(), UseCounter::DialogInSandboxedContext); if (RuntimeEnabledFeatures::sandboxBlocksModalsEnabled()) { frameConsole()->addMessage(ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, "Ignored call to 'print()'. The document is sandboxed, and the 'allow-modals' keyword is not set.")); return; @@ -739,7 +739,7 @@ } if (scriptState && v8::MicrotasksScope::IsRunningMicrotasks(scriptState->isolate())) { - UseCounter::count(frame()->document(), UseCounter::During_Microtask_Print); + UseCounter::count(document(), UseCounter::During_Microtask_Print); } if (frame()->isLoading()) { @@ -747,8 +747,7 @@ return; } - if (frame()->isCrossOrigin()) - UseCounter::count(frame()->document(), UseCounter::CrossOriginWindowPrint); + UseCounter::countCrossOriginIframe(*document(), UseCounter::CrossOriginWindowPrint); m_shouldPrintWhenFinishedLoading = false; host->chromeClient().print(frame()); @@ -766,8 +765,8 @@ if (!frame()) return; - if (frame()->document()->isSandboxed(SandboxModals)) { - UseCounter::count(frame()->document(), UseCounter::DialogInSandboxedContext); + if (document()->isSandboxed(SandboxModals)) { + UseCounter::count(document(), UseCounter::DialogInSandboxedContext); if (RuntimeEnabledFeatures::sandboxBlocksModalsEnabled()) { frameConsole()->addMessage(ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, "Ignored call to 'alert()'. The document is sandboxed, and the 'allow-modals' keyword is not set.")); return; @@ -775,17 +774,16 @@ } if (v8::MicrotasksScope::IsRunningMicrotasks(scriptState->isolate())) { - UseCounter::count(frame()->document(), UseCounter::During_Microtask_Alert); + UseCounter::count(document(), UseCounter::During_Microtask_Alert); } - frame()->document()->updateStyleAndLayoutTree(); + document()->updateStyleAndLayoutTree(); FrameHost* host = frame()->host(); if (!host) return; - if (frame()->isCrossOrigin()) - UseCounter::count(frame()->document(), UseCounter::CrossOriginWindowAlert); + UseCounter::countCrossOriginIframe(*document(), UseCounter::CrossOriginWindowAlert); host->chromeClient().openJavaScriptAlert(frame(), message); } @@ -795,8 +793,8 @@ if (!frame()) return false; - if (frame()->document()->isSandboxed(SandboxModals)) { - UseCounter::count(frame()->document(), UseCounter::DialogInSandboxedContext); + if (document()->isSandboxed(SandboxModals)) { + UseCounter::count(document(), UseCounter::DialogInSandboxedContext); if (RuntimeEnabledFeatures::sandboxBlocksModalsEnabled()) { frameConsole()->addMessage(ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, "Ignored call to 'confirm()'. The document is sandboxed, and the 'allow-modals' keyword is not set.")); return false; @@ -804,17 +802,16 @@ } if (v8::MicrotasksScope::IsRunningMicrotasks(scriptState->isolate())) { - UseCounter::count(frame()->document(), UseCounter::During_Microtask_Confirm); + UseCounter::count(document(), UseCounter::During_Microtask_Confirm); } - frame()->document()->updateStyleAndLayoutTree(); + document()->updateStyleAndLayoutTree(); FrameHost* host = frame()->host(); if (!host) return false; - if (frame()->isCrossOrigin()) - UseCounter::count(frame()->document(), UseCounter::CrossOriginWindowConfirm); + UseCounter::countCrossOriginIframe(*document(), UseCounter::CrossOriginWindowConfirm); return host->chromeClient().openJavaScriptConfirm(frame(), message); } @@ -824,8 +821,8 @@ if (!frame()) return String(); - if (frame()->document()->isSandboxed(SandboxModals)) { - UseCounter::count(frame()->document(), UseCounter::DialogInSandboxedContext); + if (document()->isSandboxed(SandboxModals)) { + UseCounter::count(document(), UseCounter::DialogInSandboxedContext); if (RuntimeEnabledFeatures::sandboxBlocksModalsEnabled()) { frameConsole()->addMessage(ConsoleMessage::create(SecurityMessageSource, ErrorMessageLevel, "Ignored call to 'prompt()'. The document is sandboxed, and the 'allow-modals' keyword is not set.")); return String(); @@ -833,10 +830,10 @@ } if (v8::MicrotasksScope::IsRunningMicrotasks(scriptState->isolate())) { - UseCounter::count(frame()->document(), UseCounter::During_Microtask_Prompt); + UseCounter::count(document(), UseCounter::During_Microtask_Prompt); } - frame()->document()->updateStyleAndLayoutTree(); + document()->updateStyleAndLayoutTree(); FrameHost* host = frame()->host(); if (!host) @@ -846,8 +843,7 @@ if (host->chromeClient().openJavaScriptPrompt(frame(), message, defaultValue, returnValue)) return returnValue; - if (frame()->isCrossOrigin()) - UseCounter::count(frame()->document(), UseCounter::CrossOriginWindowPrompt); + UseCounter::countCrossOriginIframe(*document(), UseCounter::CrossOriginWindowPrompt); return String(); } @@ -859,7 +855,7 @@ // Up-to-date, clean tree is required for finding text in page, since it relies // on TextIterator to look over the text. - frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets(); + document()->updateStyleAndLayoutIgnorePendingStylesheets(); // FIXME (13016): Support searchInFrames and showDialog FindOptions options = (backwards ? Backwards : 0) | (caseSensitive ? 0 : CaseInsensitive) | (wrap ? WrapAround : 0) | (wholeWord ? WholeWord | AtWordStarts : 0); @@ -920,7 +916,7 @@ // layout, perform one now so queries during page load will use the up to // date viewport. if (host->settings().viewportEnabled() && frame()->isMainFrame()) - frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets(); + document()->updateStyleAndLayoutIgnorePendingStylesheets(); // FIXME: This is potentially too much work. We really only need to know the dimensions of the parent frame's layoutObject. if (Frame* parent = frame()->tree().parent()) { @@ -993,7 +989,7 @@ if (!view) return 0; - frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets(); + document()->updateStyleAndLayoutIgnorePendingStylesheets(); double viewportX = view->layoutViewportScrollableArea()->scrollPositionDouble().x(); return adjustScrollForAbsoluteZoom(viewportX, frame()->pageZoomFactor()); @@ -1011,7 +1007,7 @@ if (!view) return 0; - frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets(); + document()->updateStyleAndLayoutIgnorePendingStylesheets(); double viewportY = view->layoutViewportScrollableArea()->scrollPositionDouble().y(); return adjustScrollForAbsoluteZoom(viewportY, frame()->pageZoomFactor()); @@ -1057,7 +1053,6 @@ if (!host) return; - ASSERT(frame()->document()); // Client calls shouldn't be made when the frame is in inconsistent state. host->chromeClient().setStatusbarText(m_status); } @@ -1072,7 +1067,6 @@ if (!host) return; - ASSERT(frame()->document()); // Client calls shouldn't be made when the frame is in inconsistent state. host->chromeClient().setStatusbarText(m_defaultStatus); } @@ -1110,7 +1104,7 @@ unsigned rulesToInclude = StyleResolver::AuthorCSSRules; PseudoId pseudoId = CSSSelector::pseudoId(pseudoType); element->document().updateStyleAndLayoutTree(); - return frame()->document()->ensureStyleResolver().pseudoCSSRulesForElement(element, pseudoId, rulesToInclude); + return document()->ensureStyleResolver().pseudoCSSRulesForElement(element, pseudoId, rulesToInclude); } double LocalDOMWindow::devicePixelRatio() const
diff --git a/third_party/WebKit/Source/core/frame/LocalFrame.cpp b/third_party/WebKit/Source/core/frame/LocalFrame.cpp index 573e327..de4cd1c9 100644 --- a/third_party/WebKit/Source/core/frame/LocalFrame.cpp +++ b/third_party/WebKit/Source/core/frame/LocalFrame.cpp
@@ -529,6 +529,14 @@ return curFrame; } + +bool LocalFrame::isCrossOriginSubframe() const +{ + const SecurityOrigin* securityOrigin = securityContext()->getSecurityOrigin(); + Frame* top = tree().top(); + return top && !securityOrigin->canAccess(top->securityContext()->getSecurityOrigin()); +} + void LocalFrame::setPrinting(bool printing, const FloatSize& pageSize, const FloatSize& originalPageSize, float maximumShrinkRatio) { // In setting printing, we should not validate resources already cached for the document.
diff --git a/third_party/WebKit/Source/core/frame/LocalFrame.h b/third_party/WebKit/Source/core/frame/LocalFrame.h index 889f341..67c3960 100644 --- a/third_party/WebKit/Source/core/frame/LocalFrame.h +++ b/third_party/WebKit/Source/core/frame/LocalFrame.h
@@ -134,6 +134,14 @@ // should be updated to avoid storing things on the main frame. LocalFrame* localFrameRoot(); + // Note that the result of this function should not be cached: a frame is + // not necessarily detached when it is navigated, so the return value can + // change. + // In addition, this function will always return true for a detached frame. + // TODO(dcheng): Move this to LocalDOMWindow and figure out the right + // behavior for detached windows. + bool isCrossOriginSubframe() const; + InstrumentingAgents* instrumentingAgents() { return m_instrumentingAgents.get(); } // ======== All public functions below this point are candidates to move out of LocalFrame into another class. ========
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.cpp b/third_party/WebKit/Source/core/frame/UseCounter.cpp index 3f8b2814..9ebca1e 100644 --- a/third_party/WebKit/Source/core/frame/UseCounter.cpp +++ b/third_party/WebKit/Source/core/frame/UseCounter.cpp
@@ -738,8 +738,8 @@ void UseCounter::countCrossOriginIframe(const Document& document, Feature feature) { - Frame* frame = document.frame(); - if (frame && frame->isCrossOrigin()) + LocalFrame* frame = document.frame(); + if (frame && frame->isCrossOriginSubframe()) count(frame, feature); }
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.h b/third_party/WebKit/Source/core/frame/UseCounter.h index 0552223..3a7671b 100644 --- a/third_party/WebKit/Source/core/frame/UseCounter.h +++ b/third_party/WebKit/Source/core/frame/UseCounter.h
@@ -1274,6 +1274,8 @@ ChromeLoadTimesConnectionInfo = 1498, ChromeLoadTimesUnknown = 1499, + SVGViewElement = 1500, + // Add new features immediately above this line. Don't change assigned // numbers of any item, and don't reuse removed slots. // Also, run update_use_counter_feature_enum.py in chromium/src/tools/metrics/histograms/
diff --git a/third_party/WebKit/Source/core/html/HTMLAreaElement.cpp b/third_party/WebKit/Source/core/html/HTMLAreaElement.cpp index 7e72fd17..bbc7919 100644 --- a/third_party/WebKit/Source/core/html/HTMLAreaElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLAreaElement.cpp
@@ -199,7 +199,7 @@ bool HTMLAreaElement::layoutObjectIsFocusable() const { HTMLImageElement* image = imageElement(); - if (!image || !image->layoutObject() || image->layoutObject()->style()->visibility() != VISIBLE) + if (!image || !image->layoutObject() || image->layoutObject()->style()->visibility() != EVisibility::Visible) return false; return supportsFocus() && Element::tabIndex() >= 0;
diff --git a/third_party/WebKit/Source/core/html/HTMLEmbedElement.cpp b/third_party/WebKit/Source/core/html/HTMLEmbedElement.cpp index dfb698d..b10434d 100644 --- a/third_party/WebKit/Source/core/html/HTMLEmbedElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLEmbedElement.cpp
@@ -33,6 +33,7 @@ #include "core/html/PluginDocument.h" #include "core/html/parser/HTMLParserIdioms.h" #include "core/layout/LayoutPart.h" +#include "core/loader/FrameLoaderClient.h" namespace blink { @@ -146,6 +147,14 @@ if (!layoutObject()) return; + // Overwrites the URL and MIME type of a Flash embed to use an + // HTML5 embed when possible. + KURL overridenUrl = document().frame()->loader().client()->overrideFlashEmbedWithHTML(document().completeURL(m_url)); + if (!overridenUrl.isEmpty()) { + m_url = overridenUrl.getString(); + m_serviceType = "text/html"; + } + requestObject(m_url, m_serviceType, paramNames, paramValues); }
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp index 6fd1abf3..477cbbb 100644 --- a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
@@ -333,8 +333,8 @@ // Frame bool isCrossOrigin() const override { - const Frame* frame = m_element->document().frame(); - return frame && frame->isCrossOrigin(); + const LocalFrame* frame = m_element->document().frame(); + return frame && frame->isCrossOriginSubframe(); } bool isAutoplayAllowedPerSettings() const override;
diff --git a/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp b/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp index 52e34180..b9c293c4 100644 --- a/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp
@@ -45,6 +45,7 @@ #include "core/page/Page.h" #include "core/page/scrolling/ScrollingCoordinator.h" #include "core/plugins/PluginView.h" +#include "platform/Histogram.h" #include "platform/Logging.h" #include "platform/MIMETypeFromURL.h" #include "platform/MIMETypeRegistry.h" @@ -57,6 +58,18 @@ using namespace HTMLNames; +namespace { + +// Used for histograms, do not change the order. +enum PluginRequestObjectResult { + PluginRequestObjectResultFailure = 0, + PluginRequestObjectResultSuccess = 1, + // Keep at the end. + PluginRequestObjectResultMax +}; + +} // anonymous namespace + HTMLPlugInElement::HTMLPlugInElement(const QualifiedName& tagName, Document& doc, bool createdByParser, PreferPlugInsForImagesOption preferPlugInsForImagesOption) : HTMLFrameOwnerElement(tagName, doc) , m_isDelayingLoadEvent(false) @@ -97,6 +110,31 @@ m_persistedPluginWidget = widget; } +bool HTMLPlugInElement::requestObjectInternal(const String& url, const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues) +{ + if (url.isEmpty() && mimeType.isEmpty()) + return false; + + if (protocolIsJavaScript(url)) + return false; + + KURL completedURL = url.isEmpty() ? KURL() : document().completeURL(url); + if (!allowedToLoadObject(completedURL, mimeType)) + return false; + + bool useFallback; + if (!shouldUsePlugin(completedURL, mimeType, hasFallbackContent(), useFallback)) { + // If the plugin element already contains a subframe, + // loadOrRedirectSubframe will re-use it. Otherwise, it will create a + // new frame and set it as the LayoutPart's widget, causing what was + // previously in the widget to be torn down. + return loadOrRedirectSubframe(completedURL, getNameAttribute(), true); + } + + return loadPlugin(completedURL, mimeType, paramNames, paramValues, useFallback, true); +} + + bool HTMLPlugInElement::canProcessDrag() const { return pluginWidget() && pluginWidget()->isPluginView() && toPluginView(pluginWidget())->canProcessDrag(); @@ -446,26 +484,12 @@ bool HTMLPlugInElement::requestObject(const String& url, const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues) { - if (url.isEmpty() && mimeType.isEmpty()) - return false; + bool result = requestObjectInternal(url, mimeType, paramNames, paramValues); - if (protocolIsJavaScript(url)) - return false; + DEFINE_STATIC_LOCAL(EnumerationHistogram, resultHistogram, ("Plugin.RequestObjectResult", PluginRequestObjectResultMax)); + resultHistogram.count(result ? PluginRequestObjectResultSuccess : PluginRequestObjectResultFailure); - KURL completedURL = url.isEmpty() ? KURL() : document().completeURL(url); - if (!allowedToLoadObject(completedURL, mimeType)) - return false; - - bool useFallback; - if (!shouldUsePlugin(completedURL, mimeType, hasFallbackContent(), useFallback)) { - // If the plugin element already contains a subframe, - // loadOrRedirectSubframe will re-use it. Otherwise, it will create a - // new frame and set it as the LayoutPart's widget, causing what was - // previously in the widget to be torn down. - return loadOrRedirectSubframe(completedURL, getNameAttribute(), true); - } - - return loadPlugin(completedURL, mimeType, paramNames, paramValues, useFallback, true); + return result; } bool HTMLPlugInElement::loadPlugin(const KURL& url, const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback, bool requireLayoutObject)
diff --git a/third_party/WebKit/Source/core/html/HTMLPlugInElement.h b/third_party/WebKit/Source/core/html/HTMLPlugInElement.h index 2d7aaecc..d38b9a5 100644 --- a/third_party/WebKit/Source/core/html/HTMLPlugInElement.h +++ b/third_party/WebKit/Source/core/html/HTMLPlugInElement.h
@@ -137,6 +137,8 @@ void setPersistedPluginWidget(Widget*); + bool requestObjectInternal(const String& url, const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues); + mutable RefPtr<SharedPersistent<v8::Object>> m_pluginWrapper; bool m_needsWidgetUpdate; bool m_shouldPreferPlugInsForImages;
diff --git a/third_party/WebKit/Source/core/html/ImageData.cpp b/third_party/WebKit/Source/core/html/ImageData.cpp index 68e82d6..22489bac 100644 --- a/third_party/WebKit/Source/core/html/ImageData.cpp +++ b/third_party/WebKit/Source/core/html/ImageData.cpp
@@ -87,7 +87,7 @@ DOMUint8ClampedArray* byteArray = DOMUint8ClampedArray::createOrNull(dataSize.ValueOrDie()); if (!byteArray) { - exceptionState.throwDOMException(V8GeneralError, "Out of memory at ImageData creation"); + exceptionState.throwDOMException(V8Error, "Out of memory at ImageData creation"); return nullptr; }
diff --git a/third_party/WebKit/Source/core/html/forms/InputType.cpp b/third_party/WebKit/Source/core/html/forms/InputType.cpp index 2bb347f1..2ffac57 100644 --- a/third_party/WebKit/Source/core/html/forms/InputType.cpp +++ b/third_party/WebKit/Source/core/html/forms/InputType.cpp
@@ -593,7 +593,7 @@ { // Don't warn if the value is set in Modernizr. const ComputedStyle* style = element().computedStyle(); - if (style && style->visibility() != HIDDEN) + if (style && style->visibility() != EVisibility::Hidden) warnIfValueIsInvalid(value); } @@ -911,7 +911,7 @@ void InputType::countUsageIfVisible(UseCounter::Feature feature) const { if (const ComputedStyle* style = element().computedStyle()) { - if (style->visibility() != HIDDEN) + if (style->visibility() != EVisibility::Hidden) UseCounter::count(element().document(), feature); } }
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.cpp b/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.cpp index b58829e..d386b0977 100644 --- a/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.cpp +++ b/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.cpp
@@ -435,7 +435,7 @@ } else { ASSERT(m_scriptNestingLevel > 1); m_parserBlockingScript->releaseElementAndClear(); - ScriptSourceCode sourceCode(CompressibleString(script->textContent().impl()), documentURLForScriptExecution(m_document), scriptStartPosition); + ScriptSourceCode sourceCode(script->textContent(), documentURLForScriptExecution(m_document), scriptStartPosition); doExecuteScript(script, sourceCode, scriptStartPosition); } } else {
diff --git a/third_party/WebKit/Source/core/html/shadow/MediaControls.cpp b/third_party/WebKit/Source/core/html/shadow/MediaControls.cpp index abb61be..439d992 100644 --- a/third_party/WebKit/Source/core/html/shadow/MediaControls.cpp +++ b/third_party/WebKit/Source/core/html/shadow/MediaControls.cpp
@@ -706,9 +706,11 @@ // should be available the first time we're called after layout. This will // also be the first time we have m_panelWidth!=0, so it won't matter if // we get this wrong before that. - int minimumWidth = (m_playButton->layoutObject() && m_playButton->layoutObject()->style()) - ? m_playButton->layoutObject()->style()->width().pixels() - : 48; + int minimumWidth = 48; + if (m_playButton->layoutObject() && m_playButton->layoutObject()->style()) { + const ComputedStyle* style = m_playButton->layoutObject()->style(); + minimumWidth = ceil(style->width().pixels() / style->effectiveZoom()); + } // Special-case the play button; it always fits. if (m_playButton->isWanted()) {
diff --git a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.cpp b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.cpp index 9087a88..e8ebd69 100644 --- a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.cpp +++ b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.cpp
@@ -56,7 +56,7 @@ namespace blink { -static inline ImageBitmapSource* toImageBitmapSourceInternal(const ImageBitmapSourceUnion& value, ExceptionState& exceptionState, bool hasCropRect) +static inline ImageBitmapSource* toImageBitmapSourceInternal(const ImageBitmapSourceUnion& value, ExceptionState& exceptionState, const ImageBitmapOptions& options, bool hasCropRect) { if (value.isHTMLImageElement()) { HTMLImageElement* imageElement = value.getAsHTMLImageElement(); @@ -66,8 +66,8 @@ } if (imageElement->cachedImage()->getImage()->isSVGImage()) { SVGImage* image = toSVGImage(imageElement->cachedImage()->getImage()); - if (!image->hasIntrinsicDimensions() && !hasCropRect) { - exceptionState.throwDOMException(InvalidStateError, "The image element contains an SVG image without intrinsic dimensions."); + if (!image->hasIntrinsicDimensions() && (!hasCropRect && (!options.hasResizeWidth() || !options.hasResizeHeight()))) { + exceptionState.throwDOMException(InvalidStateError, "The image element contains an SVG image without intrinsic dimensions, and no resize options or crop region are specified."); return nullptr; } } @@ -105,7 +105,7 @@ { UseCounter::Feature feature = UseCounter::CreateImageBitmap; UseCounter::count(scriptState->getExecutionContext(), feature); - ImageBitmapSource* bitmapSourceInternal = toImageBitmapSourceInternal(bitmapSource, exceptionState, false); + ImageBitmapSource* bitmapSourceInternal = toImageBitmapSourceInternal(bitmapSource, exceptionState, options, false); if (!bitmapSourceInternal) return ScriptPromise(); return createImageBitmap(scriptState, eventTarget, bitmapSourceInternal, Optional<IntRect>(), options, exceptionState); @@ -115,7 +115,7 @@ { UseCounter::Feature feature = UseCounter::CreateImageBitmap; UseCounter::count(scriptState->getExecutionContext(), feature); - ImageBitmapSource* bitmapSourceInternal = toImageBitmapSourceInternal(bitmapSource, exceptionState, true); + ImageBitmapSource* bitmapSourceInternal = toImageBitmapSourceInternal(bitmapSource, exceptionState, options, true); if (!bitmapSourceInternal) return ScriptPromise(); Optional<IntRect> cropRect = IntRect(sx, sy, sw, sh);
diff --git a/third_party/WebKit/Source/core/input/EventHandler.cpp b/third_party/WebKit/Source/core/input/EventHandler.cpp index a8011432..0f1e3bc 100644 --- a/third_party/WebKit/Source/core/input/EventHandler.cpp +++ b/third_party/WebKit/Source/core/input/EventHandler.cpp
@@ -1491,6 +1491,11 @@ m_pointerEventManager.releasePointerCapture(pointerId, target); } +bool EventHandler::hasPointerCapture(int pointerId, EventTarget* target) +{ + return m_pointerEventManager.hasPointerCapture(pointerId, target); +} + void EventHandler::elementRemoved(EventTarget* target) { m_pointerEventManager.elementRemoved(target);
diff --git a/third_party/WebKit/Source/core/input/EventHandler.h b/third_party/WebKit/Source/core/input/EventHandler.h index 36ca6f2..ec677e8 100644 --- a/third_party/WebKit/Source/core/input/EventHandler.h +++ b/third_party/WebKit/Source/core/input/EventHandler.h
@@ -186,6 +186,8 @@ void setPointerCapture(int, EventTarget*); void releasePointerCapture(int, EventTarget*); + bool hasPointerCapture(int, EventTarget*); + void elementRemoved(EventTarget*); void setMouseDownMayStartAutoscroll() { m_mouseDownMayStartAutoscroll = true; }
diff --git a/third_party/WebKit/Source/core/input/PointerEventManager.cpp b/third_party/WebKit/Source/core/input/PointerEventManager.cpp index 035250a9..d258c2e 100644 --- a/third_party/WebKit/Source/core/input/PointerEventManager.cpp +++ b/third_party/WebKit/Source/core/input/PointerEventManager.cpp
@@ -760,6 +760,11 @@ releasePointerCapture(pointerId); } +bool PointerEventManager::hasPointerCapture(int pointerId, EventTarget* target) +{ + return m_pendingPointerCaptureTarget.get(pointerId) == target; +} + void PointerEventManager::releasePointerCapture(int pointerId) { m_pendingPointerCaptureTarget.remove(pointerId);
diff --git a/third_party/WebKit/Source/core/input/PointerEventManager.h b/third_party/WebKit/Source/core/input/PointerEventManager.h index 1e4f045..fab3b691 100644 --- a/third_party/WebKit/Source/core/input/PointerEventManager.h +++ b/third_party/WebKit/Source/core/input/PointerEventManager.h
@@ -63,8 +63,11 @@ void clear(); void elementRemoved(EventTarget*); + void setPointerCapture(int, EventTarget*); void releasePointerCapture(int, EventTarget*); + bool hasPointerCapture(int, EventTarget*); + bool isActive(const int) const; // Returns whether there is any touch on the screen.
diff --git a/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp index 6c459fc..9abe2d5 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp +++ b/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp
@@ -232,7 +232,7 @@ maybeEncodeTextContent(toCSSStyleSheetResource(cachedResource)->sheetText(), cachedResource->resourceBuffer(), result, base64Encoded); return true; case Resource::Script: - maybeEncodeTextContent(cachedResource->resourceBuffer() ? toScriptResource(cachedResource)->decodedText() : toScriptResource(cachedResource)->script().toString(), cachedResource->resourceBuffer(), result, base64Encoded); + maybeEncodeTextContent(cachedResource->resourceBuffer() ? toScriptResource(cachedResource)->decodedText() : toScriptResource(cachedResource)->script(), cachedResource->resourceBuffer(), result, base64Encoded); return true; default: String textEncodingName = cachedResource->response().textEncodingName();
diff --git a/third_party/WebKit/Source/core/inspector/browser_protocol.json b/third_party/WebKit/Source/core/inspector/browser_protocol.json index d442142..df48813 100644 --- a/third_party/WebKit/Source/core/inspector/browser_protocol.json +++ b/third_party/WebKit/Source/core/inspector/browser_protocol.json
@@ -2,7 +2,7 @@ "version": { "major": "1", "minor": "1" }, "domains": [{ "domain": "Inspector", - "hidden": true, + "experimental": true, "types": [], "commands": [ { @@ -34,7 +34,7 @@ }, { "domain": "Memory", - "hidden": true, + "experimental": true, "types": [ { "id": "PressureLevel", @@ -111,7 +111,7 @@ { "name": "failed", "type": "boolean", "optional": true, "description": "True if the resource failed to load." }, { "name": "canceled", "type": "boolean", "optional": true, "description": "True if the resource was canceled during loading." } ], - "hidden": true + "experimental": true }, { "id": "FrameResourceTree", @@ -122,13 +122,13 @@ { "name": "childFrames", "type": "array", "optional": true, "items": { "$ref": "FrameResourceTree" }, "description": "Child frames." }, { "name": "resources", "type": "array", "items": { "$ref": "FrameResource" }, "description": "Information about frame resources." } ], - "hidden": true + "experimental": true }, { "id": "ScriptIdentifier", "type": "string", "description": "Unique script identifier.", - "hidden": true + "experimental": true }, { "id": "NavigationEntry", @@ -139,29 +139,29 @@ { "name": "url", "type": "string", "description": "URL of the navigation history entry." }, { "name": "title", "type": "string", "description": "Title of the navigation history entry." } ], - "hidden": true + "experimental": true }, { "id": "ScreencastFrameMetadata", "type": "object", "description": "Screencast frame metadata.", "properties": [ - { "name": "offsetTop", "type": "number", "hidden": true, "description": "Top offset in DIP." }, - { "name": "pageScaleFactor", "type": "number", "hidden": true, "description": "Page scale factor." }, - { "name": "deviceWidth", "type": "number", "hidden": true, "description": "Device screen width in DIP." }, - { "name": "deviceHeight", "type": "number", "hidden": true, "description": "Device screen height in DIP." }, - { "name": "scrollOffsetX", "type": "number", "hidden": true, "description": "Position of horizontal scroll in CSS pixels." }, - { "name": "scrollOffsetY", "type": "number", "hidden": true, "description": "Position of vertical scroll in CSS pixels." }, - { "name": "timestamp", "type": "number", "optional": true, "hidden": true, "description": "Frame swap timestamp." } + { "name": "offsetTop", "type": "number", "experimental": true, "description": "Top offset in DIP." }, + { "name": "pageScaleFactor", "type": "number", "experimental": true, "description": "Page scale factor." }, + { "name": "deviceWidth", "type": "number", "experimental": true, "description": "Device screen width in DIP." }, + { "name": "deviceHeight", "type": "number", "experimental": true, "description": "Device screen height in DIP." }, + { "name": "scrollOffsetX", "type": "number", "experimental": true, "description": "Position of horizontal scroll in CSS pixels." }, + { "name": "scrollOffsetY", "type": "number", "experimental": true, "description": "Position of vertical scroll in CSS pixels." }, + { "name": "timestamp", "type": "number", "optional": true, "experimental": true, "description": "Frame swap timestamp." } ], - "hidden": true + "experimental": true }, { "id": "DialogType", "description": "Javascript dialog type.", "type": "string", "enum": ["alert", "confirm", "prompt", "beforeunload"], - "hidden": true + "experimental": true }, { "id": "AppManifestError", @@ -173,14 +173,14 @@ { "name": "line", "type": "integer", "description": "Error line." }, { "name": "column", "type": "integer", "description": "Error column." } ], - "hidden": true + "experimental": true }, { "id": "NavigationResponse", "description": "Proceed: allow the navigation; Cancel: cancel the navigation; CancelAndIgnore: cancels the navigation and makes the requester of the navigation acts like the request was never made.", "type": "string", "enum": ["Proceed", "Cancel", "CancelAndIgnore"], - "hidden": true + "experimental": true } ], "commands": [ @@ -202,14 +202,14 @@ "returns": [ { "name": "identifier", "$ref": "ScriptIdentifier", "description": "Identifier of the added script." } ], - "hidden": true + "experimental": true }, { "name": "removeScriptToEvaluateOnLoad", "parameters": [ { "name": "identifier", "$ref": "ScriptIdentifier" } ], - "hidden": true + "experimental": true }, { "name": "setAutoAttachToCreatedPages", @@ -217,7 +217,7 @@ { "name": "autoAttach", "type": "boolean", "description": "If true, browser will open a new inspector window for every page created from this one." } ], "description": "Controls whether browser will open a new inspector window for connected pages.", - "hidden": true + "experimental": true }, { "name": "reload", @@ -234,7 +234,7 @@ { "name": "url", "type": "string", "description": "URL to navigate the page to." } ], "returns": [ - { "name": "frameId", "$ref": "FrameId", "hidden": true, "description": "Frame id that will be navigated." } + { "name": "frameId", "$ref": "FrameId", "experimental": true, "description": "Frame id that will be navigated." } ], "description": "Navigates current page to the given URL.", "handlers": ["browser", "renderer"] @@ -246,7 +246,7 @@ { "name": "entries", "type": "array", "items": { "$ref": "NavigationEntry" }, "description": "Array of navigation history entries." } ], "description": "Returns navigation history for the current page.", - "hidden": true, + "experimental": true, "handlers": ["browser"] }, { @@ -255,7 +255,7 @@ { "name": "entryId", "type": "integer", "description": "Unique id of the entry to navigate to." } ], "description": "Navigates current page to the given history entry.", - "hidden": true, + "experimental": true, "handlers": ["browser"] }, { @@ -266,7 +266,7 @@ "description": "Returns all browser cookies. Depending on the backend support, will return detailed cookie information in the <code>cookies</code> field.", "handlers": ["browser"], "async": true, - "hidden": true, + "experimental": true, "redirect": "Network" }, { @@ -278,7 +278,7 @@ "description": "Deletes browser cookie with given name, domain and path.", "handlers": ["browser"], "async": true, - "hidden": true, + "experimental": true, "redirect": "Network" }, { @@ -287,7 +287,7 @@ "returns": [ { "name": "frameTree", "$ref": "FrameResourceTree", "description": "Present frame / resource tree structure." } ], - "hidden": true + "experimental": true }, { "name": "getResourceContent", @@ -301,7 +301,7 @@ { "name": "content", "type": "string", "description": "Resource content." }, { "name": "base64Encoded", "type": "boolean", "description": "True, if content was served as base64." } ], - "hidden": true + "experimental": true }, { "name": "searchInResource", @@ -317,7 +317,7 @@ "returns": [ { "name": "result", "type": "array", "items": { "$ref": "Debugger.SearchMatch" }, "description": "List of search matches." } ], - "hidden": true + "experimental": true }, { "name": "setDocumentContent", @@ -326,7 +326,7 @@ { "name": "frameId", "$ref": "FrameId", "description": "Frame id to set HTML for." }, { "name": "html", "type": "string", "description": "HTML content to set." } ], - "hidden": true + "experimental": true }, { "name": "setDeviceMetricsOverride", @@ -348,14 +348,14 @@ ], "handlers": ["browser"], "redirect": "Emulation", - "hidden": true + "experimental": true }, { "name": "clearDeviceMetricsOverride", "description": "Clears the overriden device metrics.", "handlers": ["browser"], "redirect": "Emulation", - "hidden": true + "experimental": true }, { "name": "setGeolocationOverride", @@ -383,13 +383,13 @@ { "name": "gamma", "type": "number", "description": "Mock gamma"} ], "redirect": "DeviceOrientation", - "hidden": true + "experimental": true }, { "name": "clearDeviceOrientationOverride", "description": "Clears the overridden Device Orientation.", "redirect": "DeviceOrientation", - "hidden": true + "experimental": true }, { "name": "setTouchEmulationEnabled", @@ -398,7 +398,7 @@ { "name": "configuration", "type": "string", "enum": ["mobile", "desktop"], "optional": true, "description": "Touch/gesture events configuration. Default: current platform." } ], "description": "Toggles mouse event-based touch event emulation.", - "hidden": true, + "experimental": true, "redirect": "Emulation", "handlers": ["browser", "renderer"] }, @@ -409,7 +409,7 @@ "returns": [ { "name": "data", "type": "string", "description": "Base64-encoded image data (PNG)." } ], - "hidden": true, + "experimental": true, "handlers": ["browser"] }, { @@ -422,13 +422,13 @@ { "name": "maxHeight", "type": "integer", "optional": true, "description": "Maximum screenshot height." }, { "name": "everyNthFrame", "type": "integer", "optional": true, "description": "Send every n-th frame." } ], - "hidden": true, + "experimental": true, "handlers": ["browser", "renderer"] }, { "name": "stopScreencast", "description": "Stops sending each frame in the <code>screencastFrame</code>.", - "hidden": true, + "experimental": true, "handlers": ["browser", "renderer"] }, { @@ -437,7 +437,7 @@ "parameters": [ { "name": "sessionId", "type": "integer", "description": "Frame number." } ], - "hidden": true, + "experimental": true, "handlers": ["browser"] }, { @@ -447,7 +447,7 @@ { "name": "accept", "type": "boolean", "description": "Whether to accept or dismiss the dialog." }, { "name": "promptText", "type": "string", "optional": true, "description": "The text to enter into the dialog prompt before accepting. Used only if this is a prompt dialog." } ], - "hidden": true, + "experimental": true, "handlers": ["browser"] }, { @@ -456,7 +456,7 @@ { "name": "enabled", "type": "boolean", "description": "Shows / hides color picker" } ], "description": "Shows / hides color picker", - "hidden": true, + "experimental": true, "handlers": ["browser"] }, { @@ -465,12 +465,12 @@ { "name": "suspended", "type": "boolean", "optional": true, "description": "Whether overlay should be suspended and not consume any resources." }, { "name": "message", "type": "string", "optional": true, "description": "Overlay message to display." } ], - "hidden": true, + "experimental": true, "description": "Configures overlay." }, { "name": "getAppManifest", - "hidden": true, + "experimental": true, "returns": [ { "name": "url", "type": "string", "description": "Manifest location." }, { "name": "errors", "type": "array", "items": { "$ref": "AppManifestError" } }, @@ -480,12 +480,12 @@ }, { "name": "requestAppBanner", - "hidden": true, + "experimental": true, "handlers": ["browser"] }, { "name": "setBlockedEventsWarningThreshold", - "hidden": true, + "experimental": true, "parameters": [ { "name": "threshold", "type": "number", "description": "If set to a positive number, specifies threshold in seconds for input event latency that will cause a console warning about blocked event to be issued. If zero or less, the warning is disabled." } ] @@ -496,7 +496,7 @@ { "name": "enabled", "type": "boolean" } ], "description": "Toggles navigation throttling which allows programatic control over navigation and redirect response.", - "hidden": true, + "experimental": true, "handlers": ["browser"] }, { @@ -506,7 +506,7 @@ { "name": "navigationId", "type": "integer" } ], "description": "Should be sent in response to a navigationRequested or a redirectRequested event, telling the browser how to handle the navigation.", - "hidden": true, + "experimental": true, "handlers": ["browser"] } ], @@ -551,7 +551,7 @@ "parameters": [ { "name": "frameId", "$ref": "FrameId", "description": "Id of the frame that has started loading." } ], - "hidden": true + "experimental": true }, { "name": "frameStoppedLoading", @@ -559,7 +559,7 @@ "parameters": [ { "name": "frameId", "$ref": "FrameId", "description": "Id of the frame that has stopped loading." } ], - "hidden": true + "experimental": true }, { "name": "frameScheduledNavigation", @@ -568,7 +568,7 @@ { "name": "frameId", "$ref": "FrameId", "description": "Id of the frame that has scheduled a navigation." }, { "name": "delay", "type": "number", "description": "Delay (in seconds) until the navigation is scheduled to begin. The navigation is not guaranteed to start." } ], - "hidden": true + "experimental": true }, { "name": "frameClearedScheduledNavigation", @@ -576,11 +576,11 @@ "parameters": [ { "name": "frameId", "$ref": "FrameId", "description": "Id of the frame that has cleared its scheduled navigation." } ], - "hidden": true + "experimental": true }, { "name": "frameResized", - "hidden": true + "experimental": true }, { "name": "javascriptDialogOpening", @@ -589,7 +589,7 @@ { "name": "message", "type": "string", "description": "Message that will be displayed by the dialog." }, { "name": "type", "$ref": "DialogType", "description": "Dialog type." } ], - "hidden": true + "experimental": true }, { "name": "javascriptDialogClosed", @@ -597,7 +597,7 @@ "parameters": [ { "name": "result", "type": "boolean", "description": "Whether dialog was confirmed." } ], - "hidden": true + "experimental": true }, { "name": "screencastFrame", @@ -607,7 +607,7 @@ { "name": "metadata", "$ref": "ScreencastFrameMetadata", "description": "Screencast frame metadata."}, { "name": "sessionId", "type": "integer", "description": "Frame number."} ], - "hidden": true, + "experimental": true, "handlers": ["browser"] }, { @@ -616,7 +616,7 @@ "parameters": [ { "name": "visible", "type": "boolean", "description": "True if the page is visible." } ], - "hidden": true, + "experimental": true, "handlers": ["browser"] }, { @@ -625,19 +625,19 @@ "parameters": [ { "name": "color", "$ref": "DOM.RGBA", "description": "RGBA of the picked color." } ], - "hidden": true, + "experimental": true, "handlers": ["browser"] }, { "name": "interstitialShown", "description": "Fired when interstitial page was shown", - "hidden": true, + "experimental": true, "handlers": ["browser"] }, { "name": "interstitialHidden", "description": "Fired when interstitial page was hidden", - "hidden": true, + "experimental": true, "handlers": ["browser"] }, { @@ -656,7 +656,7 @@ { "domain": "Rendering", "description": "This domain allows to control rendering of the page.", - "hidden": true, + "experimental": true, "commands": [ { "name": "setShowPaintRects", @@ -698,7 +698,7 @@ { "domain": "Emulation", "description": "This domain emulates different environments for the page.", - "hidden": true, + "experimental": true, "types": [ { "id": "ScreenOrientation", @@ -817,7 +817,7 @@ { "name": "policy", "$ref": "VirtualTimePolicy" }, { "name": "budget", "type": "integer", "optional": true, "description": "If set, after this many virtual milliseconds have elapsed virtual time will be paused and a virtualTimeBudgetExpired event is sent." } ], - "hidden": true + "experimental": true } ], "events": [ @@ -830,7 +830,7 @@ { "domain": "Security", "description": "Security", - "hidden": true, + "experimental": true, "types": [ { "id": "CertificateId", @@ -937,12 +937,12 @@ { "name": "connectEnd", "type": "number", "description": "Connected to the remote host." }, { "name": "sslStart", "type": "number", "description": "Started SSL handshake." }, { "name": "sslEnd", "type": "number", "description": "Finished SSL handshake." }, - { "name": "workerStart", "type": "number", "description": "Started running ServiceWorker.", "hidden": true }, - { "name": "workerReady", "type": "number", "description": "Finished Starting ServiceWorker.", "hidden": true }, + { "name": "workerStart", "type": "number", "description": "Started running ServiceWorker.", "experimental": true }, + { "name": "workerReady", "type": "number", "description": "Finished Starting ServiceWorker.", "experimental": true }, { "name": "sendStart", "type": "number", "description": "Started sending request." }, { "name": "sendEnd", "type": "number", "description": "Finished sending request." }, - { "name": "pushStart", "type": "number", "description": "Time the server started pushing request.", "hidden": true }, - { "name": "pushEnd", "type": "number", "description": "Time the server finished pushing request.", "hidden": true }, + { "name": "pushStart", "type": "number", "description": "Time the server started pushing request.", "experimental": true }, + { "name": "pushEnd", "type": "number", "description": "Time the server finished pushing request.", "experimental": true }, { "name": "receiveHeadersEnd", "type": "number", "description": "Finished receiving response headers." } ] }, @@ -1019,7 +1019,7 @@ "type": "string", "description": "The reason why request was blocked.", "enum": ["csp", "mixed-content", "origin", "inspector", "subresource-filter", "other"], - "hidden": true + "experimental": true }, { "id": "Response", @@ -1036,8 +1036,8 @@ { "name": "requestHeadersText", "type": "string", "optional": true, "description": "HTTP request headers text." }, { "name": "connectionReused", "type": "boolean", "description": "Specifies whether physical connection was actually reused for this request." }, { "name": "connectionId", "type": "number", "description": "Physical connection id that was actually used for this request." }, - { "name": "remoteIPAddress", "type": "string", "optional": true, "hidden": true, "description": "Remote IP address." }, - { "name": "remotePort", "type": "integer", "optional": true, "hidden": true, "description": "Remote port."}, + { "name": "remoteIPAddress", "type": "string", "optional": true, "experimental": true, "description": "Remote IP address." }, + { "name": "remotePort", "type": "integer", "optional": true, "experimental": true, "description": "Remote port."}, { "name": "fromDiskCache", "type": "boolean", "optional": true, "description": "Specifies that the request was served from the disk cache." }, { "name": "fromServiceWorker", "type": "boolean", "optional": true, "description": "Specifies that the request was served from the ServiceWorker." }, { "name": "encodedDataLength", "type": "number", "optional": false, "description": "Total number of bytes received for this request so far." }, @@ -1051,7 +1051,7 @@ "id": "WebSocketRequest", "type": "object", "description": "WebSocket request data.", - "hidden": true, + "experimental": true, "properties": [ { "name": "headers", "$ref": "Headers", "description": "HTTP request headers." } ] @@ -1060,7 +1060,7 @@ "id": "WebSocketResponse", "type": "object", "description": "WebSocket response data.", - "hidden": true, + "experimental": true, "properties": [ { "name": "status", "type": "number", "description": "HTTP response status code." }, { "name": "statusText", "type": "string", "description": "HTTP response status text." }, @@ -1074,7 +1074,7 @@ "id": "WebSocketFrame", "type": "object", "description": "WebSocket frame data.", - "hidden": true, + "experimental": true, "properties": [ { "name": "opcode", "type": "number", "description": "WebSocket frame opcode." }, { "name": "mask", "type": "boolean", "description": "WebSocke frame mask." }, @@ -1119,7 +1119,7 @@ { "name": "session", "type": "boolean", "description": "True in case of session cookie." }, { "name": "sameSite", "type": "string", "optional": true, "enum": ["Strict", "Lax"], "description": "Represents the cookies' 'SameSite' status: https://tools.ietf.org/html/draft-west-first-party-cookies" } ], - "hidden": true + "experimental": true } ], "commands": [ @@ -1127,8 +1127,8 @@ "name": "enable", "description": "Enables network tracking, network events will now be delivered to the client.", "parameters": [ - { "name": "maxTotalBufferSize", "type": "integer", "optional": true, "hidden": true, "description": "Buffer size in bytes to use when preserving network payloads (XHRs, etc)." }, - { "name": "maxResourceBufferSize", "type": "integer", "optional": true, "hidden": true, "description": "Per-resource buffer size in bytes to use when preserving network payloads (XHRs, etc)." } + { "name": "maxTotalBufferSize", "type": "integer", "optional": true, "experimental": true, "description": "Buffer size in bytes to use when preserving network payloads (XHRs, etc)." }, + { "name": "maxResourceBufferSize", "type": "integer", "optional": true, "experimental": true, "description": "Per-resource buffer size in bytes to use when preserving network payloads (XHRs, etc)." } ] }, { @@ -1167,7 +1167,7 @@ "parameters": [ { "name": "url", "type": "string", "description": "URL to block." } ], - "hidden": true + "experimental": true }, { "name": "removeBlockedURL", @@ -1175,7 +1175,7 @@ "parameters": [ { "name": "url", "type": "string", "description": "URL to stop blocking." } ], - "hidden": true + "experimental": true }, { "name": "replayXHR", @@ -1183,7 +1183,7 @@ "parameters": [ { "name": "requestId", "$ref": "RequestId", "description": "Identifier of XHR to replay." } ], - "hidden": true + "experimental": true }, { "name": "setMonitoringXHREnabled", @@ -1191,7 +1191,7 @@ { "name": "enabled", "type": "boolean", "description": "Monitoring enabled state." } ], "description": "Toggles monitoring of XMLHttpRequest. If <code>true</code>, console will receive messages upon each XHR issued.", - "hidden": true + "experimental": true }, { "name": "canClearBrowserCache", @@ -1225,7 +1225,7 @@ "description": "Returns all browser cookies. Depending on the backend support, will return detailed cookie information in the <code>cookies</code> field.", "handlers": ["browser"], "async": true, - "hidden": true + "experimental": true }, { "name": "deleteCookie", @@ -1236,7 +1236,7 @@ "description": "Deletes browser cookie with given name, domain and path.", "handlers": ["browser"], "async": true, - "hidden": true + "experimental": true }, { "name": "canEmulateNetworkConditions", @@ -1244,7 +1244,7 @@ "returns": [ { "name": "result", "type": "boolean", "description": "True if emulation of network conditions is supported." } ], - "hidden": true, + "experimental": true, "handlers": ["browser"] }, { @@ -1257,7 +1257,7 @@ { "name": "uploadThroughput", "type": "number", "description": "Maximal aggregated upload throughput." }, { "name": "connectionType", "$ref": "ConnectionType", "optional": true, "description": "Connection type if known."} ], - "hidden": true, + "experimental": true, "handlers": ["browser", "renderer"] }, { @@ -1272,7 +1272,7 @@ "parameters": [ { "name": "bypass", "type": "boolean", "description": "Bypass service worker and load from network." } ], - "hidden": true, + "experimental": true, "description": "Toggles ignoring of service worker for each request." }, { @@ -1282,7 +1282,7 @@ { "name": "maxResourceSize", "type": "integer", "description": "Maximum per-resource size." } ], "description": "For testing.", - "hidden": true + "experimental": true }, { "name": "getCertificateDetails", @@ -1313,22 +1313,22 @@ { "name": "newPriority", "$ref": "ResourcePriority", "description": "New priority" }, { "name": "timestamp", "$ref": "Timestamp", "description": "Timestamp." } ], - "hidden": true + "experimental": true }, { "name": "requestWillBeSent", "description": "Fired when page is about to send HTTP request.", "parameters": [ { "name": "requestId", "$ref": "RequestId", "description": "Request identifier." }, - { "name": "frameId", "$ref": "Page.FrameId", "description": "Frame identifier.", "hidden": true }, + { "name": "frameId", "$ref": "Page.FrameId", "description": "Frame identifier.", "experimental": true }, { "name": "loaderId", "$ref": "LoaderId", "description": "Loader identifier." }, { "name": "documentURL", "type": "string", "description": "URL of the document this request is loaded for." }, { "name": "request", "$ref": "Request", "description": "Request data." }, { "name": "timestamp", "$ref": "Timestamp", "description": "Timestamp." }, - { "name": "wallTime", "$ref": "Timestamp", "hidden": true, "description": "UTC Timestamp." }, + { "name": "wallTime", "$ref": "Timestamp", "experimental": true, "description": "UTC Timestamp." }, { "name": "initiator", "$ref": "Initiator", "description": "Request initiator." }, { "name": "redirectResponse", "optional": true, "$ref": "Response", "description": "Redirect response data." }, - { "name": "type", "$ref": "Page.ResourceType", "optional": true, "hidden": true, "description": "Type of this resource." } + { "name": "type", "$ref": "Page.ResourceType", "optional": true, "experimental": true, "description": "Type of this resource." } ] }, { @@ -1343,7 +1343,7 @@ "description": "Fired when HTTP response is available.", "parameters": [ { "name": "requestId", "$ref": "RequestId", "description": "Request identifier." }, - { "name": "frameId", "$ref": "Page.FrameId", "description": "Frame identifier.", "hidden": true }, + { "name": "frameId", "$ref": "Page.FrameId", "description": "Frame identifier.", "experimental": true }, { "name": "loaderId", "$ref": "LoaderId", "description": "Loader identifier." }, { "name": "timestamp", "$ref": "Timestamp", "description": "Timestamp." }, { "name": "type", "$ref": "Page.ResourceType", "description": "Resource type." }, @@ -1378,7 +1378,7 @@ { "name": "type", "$ref": "Page.ResourceType", "description": "Resource type." }, { "name": "errorText", "type": "string", "description": "User friendly error message." }, { "name": "canceled", "type": "boolean", "optional": true, "description": "True if loading was canceled." }, - { "name": "blockedReason", "$ref": "BlockedReason", "optional": true, "description": "The reason why loading was blocked, if any.", "hidden": true } + { "name": "blockedReason", "$ref": "BlockedReason", "optional": true, "description": "The reason why loading was blocked, if any.", "experimental": true } ] }, { @@ -1387,10 +1387,10 @@ "parameters": [ { "name": "requestId", "$ref": "RequestId", "description": "Request identifier." }, { "name": "timestamp", "$ref": "Timestamp", "description": "Timestamp." }, - { "name": "wallTime", "$ref": "Timestamp", "hidden": true, "description": "UTC Timestamp." }, + { "name": "wallTime", "$ref": "Timestamp", "experimental": true, "description": "UTC Timestamp." }, { "name": "request", "$ref": "WebSocketRequest", "description": "WebSocket request data." } ], - "hidden": true + "experimental": true }, { "name": "webSocketHandshakeResponseReceived", @@ -1400,7 +1400,7 @@ { "name": "timestamp", "$ref": "Timestamp", "description": "Timestamp." }, { "name": "response", "$ref": "WebSocketResponse", "description": "WebSocket response data." } ], - "hidden": true + "experimental": true }, { "name": "webSocketCreated", @@ -1410,7 +1410,7 @@ { "name": "url", "type": "string", "description": "WebSocket request URL." }, { "name": "initiator", "$ref": "Initiator", "optional": true, "description": "Request initiator." } ], - "hidden": true + "experimental": true }, { "name": "webSocketClosed", @@ -1419,7 +1419,7 @@ { "name": "requestId", "$ref": "RequestId", "description": "Request identifier." }, { "name": "timestamp", "$ref": "Timestamp", "description": "Timestamp." } ], - "hidden": true + "experimental": true }, { "name": "webSocketFrameReceived", @@ -1429,7 +1429,7 @@ { "name": "timestamp", "$ref": "Timestamp", "description": "Timestamp." }, { "name": "response", "$ref": "WebSocketFrame", "description": "WebSocket response data." } ], - "hidden": true + "experimental": true }, { "name": "webSocketFrameError", @@ -1439,7 +1439,7 @@ { "name": "timestamp", "$ref": "Timestamp", "description": "Timestamp." }, { "name": "errorMessage", "type": "string", "description": "WebSocket frame error message." } ], - "hidden": true + "experimental": true }, { "name": "webSocketFrameSent", @@ -1449,7 +1449,7 @@ { "name": "timestamp", "$ref": "Timestamp", "description": "Timestamp." }, { "name": "response", "$ref": "WebSocketFrame", "description": "WebSocket response data." } ], - "hidden": true + "experimental": true }, { "name": "eventSourceMessageReceived", @@ -1461,25 +1461,25 @@ { "name": "eventId", "type": "string", "description": "Message identifier." }, { "name": "data", "type": "string", "description": "Message content." } ], - "hidden": true + "experimental": true } ] }, { "domain": "Database", - "hidden": true, + "experimental": true, "types": [ { "id": "DatabaseId", "type": "string", "description": "Unique identifier of Database object.", - "hidden": true + "experimental": true }, { "id": "Database", "type": "object", "description": "Database object.", - "hidden": true, + "experimental": true, "properties": [ { "name": "id", "$ref": "DatabaseId", "description": "Database ID." }, { "name": "domain", "type": "string", "description": "Database domain." }, @@ -1541,7 +1541,7 @@ { "domain": "IndexedDB", "dependencies": ["Runtime"], - "hidden": true, + "experimental": true, "types": [ { "id": "DatabaseWithObjectStores", @@ -1685,7 +1685,7 @@ }, { "domain": "CacheStorage", - "hidden": true, + "experimental": true, "types": [ { "id": "CacheId", @@ -1759,14 +1759,14 @@ }, { "domain": "DOMStorage", - "hidden": true, + "experimental": true, "description": "Query and modify DOM storage.", "types": [ { "id": "StorageId", "type": "object", "description": "DOM Storage identifier.", - "hidden": true, + "experimental": true, "properties": [ { "name": "securityOrigin", "type": "string", "description": "Security origin for the storage." }, { "name": "isLocalStorage", "type": "boolean", "description": "Whether the storage is local storage (not session storage)." } @@ -1776,7 +1776,7 @@ "id": "Item", "type": "array", "description": "DOM Storage item.", - "hidden": true, + "experimental": true, "items": { "type": "string" } } ], @@ -1849,7 +1849,7 @@ }, { "domain": "ApplicationCache", - "hidden": true, + "experimental": true, "types": [ { "id": "ApplicationCacheResource", @@ -1948,7 +1948,7 @@ "id": "BackendNodeId", "type": "integer", "description": "Unique DOM node identifier used to reference a node that may not have been pushed to the front-end.", - "hidden": true + "experimental": true }, { "id": "BackendNode", @@ -1958,7 +1958,7 @@ { "name": "nodeName", "type": "string", "description": "<code>Node</code>'s nodeName." }, { "name": "backendNodeId", "$ref": "BackendNodeId" } ], - "hidden": true, + "experimental": true, "description": "Backend node with a friendly name." }, { @@ -2002,7 +2002,7 @@ { "name": "children", "type": "array", "optional": true, "items": { "$ref": "Node" }, "description": "Child nodes of this node when requested with children." }, { "name": "attributes", "type": "array", "optional": true, "items": { "type": "string" }, "description": "Attributes of the <code>Element</code> node in the form of flat array <code>[name1, value1, name2, value2]</code>." }, { "name": "documentURL", "type": "string", "optional": true, "description": "Document URL that <code>Document</code> or <code>FrameOwner</code> node points to." }, - { "name": "baseURL", "type": "string", "optional": true, "description": "Base URL that <code>Document</code> or <code>FrameOwner</code> node uses for URL completion.", "hidden": true }, + { "name": "baseURL", "type": "string", "optional": true, "description": "Base URL that <code>Document</code> or <code>FrameOwner</code> node uses for URL completion.", "experimental": true }, { "name": "publicId", "type": "string", "optional": true, "description": "<code>DocumentType</code>'s publicId." }, { "name": "systemId", "type": "string", "optional": true, "description": "<code>DocumentType</code>'s systemId." }, { "name": "internalSubset", "type": "string", "optional": true, "description": "<code>DocumentType</code>'s internalSubset." }, @@ -2011,13 +2011,13 @@ { "name": "value", "type": "string", "optional": true, "description": "<code>Attr</code>'s value." }, { "name": "pseudoType", "$ref": "PseudoType", "optional": true, "description": "Pseudo element type for this node." }, { "name": "shadowRootType", "$ref": "ShadowRootType", "optional": true, "description": "Shadow root type." }, - { "name": "frameId", "$ref": "Page.FrameId", "optional": true, "description": "Frame ID for frame owner elements.", "hidden": true }, + { "name": "frameId", "$ref": "Page.FrameId", "optional": true, "description": "Frame ID for frame owner elements.", "experimental": true }, { "name": "contentDocument", "$ref": "Node", "optional": true, "description": "Content document for frame owner elements." }, - { "name": "shadowRoots", "type": "array", "optional": true, "items": { "$ref": "Node" }, "description": "Shadow root list for given element host.", "hidden": true }, - { "name": "templateContent", "$ref": "Node", "optional": true, "description": "Content document fragment for template elements.", "hidden": true }, - { "name": "pseudoElements", "type": "array", "items": { "$ref": "Node" }, "optional": true, "description": "Pseudo elements associated with this node.", "hidden": true }, + { "name": "shadowRoots", "type": "array", "optional": true, "items": { "$ref": "Node" }, "description": "Shadow root list for given element host.", "experimental": true }, + { "name": "templateContent", "$ref": "Node", "optional": true, "description": "Content document fragment for template elements.", "experimental": true }, + { "name": "pseudoElements", "type": "array", "items": { "$ref": "Node" }, "optional": true, "description": "Pseudo elements associated with this node.", "experimental": true }, { "name": "importedDocument", "$ref": "Node", "optional": true, "description": "Import document for the HTMLImport links." }, - { "name": "distributedNodes", "type": "array", "items": { "$ref": "BackendNode" }, "optional": true, "description": "Distributed nodes for given insertion point.", "hidden": true } + { "name": "distributedNodes", "type": "array", "items": { "$ref": "BackendNode" }, "optional": true, "description": "Distributed nodes for given insertion point.", "experimental": true } ], "description": "DOM interaction is implemented in terms of mirror objects that represent the actual DOM nodes. DOMNode is a base node mirror type." }, @@ -2039,12 +2039,12 @@ "minItems": 8, "maxItems": 8, "description": "An array of quad vertices, x immediately followed by y for each point, points clock-wise.", - "hidden": true + "experimental": true }, { "id": "BoxModel", "type": "object", - "hidden": true, + "experimental": true, "properties": [ { "name": "content", "$ref": "Quad", "description": "Content box" }, { "name": "padding", "$ref": "Quad", "description": "Padding box" }, @@ -2059,7 +2059,7 @@ { "id": "ShapeOutsideInfo", "type": "object", - "hidden": true, + "experimental": true, "properties": [ { "name": "bounds", "$ref": "Quad", "description": "Shape bounds" }, { "name": "shape", "type": "array", "items": { "type": "any"}, "description": "Shape coordinate details" }, @@ -2070,7 +2070,7 @@ { "id": "Rect", "type": "object", - "hidden": true, + "experimental": true, "properties": [ { "name": "x", "type": "number", "description": "X coordinate" }, { "name": "y", "type": "number", "description": "Y coordinate" }, @@ -2086,14 +2086,14 @@ { "name": "showInfo", "type": "boolean", "optional": true, "description": "Whether the node info tooltip should be shown (default: false)." }, { "name": "showRulers", "type": "boolean", "optional": true, "description": "Whether the rulers should be shown (default: false)." }, { "name": "showExtensionLines", "type": "boolean", "optional": true, "description": "Whether the extension lines from node to the rulers should be shown (default: false)." }, - { "name": "displayAsMaterial", "type": "boolean", "optional": true, "hidden": true}, + { "name": "displayAsMaterial", "type": "boolean", "optional": true, "experimental": true}, { "name": "contentColor", "$ref": "RGBA", "optional": true, "description": "The content box highlight fill color (default: transparent)." }, { "name": "paddingColor", "$ref": "RGBA", "optional": true, "description": "The padding highlight fill color (default: transparent)." }, { "name": "borderColor", "$ref": "RGBA", "optional": true, "description": "The border highlight fill color (default: transparent)." }, { "name": "marginColor", "$ref": "RGBA", "optional": true, "description": "The margin highlight fill color (default: transparent)." }, - { "name": "eventTargetColor", "$ref": "RGBA", "optional": true, "hidden": true, "description": "The event target element highlight fill color (default: transparent)." }, - { "name": "shapeColor", "$ref": "RGBA", "optional": true, "hidden": true, "description": "The shape outside fill color (default: transparent)." }, - { "name": "shapeMarginColor", "$ref": "RGBA", "optional": true, "hidden": true, "description": "The shape margin fill color (default: transparent)." }, + { "name": "eventTargetColor", "$ref": "RGBA", "optional": true, "experimental": true, "description": "The event target element highlight fill color (default: transparent)." }, + { "name": "shapeColor", "$ref": "RGBA", "optional": true, "experimental": true, "description": "The shape outside fill color (default: transparent)." }, + { "name": "shapeMarginColor", "$ref": "RGBA", "optional": true, "experimental": true, "description": "The shape margin fill color (default: transparent)." }, { "name": "selectorList", "type": "string", "optional": true, "description": "Selectors to highlight relevant nodes."} ], "description": "Configuration data for the highlighting of page elements." @@ -2101,7 +2101,7 @@ { "id": "InspectMode", "type": "string", - "hidden": true, + "experimental": true, "enum": [ "searchForNode", "searchForUAShadowDOM", @@ -2130,7 +2130,7 @@ "name": "requestChildNodes", "parameters": [ { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node to get children for." }, - { "name": "depth", "type": "integer", "optional": true, "description": "The maximum depth at which children should be retrieved, defaults to 1. Use -1 for the entire subtree or provide an integer larger than 0.", "hidden": true } + { "name": "depth", "type": "integer", "optional": true, "description": "The maximum depth at which children should be retrieved, defaults to 1. Use -1 for the entire subtree or provide an integer larger than 0.", "experimental": true } ], "description": "Requests that children of the node with given id are returned to the caller in form of <code>setChildNodes</code> events where not only immediate children are retrieved, but all children down to the specified depth." }, @@ -2230,14 +2230,14 @@ "name": "performSearch", "parameters": [ { "name": "query", "type": "string", "description": "Plain text or query selector or XPath search query." }, - { "name": "includeUserAgentShadowDOM", "type": "boolean", "optional": true, "description": "True to search in user agent shadow DOM.", "hidden": true } + { "name": "includeUserAgentShadowDOM", "type": "boolean", "optional": true, "description": "True to search in user agent shadow DOM.", "experimental": true } ], "returns": [ { "name": "searchId", "type": "string", "description": "Unique search session identifier." }, { "name": "resultCount", "type": "integer", "description": "Number of search results." } ], "description": "Searches for a given string in the DOM tree. Use <code>getSearchResults</code> to access search results or <code>cancelSearch</code> to end this search session.", - "hidden": true + "experimental": true }, { "name": "getSearchResults", @@ -2250,7 +2250,7 @@ { "name": "nodeIds", "type": "array", "items": { "$ref": "NodeId" }, "description": "Ids of the search result nodes." } ], "description": "Returns search results from given <code>fromIndex</code> to given <code>toIndex</code> from the sarch with the given identifier.", - "hidden": true + "experimental": true }, { "name": "discardSearchResults", @@ -2258,7 +2258,7 @@ { "name": "searchId", "type": "string", "description": "Unique search session identifier." } ], "description": "Discards search results from the session with the given id. <code>getSearchResults</code> should no longer be called for that search.", - "hidden": true + "experimental": true }, { "name": "requestNode", @@ -2272,7 +2272,7 @@ }, { "name": "setInspectMode", - "hidden": true, + "experimental": true, "parameters": [ { "name": "mode", "$ref": "InspectMode", "description": "Set an inspection mode." }, { "name": "highlightConfig", "$ref": "HighlightConfig", "optional": true, "description": "A descriptor for the highlight appearance of hovered-over nodes. May be omitted if <code>enabled == false</code>." } @@ -2299,7 +2299,7 @@ { "name": "outlineColor", "$ref": "RGBA", "optional": true, "description": "The highlight outline color (default: transparent)." } ], "description": "Highlights given quad. Coordinates are absolute with respect to the main frame viewport.", - "hidden": true + "experimental": true }, { "name": "highlightNode", @@ -2307,7 +2307,7 @@ { "name": "highlightConfig", "$ref": "HighlightConfig", "description": "A descriptor for the highlight appearance." }, { "name": "nodeId", "$ref": "NodeId", "optional": true, "description": "Identifier of the node to highlight." }, { "name": "backendNodeId", "$ref": "BackendNodeId", "optional": true, "description": "Identifier of the backend node to highlight." }, - { "name": "objectId", "$ref": "Runtime.RemoteObjectId", "optional": true, "description": "JavaScript object id of the node to be highlighted.", "hidden": true } + { "name": "objectId", "$ref": "Runtime.RemoteObjectId", "optional": true, "description": "JavaScript object id of the node to be highlighted.", "experimental": true } ], "description": "Highlights DOM node with given id or with the given JavaScript object wrapper. Either nodeId or objectId must be specified." }, @@ -2323,7 +2323,7 @@ { "name": "contentOutlineColor", "$ref": "RGBA", "optional": true, "description": "The content box highlight outline color (default: transparent)." } ], "description": "Highlights owner element of the frame with given id.", - "hidden": true + "experimental": true }, { "name": "pushNodeByPathToFrontend", @@ -2334,7 +2334,7 @@ { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node for given path." } ], "description": "Requests that the node is sent to the caller given its path. // FIXME, use XPath", - "hidden": true + "experimental": true }, { "name": "pushNodesByBackendIdsToFrontend", @@ -2345,7 +2345,7 @@ { "name": "nodeIds", "type": "array", "items": {"$ref": "NodeId"}, "description": "The array of ids of pushed nodes that correspond to the backend ids specified in backendNodeIds." } ], "description": "Requests that a batch of nodes is sent to the caller given their backend node ids.", - "hidden": true + "experimental": true }, { "name": "setInspectedNode", @@ -2353,7 +2353,7 @@ { "name": "nodeId", "$ref": "NodeId", "description": "DOM node id to be accessible by means of $x command line API." } ], "description": "Enables console to refer to the node with given id via $x (see Command Line API for more details $x functions).", - "hidden": true + "experimental": true }, { "name": "resolveNode", @@ -2387,7 +2387,7 @@ { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node clone." } ], "description": "Creates a deep copy of the specified node and places it into the target container before the given anchor.", - "hidden": true + "experimental": true }, { "name": "moveTo", @@ -2404,17 +2404,17 @@ { "name": "undo", "description": "Undoes the last performed action.", - "hidden": true + "experimental": true }, { "name": "redo", "description": "Re-does the last undone action.", - "hidden": true + "experimental": true }, { "name": "markUndoableState", "description": "Marks last undoable state.", - "hidden": true + "experimental": true }, { "name": "focus", @@ -2422,7 +2422,7 @@ { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node to focus." } ], "description": "Focuses the given element.", - "hidden": true + "experimental": true }, { "name": "setFileInputFiles", @@ -2431,7 +2431,7 @@ { "name": "files", "type": "array", "items": { "type": "string" }, "description": "Array of file paths to set." } ], "description": "Sets files for the given file input element.", - "hidden": true, + "experimental": true, "handlers": ["browser", "renderer"] }, { @@ -2443,7 +2443,7 @@ { "name": "model", "$ref": "BoxModel", "description": "Box model for the node." } ], "description": "Returns boxes for the currently selected nodes.", - "hidden": true + "experimental": true }, { "name": "getNodeForLocation", @@ -2455,7 +2455,7 @@ { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node at given coordinates." } ], "description": "Returns node id at given location.", - "hidden": true + "experimental": true }, { "name": "getRelayoutBoundary", @@ -2466,7 +2466,7 @@ { "name": "nodeId", "$ref": "NodeId", "description": "Relayout boundary node id for the given node." } ], "description": "Returns the id of the nearest ancestor that is a relayout boundary.", - "hidden": true + "experimental": true }, { "name": "getHighlightObjectForTest", @@ -2477,7 +2477,7 @@ { "name": "highlight", "type": "object", "description": "Highlight data for the node." } ], "description": "For testing.", - "hidden": true + "experimental": true } ], "events": [ @@ -2491,7 +2491,7 @@ { "name": "backendNodeId", "$ref": "BackendNodeId", "description": "Id of the node to inspect." } ], "description": "Fired when the node should be inspected. This happens after call to <code>setInspectMode</code>.", - "hidden" : true + "experimental" : true }, { "name": "setChildNodes", @@ -2524,7 +2524,7 @@ { "name": "nodeIds", "type": "array", "items": { "$ref": "NodeId" }, "description": "Ids of the nodes for which the inline styles have been invalidated." } ], "description": "Fired when <code>Element</code>'s inline style is modified via a CSS property modification.", - "hidden": true + "experimental": true }, { "name": "characterDataModified", @@ -2566,7 +2566,7 @@ { "name": "root", "$ref": "Node", "description": "Shadow root." } ], "description": "Called when shadow root is pushed into the element.", - "hidden": true + "experimental": true }, { "name": "shadowRootPopped", @@ -2575,7 +2575,7 @@ { "name": "rootId", "$ref": "NodeId", "description": "Shadow root id." } ], "description": "Called when shadow root is popped from the element.", - "hidden": true + "experimental": true }, { "name": "pseudoElementAdded", @@ -2584,7 +2584,7 @@ { "name": "pseudoElement", "$ref": "Node", "description": "The added pseudo element." } ], "description": "Called when a pseudo element is added to an element.", - "hidden": true + "experimental": true }, { "name": "pseudoElementRemoved", @@ -2593,7 +2593,7 @@ { "name": "pseudoElementId", "$ref": "NodeId", "description": "The removed pseudo element id." } ], "description": "Called when a pseudo element is removed from an element.", - "hidden": true + "experimental": true }, { "name": "distributedNodesUpdated", @@ -2602,20 +2602,20 @@ { "name": "distributedNodes", "type": "array", "items": { "$ref": "BackendNode" }, "description": "Distributed nodes for given insertion point." } ], "description": "Called when distrubution is changed.", - "hidden": true + "experimental": true }, { "name": "nodeHighlightRequested", "parameters": [ {"name": "nodeId", "$ref": "NodeId"} ], - "hidden": true + "experimental": true } ] }, { "domain": "CSS", - "hidden": true, + "experimental": true, "description": "This domain exposes CSS read/write operations. All CSS objects (stylesheets, rules, and styles) have an associated <code>id</code> used in subsequent operations on the related object. Each object type has a specific <code>id</code> structure, and those are not interchangeable between objects of different kinds. CSS objects can be loaded using the <code>get*ForNode()</code> calls (which accept a DOM node id). A client can also discover all the existing stylesheets with the <code>getAllStyleSheets()</code> method (or keeping track of the <code>styleSheetAdded</code>/<code>styleSheetRemoved</code> events) and subsequently load the required stylesheet contents using the <code>getStyleSheet[Text]()</code> methods.", "dependencies": ["DOM"], "types": [ @@ -2769,7 +2769,7 @@ { "name": "sourceURL", "type": "string", "optional": true, "description": "URL of the document containing the media query description." }, { "name": "range", "$ref": "SourceRange", "optional": true, "description": "The associated rule (@media or @import) header range in the enclosing stylesheet (if available)." }, { "name": "styleSheetId", "$ref": "StyleSheetId", "optional": true, "description": "Identifier of the stylesheet containing this object (if exists)." }, - { "name": "mediaList", "type": "array", "items": { "$ref": "MediaQuery" }, "optional": true, "hidden": true, "description": "Array of media queries." } + { "name": "mediaList", "type": "array", "items": { "$ref": "MediaQuery" }, "optional": true, "experimental": true, "description": "Array of media queries." } ], "description": "CSS media rule descriptor." }, @@ -2781,7 +2781,7 @@ { "name": "active", "type": "boolean", "description": "Whether the media query condition is satisfied." } ], "description": "Media query descriptor.", - "hidden": true + "experimental": true }, { "id": "MediaQueryExpression", @@ -2794,7 +2794,7 @@ { "name": "computedLength", "type": "number", "optional": true, "description": "Computed length of media query expression (if applicable)."} ], "description": "Media query expression descriptor.", - "hidden": true + "experimental": true }, { "id": "PlatformFontUsage", @@ -2805,7 +2805,7 @@ { "name": "glyphCount", "type": "number", "description": "Amount of glyphs that were rendered with this font."} ], "description": "Information about amount of glyphs that were rendered with given font.", - "hidden": true + "experimental": true }, { "id": "CSSKeyframesRule", @@ -2893,7 +2893,7 @@ { "name": "fonts", "type": "array", "items": { "$ref": "PlatformFontUsage" }, "description": "Usage statistics for every employed platform font." } ], "description": "Requests information about platform fonts which we used to render child TextNodes in the given node.", - "hidden": true + "experimental": true }, { "name": "getStyleSheetText", @@ -2998,7 +2998,7 @@ { "name": "medias", "type": "array", "items": { "$ref": "CSSMedia" } } ], "description": "Returns all media queries parsed by the rendering engine.", - "hidden": true + "experimental": true }, { "name": "setEffectivePropertyValueForNode", @@ -3008,7 +3008,7 @@ { "name": "value", "type": "string"} ], "description": "Find a rule with the given active property for the given node and set the new value for this property", - "hidden": true + "experimental": true }, { "name": "getBackgroundColors", @@ -3018,7 +3018,7 @@ "returns": [ { "name": "backgroundColors", "type": "array", "items": { "type": "string" }, "description": "The range of background colors behind this element, if it contains any visible text. If no visible text is present, this will be undefined. In the case of a flat background color, this will consist of simply that color. In the case of a gradient, this will consist of each of the color stops. For anything more complicated, this will be an empty array. Images will be ignored (as if the image had failed to load).", "optional": true } ], - "hidden": true + "experimental": true } ], "events": [ @@ -3063,7 +3063,7 @@ { "domain": "IO", "description": "Input/Output operations for streams produced by DevTools.", - "hidden": true, + "experimental": true, "types": [ { "id": "StreamHandle", @@ -3122,7 +3122,7 @@ { "name": "originalHandler", "$ref": "Runtime.RemoteObject", "optional": true, "description": "Event original handler function value." }, { "name": "removeFunction", "$ref": "Runtime.RemoteObject", "optional": true, "description": "Event listener remove function." } ], - "hidden": true + "experimental": true } ], "commands": [ @@ -3146,7 +3146,7 @@ "name": "setEventListenerBreakpoint", "parameters": [ { "name": "eventName", "type": "string", "description": "DOM Event name to stop on (any DOM event will do)." }, - { "name": "targetName", "type": "string", "optional": true, "description": "EventTarget interface name to stop on. If equal to <code>\"*\"</code> or not provided, will stop on any EventTarget.", "hidden": true } + { "name": "targetName", "type": "string", "optional": true, "description": "EventTarget interface name to stop on. If equal to <code>\"*\"</code> or not provided, will stop on any EventTarget.", "experimental": true } ], "description": "Sets breakpoint on particular DOM event." }, @@ -3154,7 +3154,7 @@ "name": "removeEventListenerBreakpoint", "parameters": [ { "name": "eventName", "type": "string", "description": "Event name." }, - { "name": "targetName", "type": "string", "optional": true, "description": "EventTarget interface name.", "hidden": true } + { "name": "targetName", "type": "string", "optional": true, "description": "EventTarget interface name.", "experimental": true } ], "description": "Removes breakpoint on particular DOM event." }, @@ -3164,7 +3164,7 @@ { "name": "eventName", "type": "string", "description": "Instrumentation name to stop on." } ], "description": "Sets breakpoint on particular native event.", - "hidden": true + "experimental": true }, { "name": "removeInstrumentationBreakpoint", @@ -3172,7 +3172,7 @@ { "name": "eventName", "type": "string", "description": "Instrumentation name to stop on." } ], "description": "Removes breakpoint on particular native event.", - "hidden": true + "experimental": true }, { "name": "setXHRBreakpoint", @@ -3190,7 +3190,7 @@ }, { "name": "getEventListeners", - "hidden": true, + "experimental": true, "parameters": [ { "name": "objectId", "$ref": "Runtime.RemoteObjectId", "description": "Identifier of the object to return listeners for." } ], @@ -3203,7 +3203,7 @@ }, { "domain": "Worker", - "hidden": true, + "experimental": true, "types": [], "commands": [ { @@ -3252,7 +3252,7 @@ }, { "domain": "ServiceWorker", - "hidden": true, + "experimental": true, "types": [ { "id": "ServiceWorkerRegistration", @@ -3481,7 +3481,7 @@ { "id": "TouchPoint", "type": "object", - "hidden": true, + "experimental": true, "properties": [ { "name": "state", "type": "string", "enum": ["touchPressed", "touchReleased", "touchMoved", "touchStationary", "touchCancelled"], "description": "State of the touch point." }, { "name": "x", "type": "integer", "description": "X coordinate of the event relative to the main frame's viewport."}, @@ -3496,7 +3496,7 @@ { "id": "GestureSourceType", "type": "string", - "hidden": true, + "experimental": true, "enum": ["default", "touch", "mouse"] } ], @@ -3537,7 +3537,7 @@ }, { "name": "dispatchTouchEvent", - "hidden": true, + "experimental": true, "parameters": [ { "name": "type", "type": "string", "enum": ["touchStart", "touchEnd", "touchMove"], "description": "Type of the touch event." }, { "name": "touchPoints", "type": "array", "items": { "$ref": "TouchPoint" }, "description": "Touch points." }, @@ -3548,7 +3548,7 @@ }, { "name": "emulateTouchFromMouseEvent", - "hidden": true, + "experimental": true, "parameters": [ { "name": "type", "type": "string", "enum": ["mousePressed", "mouseReleased", "mouseMoved", "mouseWheel"], "description": "Type of the mouse event." }, { "name": "x", "type": "integer", "description": "X coordinate of the mouse pointer in DIP."}, @@ -3574,7 +3574,7 @@ { "name": "gestureSourceType", "$ref": "GestureSourceType", "optional": true, "description": "Which type of input events to be generated (default: 'default', which queries the platform for the preferred input type)." } ], "description": "Synthesizes a pinch gesture over a time period by issuing appropriate touch events.", - "hidden": true, + "experimental": true, "handlers": ["browser"] }, { @@ -3595,7 +3595,7 @@ { "name": "interactionMarkerName", "type": "string", "optional": true, "description": "The name of the interaction markers to generate, if not empty (default: \"\")." } ], "description": "Synthesizes a scroll gesture over a time period by issuing appropriate touch events.", - "hidden": true, + "experimental": true, "handlers": ["browser"] }, { @@ -3609,7 +3609,7 @@ { "name": "gestureSourceType", "$ref": "GestureSourceType", "optional": true, "description": "Which type of input events to be generated (default: 'default', which queries the platform for the preferred input type)." } ], "description": "Synthesizes a tap gesture over a time period by issuing appropriate touch events.", - "hidden": true, + "experimental": true, "handlers": ["browser"] } ], @@ -3617,7 +3617,7 @@ }, { "domain": "LayerTree", - "hidden": true, + "experimental": true, "dependencies": ["DOM"], "types": [ { @@ -3781,7 +3781,7 @@ }, { "domain": "DeviceOrientation", - "hidden": true, + "experimental": true, "commands": [ { "name": "setDeviceOrientationOverride", @@ -3899,17 +3899,17 @@ }, { "domain": "Animation", - "hidden": true, + "experimental": true, "dependencies": ["Runtime", "DOM"], "types": [ { "id": "Animation", "type": "object", - "hidden": true, + "experimental": true, "properties": [ { "name": "id", "type": "string", "description": "<code>Animation</code>'s id." }, { "name": "name", "type": "string", "description": "<code>Animation</code>'s name." }, - { "name": "pausedState", "type": "boolean", "hidden": true, "description": "<code>Animation</code>'s internal paused state." }, + { "name": "pausedState", "type": "boolean", "experimental": true, "description": "<code>Animation</code>'s internal paused state." }, { "name": "playState", "type": "string", "description": "<code>Animation</code>'s play state." }, { "name": "playbackRate", "type": "number", "description": "<code>Animation</code>'s playback rate." }, { "name": "startTime", "type": "number", "description": "<code>Animation</code>'s start time." }, @@ -3923,7 +3923,7 @@ { "id": "AnimationEffect", "type": "object", - "hidden": true, + "experimental": true, "properties": [ { "name": "delay", "type": "number", "description": "<code>AnimationEffect</code>'s delay." }, { "name": "endDelay", "type": "number", "description": "<code>AnimationEffect</code>'s end delay." }, @@ -4060,7 +4060,7 @@ }, { "domain": "Accessibility", - "hidden": true, + "experimental": true, "dependencies": ["DOM"], "types": [ { @@ -4185,13 +4185,13 @@ { "name": "accessibilityNode", "$ref": "AXNode", "description": "The <code>Accessibility.AXNode</code> for this DOM node, if it exists.", "optional": true } ], "description": "Fetches the accessibility node for this DOM node, if it exists.", - "hidden": true + "experimental": true } ] }, { "domain": "Storage", - "hidden": true, + "experimental": true, "types": [ { "id": "StorageType", @@ -4227,7 +4227,7 @@ "domain": "Log", "description": "Provides access to log entries.", "dependencies": ["Runtime", "Network", "Worker"], - "hidden": true, + "experimental": true, "types": [ { "id": "LogEntry", @@ -4273,7 +4273,7 @@ { "domain": "Browser", "description": "The Browser domain allows listing, creating, activating and attaching to the targets.", - "hidden": true, + "experimental": true, "types": [ { "id": "BrowserContextID", @@ -4388,7 +4388,7 @@ { "domain": "SystemInfo", "description": "The SystemInfo domain defines methods and events for querying low-level system information.", - "hidden": true, + "experimental": true, "types": [ { "id": "GPUDevice", @@ -4430,7 +4430,7 @@ { "domain": "Tethering", "description": "The Tethering domain defines methods and events for browser port binding.", - "hidden": true, + "experimental": true, "commands": [ { "name": "bind",
diff --git a/third_party/WebKit/Source/core/layout/ImageQualityControllerTest.cpp b/third_party/WebKit/Source/core/layout/ImageQualityControllerTest.cpp index a738ac5..6ce9112 100644 --- a/third_party/WebKit/Source/core/layout/ImageQualityControllerTest.cpp +++ b/third_party/WebKit/Source/core/layout/ImageQualityControllerTest.cpp
@@ -137,6 +137,7 @@ std::unique_ptr<WebTaskRunner> clone() override { return nullptr; } double virtualTimeSeconds() const override { return 0.0; } double monotonicallyIncreasingVirtualTimeSeconds() const override { return m_time; } + SingleThreadTaskRunner* taskRunner() override { return nullptr; } double m_time; Task* m_currentTask;
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp index de99f9d3..e9b66e5 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
@@ -1149,7 +1149,7 @@ static inline bool isChildHitTestCandidate(LayoutBox* box) { - return box->size().height() && box->style()->visibility() == VISIBLE && !box->isFloatingOrOutOfFlowPositioned() && !box->isLayoutFlowThread(); + return box->size().height() && box->style()->visibility() == EVisibility::Visible && !box->isFloatingOrOutOfFlowPositioned() && !box->isLayoutFlowThread(); } PositionWithAffinity LayoutBlock::positionForPoint(const LayoutPoint& point)
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.cpp b/third_party/WebKit/Source/core/layout/LayoutBox.cpp index 6a19f03..0f97f057 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBox.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
@@ -1342,11 +1342,11 @@ bool LayoutBox::getBackgroundPaintedExtent(LayoutRect& paintedExtent) const { - ASSERT(hasBackground()); + DCHECK(styleRef().hasBackground()); // LayoutView is special in the sense that it expands to the whole canvas, // thus can't be handled by this function. - ASSERT(!isLayoutView()); + DCHECK(!isLayoutView()); LayoutRect backgroundRect(borderBoxRect()); @@ -1404,7 +1404,7 @@ const ComputedStyle& childStyle = childBox.styleRef(); if (childStyle.position() != StaticPosition && childBox.containingBlock() != childBox.parent()) return false; - if (childStyle.visibility() != VISIBLE || childStyle.shapeOutside()) + if (childStyle.visibility() != EVisibility::Visible || childStyle.shapeOutside()) return false; if (childBox.size().isZero()) return false; @@ -1459,8 +1459,7 @@ if (scrollsOverflow()) return false; // Test to see if the children trivially obscure the background. - // FIXME: This test can be much more comprehensive. - if (!hasBackground()) + if (!styleRef().hasBackground()) return false; // Root background painting is special. if (isLayoutView()) @@ -2026,13 +2025,20 @@ EBreak LayoutBox::classABreakPointValue(EBreak previousBreakAfterValue) const { + // First assert that we're at a class A break point. ASSERT(isBreakBetweenControllable(previousBreakAfterValue)); + return joinFragmentainerBreakValues(previousBreakAfterValue, breakBefore()); } bool LayoutBox::needsForcedBreakBefore(EBreak previousBreakAfterValue) const { - return isForcedFragmentainerBreakValue(classABreakPointValue(previousBreakAfterValue)); + // Forced break values are only honored when specified on in-flow objects, but floats and + // out-of-flow positioned objects may be affected by a break-after value of the previous + // in-flow object, even though we're not at a class A break point. + EBreak breakValue = isFloatingOrOutOfFlowPositioned() + ? previousBreakAfterValue : classABreakPointValue(previousBreakAfterValue); + return isForcedFragmentainerBreakValue(breakValue); } bool LayoutBox::paintedOutputOfObjectHasNoEffect() const @@ -2059,7 +2065,7 @@ LayoutRect LayoutBox::localOverflowRectForPaintInvalidation() const { - if (style()->visibility() != VISIBLE) + if (style()->visibility() != EVisibility::Visible) return LayoutRect(); return selfVisualOverflowRect(); @@ -2273,7 +2279,7 @@ // Width calculations if (treatAsReplaced) { computedValues.m_extent = LayoutUnit(logicalWidthLength.value()) + borderAndPaddingLogicalWidth(); - } else if (parent()->isLayoutGrid() && style()->logicalWidth().isAuto() && style()->logicalMinWidth().isAuto() && style()->overflowX() == OverflowVisible && containerWidthInInlineDirection < minPreferredLogicalWidth()) { + } else if (parent()->isLayoutGrid() && style()->logicalWidth().isAuto() && style()->logicalMinWidth().isAuto() && style()->overflowInlineDirection() == OverflowVisible && containerWidthInInlineDirection < minPreferredLogicalWidth()) { // TODO (lajava) Move this logic to the LayoutGrid class. // Implied minimum size of Grid items. computedValues.m_extent = constrainLogicalWidthByMinMax(minPreferredLogicalWidth(), containerWidthInInlineDirection, cb); @@ -3886,7 +3892,7 @@ for (LayoutObject* layoutObject = firstChild; layoutObject; layoutObject = layoutObject->nextSibling()) { if ((!layoutObject->slowFirstChild() && !layoutObject->isInline() && !layoutObject->isLayoutBlockFlow() ) - || layoutObject->style()->visibility() != VISIBLE) + || layoutObject->style()->visibility() != EVisibility::Visible) continue; if (!layoutObject->isBox())
diff --git a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp index dc0d617..3ea4a886 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp
@@ -488,12 +488,6 @@ descendant.addOutlineRects(rects, additionalOffset, includeBlockOverflows); } -bool LayoutBoxModelObject::calculateHasBoxDecorations() const -{ - const ComputedStyle& styleToUse = styleRef(); - return hasBackground() || styleToUse.hasBorderDecoration() || styleToUse.hasAppearance() || styleToUse.boxShadow(); -} - bool LayoutBoxModelObject::hasNonEmptyLayoutSize() const { for (const LayoutBoxModelObject* root = this; root; root = root->continuation()) { @@ -517,7 +511,7 @@ void LayoutBoxModelObject::updateFromStyle() { const ComputedStyle& styleToUse = styleRef(); - setHasBoxDecorationBackground(calculateHasBoxDecorations()); + setHasBoxDecorationBackground(styleToUse.hasBoxDecorationBackground()); setInline(styleToUse.isDisplayInlineType()); setPositionState(styleToUse.position()); setHorizontalWritingMode(styleToUse.isHorizontalWritingMode());
diff --git a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h index be67ec6..0ba7b800 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h +++ b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h
@@ -304,8 +304,6 @@ LayoutPoint adjustedPositionRelativeTo(const LayoutPoint&, const Element*) const; - bool calculateHasBoxDecorations() const; - // Returns the continuation associated with |this|. // Returns nullptr if no continuation is associated with |this|. //
diff --git a/third_party/WebKit/Source/core/layout/LayoutBoxTest.cpp b/third_party/WebKit/Source/core/layout/LayoutBoxTest.cpp index 7cd0444c..e89af5b 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBoxTest.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBoxTest.cpp
@@ -21,7 +21,7 @@ "<div class='column'> <div> <div id='target' class='white-background'> <div class='black-background'></div> </div> </div> </div>"); LayoutObject* layoutObject = getLayoutObjectByElementId("target"); ASSERT_TRUE(layoutObject); - ASSERT_TRUE(layoutObject->boxDecorationBackgroundIsKnownToBeObscured()); + ASSERT_TRUE(layoutObject->backgroundIsKnownToBeObscured()); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutDeprecatedFlexibleBox.cpp b/third_party/WebKit/Source/core/layout/LayoutDeprecatedFlexibleBox.cpp index 8f22360..b6e963d 100644 --- a/third_party/WebKit/Source/core/layout/LayoutDeprecatedFlexibleBox.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutDeprecatedFlexibleBox.cpp
@@ -130,7 +130,7 @@ static int getHeightForLineCount(const LayoutBlockFlow* blockFlow, int lineCount, bool includeBottom, int& count) { - if (blockFlow->style()->visibility() != VISIBLE) + if (blockFlow->style()->visibility() != EVisibility::Visible) return -1; if (blockFlow->childrenInline()) { for (RootInlineBox* box = blockFlow->firstRootBox(); box; box = box->nextRootBox()) { @@ -160,7 +160,7 @@ { ASSERT(i >= 0); - if (blockFlow->style()->visibility() != VISIBLE) + if (blockFlow->style()->visibility() != EVisibility::Visible) return nullptr; if (blockFlow->childrenInline()) { @@ -185,7 +185,7 @@ static int lineCount(const LayoutBlockFlow* blockFlow, const RootInlineBox* stopRootInlineBox = nullptr, bool* found = nullptr) { - if (blockFlow->style()->visibility() != VISIBLE) + if (blockFlow->style()->visibility() != EVisibility::Visible) return 0; int count = 0; if (blockFlow->childrenInline()) { @@ -218,7 +218,7 @@ static void clearTruncation(LayoutBlockFlow* blockFlow) { - if (blockFlow->style()->visibility() != VISIBLE) + if (blockFlow->style()->visibility() != EVisibility::Visible) return; if (blockFlow->childrenInline() && blockFlow->hasMarkupTruncation()) { blockFlow->setHasMarkupTruncation(false); @@ -273,7 +273,7 @@ static bool childDoesNotAffectWidthOrFlexing(LayoutObject* child) { // Positioned children and collapsed children don't affect the min/max width. - return child->isOutOfFlowPositioned() || child->style()->visibility() == COLLAPSE; + return child->isOutOfFlowPositioned() || child->style()->visibility() == EVisibility::Collapse; } static LayoutUnit contentWidthForChild(LayoutBox* child) @@ -505,7 +505,7 @@ continue; } - if (child->style()->visibility() == COLLAPSE) { + if (child->style()->visibility() == EVisibility::Collapse) { // visibility: collapsed children do not participate in our positioning. // But we need to lay them down. child->layoutIfNeeded(); @@ -606,7 +606,7 @@ // Now distribute the space to objects. for (LayoutBox* child = iterator.first(); child && spaceAvailableThisPass && totalFlex; child = iterator.next()) { - if (child->style()->visibility() == COLLAPSE) + if (child->style()->visibility() == EVisibility::Collapse) continue; if (allowedChildFlex(child, expanding, i)) { @@ -748,7 +748,7 @@ if (!haveLineClamp && (relayoutChildren || (child->isAtomicInlineLevel() && (child->style()->width().hasPercent() || child->style()->height().hasPercent())))) layoutScope.setChildNeedsLayout(child); - if (child->style()->visibility() == COLLAPSE) { + if (child->style()->visibility() == EVisibility::Collapse) { // visibility: collapsed children do not participate in our positioning. // But we need to lay them down. child->layoutIfNeeded();
diff --git a/third_party/WebKit/Source/core/layout/LayoutImage.cpp b/third_party/WebKit/Source/core/layout/LayoutImage.cpp index a582faf..e2c218e 100644 --- a/third_party/WebKit/Source/core/layout/LayoutImage.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutImage.cpp
@@ -209,7 +209,7 @@ if (!LayoutBoxModelObject::boxShadowShouldBeAppliedToBackground(bleedAvoidance)) return false; - return !const_cast<LayoutImage*>(this)->boxDecorationBackgroundIsKnownToBeObscured(); + return !const_cast<LayoutImage*>(this)->backgroundIsKnownToBeObscured(); } bool LayoutImage::foregroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect, unsigned) const @@ -243,7 +243,7 @@ bool LayoutImage::computeBackgroundIsKnownToBeObscured() const { - if (!hasBackground()) + if (!styleRef().hasBackground()) return false; LayoutRect paintedExtent;
diff --git a/third_party/WebKit/Source/core/layout/LayoutInline.cpp b/third_party/WebKit/Source/core/layout/LayoutInline.cpp index db88f217..7d1b680 100644 --- a/third_party/WebKit/Source/core/layout/LayoutInline.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutInline.cpp
@@ -1050,7 +1050,7 @@ if (!alwaysCreateLineBoxes()) return LayoutRect(); - if (style()->visibility() != VISIBLE) + if (style()->visibility() != EVisibility::Visible) return LayoutRect(); return visualOverflowRect(); @@ -1336,7 +1336,7 @@ void LayoutInline::addAnnotatedRegions(Vector<AnnotatedRegionValue>& regions) { // Convert the style regions to absolute coordinates. - if (style()->visibility() != VISIBLE) + if (style()->visibility() != EVisibility::Visible) return; if (style()->getDraggableRegionMode() == DraggableRegionNone)
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.cpp b/third_party/WebKit/Source/core/layout/LayoutObject.cpp index 6ec3f1e..b4c72b2 100644 --- a/third_party/WebKit/Source/core/layout/LayoutObject.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
@@ -66,7 +66,7 @@ #include "core/layout/LayoutTableRow.h" #include "core/layout/LayoutTheme.h" #include "core/layout/LayoutView.h" -#include "core/layout/ng/LayoutNGBlockFlow.h" +#include "core/layout/ng/layout_ng_block_flow.h" #include "core/page/AutoscrollController.h" #include "core/page/Page.h" #include "core/paint/ObjectPaintProperties.h" @@ -1391,10 +1391,10 @@ "object", this->debugName().ascii(), "info", jsonObjectForOldAndNewRects(oldBounds, oldLocation, newBounds, newLocation)); - bool boxDecorationBackgroundObscured = boxDecorationBackgroundIsKnownToBeObscured(); - if (!isFullPaintInvalidationReason(invalidationReason) && boxDecorationBackgroundObscured != m_bitfields.lastBoxDecorationBackgroundObscured()) + bool backgroundObscured = backgroundIsKnownToBeObscured(); + if (!isFullPaintInvalidationReason(invalidationReason) && backgroundObscured != m_bitfields.previousBackgroundObscured()) invalidationReason = PaintInvalidationBackgroundObscurationChange; - m_bitfields.setLastBoxDecorationBackgroundObscured(boxDecorationBackgroundObscured); + m_bitfields.setPreviousBackgroundObscured(backgroundObscured); if (invalidationReason == PaintInvalidationNone) { // TODO(trchen): Currently we don't keep track of paint offset of layout objects. @@ -1488,6 +1488,8 @@ void LayoutObject::clearPreviousPaintInvalidationRects() { setPreviousPaintInvalidationRect(LayoutRect()); + // After clearing ("invalidating" the paint invalidation rects, mark this object as needing to re-compute them. + setShouldDoFullPaintInvalidation(); } void LayoutObject::incrementallyInvalidatePaint(const LayoutBoxModelObject& paintInvalidationContainer, const LayoutRect& oldBounds, const LayoutRect& newBounds, const LayoutPoint& positionFromPaintInvalidationBacking) @@ -2666,7 +2668,7 @@ // If |this| is visible but this object was not, tell the layer it has some visible content // that needs to be drawn and layer visibility optimization can't be used - if (parent()->style()->visibility() != VISIBLE && style()->visibility() == VISIBLE && !hasLayer()) { + if (parent()->style()->visibility() != EVisibility::Visible && style()->visibility() == EVisibility::Visible && !hasLayer()) { if (!layer) layer = parent()->enclosingLayer(); if (layer) @@ -2723,7 +2725,7 @@ // If we remove a visible child from an invisible parent, we don't know the layer visibility any more. PaintLayer* layer = nullptr; - if (parent()->style()->visibility() != VISIBLE && style()->visibility() == VISIBLE && !hasLayer()) { + if (parent()->style()->visibility() != EVisibility::Visible && style()->visibility() == EVisibility::Visible && !hasLayer()) { layer = parent()->enclosingLayer(); if (layer) layer->dirtyVisibleContentStatus(); @@ -3116,7 +3118,7 @@ void LayoutObject::addAnnotatedRegions(Vector<AnnotatedRegionValue>& regions) { // Convert the style regions to absolute coordinates. - if (style()->visibility() != VISIBLE || !isBox()) + if (style()->visibility() != EVisibility::Visible || !isBox()) return; if (style()->getDraggableRegionMode() == DraggableRegionNone) @@ -3135,7 +3137,7 @@ bool LayoutObject::willRenderImage() { // Without visibility we won't render (and therefore don't care about animation). - if (style()->visibility() != VISIBLE) + if (style()->visibility() != EVisibility::Visible) return false; // We will not render a new image when Active DOM is suspended
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.h b/third_party/WebKit/Source/core/layout/LayoutObject.h index d8e9a68..d2d2015 100644 --- a/third_party/WebKit/Source/core/layout/LayoutObject.h +++ b/third_party/WebKit/Source/core/layout/LayoutObject.h
@@ -674,18 +674,11 @@ bool hasLayer() const { return m_bitfields.hasLayer(); } - // "Box decoration background" includes all box decorations and backgrounds - // that are painted as the background of the object. It includes borders, - // box-shadows, background-color and background-image, etc. - enum BoxDecorationBackgroundState { - NoBoxDecorationBackground, - HasBoxDecorationBackgroundObscurationStatusInvalid, - HasBoxDecorationBackgroundKnownToBeObscured, - HasBoxDecorationBackgroundMayBeVisible, - }; - bool hasBoxDecorationBackground() const { return m_bitfields.getBoxDecorationBackgroundState() != NoBoxDecorationBackground; } - bool boxDecorationBackgroundIsKnownToBeObscured() const; - bool hasBackground() const { return style()->hasBackground(); } + // This may be different from styleRef().hasBoxDecorationBackground() because some objects may + // have box decoration background other than from their own style. + bool hasBoxDecorationBackground() const { return m_bitfields.hasBoxDecorationBackground(); } + + bool backgroundIsKnownToBeObscured() const; bool needsLayout() const { @@ -713,6 +706,7 @@ bool hasClipRelatedProperty() const { return hasClip() || hasOverflowClip() || style()->containsPaint(); } bool hasTransformRelatedProperty() const { return m_bitfields.hasTransformRelatedProperty(); } + bool isTransformApplicable() const { return isBox() || isSVG(); } bool hasMask() const { return style() && style()->hasMask(); } bool hasClipPath() const { return style() && style()->clipPath(); } bool hasHiddenBackface() const { return style() && style()->backfaceVisibility() == BackfaceVisibilityHidden; } @@ -842,6 +836,12 @@ void setInline(bool isInline) { m_bitfields.setIsInline(isInline); } void setHasBoxDecorationBackground(bool); + + enum BackgroundObscurationState { + BackgroundObscurationStatusInvalid, + BackgroundKnownToBeObscured, + BackgroundMayBeVisible, + }; void invalidateBackgroundObscurationStatus(); virtual bool computeBackgroundIsKnownToBeObscured() const { return false; } @@ -1239,9 +1239,9 @@ parent()->removeChild(this); } - bool visibleToHitTestRequest(const HitTestRequest& request) const { return style()->visibility() == VISIBLE && (request.ignorePointerEventsNone() || style()->pointerEvents() != PE_NONE) && !isInert(); } + bool visibleToHitTestRequest(const HitTestRequest& request) const { return style()->visibility() == EVisibility::Visible && (request.ignorePointerEventsNone() || style()->pointerEvents() != PE_NONE) && !isInert(); } - bool visibleToHitTesting() const { return style()->visibility() == VISIBLE && style()->pointerEvents() != PE_NONE && !isInert(); } + bool visibleToHitTesting() const { return style()->visibility() == EVisibility::Visible && style()->pointerEvents() != PE_NONE && !isInert(); } // Map points and quads through elements, potentially via 3d transforms. You should never need to call these directly; use // localToAbsolute/absoluteToLocal methods instead. @@ -1759,17 +1759,18 @@ , m_childrenInline(false) , m_containsInlineWithOutlineAndContinuation(false) , m_alwaysCreateLineBoxesForLayoutInline(false) - , m_lastBoxDecorationBackgroundObscured(false) + , m_previousBackgroundObscured(false) , m_isBackgroundAttachmentFixedObject(false) , m_isScrollAnchorObject(false) + , m_hasBoxDecorationBackground(false) , m_positionedState(IsStaticallyPositioned) , m_selectionState(SelectionNone) - , m_boxDecorationBackgroundState(NoBoxDecorationBackground) + , m_backgroundObscurationState(BackgroundObscurationStatusInvalid) , m_fullPaintInvalidationReason(PaintInvalidationNone) { } - // 32 bits have been used in the first word, and 16 in the second. + // 32 bits have been used in the first word, and 17 in the second. // Self needs layout means that this layout object is marked for a full layout. // This is the default layout but it is expensive as it recomputes everything. @@ -1893,19 +1894,21 @@ // from LayoutInline ADD_BOOLEAN_BITFIELD(alwaysCreateLineBoxesForLayoutInline, AlwaysCreateLineBoxesForLayoutInline); - // For slimming-paint. - ADD_BOOLEAN_BITFIELD(lastBoxDecorationBackgroundObscured, LastBoxDecorationBackgroundObscured); + // Background obscuration status of the previous frame. + ADD_BOOLEAN_BITFIELD(previousBackgroundObscured, PreviousBackgroundObscured); ADD_BOOLEAN_BITFIELD(isBackgroundAttachmentFixedObject, IsBackgroundAttachmentFixedObject); ADD_BOOLEAN_BITFIELD(isScrollAnchorObject, IsScrollAnchorObject); + ADD_BOOLEAN_BITFIELD(hasBoxDecorationBackground, HasBoxDecorationBackground); + private: // This is the cached 'position' value of this object // (see ComputedStyle::position). unsigned m_positionedState : 2; // PositionedState unsigned m_selectionState : 3; // SelectionState // Mutable for getter which lazily update this field. - mutable unsigned m_boxDecorationBackgroundState : 2; // BoxDecorationBackgroundState + mutable unsigned m_backgroundObscurationState : 2; // BackgroundObscurationState unsigned m_fullPaintInvalidationReason : 5; // PaintInvalidationReason public: @@ -1925,8 +1928,8 @@ ALWAYS_INLINE SelectionState getSelectionState() const { return static_cast<SelectionState>(m_selectionState); } ALWAYS_INLINE void setSelectionState(SelectionState selectionState) { m_selectionState = selectionState; } - ALWAYS_INLINE BoxDecorationBackgroundState getBoxDecorationBackgroundState() const { return static_cast<BoxDecorationBackgroundState>(m_boxDecorationBackgroundState); } - ALWAYS_INLINE void setBoxDecorationBackgroundState(BoxDecorationBackgroundState s) const { m_boxDecorationBackgroundState = s; } + ALWAYS_INLINE BackgroundObscurationState getBackgroundObscurationState() const { return static_cast<BackgroundObscurationState>(m_backgroundObscurationState); } + ALWAYS_INLINE void setBackgroundObscurationState(BackgroundObscurationState s) const { m_backgroundObscurationState = s; } PaintInvalidationReason fullPaintInvalidationReason() const { return static_cast<PaintInvalidationReason>(m_fullPaintInvalidationReason); } void setFullPaintInvalidationReason(PaintInvalidationReason reason) { m_fullPaintInvalidationReason = reason; } @@ -2111,29 +2114,25 @@ inline void LayoutObject::setHasBoxDecorationBackground(bool b) { - if (!b) { - m_bitfields.setBoxDecorationBackgroundState(NoBoxDecorationBackground); + if (b == m_bitfields.hasBoxDecorationBackground()) return; - } - if (hasBoxDecorationBackground()) - return; - m_bitfields.setBoxDecorationBackgroundState(HasBoxDecorationBackgroundObscurationStatusInvalid); + + m_bitfields.setHasBoxDecorationBackground(b); + invalidateBackgroundObscurationStatus(); } inline void LayoutObject::invalidateBackgroundObscurationStatus() { - if (!hasBoxDecorationBackground()) - return; - m_bitfields.setBoxDecorationBackgroundState(HasBoxDecorationBackgroundObscurationStatusInvalid); + m_bitfields.setBackgroundObscurationState(BackgroundObscurationStatusInvalid); } -inline bool LayoutObject::boxDecorationBackgroundIsKnownToBeObscured() const +inline bool LayoutObject::backgroundIsKnownToBeObscured() const { - if (m_bitfields.getBoxDecorationBackgroundState() == HasBoxDecorationBackgroundObscurationStatusInvalid) { - BoxDecorationBackgroundState state = computeBackgroundIsKnownToBeObscured() ? HasBoxDecorationBackgroundKnownToBeObscured : HasBoxDecorationBackgroundMayBeVisible; - m_bitfields.setBoxDecorationBackgroundState(state); + if (m_bitfields.getBackgroundObscurationState() == BackgroundObscurationStatusInvalid) { + BackgroundObscurationState state = computeBackgroundIsKnownToBeObscured() ? BackgroundKnownToBeObscured : BackgroundMayBeVisible; + m_bitfields.setBackgroundObscurationState(state); } - return m_bitfields.getBoxDecorationBackgroundState() == HasBoxDecorationBackgroundKnownToBeObscured; + return m_bitfields.getBackgroundObscurationState() == BackgroundKnownToBeObscured; } inline void makeMatrixRenderable(TransformationMatrix& matrix, bool has3DRendering)
diff --git a/third_party/WebKit/Source/core/layout/LayoutPart.cpp b/third_party/WebKit/Source/core/layout/LayoutPart.cpp index 7dc5cf9..d56ac9de7 100644 --- a/third_party/WebKit/Source/core/layout/LayoutPart.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutPart.cpp
@@ -229,7 +229,7 @@ if (widget && widget->isFrameView()) toFrameView(widget)->recalculateCustomScrollbarStyle(); - if (style()->visibility() != VISIBLE) { + if (style()->visibility() != EVisibility::Visible) { widget->hide(); } else { widget->show(); @@ -285,7 +285,7 @@ if (!needsLayout()) updateWidgetGeometryInternal(); - if (style()->visibility() != VISIBLE) { + if (style()->visibility() != EVisibility::Visible) { widget->hide(); } else { widget->show();
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableCellTest.cpp b/third_party/WebKit/Source/core/layout/LayoutTableCellTest.cpp index 5183d90b..12c5cb1 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTableCellTest.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutTableCellTest.cpp
@@ -47,14 +47,15 @@ LayoutTableCell* m_cell; }; -TEST_F(LayoutTableCellDeathTest, CanSetColumn) +// TODO(esprehn): Disabled all of these tests because they're flaky: crbug.com/630625 +TEST_F(LayoutTableCellDeathTest, DISABLED_CanSetColumn) { static const unsigned columnIndex = 10; m_cell->setAbsoluteColumnIndex(columnIndex); EXPECT_EQ(columnIndex, m_cell->absoluteColumnIndex()); } -TEST_F(LayoutTableCellDeathTest, CanSetColumnToMaxColumnIndex) +TEST_F(LayoutTableCellDeathTest, DISABLED_CanSetColumnToMaxColumnIndex) { m_cell->setAbsoluteColumnIndex(maxColumnIndex); EXPECT_EQ(maxColumnIndex, m_cell->absoluteColumnIndex()); @@ -64,12 +65,12 @@ // See: https://bugs.webkit.org/show_bug.cgi?id=74089 #if !OS(ANDROID) -TEST_F(LayoutTableCellDeathTest, CrashIfColumnOverflowOnSetting) +TEST_F(LayoutTableCellDeathTest, DISABLED_CrashIfColumnOverflowOnSetting) { ASSERT_DEATH(m_cell->setAbsoluteColumnIndex(maxColumnIndex + 1), ""); } -TEST_F(LayoutTableCellDeathTest, CrashIfSettingUnsetColumnIndex) +TEST_F(LayoutTableCellDeathTest, DISABLED_CrashIfSettingUnsetColumnIndex) { ASSERT_DEATH(m_cell->setAbsoluteColumnIndex(unsetColumnIndex), ""); }
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableRowTest.cpp b/third_party/WebKit/Source/core/layout/LayoutTableRowTest.cpp index e71f6186..31c2a85 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTableRowTest.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutTableRowTest.cpp
@@ -47,14 +47,15 @@ LayoutTableRow* m_row; }; -TEST_F(LayoutTableRowDeathTest, CanSetRow) +// TODO(esprehn): Disabled all of these tests because they're flaky: crbug.com/630625 +TEST_F(LayoutTableRowDeathTest, DISABLED_CanSetRow) { static const unsigned rowIndex = 10; m_row->setRowIndex(rowIndex); EXPECT_EQ(rowIndex, m_row->rowIndex()); } -TEST_F(LayoutTableRowDeathTest, CanSetRowToMaxRowIndex) +TEST_F(LayoutTableRowDeathTest, DISABLED_CanSetRowToMaxRowIndex) { m_row->setRowIndex(maxRowIndex); EXPECT_EQ(maxRowIndex, m_row->rowIndex()); @@ -64,12 +65,12 @@ // See: https://bugs.webkit.org/show_bug.cgi?id=74089 #if !OS(ANDROID) -TEST_F(LayoutTableRowDeathTest, CrashIfRowOverflowOnSetting) +TEST_F(LayoutTableRowDeathTest, DISABLED_CrashIfRowOverflowOnSetting) { ASSERT_DEATH(m_row->setRowIndex(maxRowIndex + 1), ""); } -TEST_F(LayoutTableRowDeathTest, CrashIfSettingUnsetRowIndex) +TEST_F(LayoutTableRowDeathTest, DISABLED_CrashIfSettingUnsetRowIndex) { ASSERT_DEATH(m_row->setRowIndex(unsetRowIndex), ""); }
diff --git a/third_party/WebKit/Source/core/layout/LayoutText.cpp b/third_party/WebKit/Source/core/layout/LayoutText.cpp index f6b8d3e..66569d8 100644 --- a/third_party/WebKit/Source/core/layout/LayoutText.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutText.cpp
@@ -1632,7 +1632,7 @@ LayoutRect LayoutText::localOverflowRectForPaintInvalidation() const { - if (style()->visibility() != VISIBLE) + if (style()->visibility() != EVisibility::Visible) return LayoutRect(); return unionRect(visualOverflowRect(), localSelectionRect());
diff --git a/third_party/WebKit/Source/core/layout/LayoutTextControl.cpp b/third_party/WebKit/Source/core/layout/LayoutTextControl.cpp index 08b4701..a22b9cc 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTextControl.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutTextControl.cpp
@@ -120,8 +120,7 @@ logicalHeight = computeControlLogicalHeight(innerEditorBox->lineHeight(true, HorizontalLine, PositionOfInteriorLineBoxes), nonContentHeight); // We are able to have a horizontal scrollbar if the overflow style is scroll, or if its auto and there's no word wrap. - if ((isHorizontalWritingMode() && (style()->overflowX() == OverflowScroll || (style()->overflowX() == OverflowAuto && innerEditor->layoutObject()->style()->overflowWrap() == NormalOverflowWrap))) - || (!isHorizontalWritingMode() && (style()->overflowY() == OverflowScroll || (style()->overflowY() == OverflowAuto && innerEditor->layoutObject()->style()->overflowWrap() == NormalOverflowWrap)))) + if (style()->overflowInlineDirection() == OverflowScroll || (style()->overflowInlineDirection() == OverflowAuto && innerEditor->layoutObject()->style()->overflowWrap() == NormalOverflowWrap)) logicalHeight += scrollbarThickness(); // FIXME: The logical height of the inner text box should have been added before calling computeLogicalHeight to
diff --git a/third_party/WebKit/Source/core/layout/LayoutTreeAsText.cpp b/third_party/WebKit/Source/core/layout/LayoutTreeAsText.cpp index c97d0f5..fa86b98 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTreeAsText.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutTreeAsText.cpp
@@ -580,7 +580,7 @@ writeIndent(ts, indent); - if (layer.layoutObject()->style()->visibility() == HIDDEN) + if (layer.layoutObject()->style()->visibility() == EVisibility::Hidden) ts << "hidden "; ts << "layer ";
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp index 68195ca..f10007a 100644 --- a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp +++ b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp
@@ -309,8 +309,22 @@ m_graphicsLayer->setContentsOpaque(false); m_backgroundLayer->setContentsOpaque(m_owningLayer.backgroundIsKnownToBeOpaqueInRect(compositedBounds())); } else { - // For non-root layers, background is always painted by the primary graphics layer. - m_graphicsLayer->setContentsOpaque(m_owningLayer.backgroundIsKnownToBeOpaqueInRect(compositedBounds())); + // For non-root layers, background is painted by the scrolling contents layer if all backgrounds + // are background attachment local, otherwise background is painted by the primary graphics layer. + if (hasScrollingLayer() && shouldPaintBackgroundOntoScrollingContentsLayer()) { + // Backgrounds painted onto the foreground are clipped by the padding box rect. + // TODO(flackr): This should actually check the entire overflow rect within the + // scrolling contents layer but since we currently only trigger this for solid + // color backgrounds the answer will be the same. + m_scrollingContentsLayer->setContentsOpaque(m_owningLayer.backgroundIsKnownToBeOpaqueInRect(toLayoutBox(layoutObject())->paddingBoxRect())); + + // When we paint the background onto the scrolling contents layer we are going + // to leave a hole in the m_graphicsLayer where the background is so it is + // not opaque. + m_graphicsLayer->setContentsOpaque(false); + } else { + m_graphicsLayer->setContentsOpaque(m_owningLayer.backgroundIsKnownToBeOpaqueInRect(compositedBounds())); + } } } @@ -1228,7 +1242,7 @@ if (m_scrollingLayer) { // m_scrollingLayer never has backing store. // m_scrollingContentsLayer only needs backing store if the scrolled contents need to paint. - m_scrollingContentsAreEmpty = !m_owningLayer.hasVisibleContent() || !(layoutObject()->hasBackground() || layoutObject()->hasBackdropFilter() || paintsChildren()); + m_scrollingContentsAreEmpty = !m_owningLayer.hasVisibleContent() || !(layoutObject()->styleRef().hasBackground() || layoutObject()->hasBackdropFilter() || paintsChildren()); m_scrollingContentsLayer->setDrawsContent(!m_scrollingContentsAreEmpty); } @@ -2425,6 +2439,8 @@ PaintLayerFlags paintLayerFlags = 0; if (graphicsLayerPaintingPhase & GraphicsLayerPaintBackground) paintLayerFlags |= PaintLayerPaintingCompositingBackgroundPhase; + else + paintLayerFlags |= PaintLayerPaintingSkipRootBackground; if (graphicsLayerPaintingPhase & GraphicsLayerPaintForeground) paintLayerFlags |= PaintLayerPaintingCompositingForegroundPhase; if (graphicsLayerPaintingPhase & GraphicsLayerPaintMask) @@ -2438,7 +2454,7 @@ if (graphicsLayer == m_backgroundLayer.get()) paintLayerFlags |= (PaintLayerPaintingRootBackgroundOnly | PaintLayerPaintingCompositingForegroundPhase); // Need PaintLayerPaintingCompositingForegroundPhase to walk child layers. - else if (compositor()->fixedRootBackgroundLayer()) + else if (compositor()->fixedRootBackgroundLayer() && m_owningLayer.isRootLayer()) paintLayerFlags |= PaintLayerPaintingSkipRootBackground; if (graphicsLayer == m_graphicsLayer.get() @@ -2448,6 +2464,14 @@ || graphicsLayer == m_childClippingMaskLayer.get() || graphicsLayer == m_scrollingContentsLayer.get()) { + bool paintRootBackgroundOntoScrollingContentsLayer = shouldPaintBackgroundOntoScrollingContentsLayer(); + DCHECK(!paintRootBackgroundOntoScrollingContentsLayer || (!m_backgroundLayer && !m_foregroundLayer)); + if (paintRootBackgroundOntoScrollingContentsLayer) { + if (graphicsLayer == m_scrollingContentsLayer.get()) + paintLayerFlags &= ~PaintLayerPaintingSkipRootBackground; + else + paintLayerFlags |= PaintLayerPaintingSkipRootBackground; + } GraphicsLayerPaintInfo paintInfo; paintInfo.paintLayer = &m_owningLayer; paintInfo.compositedBounds = compositedBounds(); @@ -2559,6 +2583,19 @@ return false; } +bool CompositedLayerMapping::shouldPaintBackgroundOntoScrollingContentsLayer() const +{ + // TODO(flackr): Add support for painting locally attached background images. https://crbug.com/625882 + const FillLayer& backgroundLayer = m_owningLayer.layoutObject()->style()->backgroundLayers(); + return !m_owningLayer.isRootLayer() + && m_owningLayer.scrollsOverflow() + && !backgroundLayer.image() + && !backgroundLayer.next() + && (backgroundLayer.attachment() == LocalBackgroundAttachment + || backgroundLayer.clip() == PaddingFillBox) + && !m_owningLayer.stackingNode()->hasNegativeZOrderList(); +} + bool CompositedLayerMapping::updateSquashingLayerAssignment(PaintLayer* squashedLayer, size_t nextSquashedLayerIndex) { GraphicsLayerPaintInfo paintInfo;
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.h b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.h index 93154db8f..d711756 100644 --- a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.h +++ b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.h
@@ -329,6 +329,13 @@ // not appear earlier in the set of layers for this object. bool invalidateLayerIfNoPrecedingEntry(size_t); + // Returns true for layers with scrollable overflow which have a background + // that can be painted into the composited scrolling contents layer (i.e. + // the background can scroll with the content). When the background is also + // opaque this allows us to composite the scroller even on low DPI as we can + // draw with subpixel anti-aliasing. + bool shouldPaintBackgroundOntoScrollingContentsLayer() const; + PaintLayer& m_owningLayer; // The hierarchy of layers that is maintained by the CompositedLayerMapping looks like this:
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMappingTest.cpp b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMappingTest.cpp index 45d65c050..2328a074 100644 --- a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMappingTest.cpp +++ b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMappingTest.cpp
@@ -45,6 +45,12 @@ return graphicsLayer->m_previousInterestRect; } + bool shouldPaintBackgroundOntoScrollingContentsLayer(const char* elementId) + { + CompositedLayerMapping* mapping = toLayoutBlock(getLayoutObjectByElementId(elementId))->layer()->compositedLayerMapping(); + return mapping->shouldPaintBackgroundOntoScrollingContentsLayer(); + } + private: void SetUp() override { @@ -626,4 +632,31 @@ EXPECT_FALSE(mapping->foregroundLayer()); } +TEST_F(CompositedLayerMappingTest, ShouldPaintBackgroundOntoScrollingContentsLayer) +{ + document().frame()->settings()->setPreferCompositingToLCDTextEnabled(true); + setBodyInnerHTML( + "<style>.scroller { overflow: scroll; will-change: transform; width: 300px; height: 300px;} .spacer { height: 1000px; }</style>" + "<div id='scroller1' class='scroller' style='background: white local;'>" + " <div id='negative-composited-child' style='background-color: red; width: 1px; height: 1px; position: absolute; backface-visibility: hidden; z-index: -1'></div>" + " <div class='spacer'></div>" + "</div>" + "<div id='scroller2' class='scroller' style='background: white content-box; padding: 10px;'>" + " <div class='spacer'></div>" + "</div>" + "<div id='scroller3' class='scroller' style='background: white local content-box; padding: 10px;'>" + " <div class='spacer'></div>" + "</div>" + ); + + // First scroller cannot paint background into scrolling contents layer because it has a negative z-index child. + EXPECT_FALSE(shouldPaintBackgroundOntoScrollingContentsLayer("scroller1")); + + // Second scroller cannot paint background into scrolling contents layer because it has a content-box clip without local attachment. + EXPECT_FALSE(shouldPaintBackgroundOntoScrollingContentsLayer("scroller2")); + + // Third scroller can paint background into scrolling contents layer. + EXPECT_TRUE(shouldPaintBackgroundOntoScrollingContentsLayer("scroller3")); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.cpp b/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.cpp index b9b9176..2f59368 100644 --- a/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.cpp +++ b/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.cpp
@@ -25,8 +25,8 @@ #include "core/layout/compositing/PaintLayerCompositor.h" -#include "core/animation/AnimationTimeline.h" #include "core/animation/DocumentAnimations.h" +#include "core/animation/DocumentTimeline.h" #include "core/animation/ElementAnimations.h" #include "core/dom/DOMNodeIds.h" #include "core/dom/Fullscreen.h" @@ -350,7 +350,6 @@ // changing the previous position from our paint invalidation container, which is fine as // we want a full paint invalidation anyway. layoutObject->clearPreviousPaintInvalidationRects(); - layoutObject->setShouldDoFullPaintInvalidation(); for (LayoutObject* child = layoutObject->slowFirstChild(); child; child = child->nextSibling()) { if (!child->isPaintInvalidationContainer())
diff --git a/third_party/WebKit/Source/core/layout/ng/.clang-format b/third_party/WebKit/Source/core/layout/ng/.clang-format new file mode 100644 index 0000000..6fdf1dc --- /dev/null +++ b/third_party/WebKit/Source/core/layout/ng/.clang-format
@@ -0,0 +1,8 @@ +# Defines the Chromium style for automatic reformatting. +# http://clang.llvm.org/docs/ClangFormatStyleOptions.html +BasedOnStyle: Chromium +# This defaults to 'Auto'. Explicitly set it for a while, so that +# 'vector<vector<int> >' in existing files gets formatted to +# 'vector<vector<int>>'. ('Auto' means that clang-format will only use +# 'int>>' if the file already contains at least one such instance.) +Standard: Cpp11
diff --git a/third_party/WebKit/Source/core/layout/ng/LayoutNGBlockFlow.cpp b/third_party/WebKit/Source/core/layout/ng/LayoutNGBlockFlow.cpp deleted file mode 100644 index a09ffe2..0000000 --- a/third_party/WebKit/Source/core/layout/ng/LayoutNGBlockFlow.cpp +++ /dev/null
@@ -1,19 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "core/layout/ng/LayoutNGBlockFlow.h" - -namespace blink { - -LayoutNGBlockFlow::LayoutNGBlockFlow(Element* element) - : LayoutBlockFlow(element) -{ -} - -bool LayoutNGBlockFlow::isOfType(LayoutObjectType type) const -{ - return type == LayoutObjectNGBlockFlow || LayoutBlockFlow::isOfType(type); -} - -} // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/LayoutNGBlockFlow.h b/third_party/WebKit/Source/core/layout/ng/LayoutNGBlockFlow.h deleted file mode 100644 index 5e8aa01..0000000 --- a/third_party/WebKit/Source/core/layout/ng/LayoutNGBlockFlow.h +++ /dev/null
@@ -1,26 +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 LayoutNGBlockFlow_h -#define LayoutNGBlockFlow_h - -#include "core/layout/LayoutBlockFlow.h" - -namespace blink { - -// This overrides the default layout block algorithm to use Layout NG. -class LayoutNGBlockFlow final : public LayoutBlockFlow { -public: - explicit LayoutNGBlockFlow(Element*); - ~LayoutNGBlockFlow() override = default; - -private: - bool isOfType(LayoutObjectType) const override; -}; - -DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutNGBlockFlow, isLayoutNGBlockFlow()); - -} // namespace blink - -#endif // LayoutNGBlockFlow_h
diff --git a/third_party/WebKit/Source/core/layout/ng/NGBlockLayoutAlgorithm.cpp b/third_party/WebKit/Source/core/layout/ng/NGBlockLayoutAlgorithm.cpp deleted file mode 100644 index b7d4b998..0000000 --- a/third_party/WebKit/Source/core/layout/ng/NGBlockLayoutAlgorithm.cpp +++ /dev/null
@@ -1,40 +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 "core/layout/ng/NGBlockLayoutAlgorithm.h" - -#include "core/layout/LayoutBox.h" -#include "core/layout/ng/NGConstraintSpace.h" -#include "core/style/ComputedStyle.h" - -namespace blink { - -NGBlockLayoutAlgorithm::NGBlockLayoutAlgorithm() -{ -} - -NGConstraintSpace NGBlockLayoutAlgorithm::createConstraintSpaceFromLayoutObject(const LayoutBox& child) -{ - bool fixedInline = false, fixedBlock = false; - // XXX for orthogonal writing mode this is not right - LayoutUnit containerLogicalWidth = std::max(LayoutUnit(), child.containingBlockLogicalWidthForContent()); - // XXX Make sure this height is correct - LayoutUnit containerLogicalHeight = child.containingBlockLogicalHeightForContent(ExcludeMarginBorderPadding); - if (child.hasOverrideLogicalContentWidth()) { - containerLogicalWidth = child.overrideLogicalContentWidth(); - fixedInline = true; - } - if (child.hasOverrideLogicalContentHeight()) { - containerLogicalWidth = child.overrideLogicalContentHeight(); - fixedBlock = true; - } - NGConstraintSpace space(containerLogicalWidth, containerLogicalHeight); - // XXX vertical writing mode - space.setOverflowTriggersScrollbar(child.styleRef().overflowX() == OverflowAuto, - child.styleRef().overflowY() == OverflowAuto); - space.setFixedSize(fixedInline, fixedBlock); - return space; -} - -} // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/NGBlockLayoutAlgorithm.h b/third_party/WebKit/Source/core/layout/ng/NGBlockLayoutAlgorithm.h deleted file mode 100644 index 0fc44a2..0000000 --- a/third_party/WebKit/Source/core/layout/ng/NGBlockLayoutAlgorithm.h +++ /dev/null
@@ -1,22 +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 NGBlockLayoutAlgorithm_h -#define NGBlockLayoutAlgorithm_h - -namespace blink { - -class LayoutBox; -class NGConstraintSpace; - -class NGBlockLayoutAlgorithm { -public: - NGBlockLayoutAlgorithm(); - - NGConstraintSpace createConstraintSpaceFromLayoutObject(const LayoutBox&); -}; - -} // namespace blink - -#endif // NGBlockLayoutAlgorithm_h
diff --git a/third_party/WebKit/Source/core/layout/ng/NGConstraintSpace.cpp b/third_party/WebKit/Source/core/layout/ng/NGConstraintSpace.cpp deleted file mode 100644 index 3146c5c..0000000 --- a/third_party/WebKit/Source/core/layout/ng/NGConstraintSpace.cpp +++ /dev/null
@@ -1,61 +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 "core/layout/ng/NGConstraintSpace.h" - -namespace blink { - -NGConstraintSpace::NGConstraintSpace(LayoutUnit inlineContainerSize, - LayoutUnit blockContainerSize) -{ - m_inlineContainerSize = inlineContainerSize; - m_blockContainerSize = blockContainerSize; - m_inlineTriggersScrollbar = 0; - m_blockTriggersScrollbar = 0; - m_fixedInlineSize = 0; - m_fixedBlockSize = 0; - m_blockFragmentationType = FragmentNone; -} - -void NGConstraintSpace::addExclusion(const NGExclusion exclusion, - unsigned options) -{ - -} - -void NGConstraintSpace::setOverflowTriggersScrollbar(bool inlineTriggers, - bool blockTriggers) -{ - m_inlineTriggersScrollbar = inlineTriggers; - m_blockTriggersScrollbar = blockTriggers; -} - -void NGConstraintSpace::setFixedSize(bool inlineFixed, bool blockFixed) -{ - m_fixedInlineSize = inlineFixed; - m_fixedBlockSize = blockFixed; -} - -void NGConstraintSpace::setFragmentationType(NGFragmentationType type) -{ - m_blockFragmentationType = type; -} - -DoublyLinkedList<const NGExclusion> NGConstraintSpace::exclusions( - unsigned options) const -{ - DoublyLinkedList<const NGExclusion> exclusions; - // TODO(eae): Implement. - return exclusions; -} - -NGLayoutOpportunityIterator NGConstraintSpace::layoutOpportunities( - unsigned clear, NGExclusionFlowType avoid) const -{ - // TODO(eae): Implement. - NGLayoutOpportunityIterator iterator(this, clear, avoid); - return iterator; -} - -} // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/NGConstraintSpace.h b/third_party/WebKit/Source/core/layout/ng/NGConstraintSpace.h deleted file mode 100644 index d0d9a1f..0000000 --- a/third_party/WebKit/Source/core/layout/ng/NGConstraintSpace.h +++ /dev/null
@@ -1,166 +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 NGConstraintSpace_h -#define NGConstraintSpace_h - -#include "core/CoreExport.h" -#include "platform/LayoutUnit.h" -#include "wtf/DoublyLinkedList.h" - -namespace blink { - -class NGDerivedConstraintSpace; -class NGExclusion; -class NGFragment; -class NGLayoutOpportunityIterator; - -enum NGExclusionType { - NGClearNone = 0, - NGClearFloatLeft = 1, - NGClearFloatRight = 2, - NGClearFragment = 4 -}; - -enum NGFragmentationType { - FragmentNone, - FragmentPage, - FragmentColumn, - FragmentRegion -}; - -enum NGExclusionFlowType { - ExcludeNone, - ExcludeInlineFlow, - ExcludeInlineStart, - ExcludeInlineEnd, - ExcludeInlineBoth -}; - -class NGExclusion { -public: - NGExclusion(); - ~NGExclusion() { } -}; - -class CORE_EXPORT NGConstraintSpace { -public: - NGConstraintSpace(LayoutUnit inlineContainerSize, - LayoutUnit blockContainerSize); - ~NGConstraintSpace() { } - - void addExclusion(const NGExclusion, unsigned options = 0); - void setOverflowTriggersScrollbar(bool inlineTriggers, - bool blockTriggers); - void setFixedSize(bool inlineFixed, bool blockFixed); - void setFragmentationType(NGFragmentationType); - - // Size of the container in each direction. Used for the following - // three cases: - // 1) Percentage resolution. - // 2) Resolving absolute positions of children. - // 3) Defining the threashold that triggers the presence of a - // scrollbar. Only applies if the corresponding scrollbarTrigger - // flag has been set for the direction. - LayoutUnit inlineContainerSize() const - { - return m_inlineContainerSize; - } - LayoutUnit blockContainerSize() const - { - return m_blockContainerSize; - } - - // Whether exceeding the containerSize triggers the presence of a - // scrollbar for the indicated direction. - // If exceeded the current layout should be aborted and invoked again - // with a constraint space modified to reserve space for a scrollbar. - bool inlineTriggersScrollbar() const - { - return m_inlineTriggersScrollbar; - } - bool blockTriggersScrollbar() const - { - return m_blockTriggersScrollbar; - } - - // Some layout modes “stretch” their children to a fixed size (e.g. flex, - // grid). These flags represented whether a layout needs to produce a - // fragment that satisfies a fixed constraint in the inline and block - // direction respectively. - bool fixedInlineSize() const { return m_fixedInlineSize; } - bool fixedBlockSize() const { return m_fixedBlockSize; } - - // If specified a layout should produce a Fragment which fragments at the - // blockSize if possible. - NGFragmentationType blockFragmentationType() const - { - return static_cast<NGFragmentationType>(m_blockFragmentationType); - } - - DoublyLinkedList<const NGExclusion> exclusions(unsigned options = 0) const; - - NGLayoutOpportunityIterator layoutOpportunities( - unsigned clear = NGClearNone, - NGExclusionFlowType avoid = ExcludeNone) const; - - // Modifies constraint space to account for a placed fragment. Depending on - // the shape of the fragment this will either modify the inline or block - // size, or add an exclusion. - void subtract(const NGFragment); - -private: - LayoutUnit m_inlineContainerSize; - LayoutUnit m_blockContainerSize; - - unsigned m_fixedInlineSize : 1; - unsigned m_fixedBlockSize : 1; - unsigned m_inlineTriggersScrollbar : 1; - unsigned m_blockTriggersScrollbar : 1; - unsigned m_blockFragmentationType : 2; - - DoublyLinkedList<const NGExclusion> m_exclusions; -}; - - -class CORE_EXPORT NGLayoutOpportunityIterator final { -public: - NGLayoutOpportunityIterator(const NGConstraintSpace* space, - unsigned clear, NGExclusionFlowType avoid) - : m_constraintSpace(space) - , m_clear(clear) - , m_avoid(avoid) { } - ~NGLayoutOpportunityIterator() { } - - const NGDerivedConstraintSpace* next(); - -private: - const NGConstraintSpace* m_constraintSpace; - unsigned m_clear; - NGExclusionFlowType m_avoid; -}; - - -class CORE_EXPORT NGDerivedConstraintSpace final : NGConstraintSpace { -public: - ~NGDerivedConstraintSpace(); - - LayoutUnit inlineOffset() const; - LayoutUnit blockOffset() const; - LayoutUnit inlineSize() const; - LayoutUnit blockSize() const; - -private: - NGDerivedConstraintSpace(); - - LayoutUnit m_inlineOffset; - LayoutUnit m_blockOffset; - LayoutUnit m_inlineSize; - LayoutUnit m_blockSize; - NGConstraintSpace* m_original; -}; - -} // namespace blink - -#endif // NGConstraintSpace_h
diff --git a/third_party/WebKit/Source/core/layout/ng/NGFragment.cpp b/third_party/WebKit/Source/core/layout/ng/NGFragment.cpp deleted file mode 100644 index 22d1d017..0000000 --- a/third_party/WebKit/Source/core/layout/ng/NGFragment.cpp +++ /dev/null
@@ -1,21 +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 "core/layout/ng/NGFragment.h" - -namespace blink { - -NGFragment::NGFragment(LayoutUnit inlineSize, LayoutUnit blockSize) - : m_inlineSize(inlineSize) - , m_blockSize(blockSize) -{ -} - -void NGFragment::setOffset(LayoutUnit inlineOffset, LayoutUnit blockOffset) -{ - m_inlineOffset = inlineOffset; - m_blockOffset = blockOffset; -} - -} // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/NGFragment.h b/third_party/WebKit/Source/core/layout/ng/NGFragment.h deleted file mode 100644 index 3aa3bd8..0000000 --- a/third_party/WebKit/Source/core/layout/ng/NGFragment.h +++ /dev/null
@@ -1,36 +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 NGFragment_h -#define NGFragment_h - -#include "core/CoreExport.h" -#include "platform/LayoutUnit.h" - -namespace blink { - -class CORE_EXPORT NGFragment final { -public: - NGFragment(LayoutUnit inlineSize, LayoutUnit blockSize); - ~NGFragment() { } - - LayoutUnit inlineSize() const { return m_inlineSize; } - LayoutUnit blockSize() const { return m_blockSize; } - - LayoutUnit inlineOffset() const { return m_inlineOffset; } - LayoutUnit blockOffset() const { return m_blockOffset; } - - void setOffset(LayoutUnit inlineOffset, LayoutUnit blockOffset); - -private: - LayoutUnit m_inlineSize; - LayoutUnit m_blockSize; - - LayoutUnit m_inlineOffset; - LayoutUnit m_blockOffset; -}; - -} // namespace blink - -#endif // NGFragment_h
diff --git a/third_party/WebKit/Source/core/layout/ng/OWNERS b/third_party/WebKit/Source/core/layout/ng/OWNERS new file mode 100644 index 0000000..523fc3f --- /dev/null +++ b/third_party/WebKit/Source/core/layout/ng/OWNERS
@@ -0,0 +1,4 @@ +cbiesinger@chromium.org +eae@chromium.org +glebl@chromium.org +ikilpatrick@chromium.org \ No newline at end of file
diff --git a/third_party/WebKit/Source/core/layout/ng/PRESUBMIT.py b/third_party/WebKit/Source/core/layout/ng/PRESUBMIT.py new file mode 100644 index 0000000..0d4f77d --- /dev/null +++ b/third_party/WebKit/Source/core/layout/ng/PRESUBMIT.py
@@ -0,0 +1,14 @@ +# 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. + +"""Presubmit script for LayoutNG. + +See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts +for more details about the presubmit API built into depot_tools. +""" + +def CheckChangeOnUpload(input_api, output_api): + results = [] + results.extend(input_api.canned_checks.CheckPatchFormatted(input_api, output_api)) + return results
diff --git a/third_party/WebKit/Source/core/layout/ng/layout_ng_block_flow.cc b/third_party/WebKit/Source/core/layout/ng/layout_ng_block_flow.cc new file mode 100644 index 0000000..027e1f7 --- /dev/null +++ b/third_party/WebKit/Source/core/layout/ng/layout_ng_block_flow.cc
@@ -0,0 +1,16 @@ +// 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 "core/layout/ng/layout_ng_block_flow.h" + +namespace blink { + +LayoutNGBlockFlow::LayoutNGBlockFlow(Element* element) + : LayoutBlockFlow(element) {} + +bool LayoutNGBlockFlow::isOfType(LayoutObjectType type) const { + return type == LayoutObjectNGBlockFlow || LayoutBlockFlow::isOfType(type); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/layout_ng_block_flow.h b/third_party/WebKit/Source/core/layout/ng/layout_ng_block_flow.h new file mode 100644 index 0000000..0dd7a3b --- /dev/null +++ b/third_party/WebKit/Source/core/layout/ng/layout_ng_block_flow.h
@@ -0,0 +1,26 @@ +// 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 LayoutNGBlockFlow_h +#define LayoutNGBlockFlow_h + +#include "core/layout/LayoutBlockFlow.h" + +namespace blink { + +// This overrides the default layout block algorithm to use Layout NG. +class LayoutNGBlockFlow final : public LayoutBlockFlow { + public: + explicit LayoutNGBlockFlow(Element*); + ~LayoutNGBlockFlow() override = default; + + private: + bool isOfType(LayoutObjectType) const override; +}; + +DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutNGBlockFlow, isLayoutNGBlockFlow()); + +} // namespace blink + +#endif // LayoutNGBlockFlow_h
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc new file mode 100644 index 0000000..56d0fad --- /dev/null +++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
@@ -0,0 +1,46 @@ +// 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 "core/layout/ng/ng_block_layout_algorithm.h" + +#include "core/layout/LayoutBox.h" +#include "core/layout/ng/ng_constraint_space.h" +#include "core/layout/ng/ng_fragment.h" +#include "core/layout/ng/ng_length_utils.h" +#include "core/style/ComputedStyle.h" +#include "platform/LengthFunctions.h" + +namespace blink { + +NGBlockLayoutAlgorithm::NGBlockLayoutAlgorithm( + PassRefPtr<const ComputedStyle> style, + NGBox firstChild) + : m_style(style), m_firstChild(firstChild) {} + +NGFragment* NGBlockLayoutAlgorithm::layout( + const NGConstraintSpace& constraintSpace) { + LayoutUnit inlineSize = + computeInlineSizeForFragment(constraintSpace, *m_style); + + HeapVector<Member<const NGFragmentBase>> childFragments; + + LayoutUnit contentSize; + for (NGBox curr = m_firstChild; curr; curr.nextSibling()) { + NGFragment* fragment = curr.layout(constraintSpace); + // TODO(layout-ng): Take margins into account + fragment->setOffset(LayoutUnit(), contentSize); + contentSize += fragment->blockSize(); + childFragments.append(fragment); + } + + LayoutUnit blockSize = + computeBlockSizeForFragment(constraintSpace, *m_style, contentSize); + NGFragment* returnFragment = new NGFragment( + inlineSize, blockSize, inlineSize, blockSize, + NGFragmentBase::HorizontalTopBottom, NGFragmentBase::LeftToRight); + returnFragment->swapChildren(childFragments); + return returnFragment; +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h new file mode 100644 index 0000000..9f5f30b --- /dev/null +++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h
@@ -0,0 +1,38 @@ +// 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 NGBlockLayoutAlgorithm_h +#define NGBlockLayoutAlgorithm_h + +#include "core/CoreExport.h" +#include "core/layout/ng/ng_box.h" +#include "wtf/RefPtr.h" + +namespace blink { + +class ComputedStyle; +class NGConstraintSpace; +class NGFragment; + +// A class for general block layout (e.g. a <div> with no special style). +// Lays out the children in sequence. +class CORE_EXPORT NGBlockLayoutAlgorithm { + public: + NGBlockLayoutAlgorithm(PassRefPtr<const ComputedStyle>, NGBox); + + // Actual layout implementation. Lays out the children in sequence within the + // constraints given by the NGConstraintSpace. Returns a fragment with the + // resulting layout information. + // This function can not be const because for interruptible layout, we have + // to be able to store state information. + NGFragment* layout(const NGConstraintSpace&); + + private: + RefPtr<const ComputedStyle> m_style; + NGBox m_firstChild; +}; + +} // namespace blink + +#endif // NGBlockLayoutAlgorithm_h
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc new file mode 100644 index 0000000..f008d68 --- /dev/null +++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc
@@ -0,0 +1,38 @@ +// 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 "core/layout/ng/ng_block_layout_algorithm.h" + +#include "core/layout/ng/ng_box.h" +#include "core/layout/ng/ng_constraint_space.h" +#include "core/layout/ng/ng_fragment.h" +#include "core/style/ComputedStyle.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace blink { +namespace { + +class NGBlockLayoutAlgorithmTest : public ::testing::Test { + protected: + void SetUp() override { + style_ = ComputedStyle::create(); + } + + RefPtr<ComputedStyle> style_; +}; + +TEST_F(NGBlockLayoutAlgorithmTest, FixedSize) { + style_->setWidth(Length(30, Fixed)); + style_->setHeight(Length(40, Fixed)); + + NGConstraintSpace space(LayoutUnit(100), LayoutUnit(-1)); + + NGBlockLayoutAlgorithm algorithm(style_, NGBox(nullptr)); + NGFragment* frag = algorithm.layout(space); + EXPECT_EQ(frag->inlineSize(), LayoutUnit(30)); + EXPECT_EQ(frag->blockSize(), LayoutUnit(40)); +} + +} // namespace +} // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_box.cc b/third_party/WebKit/Source/core/layout/ng/ng_box.cc new file mode 100644 index 0000000..7f8a30f --- /dev/null +++ b/third_party/WebKit/Source/core/layout/ng/ng_box.cc
@@ -0,0 +1,29 @@ +// 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 "core/layout/ng/ng_box.h" + +#include "core/layout/LayoutObject.h" +#include "core/layout/ng/ng_block_layout_algorithm.h" + +namespace blink { + +NGFragment* NGBox::layout(const NGConstraintSpace& constraintSpace) { + NGBlockLayoutAlgorithm algorithm(style(), firstChild()); + return algorithm.layout(constraintSpace); +} + +const ComputedStyle* NGBox::style() const { + return m_layoutObject->style(); +} + +const NGBox NGBox::firstChild() const { + return NGBox(m_layoutObject->slowFirstChild()); +} + +const NGBox NGBox::nextSibling() const { + return NGBox(m_layoutObject->nextSibling()); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_box.h b/third_party/WebKit/Source/core/layout/ng/ng_box.h new file mode 100644 index 0000000..e2a9e2c34 --- /dev/null +++ b/third_party/WebKit/Source/core/layout/ng/ng_box.h
@@ -0,0 +1,39 @@ +// 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 NGBox_h +#define NGBox_h + +#include "core/CoreExport.h" +#include "platform/heap/Handle.h" + +namespace blink { + +class ComputedStyle; +class LayoutObject; +class NGConstraintSpace; +class NGFragment; + +// Represents a node to be laid out. +class CORE_EXPORT NGBox final { + public: + explicit NGBox(const LayoutObject* layoutObject) + : m_layoutObject(layoutObject) {} + + operator bool() const { return m_layoutObject; } + + NGFragment* layout(const NGConstraintSpace&); + const ComputedStyle* style() const; + + // TODO(layout-ng): Returning a children iterator would be better here. + const NGBox firstChild() const; + const NGBox nextSibling() const; + + private: + const LayoutObject* m_layoutObject; +}; + +} // namespace blink + +#endif // NGBox_h
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_constraint_space.cc b/third_party/WebKit/Source/core/layout/ng/ng_constraint_space.cc new file mode 100644 index 0000000..f0f49438 --- /dev/null +++ b/third_party/WebKit/Source/core/layout/ng/ng_constraint_space.cc
@@ -0,0 +1,80 @@ +// 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 "core/layout/ng/ng_constraint_space.h" + +#include "core/layout/LayoutBox.h" +#include "core/style/ComputedStyle.h" + +namespace blink { + +NGConstraintSpace::NGConstraintSpace(LayoutUnit inlineContainerSize, + LayoutUnit blockContainerSize) { + m_inlineContainerSize = inlineContainerSize; + m_blockContainerSize = blockContainerSize; + m_inlineTriggersScrollbar = 0; + m_blockTriggersScrollbar = 0; + m_fixedInlineSize = 0; + m_fixedBlockSize = 0; + m_blockFragmentationType = FragmentNone; +} + +NGConstraintSpace NGConstraintSpace::fromLayoutObject(const LayoutBox& child) { + bool fixedInline = false, fixedBlock = false; + // XXX for orthogonal writing mode this is not right + LayoutUnit containerLogicalWidth = + std::max(LayoutUnit(), child.containingBlockLogicalWidthForContent()); + // XXX Make sure this height is correct + LayoutUnit containerLogicalHeight = + child.containingBlockLogicalHeightForContent(ExcludeMarginBorderPadding); + if (child.hasOverrideLogicalContentWidth()) { + containerLogicalWidth = child.overrideLogicalContentWidth(); + fixedInline = true; + } + if (child.hasOverrideLogicalContentHeight()) { + containerLogicalWidth = child.overrideLogicalContentHeight(); + fixedBlock = true; + } + NGConstraintSpace space(containerLogicalWidth, containerLogicalHeight); + space.setOverflowTriggersScrollbar( + child.styleRef().overflowInlineDirection() == OverflowAuto, + child.styleRef().overflowBlockDirection() == OverflowAuto); + space.setFixedSize(fixedInline, fixedBlock); + return space; +} + +void NGConstraintSpace::addExclusion(const NGExclusion exclusion, + unsigned options) {} + +void NGConstraintSpace::setOverflowTriggersScrollbar(bool inlineTriggers, + bool blockTriggers) { + m_inlineTriggersScrollbar = inlineTriggers; + m_blockTriggersScrollbar = blockTriggers; +} + +void NGConstraintSpace::setFixedSize(bool inlineFixed, bool blockFixed) { + m_fixedInlineSize = inlineFixed; + m_fixedBlockSize = blockFixed; +} + +void NGConstraintSpace::setFragmentationType(NGFragmentationType type) { + m_blockFragmentationType = type; +} + +DoublyLinkedList<const NGExclusion> NGConstraintSpace::exclusions( + unsigned options) const { + DoublyLinkedList<const NGExclusion> exclusions; + // TODO(eae): Implement. + return exclusions; +} + +NGLayoutOpportunityIterator NGConstraintSpace::layoutOpportunities( + unsigned clear, + NGExclusionFlowType avoid) const { + // TODO(eae): Implement. + NGLayoutOpportunityIterator iterator(this, clear, avoid); + return iterator; +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_constraint_space.h b/third_party/WebKit/Source/core/layout/ng/ng_constraint_space.h new file mode 100644 index 0000000..e4ee8b10 --- /dev/null +++ b/third_party/WebKit/Source/core/layout/ng/ng_constraint_space.h
@@ -0,0 +1,154 @@ +// 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 NGConstraintSpace_h +#define NGConstraintSpace_h + +#include "core/CoreExport.h" +#include "platform/LayoutUnit.h" +#include "wtf/DoublyLinkedList.h" + +namespace blink { + +class NGConstraintSpace; +class NGDerivedConstraintSpace; +class NGExclusion; +class NGFragment; +class NGLayoutOpportunityIterator; +class LayoutBox; + +enum NGExclusionType { + NGClearNone = 0, + NGClearFloatLeft = 1, + NGClearFloatRight = 2, + NGClearFragment = 4 +}; + +enum NGFragmentationType { + FragmentNone, + FragmentPage, + FragmentColumn, + FragmentRegion +}; + +enum NGExclusionFlowType { + ExcludeNone, + ExcludeInlineFlow, + ExcludeInlineStart, + ExcludeInlineEnd, + ExcludeInlineBoth +}; + +class NGExclusion { + public: + NGExclusion(); + ~NGExclusion() {} +}; + +class CORE_EXPORT NGConstraintSpace { + public: + NGConstraintSpace(LayoutUnit inlineContainerSize, + LayoutUnit blockContainerSize); + ~NGConstraintSpace() {} + + // Constructs Layout NG constraint space from legacy layout object. + static NGConstraintSpace fromLayoutObject(const LayoutBox&); + + void addExclusion(const NGExclusion, unsigned options = 0); + void setOverflowTriggersScrollbar(bool inlineTriggers, bool blockTriggers); + void setFixedSize(bool inlineFixed, bool blockFixed); + void setFragmentationType(NGFragmentationType); + + // Size of the container in each direction. Used for the following + // three cases: + // 1) Percentage resolution. + // 2) Resolving absolute positions of children. + // 3) Defining the threashold that triggers the presence of a scrollbar. Only + // applies if the corresponding scrollbarTrigger flag has been set for the + // direction. + LayoutUnit inlineContainerSize() const { return m_inlineContainerSize; } + LayoutUnit blockContainerSize() const { return m_blockContainerSize; } + + // Whether exceeding the containerSize triggers the presence of a scrollbar + // for the indicated direction. + // If exceeded the current layout should be aborted and invoked again with a + // constraint space modified to reserve space for a scrollbar. + bool inlineTriggersScrollbar() const { return m_inlineTriggersScrollbar; } + bool blockTriggersScrollbar() const { return m_blockTriggersScrollbar; } + + // Some layout modes “stretch” their children to a fixed size (e.g. flex, + // grid). These flags represented whether a layout needs to produce a + // fragment that satisfies a fixed constraint in the inline and block + // direction respectively. + bool fixedInlineSize() const { return m_fixedInlineSize; } + bool fixedBlockSize() const { return m_fixedBlockSize; } + + // If specified a layout should produce a Fragment which fragments at the + // blockSize if possible. + NGFragmentationType blockFragmentationType() const { + return static_cast<NGFragmentationType>(m_blockFragmentationType); + } + + DoublyLinkedList<const NGExclusion> exclusions(unsigned options = 0) const; + + NGLayoutOpportunityIterator layoutOpportunities( + unsigned clear = NGClearNone, + NGExclusionFlowType avoid = ExcludeNone) const; + + // Modifies constraint space to account for a placed fragment. Depending on + // the shape of the fragment this will either modify the inline or block + // size, or add an exclusion. + void subtract(const NGFragment); + + private: + LayoutUnit m_inlineContainerSize; + LayoutUnit m_blockContainerSize; + + unsigned m_fixedInlineSize : 1; + unsigned m_fixedBlockSize : 1; + unsigned m_inlineTriggersScrollbar : 1; + unsigned m_blockTriggersScrollbar : 1; + unsigned m_blockFragmentationType : 2; + + DoublyLinkedList<const NGExclusion> m_exclusions; +}; + +class CORE_EXPORT NGLayoutOpportunityIterator final { + public: + NGLayoutOpportunityIterator(const NGConstraintSpace* space, + unsigned clear, + NGExclusionFlowType avoid) + : m_constraintSpace(space), m_clear(clear), m_avoid(avoid) {} + ~NGLayoutOpportunityIterator() {} + + const NGDerivedConstraintSpace* next(); + + private: + const NGConstraintSpace* m_constraintSpace; + unsigned m_clear; + NGExclusionFlowType m_avoid; +}; + +class CORE_EXPORT NGDerivedConstraintSpace final : NGConstraintSpace { + public: + ~NGDerivedConstraintSpace(); + + LayoutUnit inlineOffset() const; + LayoutUnit blockOffset() const; + LayoutUnit inlineSize() const; + LayoutUnit blockSize() const; + + private: + NGDerivedConstraintSpace(); + + LayoutUnit m_inlineOffset; + LayoutUnit m_blockOffset; + LayoutUnit m_inlineSize; + LayoutUnit m_blockSize; + NGConstraintSpace* m_original; +}; + +} // namespace blink + +#endif // NGConstraintSpace_h
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_fragment.cc b/third_party/WebKit/Source/core/layout/ng/ng_fragment.cc new file mode 100644 index 0000000..4085e38 --- /dev/null +++ b/third_party/WebKit/Source/core/layout/ng/ng_fragment.cc
@@ -0,0 +1,7 @@ +// 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 "core/layout/ng/ng_fragment.h" + +namespace blink {} // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_fragment.h b/third_party/WebKit/Source/core/layout/ng/ng_fragment.h new file mode 100644 index 0000000..59ebae85 --- /dev/null +++ b/third_party/WebKit/Source/core/layout/ng/ng_fragment.h
@@ -0,0 +1,47 @@ +// 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 NGFragment_h +#define NGFragment_h + +#include "core/CoreExport.h" +#include "core/layout/ng/ng_fragment_base.h" +#include "platform/LayoutUnit.h" +#include "platform/heap/Handle.h" +#include "wtf/Vector.h" + +namespace blink { + +class CORE_EXPORT NGFragment final : public NGFragmentBase { + public: + NGFragment(LayoutUnit inlineSize, + LayoutUnit blockSize, + LayoutUnit inlineOverflow, + LayoutUnit blockOverflow, + NGWritingMode writingMode, + NGDirection direction) + : NGFragmentBase(inlineSize, + blockSize, + inlineOverflow, + blockOverflow, + writingMode, + direction, + FragmentBox) {} + + DEFINE_INLINE_TRACE_AFTER_DISPATCH() { + visitor->trace(m_children); + NGFragmentBase::traceAfterDispatch(visitor); + } + + void swapChildren(HeapVector<Member<const NGFragmentBase>>& children) { + m_children.swap(children); + } + + private: + HeapVector<Member<const NGFragmentBase>> m_children; +}; + +} // namespace blink + +#endif // NGFragment_h
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_fragment_base.cc b/third_party/WebKit/Source/core/layout/ng/ng_fragment_base.cc new file mode 100644 index 0000000..223475b --- /dev/null +++ b/third_party/WebKit/Source/core/layout/ng/ng_fragment_base.cc
@@ -0,0 +1,43 @@ +// 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 "core/layout/ng/ng_fragment_base.h" +#include "core/layout/ng/ng_fragment.h" +#include "core/layout/ng/ng_text.h" + +namespace blink { + +NGFragmentBase::NGFragmentBase(LayoutUnit inlineSize, + LayoutUnit blockSize, + LayoutUnit inlineOverflow, + LayoutUnit blockOverflow, + NGWritingMode writingMode, + NGDirection direction, + NGFragmentType type) + : m_inlineSize(inlineSize), + m_blockSize(blockSize), + m_inlineOverflow(inlineOverflow), + m_blockOverflow(blockOverflow), + m_type(type), + m_writingMode(writingMode), + m_direction(direction), + m_hasBeenPlaced(false) {} + +void NGFragmentBase::setOffset(LayoutUnit inlineOffset, + LayoutUnit blockOffset) { + // setOffset should only be called once. + DCHECK(!m_hasBeenPlaced); + m_inlineOffset = inlineOffset; + m_blockOffset = blockOffset; + m_hasBeenPlaced = true; +} + +DEFINE_TRACE(NGFragmentBase) { + if (type() == FragmentText) + static_cast<NGText*>(this)->traceAfterDispatch(visitor); + else + static_cast<NGFragment*>(this)->traceAfterDispatch(visitor); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_fragment_base.h b/third_party/WebKit/Source/core/layout/ng/ng_fragment_base.h new file mode 100644 index 0000000..03c5df9 --- /dev/null +++ b/third_party/WebKit/Source/core/layout/ng/ng_fragment_base.h
@@ -0,0 +1,79 @@ +// 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 NGFragmentBase_h +#define NGFragmentBase_h + +#include "core/CoreExport.h" +#include "platform/LayoutUnit.h" +#include "platform/heap/Handle.h" +#include "wtf/Vector.h" + +namespace blink { + +class CORE_EXPORT NGFragmentBase : public GarbageCollected<NGFragmentBase> { + public: + enum NGFragmentType { FragmentBox = 0, FragmentText = 1 }; + + // TODO(eae): We might want to re-use WritingMode and Direction from style. + enum NGWritingMode { + HorizontalTopBottom = 0, + VerticalRightLeft = 1, + VerticalLeftRight = 2, + SidewaysRightLeft = 3, + SidewaysLeftRight = 4 + }; + enum NGDirection { LeftToRight = 0, RightToLeft = 1 }; + + NGFragmentType type() const { return static_cast<NGFragmentType>(m_type); } + NGWritingMode writingMode() const { + return static_cast<NGWritingMode>(m_writingMode); + } + NGDirection direction() const { + return static_cast<NGDirection>(m_direction); + } + + // Returns the border-box size. + LayoutUnit inlineSize() const { return m_inlineSize; } + LayoutUnit blockSize() const { return m_blockSize; } + + // Returns the total size, including the contents outside of the border-box. + LayoutUnit inlineOverflow() const { return m_inlineOverflow; } + LayoutUnit blockOverflow() const { return m_blockOverflow; } + + // Returns the offset relative to the parent fragement's content-box. + LayoutUnit inlineOffset() const { return m_inlineOffset; } + LayoutUnit blockOffset() const { return m_blockOffset; } + + // Should only be used by the parent fragement's layout. + void setOffset(LayoutUnit inlineOffset, LayoutUnit blockOffset); + + DEFINE_INLINE_TRACE_AFTER_DISPATCH() {} + DECLARE_TRACE(); + + protected: + NGFragmentBase(LayoutUnit inlineSize, + LayoutUnit blockSize, + LayoutUnit inlineOverflow, + LayoutUnit blockOverflow, + NGWritingMode, + NGDirection, + NGFragmentType); + + LayoutUnit m_inlineSize; + LayoutUnit m_blockSize; + LayoutUnit m_inlineOverflow; + LayoutUnit m_blockOverflow; + LayoutUnit m_inlineOffset; + LayoutUnit m_blockOffset; + + unsigned m_type : 1; + unsigned m_writingMode : 3; + unsigned m_direction : 1; + unsigned m_hasBeenPlaced : 1; +}; + +} // namespace blink + +#endif // NGFragmentBase_h
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_length_utils.cc b/third_party/WebKit/Source/core/layout/ng/ng_length_utils.cc new file mode 100644 index 0000000..0f039e89 --- /dev/null +++ b/third_party/WebKit/Source/core/layout/ng/ng_length_utils.cc
@@ -0,0 +1,84 @@ +// 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 "core/layout/ng/ng_length_utils.h" + +#include "core/layout/ng/ng_constraint_space.h" +#include "core/style/ComputedStyle.h" +#include "platform/LayoutUnit.h" +#include "platform/Length.h" + +namespace blink { +// TODO(layout-ng): +// - Handle border-box correctly +// - positioned and/or replaced calculations +// - Handle margins for fill-available and width: auto + +LayoutUnit resolveInlineLength(LengthResolveType type, + const Length& length, + const NGConstraintSpace& constraintSpace) { + DCHECK(!length.isMaxSizeNone()); + if (type == LengthResolveType::MinSize && length.isAuto()) + return LayoutUnit(); + // TODO(layout-ng): Handle min/max/fit-content + return valueForLength(length, constraintSpace.inlineContainerSize()); +} + +LayoutUnit resolveBlockLength(LengthResolveType type, + const Length& length, + const NGConstraintSpace& constraintSpace, + LayoutUnit contentContribution) { + DCHECK(!length.isMaxSizeNone()); + if (type == LengthResolveType::MinSize && length.isAuto()) + return LayoutUnit(); + if (length.isAuto()) + return contentContribution; + if (length.isMinContent() || length.isMaxContent() || length.isFitContent()) + return contentContribution; + return valueForLength(length, constraintSpace.blockContainerSize()); +} + +LayoutUnit computeInlineSizeForFragment( + const NGConstraintSpace& constraintSpace, + const ComputedStyle& style) { + LayoutUnit extent = resolveInlineLength( + LengthResolveType::ContentSize, style.logicalWidth(), constraintSpace); + Length maxLength = style.logicalMaxWidth(); + if (!maxLength.isMaxSizeNone()) { + LayoutUnit max = resolveInlineLength(LengthResolveType::MaxSize, maxLength, + constraintSpace); + extent = std::min(extent, max); + } + LayoutUnit min = resolveInlineLength( + LengthResolveType::MinSize, style.logicalMinWidth(), constraintSpace); + extent = std::max(extent, min); + if (style.boxSizing() == BoxSizingContentBox) { + // TODO(layout-ng): Compute border/padding size and add it + } + return extent; +} + +LayoutUnit computeBlockSizeForFragment(const NGConstraintSpace& constraintSpace, + const ComputedStyle& style, + LayoutUnit contentContribution) { + LayoutUnit extent = + resolveBlockLength(LengthResolveType::ContentSize, style.logicalHeight(), + constraintSpace, contentContribution); + Length maxLength = style.logicalMaxHeight(); + if (!maxLength.isMaxSizeNone()) { + LayoutUnit max = resolveBlockLength(LengthResolveType::MaxSize, maxLength, + constraintSpace, contentContribution); + extent = std::min(extent, max); + } + LayoutUnit min = + resolveBlockLength(LengthResolveType::MinSize, style.logicalMinHeight(), + constraintSpace, contentContribution); + extent = std::max(extent, min); + if (style.boxSizing() == BoxSizingContentBox) { + // TODO(layout-ng): Compute border/padding size and add it + } + return extent; +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_length_utils.h b/third_party/WebKit/Source/core/layout/ng/ng_length_utils.h new file mode 100644 index 0000000..c5956db --- /dev/null +++ b/third_party/WebKit/Source/core/layout/ng/ng_length_utils.h
@@ -0,0 +1,47 @@ +// 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 NGLengthUtils_h +#define NGLengthUtils_h + +#include "core/CoreExport.h" + +namespace blink { +class ComputedStyle; +class LayoutUnit; +class Length; +class NGConstraintSpace; + +enum class LengthResolveType { MinSize, MaxSize, ContentSize }; + +// Convert an inline-axis length to a layout unit using the given constraint +// space. +CORE_EXPORT LayoutUnit resolveInlineLength(LengthResolveType, + const Length&, + const NGConstraintSpace&); + +// Convert a block-axis length to a layout unit using the given constraint +// space. +CORE_EXPORT LayoutUnit resolveBlockLength(LengthResolveType, + const Length&, + const NGConstraintSpace&, + LayoutUnit contentContribution); + +// Resolves the given length to a layout unit, constraining it by the min +// logical width and max logical width properties from the ComputedStyle +// object. +CORE_EXPORT LayoutUnit computeInlineSizeForFragment(const NGConstraintSpace&, + const ComputedStyle&); + +// Resolves the given length to a layout unit, constraining it by the min +// logical height and max logical height properties from the ComputedStyle +// object. +CORE_EXPORT LayoutUnit +computeBlockSizeForFragment(const NGConstraintSpace&, + const ComputedStyle& style, + LayoutUnit contentContribution); + +} // namespace blink + +#endif // NGLengthUtils_h
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_margin_strut.h b/third_party/WebKit/Source/core/layout/ng/ng_margin_strut.h new file mode 100644 index 0000000..cbfe3838 --- /dev/null +++ b/third_party/WebKit/Source/core/layout/ng/ng_margin_strut.h
@@ -0,0 +1,24 @@ +// 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 NGMarginStrut_h +#define NGMarginStrut_h + +#include "core/CoreExport.h" +#include "platform/LayoutUnit.h" + +namespace blink { + +// This struct is used for the margin collapsing calculation. +struct NGMarginStrut { + LayoutUnit marginBlockStart; + LayoutUnit marginBlockEnd; + + LayoutUnit negativeMarginBlockStart; + LayoutUnit negativeMarginBlockEnd; +}; + +} // namespace blink + +#endif // NGMarginStrut_h
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_text.cc b/third_party/WebKit/Source/core/layout/ng/ng_text.cc new file mode 100644 index 0000000..6e0bd35e --- /dev/null +++ b/third_party/WebKit/Source/core/layout/ng/ng_text.cc
@@ -0,0 +1,7 @@ +// 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 "core/layout/ng/ng_text.h" + +namespace blink {} // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_text.h b/third_party/WebKit/Source/core/layout/ng/ng_text.h new file mode 100644 index 0000000..117bae95 --- /dev/null +++ b/third_party/WebKit/Source/core/layout/ng/ng_text.h
@@ -0,0 +1,40 @@ +// 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 NGText_h +#define NGText_h + +#include "core/CoreExport.h" +#include "core/layout/ng/ng_fragment_base.h" +#include "platform/LayoutUnit.h" +#include "wtf/text/WTFString.h" + +namespace blink { + +class CORE_EXPORT NGText final : public NGFragmentBase { + public: + NGText(LayoutUnit inlineSize, + LayoutUnit blockSize, + LayoutUnit inlineOverflow, + LayoutUnit blockOverflow, + NGWritingMode writingMode, + NGDirection direction) + : NGFragmentBase(inlineSize, + blockSize, + inlineOverflow, + blockOverflow, + writingMode, + direction, + FragmentText) {} + + const String text() const { return String(); } + + DEFINE_INLINE_TRACE_AFTER_DISPATCH() { + NGFragmentBase::traceAfterDispatch(visitor); + } +}; + +} // namespace blink + +#endif // NGText_h
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_units.h b/third_party/WebKit/Source/core/layout/ng/ng_units.h new file mode 100644 index 0000000..e0975f4 --- /dev/null +++ b/third_party/WebKit/Source/core/layout/ng/ng_units.h
@@ -0,0 +1,46 @@ +// 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 NGUnits_h +#define NGUnits_h + +namespace blink { + +class LayoutUnit; + +struct NGLogicalSize { + LayoutUnit inlineSize; + LayoutUnit blockSize; +}; + +struct NGLogicalOffset { + LayoutUnit inlineOffset; + LayoutUnit blockOffset; +}; + +struct NGPhysicalSize { + LayoutUnit width; + LayoutUnit height; +}; + +struct NGPhysicalLocation { + LayoutUnit top; + LayoutUnit left; +}; + +struct NGPhysicalRect { + NGPhysicalSize size; + NGPhysicalLocation location; +}; + +struct NGPixelSnappedPhysicalRect { + int top; + int left; + int width; + int height; +}; + +} // namespace blink + +#endif // NGUnits_h
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGImage.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGImage.cpp index 91867b2..e0499c8 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGImage.cpp +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGImage.cpp
@@ -120,7 +120,7 @@ return false; PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_IMAGE_HITTESTING, result.hitTestRequest(), style()->pointerEvents()); - bool isVisible = (style()->visibility() == VISIBLE); + bool isVisible = (style()->visibility() == EVisibility::Visible); if (isVisible || !hitRules.requireVisible) { FloatPoint localPoint; if (!SVGLayoutSupport::transformToUserSpaceAndCheckClipping(this, localToSVGParentTransform(), pointInParent, localPoint))
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceClipper.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceClipper.cpp index 262ec0d..2678f0f 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceClipper.cpp +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceClipper.cpp
@@ -86,7 +86,7 @@ continue; const ComputedStyle* style = childLayoutObject->style(); - if (!style || style->display() == NONE || (style->visibility() != VISIBLE && !isSVGUseElement(*childElement))) + if (!style || style->display() == NONE || (style->visibility() != EVisibility::Visible && !isSVGUseElement(*childElement))) continue; // Current shape in clip-path gets clipped too. Fallback to masking. @@ -177,7 +177,7 @@ continue; const ComputedStyle* style = layoutObject->style(); - if (!style || style->display() == NONE || (style->visibility() != VISIBLE && !isSVGUseElement(*childElement))) + if (!style || style->display() == NONE || (style->visibility() != EVisibility::Visible && !isSVGUseElement(*childElement))) continue; bool isUseElement = isSVGUseElement(*childElement); @@ -221,7 +221,7 @@ if (!layoutObject->isSVGShape() && !layoutObject->isSVGText() && !isSVGUseElement(*childElement)) continue; const ComputedStyle* style = layoutObject->style(); - if (!style || style->display() == NONE || (style->visibility() != VISIBLE && !isSVGUseElement(*childElement))) + if (!style || style->display() == NONE || (style->visibility() != EVisibility::Visible && !isSVGUseElement(*childElement))) continue; if (isSVGUseElement(*childElement) && !toSVGUseElement(*childElement).visibleTargetGraphicsElementForClipping()) continue;
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceMasker.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceMasker.cpp index d9b87d7..3355c67 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceMasker.cpp +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceMasker.cpp
@@ -81,7 +81,7 @@ if (!layoutObject) continue; const ComputedStyle* style = layoutObject->style(); - if (!style || style->display() == NONE || style->visibility() != VISIBLE) + if (!style || style->display() == NONE || style->visibility() != EVisibility::Visible) continue; SVGPaintContext::paintSubtree(pictureBuilder.context(), layoutObject); @@ -98,7 +98,7 @@ if (!layoutObject) continue; const ComputedStyle* style = layoutObject->style(); - if (!style || style->display() == NONE || style->visibility() != VISIBLE) + if (!style || style->display() == NONE || style->visibility() != EVisibility::Visible) continue; m_maskContentBoundaries.unite(layoutObject->localToSVGParentTransform().mapRect(layoutObject->paintInvalidationRectInLocalSVGCoordinates())); }
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.cpp index 8ba59de..d378a90 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.cpp +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.cpp
@@ -174,7 +174,7 @@ } updateLayerTransformAfterLayout(); - m_hasBoxDecorationBackground = isDocumentElement() ? calculateHasBoxDecorations() : hasBoxDecorationBackground(); + m_hasBoxDecorationBackground = isDocumentElement() ? styleRef().hasBoxDecorationBackground() : hasBoxDecorationBackground(); invalidateBackgroundObscurationStatus(); clearNeedsLayout(); @@ -216,7 +216,7 @@ setNeedsBoundariesUpdate(); if (diff.needsPaintInvalidation()) { // Box decorations may have appeared/disappeared - recompute status. - m_hasBoxDecorationBackground = calculateHasBoxDecorations(); + m_hasBoxDecorationBackground = styleRef().hasBoxDecorationBackground(); } LayoutReplaced::styleDidChange(diff, oldStyle); @@ -341,7 +341,7 @@ // (does not have background/border/etc., see LayoutSVGRootTest.OverflowRectMappingWithViewportClipWithoutBorder). // Return early for any cases where we don't actually paint. - if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent()) + if (style()->visibility() != EVisibility::Visible && !enclosingLayer()->hasVisibleContent()) return LayoutRect(); // Compute the paint invalidation rect of the content of the SVG in the border-box coordinate space.
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGShape.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGShape.cpp index 32f65ee..78c399e6 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGShape.cpp +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGShape.cpp
@@ -250,7 +250,7 @@ bool LayoutSVGShape::nodeAtFloatPointInternal(const HitTestRequest& request, const FloatPoint& localPoint, PointerEventsHitRules hitRules) { - bool isVisible = (style()->visibility() == VISIBLE); + bool isVisible = (style()->visibility() == EVisibility::Visible); if (isVisible || !hitRules.requireVisible) { const SVGComputedStyle& svgStyle = style()->svgStyle(); WindRule fillRule = svgStyle.fillRule();
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGText.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGText.cpp index 1a1502e8b..e6e77c7 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGText.cpp +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGText.cpp
@@ -290,7 +290,7 @@ return false; PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_TEXT_HITTESTING, result.hitTestRequest(), style()->pointerEvents()); - bool isVisible = (style()->visibility() == VISIBLE); + bool isVisible = (style()->visibility() == EVisibility::Visible); if (isVisible || !hitRules.requireVisible) { if ((hitRules.canHitBoundingBox && !objectBoundingBox().isEmpty()) || (hitRules.canHitStroke && (style()->svgStyle().hasStroke() || !hitRules.requireStroke))
diff --git a/third_party/WebKit/Source/core/layout/svg/SVGLayoutSupport.cpp b/third_party/WebKit/Source/core/layout/svg/SVGLayoutSupport.cpp index 6593acb..18a95646 100644 --- a/third_party/WebKit/Source/core/layout/svg/SVGLayoutSupport.cpp +++ b/third_party/WebKit/Source/core/layout/svg/SVGLayoutSupport.cpp
@@ -66,7 +66,7 @@ ASSERT(!object.isSVGRoot()); // Return early for any cases where we don't actually paint - if (object.styleRef().visibility() != VISIBLE && !object.enclosingLayer()->hasVisibleContent()) + if (object.styleRef().visibility() != EVisibility::Visible && !object.enclosingLayer()->hasVisibleContent()) return FloatRect(); FloatRect paintInvalidationRect = object.paintInvalidationRectInLocalSVGCoordinates();
diff --git a/third_party/WebKit/Source/core/layout/svg/line/SVGInlineTextBox.cpp b/third_party/WebKit/Source/core/layout/svg/line/SVGInlineTextBox.cpp index b3b9d49..7662bbf 100644 --- a/third_party/WebKit/Source/core/layout/svg/line/SVGInlineTextBox.cpp +++ b/third_party/WebKit/Source/core/layout/svg/line/SVGInlineTextBox.cpp
@@ -239,7 +239,7 @@ ASSERT(!isLineBreak()); PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_TEXT_HITTESTING, result.hitTestRequest(), getLineLayoutItem().style()->pointerEvents()); - bool isVisible = getLineLayoutItem().style()->visibility() == VISIBLE; + bool isVisible = getLineLayoutItem().style()->visibility() == EVisibility::Visible; if (isVisible || !hitRules.requireVisible) { if (hitRules.canHitBoundingBox || (hitRules.canHitStroke && (getLineLayoutItem().style()->svgStyle().hasStroke() || !hitRules.requireStroke))
diff --git a/third_party/WebKit/Source/core/loader/EmptyClients.cpp b/third_party/WebKit/Source/core/loader/EmptyClients.cpp index 3d6961a6..eebba46 100644 --- a/third_party/WebKit/Source/core/loader/EmptyClients.cpp +++ b/third_party/WebKit/Source/core/loader/EmptyClients.cpp
@@ -166,6 +166,10 @@ { } +void EmptyTextCheckerClient::cancelAllPendingRequests() +{ +} + std::unique_ptr<WebServiceWorkerProvider> EmptyFrameLoaderClient::createServiceWorkerProvider() { return nullptr;
diff --git a/third_party/WebKit/Source/core/loader/EmptyClients.h b/third_party/WebKit/Source/core/loader/EmptyClients.h index 722438a8..4095424 100644 --- a/third_party/WebKit/Source/core/loader/EmptyClients.h +++ b/third_party/WebKit/Source/core/loader/EmptyClients.h
@@ -285,6 +285,7 @@ void checkSpellingOfString(const String&, int*, int*) override {} void checkGrammarOfString(const String&, Vector<GrammarDetail>&, int*, int*) override {} void requestCheckingOfString(TextCheckingRequest*) override; + void cancelAllPendingRequests() override; }; class EmptySpellCheckerClient : public SpellCheckerClient {
diff --git a/third_party/WebKit/Source/core/loader/FrameLoaderClient.h b/third_party/WebKit/Source/core/loader/FrameLoaderClient.h index e320cdd..65da964 100644 --- a/third_party/WebKit/Source/core/loader/FrameLoaderClient.h +++ b/third_party/WebKit/Source/core/loader/FrameLoaderClient.h
@@ -272,6 +272,10 @@ // Effective connection type when this frame was loaded. virtual WebEffectiveConnectionType getEffectiveConnectionType() { return WebEffectiveConnectionType::TypeUnknown; } + + // Overwrites the given URL to use an HTML5 embed if possible. + // An empty URL is returned if the URL is not overriden. + virtual KURL overrideFlashEmbedWithHTML(const KURL&) { return KURL(); } }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.cpp b/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.cpp index 19f24037..1eb6a66f 100644 --- a/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.cpp +++ b/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.cpp
@@ -345,7 +345,8 @@ DCHECK(!m_peer); DCHECK(peer); if (m_clientWrapper->done()) { - // The loading is already cancelled. + // The thread is terminating. + m_loaderProxy->postTaskToLoader(BLINK_FROM_HERE, createCrossThreadTask(&Peer::cancel, wrapCrossThreadPersistent(peer))); return; }
diff --git a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp index 2b07694..316d340 100644 --- a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp +++ b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp
@@ -55,7 +55,7 @@ ImageBitmap* image = m_context->transferToImageBitmap(exceptionState); if (!image) { // Undocumented exception (not in spec) - exceptionState.throwDOMException(V8GeneralError, "Out of memory"); + exceptionState.throwDOMException(V8Error, "Out of memory"); } return image; }
diff --git a/third_party/WebKit/Source/core/page/Page.cpp b/third_party/WebKit/Source/core/page/Page.cpp index 4e2a89a..8198308 100644 --- a/third_party/WebKit/Source/core/page/Page.cpp +++ b/third_party/WebKit/Source/core/page/Page.cpp
@@ -52,7 +52,6 @@ #include "core/paint/PaintLayer.h" #include "platform/graphics/GraphicsLayer.h" #include "platform/plugins/PluginData.h" -#include "platform/text/CompressibleString.h" #include "public/platform/Platform.h" namespace blink { @@ -133,7 +132,6 @@ , m_isPainting(false) #endif , m_frameHost(FrameHost::create(*this)) - , m_timerForCompressStrings(this, &Page::compressStrings) { ASSERT(m_editorClient); @@ -320,8 +318,6 @@ void Page::setVisibilityState(PageVisibilityState visibilityState, bool isInitialState) { - static const double waitingTimeBeforeCompressingString = 10; - if (m_visibilityState == visibilityState) return; m_visibilityState = visibilityState; @@ -331,15 +327,6 @@ if (!isInitialState && m_mainFrame) m_mainFrame->didChangeVisibilityState(); - - // Compress CompressibleStrings when 10 seconds have passed since the page - // went to background. - if (m_visibilityState == PageVisibilityStateHidden) { - if (!m_timerForCompressStrings.isActive()) - m_timerForCompressStrings.startOneShot(waitingTimeBeforeCompressingString, BLINK_FROM_HERE); - } else if (m_timerForCompressStrings.isActive()) { - m_timerForCompressStrings.stop(); - } } PageVisibilityState Page::visibilityState() const @@ -536,13 +523,6 @@ PageVisibilityNotifier::notifyContextDestroyed(); } -void Page::compressStrings(TimerBase* timer) -{ - ASSERT_UNUSED(timer, timer == &m_timerForCompressStrings); - if (m_visibilityState == PageVisibilityStateHidden) - CompressibleStringImpl::compressAll(); -} - Page::PageClients::PageClients() : chromeClient(nullptr) , contextMenuClient(nullptr)
diff --git a/third_party/WebKit/Source/core/page/Page.h b/third_party/WebKit/Source/core/page/Page.h index 6f75adec..a54f9c9 100644 --- a/third_party/WebKit/Source/core/page/Page.h +++ b/third_party/WebKit/Source/core/page/Page.h
@@ -34,7 +34,6 @@ #include "core/page/PageVisibilityObserver.h" #include "core/page/PageVisibilityState.h" #include "platform/Supplementable.h" -#include "platform/Timer.h" #include "platform/geometry/LayoutRect.h" #include "platform/geometry/Region.h" #include "platform/heap/Handle.h" @@ -213,8 +212,6 @@ // SettingsDelegate overrides. void settingsChanged(SettingsDelegate::ChangeType) override; - void compressStrings(TimerBase*); - Member<PageAnimator> m_animator; const Member<AutoscrollController> m_autoscrollController; Member<ChromeClient> m_chromeClient; @@ -267,8 +264,6 @@ // A pointer to all the interfaces provided to in-process Frames for this Page. // FIXME: Most of the members of Page should move onto FrameHost. Member<FrameHost> m_frameHost; - - Timer<Page> m_timerForCompressStrings; }; extern template class CORE_EXTERN_TEMPLATE_EXPORT Supplement<Page>;
diff --git a/third_party/WebKit/Source/core/paint/BlockPainter.cpp b/third_party/WebKit/Source/core/paint/BlockPainter.cpp index fa66c71..8e049b59 100644 --- a/third_party/WebKit/Source/core/paint/BlockPainter.cpp +++ b/third_party/WebKit/Source/core/paint/BlockPainter.cpp
@@ -70,7 +70,7 @@ void BlockPainter::paintOverflowControlsIfNeeded(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (m_layoutBlock.hasOverflowClip() - && m_layoutBlock.style()->visibility() == VISIBLE + && m_layoutBlock.style()->visibility() == EVisibility::Visible && shouldPaintSelfBlockBackground(paintInfo.phase) && !paintInfo.paintRootBackgroundOnly()) { Optional<ClipRecorder> clipRecorder; @@ -129,7 +129,7 @@ const PaintPhase paintPhase = paintInfo.phase; if (shouldPaintSelfBlockBackground(paintPhase)) { - if (m_layoutBlock.style()->visibility() == VISIBLE && m_layoutBlock.hasBoxDecorationBackground()) + if (m_layoutBlock.style()->visibility() == EVisibility::Visible && m_layoutBlock.hasBoxDecorationBackground()) m_layoutBlock.paintBoxDecorationBackground(paintInfo, paintOffset); // We're done. We don't bother painting any children. if (paintPhase == PaintPhaseSelfBlockBackgroundOnly) @@ -139,12 +139,12 @@ if (paintInfo.paintRootBackgroundOnly()) return; - if (paintPhase == PaintPhaseMask && m_layoutBlock.style()->visibility() == VISIBLE) { + if (paintPhase == PaintPhaseMask && m_layoutBlock.style()->visibility() == EVisibility::Visible) { m_layoutBlock.paintMask(paintInfo, paintOffset); return; } - if (paintPhase == PaintPhaseClippingMask && m_layoutBlock.style()->visibility() == VISIBLE) { + if (paintPhase == PaintPhaseClippingMask && m_layoutBlock.style()->visibility() == EVisibility::Visible) { BoxPainter(m_layoutBlock).paintClippingMask(paintInfo, paintOffset); return; }
diff --git a/third_party/WebKit/Source/core/paint/BoxPainter.cpp b/third_party/WebKit/Source/core/paint/BoxPainter.cpp index b7e005a..15c4f102 100644 --- a/third_party/WebKit/Source/core/paint/BoxPainter.cpp +++ b/third_party/WebKit/Source/core/paint/BoxPainter.cpp
@@ -35,6 +35,17 @@ namespace blink { +namespace { + +bool isPaintingBackgroundOfPaintContainerIntoScrollingContentsLayer(const LayoutBoxModelObject* obj, const PaintInfo& paintInfo) +{ + return paintInfo.paintFlags() & PaintLayerPaintingOverflowContents + && !(paintInfo.paintFlags() & PaintLayerPaintingCompositingBackgroundPhase) + && obj == paintInfo.paintContainer(); +} + +} // namespace + void BoxPainter::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { LayoutPoint adjustedPaintOffset = paintOffset + m_layoutBox.location(); @@ -46,14 +57,34 @@ void BoxPainter::paintBoxDecorationBackground(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { - LayoutRect paintRect = m_layoutBox.borderBoxRect(); + LayoutRect paintRect; + if (isPaintingBackgroundOfPaintContainerIntoScrollingContentsLayer(&m_layoutBox, paintInfo)) { + // For the case where we are painting the background into the scrolling contents layer + // of a composited scroller we need to include the entire overflow rect. + paintRect = m_layoutBox.layoutOverflowRect(); + paintRect.move(-m_layoutBox.scrolledContentOffset()); + + // The background painting code assumes that the borders are part of the paintRect so we + // expand the paintRect by the border size when painting the background into the + // scrolling contents layer. + paintRect.expandEdges( + LayoutUnit(m_layoutBox.borderTop()), + LayoutUnit(m_layoutBox.borderRight()), + LayoutUnit(m_layoutBox.borderBottom()), + LayoutUnit(m_layoutBox.borderLeft())); + } else { + paintRect = m_layoutBox.borderBoxRect(); + } + paintRect.moveBy(paintOffset); paintBoxDecorationBackgroundWithRect(paintInfo, paintOffset, paintRect); } -LayoutRect BoxPainter::boundsForDrawingRecorder(const LayoutPoint& adjustedPaintOffset) +LayoutRect BoxPainter::boundsForDrawingRecorder(const PaintInfo& paintInfo, const LayoutPoint& adjustedPaintOffset) { - LayoutRect bounds = m_layoutBox.selfVisualOverflowRect(); + LayoutRect bounds = isPaintingBackgroundOfPaintContainerIntoScrollingContentsLayer(&m_layoutBox, paintInfo) + ? m_layoutBox.layoutOverflowRect() + : m_layoutBox.selfVisualOverflowRect(); bounds.moveBy(adjustedPaintOffset); return bounds; } @@ -69,6 +100,7 @@ void BoxPainter::paintBoxDecorationBackgroundWithRect(const PaintInfo& paintInfo, const LayoutPoint& paintOffset, const LayoutRect& paintRect) { + bool paintingOverflowContents = isPaintingBackgroundOfPaintContainerIntoScrollingContentsLayer(&m_layoutBox, paintInfo); const ComputedStyle& style = m_layoutBox.styleRef(); // FIXME: For now we don't have notification on media buffered range change from media player @@ -80,23 +112,26 @@ if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(paintInfo.context, m_layoutBox, DisplayItem::BoxDecorationBackground)) return; - LayoutObjectDrawingRecorder recorder(paintInfo.context, m_layoutBox, DisplayItem::BoxDecorationBackground, boundsForDrawingRecorder(paintOffset)); + LayoutObjectDrawingRecorder recorder(paintInfo.context, m_layoutBox, DisplayItem::BoxDecorationBackground, boundsForDrawingRecorder(paintInfo, paintOffset)); BoxDecorationData boxDecorationData(m_layoutBox); - - // FIXME: Should eventually give the theme control over whether the box shadow should paint, since controls could have - // custom shadows of their own. - if (!m_layoutBox.boxShadowShouldBeAppliedToBackground(boxDecorationData.bleedAvoidance)) - paintBoxShadow(paintInfo, paintRect, style, Normal); - GraphicsContextStateSaver stateSaver(paintInfo.context, false); - if (bleedAvoidanceIsClipping(boxDecorationData.bleedAvoidance)) { - stateSaver.save(); - FloatRoundedRect border = style.getRoundedBorderFor(paintRect); - paintInfo.context.clipRoundedRect(border); - if (boxDecorationData.bleedAvoidance == BackgroundBleedClipLayer) - paintInfo.context.beginLayer(); + if (!paintingOverflowContents) { + // FIXME: Should eventually give the theme control over whether the box shadow should paint, since controls could have + // custom shadows of their own. + if (!m_layoutBox.boxShadowShouldBeAppliedToBackground(boxDecorationData.bleedAvoidance)) { + paintBoxShadow(paintInfo, paintRect, style, Normal); + } + + if (bleedAvoidanceIsClipping(boxDecorationData.bleedAvoidance)) { + stateSaver.save(); + FloatRoundedRect border = style.getRoundedBorderFor(paintRect); + paintInfo.context.clipRoundedRect(border); + + if (boxDecorationData.bleedAvoidance == BackgroundBleedClipLayer) + paintInfo.context.beginLayer(); + } } // If we have a native theme appearance, paint that before painting our background. @@ -104,19 +139,26 @@ IntRect snappedPaintRect(pixelSnappedIntRect(paintRect)); ThemePainter& themePainter = LayoutTheme::theme().painter(); bool themePainted = boxDecorationData.hasAppearance && !themePainter.paint(m_layoutBox, paintInfo, snappedPaintRect); - if (!themePainted) { + bool shouldPaintBackground = !themePainted + && (!paintInfo.skipRootBackground() + || paintInfo.paintContainer() != &m_layoutBox); + if (shouldPaintBackground) { paintBackground(paintInfo, paintRect, boxDecorationData.backgroundColor, boxDecorationData.bleedAvoidance); if (boxDecorationData.hasAppearance) themePainter.paintDecorations(m_layoutBox, paintInfo, snappedPaintRect); } - paintBoxShadow(paintInfo, paintRect, style, Inset); - // The theme will tell us whether or not we should also paint the CSS border. - if (boxDecorationData.hasBorderDecoration - && (!boxDecorationData.hasAppearance || (!themePainted && LayoutTheme::theme().painter().paintBorderOnly(m_layoutBox, paintInfo, snappedPaintRect))) - && !(m_layoutBox.isTable() && toLayoutTable(&m_layoutBox)->collapseBorders())) - paintBorder(m_layoutBox, paintInfo, paintRect, style, boxDecorationData.bleedAvoidance); + if (!paintingOverflowContents) { + paintBoxShadow(paintInfo, paintRect, style, Inset); + + // The theme will tell us whether or not we should also paint the CSS border. + if (boxDecorationData.hasBorderDecoration + && (!boxDecorationData.hasAppearance || (!themePainted && LayoutTheme::theme().painter().paintBorderOnly(m_layoutBox, paintInfo, snappedPaintRect))) + && !(m_layoutBox.isTable() && toLayoutTable(&m_layoutBox)->collapseBorders())) { + paintBorder(m_layoutBox, paintInfo, paintRect, style, boxDecorationData.bleedAvoidance); + } + } if (boxDecorationData.bleedAvoidance == BackgroundBleedClipLayer) paintInfo.context.endLayer(); @@ -128,7 +170,7 @@ return; if (m_layoutBox.backgroundStolenForBeingBody()) return; - if (m_layoutBox.boxDecorationBackgroundIsKnownToBeObscured()) + if (m_layoutBox.backgroundIsKnownToBeObscured()) return; paintFillLayers(paintInfo, backgroundColor, m_layoutBox.style()->backgroundLayers(), paintRect, bleedAvoidance); } @@ -506,7 +548,7 @@ GraphicsContextStateSaver clipWithScrollingStateSaver(context, info.isClippedWithLocalScrolling); LayoutRect scrolledPaintRect = rect; - if (info.isClippedWithLocalScrolling) { + if (info.isClippedWithLocalScrolling && !isPaintingBackgroundOfPaintContainerIntoScrollingContentsLayer(&obj, paintInfo)) { // Clip to the overflow area. const LayoutBox& thisBox = toLayoutBox(obj); // TODO(chrishtr): this should be pixel-snapped. @@ -615,7 +657,7 @@ void BoxPainter::paintMask(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { - if (m_layoutBox.style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask) + if (m_layoutBox.style()->visibility() != EVisibility::Visible || paintInfo.phase != PaintPhaseMask) return; if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(paintInfo.context, m_layoutBox, paintInfo.phase)) @@ -665,7 +707,7 @@ { ASSERT(paintInfo.phase == PaintPhaseClippingMask); - if (m_layoutBox.style()->visibility() != VISIBLE) + if (m_layoutBox.style()->visibility() != EVisibility::Visible) return; if (!m_layoutBox.layer() || m_layoutBox.layer()->compositingState() != PaintsIntoOwnBacking)
diff --git a/third_party/WebKit/Source/core/paint/BoxPainter.h b/third_party/WebKit/Source/core/paint/BoxPainter.h index e511b84..0a7995d 100644 --- a/third_party/WebKit/Source/core/paint/BoxPainter.h +++ b/third_party/WebKit/Source/core/paint/BoxPainter.h
@@ -58,7 +58,7 @@ static void paintBoxShadow(const PaintInfo&, const LayoutRect&, const ComputedStyle&, ShadowStyle, bool includeLogicalLeftEdge = true, bool includeLogicalRightEdge = true); static bool shouldForceWhiteBackgroundForPrintEconomy(const ComputedStyle&, const Document&); - LayoutRect boundsForDrawingRecorder(const LayoutPoint& adjustedPaintOffset); + LayoutRect boundsForDrawingRecorder(const PaintInfo&, const LayoutPoint& adjustedPaintOffset); private: void paintBackground(const PaintInfo&, const LayoutRect&, const Color& backgroundColor, BackgroundBleedAvoidance = BackgroundBleedNone);
diff --git a/third_party/WebKit/Source/core/paint/DetailsMarkerPainter.cpp b/third_party/WebKit/Source/core/paint/DetailsMarkerPainter.cpp index 38f57a2..5c1e03a8 100644 --- a/third_party/WebKit/Source/core/paint/DetailsMarkerPainter.cpp +++ b/third_party/WebKit/Source/core/paint/DetailsMarkerPainter.cpp
@@ -15,7 +15,7 @@ void DetailsMarkerPainter::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { - if (paintInfo.phase != PaintPhaseForeground || m_layoutDetailsMarker.style()->visibility() != VISIBLE) { + if (paintInfo.phase != PaintPhaseForeground || m_layoutDetailsMarker.style()->visibility() != EVisibility::Visible) { BlockPainter(m_layoutDetailsMarker).paint(paintInfo, paintOffset); return; }
diff --git a/third_party/WebKit/Source/core/paint/FieldsetPainter.cpp b/third_party/WebKit/Source/core/paint/FieldsetPainter.cpp index 7790d91..ba73a4a 100644 --- a/third_party/WebKit/Source/core/paint/FieldsetPainter.cpp +++ b/third_party/WebKit/Source/core/paint/FieldsetPainter.cpp
@@ -69,7 +69,7 @@ void FieldsetPainter::paintMask(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { - if (m_layoutFieldset.style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask) + if (m_layoutFieldset.style()->visibility() != EVisibility::Visible || paintInfo.phase != PaintPhaseMask) return; LayoutRect paintRect = LayoutRect(paintOffset, m_layoutFieldset.size());
diff --git a/third_party/WebKit/Source/core/paint/FileUploadControlPainter.cpp b/third_party/WebKit/Source/core/paint/FileUploadControlPainter.cpp index 07d5f7e..0126d2ed 100644 --- a/third_party/WebKit/Source/core/paint/FileUploadControlPainter.cpp +++ b/third_party/WebKit/Source/core/paint/FileUploadControlPainter.cpp
@@ -18,7 +18,7 @@ void FileUploadControlPainter::paintObject(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { - if (m_layoutFileUploadControl.style()->visibility() != VISIBLE) + if (m_layoutFileUploadControl.style()->visibility() != EVisibility::Visible) return; // Push a clip.
diff --git a/third_party/WebKit/Source/core/paint/InlineFlowBoxPainter.cpp b/third_party/WebKit/Source/core/paint/InlineFlowBoxPainter.cpp index 44b647f..535e9aa 100644 --- a/third_party/WebKit/Source/core/paint/InlineFlowBoxPainter.cpp +++ b/third_party/WebKit/Source/core/paint/InlineFlowBoxPainter.cpp
@@ -172,7 +172,7 @@ void InlineFlowBoxPainter::paintBoxDecorationBackground(const PaintInfo& paintInfo, const LayoutPoint& paintOffset, const LayoutRect& cullRect) { ASSERT(paintInfo.phase == PaintPhaseForeground); - if (m_inlineFlowBox.getLineLayoutItem().style()->visibility() != VISIBLE) + if (m_inlineFlowBox.getLineLayoutItem().style()->visibility() != EVisibility::Visible) return; // You can use p::first-line to specify a background. If so, the root line boxes for @@ -232,7 +232,7 @@ void InlineFlowBoxPainter::paintMask(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { - if (m_inlineFlowBox.getLineLayoutItem().style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask) + if (m_inlineFlowBox.getLineLayoutItem().style()->visibility() != EVisibility::Visible || paintInfo.phase != PaintPhaseMask) return; LayoutRect frameRect = frameRectClampedToLineTopAndBottomIfNeeded();
diff --git a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp index 7203c811..5b9d362 100644 --- a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp +++ b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
@@ -243,7 +243,7 @@ // This code path is only called in PaintPhaseForeground whereas we would // expect PaintPhaseSelection. The existing haveSelection logic in paint() // tests for != PaintPhaseTextClip. - if (m_inlineTextBox.getLineLayoutItem().style()->visibility() != VISIBLE + if (m_inlineTextBox.getLineLayoutItem().style()->visibility() != EVisibility::Visible || m_inlineTextBox.truncation() == cFullTruncation || !m_inlineTextBox.len()) return false; @@ -715,10 +715,12 @@ LayoutUnit width = m_inlineTextBox.logicalWidth(); if (m_inlineTextBox.truncation() != cNoTruncation) { - width = LayoutUnit(m_inlineTextBox.getLineLayoutItem().width( - m_inlineTextBox.start(), m_inlineTextBox.truncation(), m_inlineTextBox.textPos(), - m_inlineTextBox.isLeftToRightDirection() ? LTR : RTL, m_inlineTextBox.isFirstLineStyle())); - if (!m_inlineTextBox.isLeftToRightDirection()) + bool ltr = m_inlineTextBox.isLeftToRightDirection(); + bool flowIsLTR = m_inlineTextBox.getLineLayoutItem().style()->isLeftToRightDirection(); + width = LayoutUnit(m_inlineTextBox.getLineLayoutItem().width(ltr == flowIsLTR ? m_inlineTextBox.start() : m_inlineTextBox.truncation(), + ltr == flowIsLTR ? m_inlineTextBox.truncation() : m_inlineTextBox.len() - m_inlineTextBox.truncation(), m_inlineTextBox.textPos(), + flowIsLTR ? LTR : RTL, m_inlineTextBox.isFirstLineStyle())); + if (!flowIsLTR) localOrigin.move(m_inlineTextBox.logicalWidth() - width, LayoutUnit()); } @@ -775,6 +777,7 @@ unsigned paintStart = underlinePaintStart(underline); unsigned paintEnd = underlinePaintEnd(underline); + // TODO(crbug.com/636060): Handle mixed-flow contexts correctly. // start of line to draw float start = paintStart == static_cast<unsigned>(m_inlineTextBox.start()) ? 0 : m_inlineTextBox.getLineLayoutItem().width(m_inlineTextBox.start(), paintStart - m_inlineTextBox.start(), m_inlineTextBox.textPos(), m_inlineTextBox.isLeftToRightDirection() ? LTR : RTL, m_inlineTextBox.isFirstLineStyle());
diff --git a/third_party/WebKit/Source/core/paint/ListMarkerPainter.cpp b/third_party/WebKit/Source/core/paint/ListMarkerPainter.cpp index ac38a5b3..0c24519 100644 --- a/third_party/WebKit/Source/core/paint/ListMarkerPainter.cpp +++ b/third_party/WebKit/Source/core/paint/ListMarkerPainter.cpp
@@ -44,7 +44,7 @@ if (paintInfo.phase != PaintPhaseForeground) return; - if (m_layoutListMarker.style()->visibility() != VISIBLE) + if (m_layoutListMarker.style()->visibility() != EVisibility::Visible) return; if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(paintInfo.context, m_layoutListMarker, paintInfo.phase))
diff --git a/third_party/WebKit/Source/core/paint/MultiColumnSetPainter.cpp b/third_party/WebKit/Source/core/paint/MultiColumnSetPainter.cpp index 61e6cc6..db069e6 100644 --- a/third_party/WebKit/Source/core/paint/MultiColumnSetPainter.cpp +++ b/third_party/WebKit/Source/core/paint/MultiColumnSetPainter.cpp
@@ -16,7 +16,7 @@ void MultiColumnSetPainter::paintObject(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { - if (m_layoutMultiColumnSet.style()->visibility() != VISIBLE) + if (m_layoutMultiColumnSet.style()->visibility() != EVisibility::Visible) return; BlockPainter(m_layoutMultiColumnSet).paintObject(paintInfo, paintOffset);
diff --git a/third_party/WebKit/Source/core/paint/ObjectPainter.cpp b/third_party/WebKit/Source/core/paint/ObjectPainter.cpp index 3e7e094..8eb4781 100644 --- a/third_party/WebKit/Source/core/paint/ObjectPainter.cpp +++ b/third_party/WebKit/Source/core/paint/ObjectPainter.cpp
@@ -206,7 +206,7 @@ ASSERT(shouldPaintSelfOutline(paintInfo.phase)); const ComputedStyle& styleToUse = m_layoutObject.styleRef(); - if (!styleToUse.hasOutline() || styleToUse.visibility() != VISIBLE) + if (!styleToUse.hasOutline() || styleToUse.visibility() != EVisibility::Visible) return; // Only paint the focus ring by hand if the theme isn't able to draw the focus ring. @@ -268,7 +268,7 @@ void ObjectPainter::addPDFURLRectIfNeeded(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { ASSERT(paintInfo.isPrinting()); - if (m_layoutObject.isElementContinuation() || !m_layoutObject.node() || !m_layoutObject.node()->isLink() || m_layoutObject.styleRef().visibility() != VISIBLE) + if (m_layoutObject.isElementContinuation() || !m_layoutObject.node() || !m_layoutObject.node()->isLink() || m_layoutObject.styleRef().visibility() != EVisibility::Visible) return; KURL url = toElement(m_layoutObject.node())->hrefURL();
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.cpp b/third_party/WebKit/Source/core/paint/PaintLayer.cpp index 956ad36..23c1b04d 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayer.cpp +++ b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
@@ -176,7 +176,7 @@ if (!layoutObject->slowFirstChild() && layoutObject->style()) { m_visibleContentStatusDirty = false; - m_hasVisibleContent = layoutObject->style()->visibility() == VISIBLE; + m_hasVisibleContent = layoutObject->style()->visibility() == EVisibility::Visible; } updateScrollableArea(); @@ -612,7 +612,7 @@ { if (m_visibleContentStatusDirty) return; - if (hasVisibleContent() == (visibility == VISIBLE)) + if (hasVisibleContent() == (visibility == EVisibility::Visible)) return; dirtyVisibleContentStatus(); } @@ -673,14 +673,14 @@ if (m_visibleContentStatusDirty) { bool previouslyHasVisibleContent = m_hasVisibleContent; - if (layoutObject()->style()->visibility() == VISIBLE) { + if (layoutObject()->style()->visibility() == EVisibility::Visible) { m_hasVisibleContent = true; } else { // layer may be hidden but still have some visible content, check for this m_hasVisibleContent = false; LayoutObject* r = layoutObject()->slowFirstChild(); while (r) { - if (r->style()->visibility() == VISIBLE && (!r->hasLayer() || !r->enclosingLayer()->isSelfPaintingLayer())) { + if (r->style()->visibility() == EVisibility::Visible && (!r->hasLayer() || !r->enclosingLayer()->isSelfPaintingLayer())) { m_hasVisibleContent = true; break; } @@ -1214,7 +1214,7 @@ oldChild->stackingNode()->dirtyStackingContextZOrderLists(); } - if (layoutObject()->style()->visibility() != VISIBLE) + if (layoutObject()->style()->visibility() != EVisibility::Visible) dirtyVisibleContentStatus(); oldChild->setPreviousSibling(0); @@ -2391,7 +2391,7 @@ // We can't use hasVisibleContent(), because that will be true if our layoutObject is hidden, but some child // is visible and that child doesn't cover the entire rect. - if (layoutObject()->style()->visibility() != VISIBLE) + if (layoutObject()->style()->visibility() != EVisibility::Visible) return false; if (paintsWithFilters() && layoutObject()->style()->filter().hasFilterThatAffectsOpacity())
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp index 58a6e0a..86176fa7 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp +++ b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
@@ -381,7 +381,9 @@ scopedPaintChunkProperties.emplace(context.getPaintController(), m_paintLayer, properties); } - bool shouldPaintBackground = isPaintingCompositedBackground && shouldPaintContent && !selectionOnly; + bool isPaintingRootLayer = (&m_paintLayer) == paintingInfo.rootLayer; + bool shouldPaintBackground = shouldPaintContent && !selectionOnly + && (isPaintingCompositedBackground || (isPaintingRootLayer && !(paintFlags & PaintLayerPaintingSkipRootBackground))); bool shouldPaintNegZOrderList = (isPaintingScrollingContent && isPaintingOverflowContents) || (!isPaintingScrollingContent && isPaintingCompositedBackground); bool shouldPaintOwnContents = isPaintingCompositedForeground && shouldPaintContent; bool shouldPaintNormalFlowAndPosZOrderLists = isPaintingCompositedForeground; @@ -574,6 +576,11 @@ PaintLayerPaintingInfo transformedPaintingInfo(&m_paintLayer, LayoutRect(enclosingIntRect(transform.inverse().mapRect(paintingInfo.paintDirtyRect))), paintingInfo.getGlobalPaintFlags(), adjustedSubPixelAccumulation); transformedPaintingInfo.ancestorHasClipPathClipping = paintingInfo.ancestorHasClipPathClipping; + + // Remove skip root background flag when we're painting with a new root. + if (&m_paintLayer != paintingInfo.rootLayer) + paintFlags &= ~PaintLayerPaintingSkipRootBackground; + return paintLayerContentsAndReflection(context, transformedPaintingInfo, paintFlags, ForceSingleFragment); }
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp index ddffbe8..eb488b2 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp +++ b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
@@ -1498,13 +1498,23 @@ if (node && node->isElementNode() && (toElement(node)->compositorMutableProperties() & (CompositorMutableProperty::kScrollTop | CompositorMutableProperty::kScrollLeft))) return true; - if (mode == PaintLayerScrollableArea::ConsiderLCDText && !layer->compositor()->preferCompositingToLCDTextEnabled()) + // TODO(schenney) The color test alone is inadequate. When https://codereview.chromium.org/2196583002 lands + // we should use PaintLayer::shouldPaintBackgroundOntoForeground() because we will not still get + // LCD text unless the conditions there are met. It also unifies logic for scrolling compositing decisions. + bool backgroundSupportsLCDText = RuntimeEnabledFeatures::compositeOpaqueScrollersEnabled() + && !layer->layoutObject()->style()->visitedDependentColor(CSSPropertyBackgroundColor).hasAlpha(); + if (mode == PaintLayerScrollableArea::ConsiderLCDText + && !layer->compositor()->preferCompositingToLCDTextEnabled() + && !backgroundSupportsLCDText) return false; - return !layer->size().isEmpty() - && !layer->hasDescendantWithClipPath() - && !layer->hasAncestorWithClipPath() - && !layer->layoutObject()->style()->hasBorderRadius(); + // TODO(schenney) Tests fail if we do not also exclude layer->layoutObject()->style()->hasBorderDecoration() + // (missing background behind dashed borders). Resolve this case, or not, and update this check with + // the results. + return !(layer->size().isEmpty() + || layer->hasDescendantWithClipPath() + || layer->hasAncestorWithClipPath() + || layer->layoutObject()->style()->hasBorderRadius()); } void PaintLayerScrollableArea::updateNeedsCompositedScrolling(LCDTextMode mode)
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.h b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.h index 6bb62e9..641417f 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.h +++ b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.h
@@ -472,7 +472,6 @@ void updateResizerAreaSet(); void updateResizerStyle(); - void updateScrollableAreaSet(bool hasOverflow); void updateCompositingLayersAfterScroll();
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerScrollableAreaTest.cpp b/third_party/WebKit/Source/core/paint/PaintLayerScrollableAreaTest.cpp new file mode 100644 index 0000000..f11b785 --- /dev/null +++ b/third_party/WebKit/Source/core/paint/PaintLayerScrollableAreaTest.cpp
@@ -0,0 +1,47 @@ +// 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 "core/paint/PaintLayerScrollableAreaTest.h" + +namespace blink { + +TEST_F(PaintLayerScrollableAreaTest, OpaqueLayersPromoted) +{ + RuntimeEnabledFeatures::setCompositeOpaqueScrollersEnabled(true); + + setBodyInnerHTML( + "<style>" + "#scroller { overflow: scroll; height: 300px; width: 300px; background-color: rgb(0,128,0); }" + "#scrolled { height: 1000px; width: 250px; }" + "</style>" + "<div id=\"scroller\"><div id=\"scrolled\"></div></div>"); + document().view()->updateAllLifecyclePhases(); + + ASSERT_TRUE(RuntimeEnabledFeatures::compositeOpaqueScrollersEnabled()); + Element* scroller = document().getElementById("scroller"); + PaintLayer* paintLayer = toLayoutBoxModelObject(scroller->layoutObject())->layer(); + ASSERT_TRUE(paintLayer); + ASSERT_TRUE(paintLayer->needsCompositedScrolling()); +} + +TEST_F(PaintLayerScrollableAreaTest, TransparentLayersNotPromoted) +{ + RuntimeEnabledFeatures::setCompositeOpaqueScrollersEnabled(true); + + setBodyInnerHTML( + "<style>" + "#scroller { overflow: scroll; height: 300px; width: 300px; background-color: rgba(0,128,0,0.5); }" + "#scrolled { height: 1000px; width: 250px; }" + "</style>" + "<div id=\"scroller\"><div id=\"scrolled\"></div></div>"); + document().view()->updateAllLifecyclePhases(); + + ASSERT_TRUE(RuntimeEnabledFeatures::compositeOpaqueScrollersEnabled()); + Element* scroller = document().getElementById("scroller"); + PaintLayer* paintLayer = toLayoutBoxModelObject(scroller->layoutObject())->layer(); + ASSERT_TRUE(paintLayer); + ASSERT_TRUE(!paintLayer->needsCompositedScrolling()); +} + +}
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerScrollableAreaTest.h b/third_party/WebKit/Source/core/paint/PaintLayerScrollableAreaTest.h new file mode 100644 index 0000000..e3906f0 --- /dev/null +++ b/third_party/WebKit/Source/core/paint/PaintLayerScrollableAreaTest.h
@@ -0,0 +1,34 @@ +// 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 "core/frame/FrameView.h" +#include "core/layout/LayoutBoxModelObject.h" +#include "core/layout/LayoutTestHelper.h" +#include "core/layout/api/LayoutViewItem.h" +#include "core/paint/PaintLayer.h" +#include "core/paint/PaintLayerScrollableArea.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace blink { + +class PaintLayerScrollableAreaTest : public RenderingTest { +public: + PaintLayerScrollableAreaTest() + : RenderingTest(SingleChildFrameLoaderClient::create()) + { } + +private: + void SetUp() override + { + RenderingTest::SetUp(); + enableCompositing(); + } + + void TearDown() override + { + RenderingTest::TearDown(); + } +}; + +}
diff --git a/third_party/WebKit/Source/core/paint/ReplacedPainter.cpp b/third_party/WebKit/Source/core/paint/ReplacedPainter.cpp index 54029e1..d8fdde3 100644 --- a/third_party/WebKit/Source/core/paint/ReplacedPainter.cpp +++ b/third_party/WebKit/Source/core/paint/ReplacedPainter.cpp
@@ -30,7 +30,7 @@ LayoutRect borderRect(adjustedPaintOffset, m_layoutReplaced.size()); - if (m_layoutReplaced.style()->visibility() == VISIBLE && m_layoutReplaced.hasBoxDecorationBackground() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection)) + if (m_layoutReplaced.style()->visibility() == EVisibility::Visible && m_layoutReplaced.hasBoxDecorationBackground() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection)) m_layoutReplaced.paintBoxDecorationBackground(paintInfo, adjustedPaintOffset); if (paintInfo.phase == PaintPhaseMask) { @@ -103,7 +103,7 @@ // If we're invisible or haven't received a layout yet, just bail. // But if it's an SVG root, there can be children, so we'll check visibility later. - if (!m_layoutReplaced.isSVGRoot() && m_layoutReplaced.style()->visibility() != VISIBLE) + if (!m_layoutReplaced.isSVGRoot() && m_layoutReplaced.style()->visibility() != EVisibility::Visible) return false; LayoutRect paintRect(m_layoutReplaced.visualOverflowRect());
diff --git a/third_party/WebKit/Source/core/paint/RootInlineBoxPainter.cpp b/third_party/WebKit/Source/core/paint/RootInlineBoxPainter.cpp index f23c69e4..18c4a617 100644 --- a/third_party/WebKit/Source/core/paint/RootInlineBoxPainter.cpp +++ b/third_party/WebKit/Source/core/paint/RootInlineBoxPainter.cpp
@@ -13,7 +13,7 @@ void RootInlineBoxPainter::paintEllipsisBox(const PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom) const { - if (m_rootInlineBox.hasEllipsisBox() && m_rootInlineBox.getLineLayoutItem().style()->visibility() == VISIBLE && paintInfo.phase == PaintPhaseForeground) + if (m_rootInlineBox.hasEllipsisBox() && m_rootInlineBox.getLineLayoutItem().style()->visibility() == EVisibility::Visible && paintInfo.phase == PaintPhaseForeground) m_rootInlineBox.ellipsisBox()->paint(paintInfo, paintOffset, lineTop, lineBottom); }
diff --git a/third_party/WebKit/Source/core/paint/SVGContainerPainter.cpp b/third_party/WebKit/Source/core/paint/SVGContainerPainter.cpp index 34b3c9a..358fff3 100644 --- a/third_party/WebKit/Source/core/paint/SVGContainerPainter.cpp +++ b/third_party/WebKit/Source/core/paint/SVGContainerPainter.cpp
@@ -57,7 +57,7 @@ if (paintInfoBeforeFiltering.phase != PaintPhaseForeground) return; - if (m_layoutSVGContainer.style()->outlineWidth() && m_layoutSVGContainer.style()->visibility() == VISIBLE) { + if (m_layoutSVGContainer.style()->outlineWidth() && m_layoutSVGContainer.style()->visibility() == EVisibility::Visible) { PaintInfo outlinePaintInfo(paintInfoBeforeFiltering); outlinePaintInfo.phase = PaintPhaseSelfOutlineOnly; ObjectPainter(m_layoutSVGContainer).paintOutline(outlinePaintInfo, LayoutPoint(boundingBox.location()));
diff --git a/third_party/WebKit/Source/core/paint/SVGImagePainter.cpp b/third_party/WebKit/Source/core/paint/SVGImagePainter.cpp index 36b24fc..7747cb1 100644 --- a/third_party/WebKit/Source/core/paint/SVGImagePainter.cpp +++ b/third_party/WebKit/Source/core/paint/SVGImagePainter.cpp
@@ -21,7 +21,7 @@ void SVGImagePainter::paint(const PaintInfo& paintInfo) { if (paintInfo.phase != PaintPhaseForeground - || m_layoutSVGImage.style()->visibility() != VISIBLE + || m_layoutSVGImage.style()->visibility() != EVisibility::Visible || !m_layoutSVGImage.imageResource()->hasImage()) return;
diff --git a/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.cpp b/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.cpp index 82e5172..620f0d5 100644 --- a/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.cpp +++ b/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.cpp
@@ -82,7 +82,7 @@ ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection); ASSERT(m_svgInlineTextBox.truncation() == cNoTruncation); - if (m_svgInlineTextBox.getLineLayoutItem().style()->visibility() != VISIBLE) + if (m_svgInlineTextBox.getLineLayoutItem().style()->visibility() != EVisibility::Visible) return; // We're explicitly not supporting composition & custom underlines and custom highlighters -- unlike InlineTextBox. @@ -191,7 +191,7 @@ void SVGInlineTextBoxPainter::paintSelectionBackground(const PaintInfo& paintInfo) { - if (m_svgInlineTextBox.getLineLayoutItem().style()->visibility() != VISIBLE) + if (m_svgInlineTextBox.getLineLayoutItem().style()->visibility() != EVisibility::Visible) return; ASSERT(!paintInfo.isPrinting()); @@ -276,7 +276,7 @@ LayoutObject* decorationLayoutObject = findLayoutObjectDefininingTextDecoration(m_svgInlineTextBox.parent()); const ComputedStyle& decorationStyle = decorationLayoutObject->styleRef(); - if (decorationStyle.visibility() != VISIBLE) + if (decorationStyle.visibility() != EVisibility::Visible) return; float scalingFactor = 1;
diff --git a/third_party/WebKit/Source/core/paint/SVGShapePainter.cpp b/third_party/WebKit/Source/core/paint/SVGShapePainter.cpp index fbf6bffc..f237a90a 100644 --- a/third_party/WebKit/Source/core/paint/SVGShapePainter.cpp +++ b/third_party/WebKit/Source/core/paint/SVGShapePainter.cpp
@@ -43,7 +43,7 @@ void SVGShapePainter::paint(const PaintInfo& paintInfo) { if (paintInfo.phase != PaintPhaseForeground - || m_layoutSVGShape.style()->visibility() != VISIBLE + || m_layoutSVGShape.style()->visibility() != EVisibility::Visible || m_layoutSVGShape.isShapeEmpty()) return;
diff --git a/third_party/WebKit/Source/core/paint/TableCellPainter.cpp b/third_party/WebKit/Source/core/paint/TableCellPainter.cpp index 77288009..4c81c5eb 100644 --- a/third_party/WebKit/Source/core/paint/TableCellPainter.cpp +++ b/third_party/WebKit/Source/core/paint/TableCellPainter.cpp
@@ -58,7 +58,7 @@ void TableCellPainter::paintCollapsedBorders(const PaintInfo& paintInfo, const LayoutPoint& paintOffset, const CollapsedBorderValue& currentBorderValue) { - if (m_layoutTableCell.style()->visibility() != VISIBLE) + if (m_layoutTableCell.style()->visibility() != EVisibility::Visible) return; LayoutPoint adjustedPaintOffset = paintOffset + m_layoutTableCell.location(); @@ -130,7 +130,7 @@ { DCHECK(backgroundObject != m_layoutTableCell); - if (m_layoutTableCell.style()->visibility() != VISIBLE) + if (m_layoutTableCell.style()->visibility() != EVisibility::Visible) return; LayoutPoint adjustedPaintOffset = paintOffset + m_layoutTableCell.location(); @@ -177,7 +177,7 @@ return; bool needsToPaintBorder = m_layoutTableCell.styleRef().hasBorderDecoration() && !table->collapseBorders(); - if (!m_layoutTableCell.hasBackground() && !m_layoutTableCell.styleRef().boxShadow() && !needsToPaintBorder) + if (!m_layoutTableCell.styleRef().hasBackground() && !m_layoutTableCell.styleRef().boxShadow() && !needsToPaintBorder) return; if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(paintInfo.context, m_layoutTableCell, DisplayItem::BoxDecorationBackground)) @@ -202,7 +202,7 @@ void TableCellPainter::paintMask(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { - if (m_layoutTableCell.style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask) + if (m_layoutTableCell.style()->visibility() != EVisibility::Visible || paintInfo.phase != PaintPhaseMask) return; LayoutTable* tableElt = m_layoutTableCell.table();
diff --git a/third_party/WebKit/Source/core/paint/TablePainter.cpp b/third_party/WebKit/Source/core/paint/TablePainter.cpp index 0beb002..c020a98 100644 --- a/third_party/WebKit/Source/core/paint/TablePainter.cpp +++ b/third_party/WebKit/Source/core/paint/TablePainter.cpp
@@ -41,7 +41,7 @@ } } - if (m_layoutTable.collapseBorders() && shouldPaintDescendantBlockBackgrounds(paintPhase) && m_layoutTable.style()->visibility() == VISIBLE) { + if (m_layoutTable.collapseBorders() && shouldPaintDescendantBlockBackgrounds(paintPhase) && m_layoutTable.style()->visibility() == EVisibility::Visible) { // Using our cached sorted styles, we then do individual passes, // painting each style of border from lowest precedence to highest precedence. LayoutTable::CollapsedBorderValues collapsedBorders = m_layoutTable.collapsedBorders(); @@ -61,7 +61,7 @@ void TablePainter::paintBoxDecorationBackground(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { - if (!m_layoutTable.hasBoxDecorationBackground() || m_layoutTable.style()->visibility() != VISIBLE) + if (!m_layoutTable.hasBoxDecorationBackground() || m_layoutTable.style()->visibility() != EVisibility::Visible) return; LayoutRect rect(paintOffset, m_layoutTable.size()); @@ -71,7 +71,7 @@ void TablePainter::paintMask(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { - if (m_layoutTable.style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask) + if (m_layoutTable.style()->visibility() != EVisibility::Visible || paintInfo.phase != PaintPhaseMask) return; if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(paintInfo.context, m_layoutTable, paintInfo.phase))
diff --git a/third_party/WebKit/Source/core/paint/TableRowPainter.cpp b/third_party/WebKit/Source/core/paint/TableRowPainter.cpp index 635fdfee..64653b9 100644 --- a/third_party/WebKit/Source/core/paint/TableRowPainter.cpp +++ b/third_party/WebKit/Source/core/paint/TableRowPainter.cpp
@@ -27,7 +27,7 @@ PaintInfo paintInfoForCells = paintInfo.forDescendants(); if (shouldPaintSelfBlockBackground(paintInfo.phase)) { paintBoxShadow(paintInfo, paintOffset, Normal); - if (m_layoutTableRow.hasBackground()) { + if (m_layoutTableRow.styleRef().hasBackground()) { // Paint row background of behind the cells. for (LayoutTableCell* cell = m_layoutTableRow.firstCell(); cell; cell = cell->nextCell()) TableCellPainter(*cell).paintContainerBackgroundBehindCell(paintInfoForCells, paintOffset, m_layoutTableRow, DisplayItem::TableCellBackgroundFromRow); @@ -62,14 +62,14 @@ return; LayoutPoint adjustedPaintOffset = paintOffset + m_layoutTableRow.location(); - LayoutRect bounds = BoxPainter(m_layoutTableRow).boundsForDrawingRecorder(adjustedPaintOffset); + LayoutRect bounds = BoxPainter(m_layoutTableRow).boundsForDrawingRecorder(paintInfo, adjustedPaintOffset); LayoutObjectDrawingRecorder recorder(paintInfo.context, m_layoutTableRow, type, bounds); BoxPainter::paintBoxShadow(paintInfo, LayoutRect(adjustedPaintOffset, m_layoutTableRow.size()), m_layoutTableRow.styleRef(), shadowStyle); } void TableRowPainter::paintBackgroundBehindCell(const LayoutTableCell& cell, const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { - DCHECK(m_layoutTableRow.hasBackground() && !m_layoutTableRow.hasSelfPaintingLayer()); + DCHECK(m_layoutTableRow.styleRef().hasBackground() && !m_layoutTableRow.hasSelfPaintingLayer()); LayoutPoint cellPoint = m_layoutTableRow.section()->flipForWritingModeForChild(&cell, paintOffset); TableCellPainter(cell).paintContainerBackgroundBehindCell(paintInfo, cellPoint, m_layoutTableRow, DisplayItem::TableCellBackgroundFromRow); }
diff --git a/third_party/WebKit/Source/core/paint/TableSectionPainter.cpp b/third_party/WebKit/Source/core/paint/TableSectionPainter.cpp index e1534bc..7d12fba 100644 --- a/third_party/WebKit/Source/core/paint/TableSectionPainter.cpp +++ b/third_party/WebKit/Source/core/paint/TableSectionPainter.cpp
@@ -43,8 +43,10 @@ LayoutTable* table = m_layoutTableSection.table(); LayoutPoint paginationOffset = paintOffset; LayoutUnit pageHeight = table->pageLogicalHeightForOffset(LayoutUnit()); - // Move paginationOffset to the top of the second page. - paginationOffset.move(0, pageHeight - table->pageLogicalOffset()); + + // Move paginationOffset to the top of the next page. + LayoutUnit offsetToNextPage = pageHeight - intMod(table->pageLogicalOffset(), pageHeight); + paginationOffset.move(0, offsetToNextPage); // Now move paginationOffset to the top of the page the cull rect starts on. if (paintInfo.cullRect().m_rect.y() > paginationOffset.y()) paginationOffset.move(0, pageHeight * static_cast<int>((paintInfo.cullRect().m_rect.y() - paginationOffset.y()) / pageHeight)); @@ -189,7 +191,7 @@ TableRowPainter rowPainter(*row); rowPainter.paintBoxShadow(paintInfoForDescendants, paintOffset, Normal); - if (row->hasBackground()) { + if (row->styleRef().hasBackground()) { for (unsigned c = dirtiedColumns.start(); c < dirtiedColumns.end(); c++) { if (const LayoutTableCell* cell = primaryCellToPaint(r, c, dirtiedRows, dirtiedColumns)) rowPainter.paintBackgroundBehindCell(*cell, paintInfoForDescendants, paintOffset); @@ -267,13 +269,13 @@ // the stack, since we have already opened a transparency layer (potentially) for the table row group. // Note that we deliberately ignore whether or not the cell has a layer, since these backgrounds paint "behind" the // cell. - if (columnGroup && columnGroup->hasBackground()) + if (columnGroup && columnGroup->styleRef().hasBackground()) tableCellPainter.paintContainerBackgroundBehindCell(paintInfoForCells, cellPoint, *columnGroup, DisplayItem::TableCellBackgroundFromColumnGroup); - if (column && column->hasBackground()) + if (column && column->styleRef().hasBackground()) tableCellPainter.paintContainerBackgroundBehindCell(paintInfoForCells, cellPoint, *column, DisplayItem::TableCellBackgroundFromColumn); // Paint the row group next. - if (m_layoutTableSection.hasBackground()) + if (m_layoutTableSection.styleRef().hasBackground()) tableCellPainter.paintContainerBackgroundBehindCell(paintInfoForCells, cellPoint, m_layoutTableSection, DisplayItem::TableCellBackgroundFromSection); } @@ -295,7 +297,7 @@ if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(paintInfo.context, m_layoutTableSection, type)) return; - LayoutRect bounds = BoxPainter(m_layoutTableSection).boundsForDrawingRecorder(paintOffset); + LayoutRect bounds = BoxPainter(m_layoutTableSection).boundsForDrawingRecorder(paintInfo, paintOffset); LayoutObjectDrawingRecorder recorder(paintInfo.context, m_layoutTableSection, type, bounds); BoxPainter::paintBoxShadow(paintInfo, LayoutRect(paintOffset, m_layoutTableSection.size()), m_layoutTableSection.styleRef(), shadowStyle); }
diff --git a/third_party/WebKit/Source/core/paint/ThemePainterDefault.cpp b/third_party/WebKit/Source/core/paint/ThemePainterDefault.cpp index 8fc7a58d..952f28a 100644 --- a/third_party/WebKit/Source/core/paint/ThemePainterDefault.cpp +++ b/third_party/WebKit/Source/core/paint/ThemePainterDefault.cpp
@@ -177,7 +177,7 @@ WebCanvas* canvas = i.context.canvas(); extraParams.button.hasBorder = true; extraParams.button.backgroundColor = useMockTheme() ? 0xffc0c0c0 : defaultButtonBackgroundColor; - if (o.hasBackground()) + if (o.styleRef().hasBackground()) extraParams.button.backgroundColor = o.resolveColor(CSSPropertyBackgroundColor).rgb(); Platform::current()->themeEngine()->paint(canvas, WebThemeEngine::PartButton, getWebThemeState(o), WebRect(rect), &extraParams); @@ -218,7 +218,7 @@ extraParams.menuList.hasBorderRadius = o.styleRef().hasBorderRadius(); // Fallback to transparent if the specified color object is invalid. Color backgroundColor(Color::transparent); - if (o.hasBackground()) + if (o.styleRef().hasBackground()) backgroundColor = o.resolveColor(CSSPropertyBackgroundColor); extraParams.menuList.backgroundColor = backgroundColor.rgb();
diff --git a/third_party/WebKit/Source/core/streams/ReadableByteStream.cpp b/third_party/WebKit/Source/core/streams/ReadableByteStream.cpp deleted file mode 100644 index df0f44d7b..0000000 --- a/third_party/WebKit/Source/core/streams/ReadableByteStream.cpp +++ /dev/null
@@ -1,21 +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 "core/streams/ReadableByteStream.h" - -#include "bindings/core/v8/ExceptionState.h" -#include "bindings/core/v8/ScriptState.h" -#include "core/streams/ReadableByteStreamReader.h" - -namespace blink { - -ReadableByteStreamReader* ReadableByteStream::getBytesReader(ExecutionContext* executionContext, ExceptionState& es) -{ - ReadableStreamReader* reader = getReader(executionContext, es); - if (es.hadException()) - return nullptr; - return new ReadableByteStreamReader(reader); -} - -} // namespace blink
diff --git a/third_party/WebKit/Source/core/streams/ReadableByteStream.h b/third_party/WebKit/Source/core/streams/ReadableByteStream.h deleted file mode 100644 index b502b0f7..0000000 --- a/third_party/WebKit/Source/core/streams/ReadableByteStream.h +++ /dev/null
@@ -1,33 +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 ReadableByteStream_h -#define ReadableByteStream_h - -#include "bindings/core/v8/ScriptWrappable.h" -#include "core/CoreExport.h" -#include "core/streams/ReadableStreamImpl.h" - -namespace blink { - -class DOMArrayBufferView; -class ExceptionState; -class ExecutionContext; -class ReadableByteStreamReader; -class ScriptState; -class Strategy; -class UnderlyingSource; - -class CORE_EXPORT ReadableByteStream : public ReadableStreamImpl<ReadableStreamChunkTypeTraits<DOMArrayBufferView>>, public ScriptWrappable { - DEFINE_WRAPPERTYPEINFO(); -public: - explicit ReadableByteStream(UnderlyingSource* source) : ReadableStreamImpl<ReadableStreamChunkTypeTraits<DOMArrayBufferView>>(source) { } - ReadableByteStream(UnderlyingSource* source, Strategy* strategy) : ReadableStreamImpl<ReadableStreamChunkTypeTraits<DOMArrayBufferView>>(source, strategy) { } - - ReadableByteStreamReader* getBytesReader(ExecutionContext*, ExceptionState&); -}; - -} // namespace blink - -#endif // ReadableByteStream_h
diff --git a/third_party/WebKit/Source/core/streams/ReadableByteStream.idl b/third_party/WebKit/Source/core/streams/ReadableByteStream.idl deleted file mode 100644 index a973a02..0000000 --- a/third_party/WebKit/Source/core/streams/ReadableByteStream.idl +++ /dev/null
@@ -1,12 +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. - -[ - Exposed=(Window,Worker), - // This interface is deprecated. - NoInterfaceObject, -] interface ReadableByteStream { - [CallWith=ExecutionContext, RaisesException, ImplementedAs=getBytesReader] ReadableByteStreamReader getReader(); - [CallWith=ScriptState] Promise<void> cancel(optional any reason); -};
diff --git a/third_party/WebKit/Source/core/streams/ReadableByteStreamReader.h b/third_party/WebKit/Source/core/streams/ReadableByteStreamReader.h deleted file mode 100644 index db090ff..0000000 --- a/third_party/WebKit/Source/core/streams/ReadableByteStreamReader.h +++ /dev/null
@@ -1,43 +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 ReadableByteStreamReader_h -#define ReadableByteStreamReader_h - -#include "bindings/core/v8/ScriptPromise.h" -#include "bindings/core/v8/ScriptValue.h" -#include "bindings/core/v8/ScriptWrappable.h" -#include "core/CoreExport.h" -#include "core/streams/ReadableStreamReader.h" -#include "platform/heap/Handle.h" - -namespace blink { - -class ExceptionState; -class ScriptState; - -class CORE_EXPORT ReadableByteStreamReader final : public GarbageCollected<ReadableByteStreamReader>, public ScriptWrappable { - DEFINE_WRAPPERTYPEINFO(); -public: - explicit ReadableByteStreamReader(ReadableStreamReader* reader) : m_reader(reader) { } - - ScriptPromise closed(ScriptState* scriptState) { return m_reader->closed(scriptState); } - ScriptPromise read(ScriptState* scriptState) { return m_reader->read(scriptState); } - ScriptPromise cancel(ScriptState* scriptState) { return m_reader->cancel(scriptState); } - ScriptPromise cancel(ScriptState* scriptState, ScriptValue reason) { return m_reader->cancel(scriptState, reason); } - void releaseLock(ExceptionState& es) { return m_reader->releaseLock(es); } - void releaseLock() { return m_reader->releaseLock(); } - - DEFINE_INLINE_TRACE() - { - visitor->trace(m_reader); - } - -private: - Member<ReadableStreamReader> m_reader; -}; - -} // namespace blink - -#endif // ReadableByteStreamReader_h
diff --git a/third_party/WebKit/Source/core/streams/ReadableByteStreamReader.idl b/third_party/WebKit/Source/core/streams/ReadableByteStreamReader.idl deleted file mode 100644 index e277966e..0000000 --- a/third_party/WebKit/Source/core/streams/ReadableByteStreamReader.idl +++ /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. - -[ - // We don't expose the interface now, because the name is not stable - // enough. We will expose it in the future. - NoInterfaceObject, -] interface ReadableByteStreamReader { - [CallWith=ScriptState] readonly attribute Promise<void> closed; - [CallWith=ScriptState] Promise<any> read(); - - [CallWith=ScriptState] Promise<void> cancel(optional any reason); - [RaisesException] void releaseLock(); -};
diff --git a/third_party/WebKit/Source/core/streams/ReadableStream.cpp b/third_party/WebKit/Source/core/streams/ReadableStream.cpp deleted file mode 100644 index 9f907f1..0000000 --- a/third_party/WebKit/Source/core/streams/ReadableStream.cpp +++ /dev/null
@@ -1,191 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "core/streams/ReadableStream.h" - -#include "bindings/core/v8/ExceptionState.h" -#include "bindings/core/v8/ScriptFunction.h" -#include "bindings/core/v8/ScriptPromiseResolver.h" -#include "bindings/core/v8/V8Binding.h" -#include "core/dom/DOMException.h" -#include "core/streams/ReadableStreamReader.h" -#include "core/streams/UnderlyingSource.h" - -namespace blink { - -namespace { - -class ConstUndefined : public ScriptFunction { -public: - static v8::Local<v8::Function> create(ScriptState* scriptState) - { - return (new ConstUndefined(scriptState))->bindToV8Function(); - } - -private: - explicit ConstUndefined(ScriptState* scriptState) : ScriptFunction(scriptState) { } - ScriptValue call(ScriptValue value) override - { - return ScriptValue(getScriptState(), v8::Undefined(getScriptState()->isolate())); - } -}; - -} // namespace - -ReadableStream::ReadableStream(UnderlyingSource* source) - : m_source(source) - , m_isStarted(false) - , m_isDraining(false) - , m_isPulling(false) - , m_isDisturbed(false) - , m_state(Readable) -{ -} - -ReadableStream::~ReadableStream() -{ -} - -bool ReadableStream::enqueuePreliminaryCheck() -{ - // This is a bit different from what spec says: it says we should throw - // an exception here. But sometimes a caller is not in any JavaScript - // context, and we don't want to throw an exception in such a case. - if (m_state == Errored || m_state == Closed || m_isDraining) - return false; - - return true; -} - -bool ReadableStream::enqueuePostAction() -{ - m_isPulling = false; - - bool shouldApplyBackpressure = this->shouldApplyBackpressure(); - // this->shouldApplyBackpressure may call this->error(). - if (m_state == Errored) - return false; - - return !shouldApplyBackpressure; -} - -void ReadableStream::close() -{ - if (m_state != Readable) - return; - - if (isQueueEmpty()) - closeInternal(); - else - m_isDraining = true; -} - -void ReadableStream::readInternalPostAction() -{ - ASSERT(m_state == Readable); - if (isQueueEmpty() && m_isDraining) - closeInternal(); - callPullIfNeeded(); -} - -ScriptPromise ReadableStream::cancel(ScriptState* scriptState) -{ - return cancel(scriptState, ScriptValue(scriptState, v8::Undefined(scriptState->isolate()))); -} - -ScriptPromise ReadableStream::cancel(ScriptState* scriptState, ScriptValue reason) -{ - if (m_reader) - return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError(scriptState->isolate(), "this stream is locked to a ReadableStreamReader")); - setIsDisturbed(); - if (m_state == Closed) - return ScriptPromise::castUndefined(scriptState); - if (m_state == Errored) - return ScriptPromise::rejectWithDOMException(scriptState, m_exception); - - return cancelInternal(scriptState, reason); -} - -ScriptPromise ReadableStream::cancelInternal(ScriptState* scriptState, ScriptValue reason) -{ - setIsDisturbed(); - closeInternal(); - return m_source->cancelSource(scriptState, reason).then(ConstUndefined::create(scriptState)); -} - -void ReadableStream::error(DOMException* exception) -{ - if (m_state != ReadableStream::Readable) - return; - - m_exception = exception; - clearQueue(); - rejectAllPendingReads(m_exception); - m_state = Errored; - if (m_reader) - m_reader->error(); -} - -void ReadableStream::didSourceStart() -{ - m_isStarted = true; - callPullIfNeeded(); -} - -ReadableStreamReader* ReadableStream::getReader(ExecutionContext* executionContext, ExceptionState& exceptionState) -{ - if (m_reader) { - exceptionState.throwTypeError("already locked to a ReadableStreamReader"); - return nullptr; - } - return new ReadableStreamReader(executionContext, this); -} - -void ReadableStream::setReader(ReadableStreamReader* reader) -{ - ASSERT((reader && !m_reader) || (!reader && m_reader)); - m_reader = reader; -} - -void ReadableStream::callPullIfNeeded() -{ - if (m_isPulling || m_isDraining || !m_isStarted || m_state == Closed || m_state == Errored) - return; - - bool shouldApplyBackpressure = this->shouldApplyBackpressure(); - if (m_state == Errored) { - // this->shouldApplyBackpressure may call this->error(). - return; - } - - // Note: We call |pull| if |hasPendingReads| returns true. This is not yet - // specified, but we need this for the fetch implementation. Because - // it is the only practical customer, it should be no problem for now. - // We need to propose this behavior to the spec. - if (!hasPendingReads() && shouldApplyBackpressure) { - // No pull is needed. - return; - } - m_isPulling = true; - m_source->pullSource(); -} - -void ReadableStream::closeInternal() -{ - ASSERT(m_state == Readable); - m_state = Closed; - resolveAllPendingReadsAsDone(); - clearQueue(); - if (m_reader) - m_reader->close(); -} - -DEFINE_TRACE(ReadableStream) -{ - visitor->trace(m_source); - visitor->trace(m_exception); - visitor->trace(m_reader); -} - -} // namespace blink
diff --git a/third_party/WebKit/Source/core/streams/ReadableStream.h b/third_party/WebKit/Source/core/streams/ReadableStream.h deleted file mode 100644 index 11e208a..0000000 --- a/third_party/WebKit/Source/core/streams/ReadableStream.h +++ /dev/null
@@ -1,106 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ReadableStream_h -#define ReadableStream_h - -#include "bindings/core/v8/ScriptPromise.h" -#include "bindings/core/v8/ScriptPromiseProperty.h" -#include "bindings/core/v8/ScriptState.h" -#include "bindings/core/v8/ScriptValue.h" -#include "bindings/core/v8/ScriptWrappable.h" -#include "bindings/core/v8/V8Binding.h" -#include "core/CoreExport.h" -#include "platform/heap/Handle.h" -#include "wtf/Forward.h" -#include "wtf/PassRefPtr.h" -#include "wtf/RefPtr.h" - -namespace blink { - -class DOMException; -class ExceptionState; -class ExecutionContext; -class ReadableStreamReader; -class UnderlyingSource; - -class CORE_EXPORT ReadableStream : public GarbageCollectedFinalized<ReadableStream> { -public: - enum State { - Readable, - Closed, - Errored, - }; - - // After ReadableStream construction, |didSourceStart| must be called when - // |source| initialization succeeds and |error| must be called when - // |source| initialization fails. - explicit ReadableStream(UnderlyingSource* /* source */); - virtual ~ReadableStream(); - - bool isStarted() const { return m_isStarted; } - bool isDraining() const { return m_isDraining; } - bool isPulling() const { return m_isPulling; } - State stateInternal() const { return m_state; } - DOMException* storedException() { return m_exception.get(); } - - virtual ScriptPromise read(ScriptState*) = 0; - ScriptPromise cancel(ScriptState*); - ScriptPromise cancel(ScriptState*, ScriptValue reason); - ScriptPromise cancelInternal(ScriptState*, ScriptValue reason); - - virtual bool hasPendingReads() const = 0; - virtual void resolveAllPendingReadsAsDone() = 0; - virtual void rejectAllPendingReads(DOMException*) = 0; - - void close(); - void error(DOMException*); - - void didSourceStart(); - - // This function is not a getter. It creates an ReadableStreamReader and - // returns it. - ReadableStreamReader* getReader(ExecutionContext*, ExceptionState&); - // Only ReadableStreamReader methods should call this function. - void setReader(ReadableStreamReader*); - - bool isLocked() const { return m_reader; } - bool isLockedTo(const ReadableStreamReader* reader) const { return m_reader == reader; } - - bool isDisturbed() const { return m_isDisturbed; } - void setIsDisturbed() { m_isDisturbed = true; } - - DECLARE_VIRTUAL_TRACE(); - -protected: - bool enqueuePreliminaryCheck(); - bool enqueuePostAction(); - void readInternalPostAction(); - -private: - using WaitPromise = ScriptPromiseProperty<Member<ReadableStream>, ToV8UndefinedGenerator, Member<DOMException>>; - using ClosedPromise = ScriptPromiseProperty<Member<ReadableStream>, ToV8UndefinedGenerator, Member<DOMException>>; - - virtual bool isQueueEmpty() const = 0; - virtual void clearQueue() = 0; - // This function will call ReadableStream::error on error. - virtual bool shouldApplyBackpressure() = 0; - - void callPullIfNeeded(); - void closeInternal(); - - Member<UnderlyingSource> m_source; - bool m_isStarted; - bool m_isDraining; - bool m_isPulling; - bool m_isDisturbed; - State m_state; - - Member<DOMException> m_exception; - Member<ReadableStreamReader> m_reader; -}; - -} // namespace blink - -#endif // ReadableStream_h
diff --git a/third_party/WebKit/Source/core/streams/ReadableStreamImpl.h b/third_party/WebKit/Source/core/streams/ReadableStreamImpl.h deleted file mode 100644 index 06beb8d..0000000 --- a/third_party/WebKit/Source/core/streams/ReadableStreamImpl.h +++ /dev/null
@@ -1,235 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ReadableStreamImpl_h -#define ReadableStreamImpl_h - -#include "bindings/core/v8/ExceptionState.h" -#include "bindings/core/v8/ScriptPromise.h" -#include "bindings/core/v8/ScriptPromiseResolver.h" -#include "bindings/core/v8/ScriptState.h" -#include "bindings/core/v8/ScriptValue.h" -#include "bindings/core/v8/ToV8.h" -#include "bindings/core/v8/V8ArrayBuffer.h" -#include "bindings/core/v8/V8Binding.h" -#include "bindings/core/v8/V8IteratorResultValue.h" -#include "core/dom/DOMArrayBuffer.h" -#include "core/dom/DOMArrayBufferView.h" -#include "core/dom/DOMException.h" -#include "core/streams/ReadableStream.h" -#include "wtf/Deque.h" -#include "wtf/RefPtr.h" -#include "wtf/text/WTFString.h" -#include <utility> - -namespace blink { - -// We define the default ChunkTypeTraits for frequently used types. -template<typename ChunkType> -class ReadableStreamChunkTypeTraits { - STATIC_ONLY(ReadableStreamChunkTypeTraits); -}; - -template<> -class ReadableStreamChunkTypeTraits<String> { -public: - typedef String HoldType; - typedef const String& PassType; - - static size_t size(const String& chunk) { return chunk.length(); } - static ScriptValue toScriptValue(ScriptState* scriptState, const HoldType& value) - { - return ScriptValue(scriptState, v8String(scriptState->isolate(), value)); - } -}; - -template<> -class ReadableStreamChunkTypeTraits<DOMArrayBuffer> { -public: - typedef DOMArrayBuffer* HoldType; - typedef DOMArrayBuffer* PassType; - - static size_t size(const PassType& chunk) { return chunk->byteLength(); } - static ScriptValue toScriptValue(ScriptState* scriptState, const HoldType& value) - { - return ScriptValue(scriptState, toV8(value, scriptState->context()->Global(), scriptState->isolate())); - } -}; - -template<> -class ReadableStreamChunkTypeTraits<DOMArrayBufferView> { -public: - typedef DOMArrayBufferView* HoldType; - typedef DOMArrayBufferView* PassType; - - static size_t size(const PassType& chunk) { return chunk->byteLength(); } - static ScriptValue toScriptValue(ScriptState* scriptState, const HoldType& value) - { - return ScriptValue(scriptState, toV8(value, scriptState->context()->Global(), scriptState->isolate())); - } -}; - -// ReadableStreamImpl<ChunkTypeTraits> is a ReadableStream subtype. It has a -// queue whose type depends on ChunkTypeTraits and it implements queue-related -// ReadableStream pure virtual methods. -template <typename ChunkTypeTraits> -class ReadableStreamImpl : public ReadableStream { -public: - class Strategy : public GarbageCollectedFinalized<Strategy> { - public: - virtual ~Strategy() { } - - // These functions call ReadableStream::error on error. - virtual size_t size(const typename ChunkTypeTraits::PassType& chunk, ReadableStream*) { return ChunkTypeTraits::size(chunk); } - virtual bool shouldApplyBackpressure(size_t totalQueueSize, ReadableStream*) = 0; - - DEFINE_INLINE_VIRTUAL_TRACE() { } - }; - - class DefaultStrategy : public Strategy { - public: - size_t size(const typename ChunkTypeTraits::PassType& chunk, ReadableStream*) override { return 1; } - bool shouldApplyBackpressure(size_t totalQueueSize, ReadableStream*) override { return totalQueueSize > 1; } - }; - - class StrictStrategy : public Strategy { - public: - size_t size(const typename ChunkTypeTraits::PassType& chunk, ReadableStream*) override { return 1; } - bool shouldApplyBackpressure(size_t totalQueueSize, ReadableStream*) override { return true; } - }; - - explicit ReadableStreamImpl(UnderlyingSource* source) - : ReadableStreamImpl(source, new DefaultStrategy) { } - ReadableStreamImpl(UnderlyingSource* source, Strategy* strategy) - : ReadableStream(source) - , m_strategy(strategy) - , m_totalQueueSize(0) { } - ~ReadableStreamImpl() override { } - - // ReadableStream methods - ScriptPromise read(ScriptState*) override; - - bool enqueue(typename ChunkTypeTraits::PassType); - - // This function is intended to be used by internal code to withdraw - // queued data. This pulls all data from this stream's queue, but - // ReadableStream public APIs can work with the behavior (i.e. it behaves - // as if multiple read-one-buffer calls were made). - void readInternal(Deque<std::pair<typename ChunkTypeTraits::HoldType, size_t>>& queue); - - DEFINE_INLINE_VIRTUAL_TRACE() - { - visitor->trace(m_strategy); - visitor->trace(m_pendingReads); - ReadableStream::trace(visitor); - } - -private: - using PendingReads = HeapDeque<Member<ScriptPromiseResolver>>; - - // ReadableStream methods - bool isQueueEmpty() const override { return m_queue.isEmpty(); } - void clearQueue() override - { - m_queue.clear(); - m_totalQueueSize = 0; - } - - void resolveAllPendingReadsAsDone() override - { - for (auto& resolver : m_pendingReads) { - ScriptState* scriptState = resolver->getScriptState(); - if (!scriptState->contextIsValid()) - continue; - ScriptState::Scope scope(scriptState); - resolver->resolve(v8IteratorResultDone(scriptState)); - } - m_pendingReads.clear(); - } - - void rejectAllPendingReads(DOMException* reason) override - { - for (auto& resolver : m_pendingReads) - resolver->reject(reason); - m_pendingReads.clear(); - } - - bool shouldApplyBackpressure() override - { - return m_strategy->shouldApplyBackpressure(m_totalQueueSize, this); - } - bool hasPendingReads() const override { return !m_pendingReads.isEmpty(); } - - Member<Strategy> m_strategy; - Deque<std::pair<typename ChunkTypeTraits::HoldType, size_t>> m_queue; - PendingReads m_pendingReads; - size_t m_totalQueueSize; -}; - -template <typename ChunkTypeTraits> -bool ReadableStreamImpl<ChunkTypeTraits>::enqueue(typename ChunkTypeTraits::PassType chunk) -{ - size_t size = m_strategy->size(chunk, this); - if (!enqueuePreliminaryCheck()) - return false; - - if (m_pendingReads.isEmpty()) { - m_queue.append(std::make_pair(chunk, size)); - m_totalQueueSize += size; - return enqueuePostAction(); - } - - ScriptPromiseResolver* resolver = m_pendingReads.takeFirst(); - ScriptState* scriptState = resolver->getScriptState(); - if (!scriptState->contextIsValid()) - return false; - ScriptState::Scope scope(scriptState); - resolver->resolve(v8IteratorResult(scriptState, chunk)); - return enqueuePostAction(); -} - -template <typename ChunkTypeTraits> -ScriptPromise ReadableStreamImpl<ChunkTypeTraits>::read(ScriptState* scriptState) -{ - if (stateInternal() == Closed) - return ScriptPromise::cast(scriptState, v8IteratorResultDone(scriptState)); - if (stateInternal() == Errored) - return ScriptPromise::reject(scriptState, toV8(storedException(), scriptState->context()->Global(), scriptState->isolate())); - - ASSERT(stateInternal() == Readable); - setIsDisturbed(); - if (m_queue.isEmpty()) { - m_pendingReads.append(ScriptPromiseResolver::create(scriptState)); - ScriptPromise promise = m_pendingReads.last()->promise(); - readInternalPostAction(); - return promise; - } - - auto pair = m_queue.takeFirst(); - typename ChunkTypeTraits::HoldType chunk = pair.first; - size_t size = pair.second; - ASSERT(m_totalQueueSize >= size); - m_totalQueueSize -= size; - readInternalPostAction(); - - return ScriptPromise::cast(scriptState, v8IteratorResult(scriptState, chunk)); -} - -template <typename ChunkTypeTraits> -void ReadableStreamImpl<ChunkTypeTraits>::readInternal(Deque<std::pair<typename ChunkTypeTraits::HoldType, size_t>>& queue) -{ - // We omit the preliminary check. Check it by yourself. - ASSERT(stateInternal() == Readable); - ASSERT(m_pendingReads.isEmpty()); - ASSERT(queue.isEmpty()); - - setIsDisturbed(); - queue.swap(m_queue); - m_totalQueueSize = 0; - readInternalPostAction(); -} - -} // namespace blink - -#endif // ReadableStreamImpl_h
diff --git a/third_party/WebKit/Source/core/streams/ReadableStreamReader.cpp b/third_party/WebKit/Source/core/streams/ReadableStreamReader.cpp deleted file mode 100644 index f97baaf7..0000000 --- a/third_party/WebKit/Source/core/streams/ReadableStreamReader.cpp +++ /dev/null
@@ -1,130 +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 "core/streams/ReadableStreamReader.h" - -#include "bindings/core/v8/ExceptionState.h" -#include "bindings/core/v8/ScriptPromiseResolver.h" -#include "bindings/core/v8/ToV8.h" -#include "bindings/core/v8/V8IteratorResultValue.h" -#include "core/dom/DOMException.h" -#include "core/dom/ExceptionCode.h" -#include "core/streams/ReadableStream.h" - -namespace blink { - -ReadableStreamReader::ReadableStreamReader(ExecutionContext* executionContext, ReadableStream* stream) - : ActiveScriptWrappable(this) - , ActiveDOMObject(executionContext) - , m_stream(stream) - , m_closed(new ClosedPromise(executionContext, this, ClosedPromise::Closed)) -{ - suspendIfNeeded(); - ASSERT(m_stream->isLockedTo(nullptr)); - m_stream->setReader(this); - - if (m_stream->stateInternal() == ReadableStream::Closed) - m_closed->resolve(ToV8UndefinedGenerator()); - if (m_stream->stateInternal() == ReadableStream::Errored) - m_closed->reject(m_stream->storedException()); -} - -ScriptPromise ReadableStreamReader::closed(ScriptState* scriptState) -{ - return m_closed->promise(scriptState->world()); -} - -bool ReadableStreamReader::isActive() const -{ - return m_stream->isLockedTo(this); -} - -ScriptPromise ReadableStreamReader::cancel(ScriptState* scriptState) -{ - return cancel(scriptState, ScriptValue(scriptState, v8::Undefined(scriptState->isolate()))); -} - -ScriptPromise ReadableStreamReader::cancel(ScriptState* scriptState, ScriptValue reason) -{ - if (isActive()) - return m_stream->cancelInternal(scriptState, reason); - - return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError(scriptState->isolate(), "the reader is already released")); -} - -ScriptPromise ReadableStreamReader::read(ScriptState* scriptState) -{ - if (!isActive()) - return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError(scriptState->isolate(), "the reader is already released")); - - return m_stream->read(scriptState); -} - -void ReadableStreamReader::releaseLock(ExceptionState& es) -{ - if (!isActive()) - return; - if (m_stream->hasPendingReads()) { - es.throwTypeError("The stream has pending read operations."); - return; - } - - releaseLock(); -} - -void ReadableStreamReader::releaseLock() -{ - if (!isActive()) - return; - - ASSERT(!m_stream->hasPendingReads()); - if (m_stream->stateInternal() != ReadableStream::Readable) - m_closed->reset(); - // Note: It is generally a bad idea to store world-dependent values - // (e.g. v8::Object) in a ScriptPromiseProperty, so we use DOMException - // though the spec says the promise should be rejected with a TypeError. - m_closed->reject(DOMException::create(AbortError, "the reader is already released")); - - // We call setReader(nullptr) after resolving / rejecting |m_closed| - // because it affects hasPendingActivity. - m_stream->setReader(nullptr); - ASSERT(!isActive()); -} - -void ReadableStreamReader::close() -{ - ASSERT(isActive()); - m_closed->resolve(ToV8UndefinedGenerator()); -} - -void ReadableStreamReader::error() -{ - ASSERT(isActive()); - m_closed->reject(m_stream->storedException()); -} - -bool ReadableStreamReader::hasPendingActivity() const -{ - // We need to extend ReadableStreamReader's wrapper's life while it is - // active in order to call resolve / reject on ScriptPromiseProperties. - return isActive() && m_stream->stateInternal() == ReadableStream::Readable; -} - -void ReadableStreamReader::stop() -{ - if (isActive()) { - // Calling |error| will release the lock. - m_stream->error(DOMException::create(AbortError, "The frame stops working.")); - } - ActiveDOMObject::stop(); -} - -DEFINE_TRACE(ReadableStreamReader) -{ - visitor->trace(m_stream); - visitor->trace(m_closed); - ActiveDOMObject::trace(visitor); -} - -} // namespace blink
diff --git a/third_party/WebKit/Source/core/streams/ReadableStreamReader.h b/third_party/WebKit/Source/core/streams/ReadableStreamReader.h deleted file mode 100644 index 3c79ea9..0000000 --- a/third_party/WebKit/Source/core/streams/ReadableStreamReader.h +++ /dev/null
@@ -1,59 +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 ReadableStreamReader_h -#define ReadableStreamReader_h - -#include "bindings/core/v8/ActiveScriptWrappable.h" -#include "bindings/core/v8/ScriptPromise.h" -#include "bindings/core/v8/ScriptPromiseProperty.h" -#include "bindings/core/v8/ScriptValue.h" -#include "bindings/core/v8/ScriptWrappable.h" -#include "bindings/core/v8/ToV8.h" -#include "core/CoreExport.h" -#include "core/dom/ActiveDOMObject.h" -#include "core/streams/ReadableStream.h" -#include "platform/heap/Handle.h" - -namespace blink { - -class DOMException; -class ExceptionState; -class ExecutionContext; -class ScriptState; - -// ReadableStreamReader corresponds to the same-name class in the Streams spec -// https://streams.spec.whatwg.org/. -class CORE_EXPORT ReadableStreamReader final : public GarbageCollectedFinalized<ReadableStreamReader>, public ScriptWrappable, public ActiveScriptWrappable, public ActiveDOMObject { - DEFINE_WRAPPERTYPEINFO(); - USING_GARBAGE_COLLECTED_MIXIN(ReadableStreamReader); -public: - // The stream must not be locked to any ReadableStreamReader when called. - ReadableStreamReader(ExecutionContext*, ReadableStream*); - - ScriptPromise closed(ScriptState*); - bool isActive() const; - ScriptPromise cancel(ScriptState*); - ScriptPromise cancel(ScriptState*, ScriptValue reason); - ScriptPromise read(ScriptState*); - void releaseLock(ExceptionState&); - void releaseLock(); - void close(); - void error(); - - bool hasPendingActivity() const final; - void stop() override; - - DECLARE_TRACE(); - -private: - using ClosedPromise = ScriptPromiseProperty<Member<ReadableStreamReader>, ToV8UndefinedGenerator, Member<DOMException>>; - - const Member<ReadableStream> m_stream; - Member<ClosedPromise> m_closed; -}; - -} // namespace blink - -#endif // ReadableStreamReader_h
diff --git a/third_party/WebKit/Source/core/streams/ReadableStreamReader.idl b/third_party/WebKit/Source/core/streams/ReadableStreamReader.idl deleted file mode 100644 index b611b14b..0000000 --- a/third_party/WebKit/Source/core/streams/ReadableStreamReader.idl +++ /dev/null
@@ -1,18 +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. - -[ - ActiveScriptWrappable, - DependentLifetime, - Exposed=(Window,Worker), - NoInterfaceObject, -] interface ReadableStreamReader { - // FIXME: Add constructor. - - [CallWith=ScriptState] readonly attribute Promise<void> closed; - [CallWith=ScriptState] Promise<any> read(); - - [CallWith=ScriptState] Promise<void> cancel(optional any reason); - [RaisesException] void releaseLock(); -};
diff --git a/third_party/WebKit/Source/core/streams/ReadableStreamReaderTest.cpp b/third_party/WebKit/Source/core/streams/ReadableStreamReaderTest.cpp deleted file mode 100644 index 9004c71..0000000 --- a/third_party/WebKit/Source/core/streams/ReadableStreamReaderTest.cpp +++ /dev/null
@@ -1,586 +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 "core/streams/ReadableStreamReader.h" - -#include "bindings/core/v8/ExceptionState.h" -#include "bindings/core/v8/ScriptState.h" -#include "bindings/core/v8/ToV8.h" -#include "bindings/core/v8/V8ThrowException.h" -#include "core/dom/DOMException.h" -#include "core/dom/Document.h" -#include "core/dom/ExceptionCode.h" -#include "core/streams/ReadableStream.h" -#include "core/streams/ReadableStreamImpl.h" -#include "core/streams/UnderlyingSource.h" -#include "core/testing/DummyPageHolder.h" -#include "testing/gtest/include/gtest/gtest.h" -#include <memory> - -namespace blink { - -using StringStream = ReadableStreamImpl<ReadableStreamChunkTypeTraits<String>>; - -namespace { - -struct ReadResult { - ReadResult() : isDone(false), isSet(false) { } - - String valueString; - bool isDone; - bool isSet; -}; - -class StringCapturingFunction final : public ScriptFunction { -public: - static v8::Local<v8::Function> createFunction(ScriptState* scriptState, String* value) - { - StringCapturingFunction* self = new StringCapturingFunction(scriptState, value); - return self->bindToV8Function(); - } - -private: - StringCapturingFunction(ScriptState* scriptState, String* value) - : ScriptFunction(scriptState) - , m_value(value) - { - } - - ScriptValue call(ScriptValue value) override - { - ASSERT(!value.isEmpty()); - *m_value = toCoreString(value.v8Value()->ToString(getScriptState()->context()).ToLocalChecked()); - return value; - } - - String* m_value; -}; - -class ReadResultCapturingFunction final : public ScriptFunction { -public: - static v8::Local<v8::Function> createFunction(ScriptState* scriptState, ReadResult* value) - { - ReadResultCapturingFunction* self = new ReadResultCapturingFunction(scriptState, value); - return self->bindToV8Function(); - } - -private: - ReadResultCapturingFunction(ScriptState* scriptState, ReadResult* value) - : ScriptFunction(scriptState) - , m_result(value) - { - } - - ScriptValue call(ScriptValue result) override - { - ASSERT(!result.isEmpty()); - v8::Isolate* isolate = getScriptState()->isolate(); - if (!result.isObject()) { - return result; - } - v8::Local<v8::Object> object = result.v8Value().As<v8::Object>(); - v8::Local<v8::String> doneString = v8String(isolate, "done"); - v8::Local<v8::String> valueString = v8String(isolate, "value"); - v8::Local<v8::Context> context = getScriptState()->context(); - v8::Maybe<bool> hasDone = object->Has(context, doneString); - v8::Maybe<bool> hasValue = object->Has(context, valueString); - - if (hasDone.IsNothing() || !hasDone.FromJust() || hasValue.IsNothing() || !hasValue.FromJust()) { - return result; - } - - v8::Local<v8::Value> done; - v8::Local<v8::Value> value; - - if (!object->Get(context, doneString).ToLocal(&done) || !object->Get(context, valueString).ToLocal(&value) || !done->IsBoolean()) { - return result; - } - - m_result->isSet = true; - m_result->isDone = done.As<v8::Boolean>()->Value(); - m_result->valueString = toCoreString(value->ToString(getScriptState()->context()).ToLocalChecked()); - return result; - } - - ReadResult* m_result; -}; - -class NoopUnderlyingSource final : public GarbageCollectedFinalized<NoopUnderlyingSource>, public UnderlyingSource { - USING_GARBAGE_COLLECTED_MIXIN(NoopUnderlyingSource); -public: - ~NoopUnderlyingSource() override { } - - void pullSource() override { } - ScriptPromise cancelSource(ScriptState* scriptState, ScriptValue reason) { return ScriptPromise::cast(scriptState, reason); } - DEFINE_INLINE_VIRTUAL_TRACE() { UnderlyingSource::trace(visitor); } -}; - -class PermissiveStrategy final : public StringStream::Strategy { -public: - bool shouldApplyBackpressure(size_t, ReadableStream*) override { return false; } -}; - -class ReadableStreamReaderTest : public ::testing::Test { -public: - ReadableStreamReaderTest() - : m_page(DummyPageHolder::create(IntSize(1, 1))) - , m_stream(new StringStream(new NoopUnderlyingSource, new PermissiveStrategy)) - { - m_stream->didSourceStart(); - } - - ~ReadableStreamReaderTest() override - { - // We need to call |error| in order to make - // ActiveDOMObject::hasPendingActivity return false. - m_stream->error(DOMException::create(AbortError, "done")); - } - - ScriptState* getScriptState() { return ScriptState::forMainWorld(m_page->document().frame()); } - v8::Isolate* isolate() { return getScriptState()->isolate(); } - ExecutionContext* getExecutionContext() { return getScriptState()->getExecutionContext(); } - - v8::Local<v8::Function> createCaptor(String* value) - { - return StringCapturingFunction::createFunction(getScriptState(), value); - } - - v8::Local<v8::Function> createResultCaptor(ReadResult* value) - { - return ReadResultCapturingFunction::createFunction(getScriptState(), value); - } - - std::unique_ptr<DummyPageHolder> m_page; - Persistent<StringStream> m_stream; -}; - -TEST_F(ReadableStreamReaderTest, Construct) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - ReadableStreamReader* reader = new ReadableStreamReader(getExecutionContext(), m_stream); - EXPECT_TRUE(reader->isActive()); - EXPECT_FALSE(exceptionState.hadException()); -} - -TEST_F(ReadableStreamReaderTest, Release) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - String onFulfilled, onRejected; - ReadableStreamReader* reader = new ReadableStreamReader(getExecutionContext(), m_stream); - EXPECT_TRUE(reader->isActive()); - - reader->closed(getScriptState()).then(createCaptor(&onFulfilled), createCaptor(&onRejected)); - reader->releaseLock(exceptionState); - EXPECT_FALSE(reader->isActive()); - EXPECT_FALSE(exceptionState.hadException()); - - EXPECT_TRUE(onFulfilled.isNull()); - EXPECT_TRUE(onRejected.isNull()); - - v8::MicrotasksScope::PerformCheckpoint(isolate()); - EXPECT_TRUE(onFulfilled.isNull()); - EXPECT_EQ("AbortError: the reader is already released", onRejected); - - ReadableStreamReader* another = new ReadableStreamReader(getExecutionContext(), m_stream); - EXPECT_TRUE(another->isActive()); - EXPECT_FALSE(reader->isActive()); - reader->releaseLock(exceptionState); - EXPECT_TRUE(another->isActive()); - EXPECT_FALSE(reader->isActive()); - EXPECT_FALSE(exceptionState.hadException()); -} - -TEST_F(ReadableStreamReaderTest, ReadAfterRelease) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - ReadableStreamReader* reader = new ReadableStreamReader(getExecutionContext(), m_stream); - EXPECT_TRUE(reader->isActive()); - reader->releaseLock(exceptionState); - EXPECT_FALSE(exceptionState.hadException()); - EXPECT_FALSE(reader->isActive()); - - ReadResult result; - String onRejected; - reader->read(getScriptState()).then(createResultCaptor(&result), createCaptor(&onRejected)); - - EXPECT_FALSE(result.isSet); - EXPECT_TRUE(onRejected.isNull()); - v8::MicrotasksScope::PerformCheckpoint(isolate()); - - EXPECT_FALSE(result.isSet); - EXPECT_EQ("TypeError: the reader is already released", onRejected); - EXPECT_FALSE(exceptionState.hadException()); -} - -TEST_F(ReadableStreamReaderTest, ReleaseShouldFailWhenCalledWhileReading) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - ReadableStreamReader* reader = new ReadableStreamReader(getExecutionContext(), m_stream); - EXPECT_TRUE(reader->isActive()); - reader->read(getScriptState()); - - reader->releaseLock(exceptionState); - EXPECT_TRUE(reader->isActive()); - EXPECT_TRUE(exceptionState.hadException()); - exceptionState.clearException(); - - m_stream->enqueue("hello"); - reader->releaseLock(exceptionState); - EXPECT_FALSE(reader->isActive()); - EXPECT_FALSE(exceptionState.hadException()); -} - -TEST_F(ReadableStreamReaderTest, EnqueueThenRead) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - m_stream->enqueue("hello"); - m_stream->enqueue("world"); - ReadableStreamReader* reader = new ReadableStreamReader(getExecutionContext(), m_stream); - EXPECT_EQ(ReadableStream::Readable, m_stream->stateInternal()); - - ReadResult result; - String onRejected; - reader->read(getScriptState()).then(createResultCaptor(&result), createCaptor(&onRejected)); - - EXPECT_FALSE(result.isSet); - EXPECT_TRUE(onRejected.isNull()); - - v8::MicrotasksScope::PerformCheckpoint(isolate()); - - EXPECT_TRUE(result.isSet); - EXPECT_FALSE(result.isDone); - EXPECT_EQ("hello", result.valueString); - EXPECT_TRUE(onRejected.isNull()); - - ReadResult result2; - String onRejected2; - reader->read(getScriptState()).then(createResultCaptor(&result2), createCaptor(&onRejected2)); - - EXPECT_FALSE(result2.isSet); - EXPECT_TRUE(onRejected2.isNull()); - - v8::MicrotasksScope::PerformCheckpoint(isolate()); - - EXPECT_TRUE(result2.isSet); - EXPECT_FALSE(result2.isDone); - EXPECT_EQ("world", result2.valueString); - EXPECT_TRUE(onRejected2.isNull()); - EXPECT_FALSE(exceptionState.hadException()); -} - -TEST_F(ReadableStreamReaderTest, ReadThenEnqueue) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - ReadableStreamReader* reader = new ReadableStreamReader(getExecutionContext(), m_stream); - EXPECT_EQ(ReadableStream::Readable, m_stream->stateInternal()); - - ReadResult result, result2; - String onRejected, onRejected2; - reader->read(getScriptState()).then(createResultCaptor(&result), createCaptor(&onRejected)); - reader->read(getScriptState()).then(createResultCaptor(&result2), createCaptor(&onRejected2)); - - EXPECT_FALSE(result.isSet); - EXPECT_TRUE(onRejected.isNull()); - EXPECT_FALSE(result2.isSet); - EXPECT_TRUE(onRejected2.isNull()); - - v8::MicrotasksScope::PerformCheckpoint(isolate()); - - EXPECT_FALSE(result.isSet); - EXPECT_TRUE(onRejected.isNull()); - EXPECT_FALSE(result2.isSet); - EXPECT_TRUE(onRejected2.isNull()); - - m_stream->enqueue("hello"); - v8::MicrotasksScope::PerformCheckpoint(isolate()); - - EXPECT_TRUE(result.isSet); - EXPECT_FALSE(result.isDone); - EXPECT_EQ("hello", result.valueString); - EXPECT_TRUE(onRejected.isNull()); - EXPECT_FALSE(result2.isSet); - EXPECT_TRUE(onRejected2.isNull()); - - m_stream->enqueue("world"); - v8::MicrotasksScope::PerformCheckpoint(isolate()); - - EXPECT_TRUE(result2.isSet); - EXPECT_FALSE(result2.isDone); - EXPECT_EQ("world", result2.valueString); - EXPECT_TRUE(onRejected2.isNull()); - EXPECT_FALSE(exceptionState.hadException()); -} - -TEST_F(ReadableStreamReaderTest, ClosedReader) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - ReadableStreamReader* reader = new ReadableStreamReader(getExecutionContext(), m_stream); - - m_stream->close(); - - EXPECT_TRUE(reader->isActive()); - - String onClosedFulfilled, onClosedRejected; - ReadResult result; - String onReadRejected; - v8::MicrotasksScope::PerformCheckpoint(isolate()); - reader->closed(getScriptState()).then(createCaptor(&onClosedFulfilled), createCaptor(&onClosedRejected)); - reader->read(getScriptState()).then(createResultCaptor(&result), createCaptor(&onReadRejected)); - EXPECT_TRUE(onClosedFulfilled.isNull()); - EXPECT_TRUE(onClosedRejected.isNull()); - EXPECT_FALSE(result.isSet); - EXPECT_TRUE(onReadRejected.isNull()); - - v8::MicrotasksScope::PerformCheckpoint(isolate()); - EXPECT_EQ("undefined", onClosedFulfilled); - EXPECT_TRUE(onClosedRejected.isNull()); - EXPECT_TRUE(result.isSet); - EXPECT_TRUE(result.isDone); - EXPECT_EQ("undefined", result.valueString); - EXPECT_TRUE(onReadRejected.isNull()); - EXPECT_FALSE(exceptionState.hadException()); -} - -TEST_F(ReadableStreamReaderTest, ErroredReader) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - ReadableStreamReader* reader = new ReadableStreamReader(getExecutionContext(), m_stream); - - m_stream->error(DOMException::create(SyntaxError, "some error")); - - EXPECT_EQ(ReadableStream::Errored, m_stream->stateInternal()); - EXPECT_TRUE(reader->isActive()); - - String onClosedFulfilled, onClosedRejected; - String onReadFulfilled, onReadRejected; - v8::MicrotasksScope::PerformCheckpoint(isolate()); - reader->closed(getScriptState()).then(createCaptor(&onClosedFulfilled), createCaptor(&onClosedRejected)); - reader->read(getScriptState()).then(createCaptor(&onReadFulfilled), createCaptor(&onReadRejected)); - EXPECT_TRUE(onClosedFulfilled.isNull()); - EXPECT_TRUE(onClosedRejected.isNull()); - EXPECT_TRUE(onReadFulfilled.isNull()); - EXPECT_TRUE(onReadRejected.isNull()); - - v8::MicrotasksScope::PerformCheckpoint(isolate()); - EXPECT_TRUE(onClosedFulfilled.isNull()); - EXPECT_EQ("SyntaxError: some error", onClosedRejected); - EXPECT_TRUE(onReadFulfilled.isNull()); - EXPECT_EQ("SyntaxError: some error", onReadRejected); - EXPECT_FALSE(exceptionState.hadException()); -} - -TEST_F(ReadableStreamReaderTest, PendingReadsShouldBeResolvedWhenClosed) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - ReadableStreamReader* reader = new ReadableStreamReader(getExecutionContext(), m_stream); - EXPECT_EQ(ReadableStream::Readable, m_stream->stateInternal()); - - ReadResult result, result2; - String onRejected, onRejected2; - reader->read(getScriptState()).then(createResultCaptor(&result), createCaptor(&onRejected)); - reader->read(getScriptState()).then(createResultCaptor(&result2), createCaptor(&onRejected2)); - - v8::MicrotasksScope::PerformCheckpoint(isolate()); - EXPECT_FALSE(result.isSet); - EXPECT_TRUE(onRejected.isNull()); - EXPECT_FALSE(result2.isSet); - EXPECT_TRUE(onRejected2.isNull()); - - m_stream->close(); - EXPECT_FALSE(result.isSet); - EXPECT_TRUE(onRejected.isNull()); - EXPECT_FALSE(result2.isSet); - EXPECT_TRUE(onRejected2.isNull()); - - v8::MicrotasksScope::PerformCheckpoint(isolate()); - - EXPECT_TRUE(result.isSet); - EXPECT_TRUE(result.isDone); - EXPECT_EQ("undefined", result.valueString); - EXPECT_TRUE(onRejected.isNull()); - - EXPECT_TRUE(result2.isSet); - EXPECT_TRUE(result2.isDone); - EXPECT_EQ("undefined", result2.valueString); - EXPECT_TRUE(onRejected2.isNull()); - EXPECT_FALSE(exceptionState.hadException()); -} - -TEST_F(ReadableStreamReaderTest, PendingReadsShouldBeRejectedWhenErrored) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - ReadableStreamReader* reader = new ReadableStreamReader(getExecutionContext(), m_stream); - EXPECT_EQ(ReadableStream::Readable, m_stream->stateInternal()); - - String onFulfilled, onFulfilled2; - String onRejected, onRejected2; - reader->read(getScriptState()).then(createCaptor(&onFulfilled), createCaptor(&onRejected)); - reader->read(getScriptState()).then(createCaptor(&onFulfilled2), createCaptor(&onRejected2)); - - v8::MicrotasksScope::PerformCheckpoint(isolate()); - EXPECT_TRUE(onFulfilled.isNull()); - EXPECT_TRUE(onRejected.isNull()); - EXPECT_TRUE(onFulfilled2.isNull()); - EXPECT_TRUE(onRejected2.isNull()); - - m_stream->error(DOMException::create(SyntaxError, "some error")); - EXPECT_TRUE(onFulfilled.isNull()); - EXPECT_TRUE(onRejected.isNull()); - EXPECT_TRUE(onFulfilled2.isNull()); - EXPECT_TRUE(onRejected2.isNull()); - - v8::MicrotasksScope::PerformCheckpoint(isolate()); - - EXPECT_TRUE(onFulfilled.isNull()); - EXPECT_EQ(onRejected, "SyntaxError: some error"); - EXPECT_TRUE(onFulfilled2.isNull()); - EXPECT_EQ(onRejected2, "SyntaxError: some error"); - EXPECT_FALSE(exceptionState.hadException()); -} - -TEST_F(ReadableStreamReaderTest, PendingReadsShouldBeResolvedWhenCanceled) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - ReadableStreamReader* reader = new ReadableStreamReader(getExecutionContext(), m_stream); - EXPECT_EQ(ReadableStream::Readable, m_stream->stateInternal()); - - ReadResult result, result2; - String onRejected, onRejected2; - reader->read(getScriptState()).then(createResultCaptor(&result), createCaptor(&onRejected)); - reader->read(getScriptState()).then(createResultCaptor(&result2), createCaptor(&onRejected2)); - - v8::MicrotasksScope::PerformCheckpoint(isolate()); - EXPECT_FALSE(result.isSet); - EXPECT_TRUE(onRejected.isNull()); - EXPECT_FALSE(result2.isSet); - EXPECT_TRUE(onRejected2.isNull()); - - reader->cancel(getScriptState(), ScriptValue(getScriptState(), v8::Undefined(isolate()))); - EXPECT_TRUE(reader->isActive()); - EXPECT_FALSE(result.isSet); - EXPECT_TRUE(onRejected.isNull()); - EXPECT_FALSE(result2.isSet); - EXPECT_TRUE(onRejected2.isNull()); - - v8::MicrotasksScope::PerformCheckpoint(isolate()); - - EXPECT_TRUE(result.isSet); - EXPECT_TRUE(result.isDone); - EXPECT_EQ("undefined", result.valueString); - EXPECT_TRUE(onRejected.isNull()); - - EXPECT_TRUE(result2.isSet); - EXPECT_TRUE(result2.isDone); - EXPECT_EQ("undefined", result2.valueString); - EXPECT_TRUE(onRejected2.isNull()); - EXPECT_FALSE(exceptionState.hadException()); -} - -TEST_F(ReadableStreamReaderTest, CancelShouldNotWorkWhenNotActive) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - ReadableStreamReader* reader = new ReadableStreamReader(getExecutionContext(), m_stream); - reader->releaseLock(exceptionState); - EXPECT_FALSE(reader->isActive()); - - String onFulfilled, onRejected; - reader->cancel(getScriptState(), ScriptValue(getScriptState(), v8::Undefined(isolate()))).then(createCaptor(&onFulfilled), createCaptor(&onRejected)); - EXPECT_EQ(ReadableStream::Readable, m_stream->stateInternal()); - - EXPECT_TRUE(onFulfilled.isNull()); - EXPECT_TRUE(onRejected.isNull()); - - v8::MicrotasksScope::PerformCheckpoint(isolate()); - - EXPECT_TRUE(onFulfilled.isNull()); - EXPECT_EQ("TypeError: the reader is already released", onRejected); - EXPECT_EQ(ReadableStream::Readable, m_stream->stateInternal()); - EXPECT_FALSE(exceptionState.hadException()); -} - -TEST_F(ReadableStreamReaderTest, Cancel) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - ReadableStreamReader* reader = new ReadableStreamReader(getExecutionContext(), m_stream); - EXPECT_EQ(ReadableStream::Readable, m_stream->stateInternal()); - - String onClosedFulfilled, onClosedRejected; - String onCancelFulfilled, onCancelRejected; - reader->closed(getScriptState()).then(createCaptor(&onClosedFulfilled), createCaptor(&onClosedRejected)); - reader->cancel(getScriptState(), ScriptValue(getScriptState(), v8::Undefined(isolate()))).then(createCaptor(&onCancelFulfilled), createCaptor(&onCancelRejected)); - - EXPECT_EQ(ReadableStream::Closed, m_stream->stateInternal()); - EXPECT_TRUE(onClosedFulfilled.isNull()); - EXPECT_TRUE(onClosedRejected.isNull()); - EXPECT_TRUE(onCancelFulfilled.isNull()); - EXPECT_TRUE(onCancelRejected.isNull()); - - v8::MicrotasksScope::PerformCheckpoint(isolate()); - EXPECT_EQ("undefined", onClosedFulfilled); - EXPECT_TRUE(onClosedRejected.isNull()); - EXPECT_EQ("undefined", onCancelFulfilled); - EXPECT_TRUE(onCancelRejected.isNull()); - EXPECT_FALSE(exceptionState.hadException()); -} - -TEST_F(ReadableStreamReaderTest, Close) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - ReadableStreamReader* reader = new ReadableStreamReader(getExecutionContext(), m_stream); - EXPECT_EQ(ReadableStream::Readable, m_stream->stateInternal()); - - String onFulfilled, onRejected; - reader->closed(getScriptState()).then(createCaptor(&onFulfilled), createCaptor(&onRejected)); - - m_stream->close(); - - EXPECT_EQ(ReadableStream::Closed, m_stream->stateInternal()); - EXPECT_TRUE(onFulfilled.isNull()); - EXPECT_TRUE(onRejected.isNull()); - - v8::MicrotasksScope::PerformCheckpoint(isolate()); - EXPECT_EQ("undefined", onFulfilled); - EXPECT_TRUE(onRejected.isNull()); - EXPECT_FALSE(exceptionState.hadException()); -} - -TEST_F(ReadableStreamReaderTest, Error) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - ReadableStreamReader* reader = new ReadableStreamReader(getExecutionContext(), m_stream); - EXPECT_EQ(ReadableStream::Readable, m_stream->stateInternal()); - - String onFulfilled, onRejected; - reader->closed(getScriptState()).then(createCaptor(&onFulfilled), createCaptor(&onRejected)); - - m_stream->error(DOMException::create(SyntaxError, "some error")); - - EXPECT_EQ(ReadableStream::Errored, m_stream->stateInternal()); - EXPECT_TRUE(onFulfilled.isNull()); - EXPECT_TRUE(onRejected.isNull()); - - v8::MicrotasksScope::PerformCheckpoint(isolate()); - EXPECT_TRUE(onFulfilled.isNull()); - EXPECT_EQ("SyntaxError: some error", onRejected); - EXPECT_FALSE(exceptionState.hadException()); -} - -} // namespace - -} // namespace blink
diff --git a/third_party/WebKit/Source/core/streams/ReadableStreamTest.cpp b/third_party/WebKit/Source/core/streams/ReadableStreamTest.cpp deleted file mode 100644 index dc0a0d70..0000000 --- a/third_party/WebKit/Source/core/streams/ReadableStreamTest.cpp +++ /dev/null
@@ -1,654 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "core/streams/ReadableStream.h" - -#include "bindings/core/v8/ExceptionState.h" -#include "bindings/core/v8/ScriptPromiseResolver.h" -#include "bindings/core/v8/ScriptState.h" -#include "bindings/core/v8/V8Binding.h" -#include "core/dom/DOMArrayBuffer.h" -#include "core/dom/DOMException.h" -#include "core/dom/Document.h" -#include "core/dom/ExceptionCode.h" -#include "core/streams/ReadableStreamImpl.h" -#include "core/streams/ReadableStreamReader.h" -#include "core/streams/UnderlyingSource.h" -#include "core/testing/DummyPageHolder.h" -#include "testing/gmock/include/gmock/gmock-more-actions.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" -#include <memory> - -namespace blink { - -using ::testing::_; -using ::testing::InSequence; -using ::testing::Invoke; -using ::testing::Return; -using ::testing::ReturnPointee; - -namespace { - -using Checkpoint = ::testing::StrictMock<::testing::MockFunction<void(int)>>; -using StringStream = ReadableStreamImpl<ReadableStreamChunkTypeTraits<String>>; - -class StringCapturingFunction : public ScriptFunction { -public: - static v8::Local<v8::Function> createFunction(ScriptState* scriptState, String* value) - { - StringCapturingFunction* self = new StringCapturingFunction(scriptState, value); - return self->bindToV8Function(); - } - -private: - StringCapturingFunction(ScriptState* scriptState, String* value) - : ScriptFunction(scriptState) - , m_value(value) - { - } - - ScriptValue call(ScriptValue value) override - { - ASSERT(!value.isEmpty()); - *m_value = toCoreString(value.v8Value()->ToString(getScriptState()->context()).ToLocalChecked()); - return value; - } - - String* m_value; -}; - -class MockUnderlyingSource : public GarbageCollectedFinalized<MockUnderlyingSource>, public UnderlyingSource { - USING_GARBAGE_COLLECTED_MIXIN(MockUnderlyingSource); -public: - ~MockUnderlyingSource() override { } - DEFINE_INLINE_VIRTUAL_TRACE() - { - UnderlyingSource::trace(visitor); - } - - MOCK_METHOD0(pullSource, void()); - MOCK_METHOD2(cancelSource, ScriptPromise(ScriptState*, ScriptValue)); -}; - -class PermissiveStrategy : public StringStream::Strategy { -public: - bool shouldApplyBackpressure(size_t, ReadableStream*) override { return false; } -}; - -class MockStrategy : public StringStream::Strategy { -public: - static ::testing::StrictMock<MockStrategy>* create() { return new ::testing::StrictMock<MockStrategy>; } - - MOCK_METHOD2(shouldApplyBackpressure, bool(size_t, ReadableStream*)); - MOCK_METHOD2(size, size_t(const String&, ReadableStream*)); -}; - -class ThrowError { -public: - explicit ThrowError(const String& message) - : m_message(message) { } - - void operator()(ExceptionState* exceptionState) - { - exceptionState->throwTypeError(m_message); - } - -private: - String m_message; -}; - -} // unnamed namespace - -// ReadableStream::read and some related functionalities are tested in -// ReadableStreamReaderTest. -class ReadableStreamTest : public ::testing::Test { -public: - ReadableStreamTest() - : m_page(DummyPageHolder::create(IntSize(1, 1))) - , m_underlyingSource(new ::testing::StrictMock<MockUnderlyingSource>) - { - } - - ~ReadableStreamTest() override - { - } - - ScriptState* getScriptState() { return ScriptState::forMainWorld(m_page->document().frame()); } - v8::Isolate* isolate() { return getScriptState()->isolate(); } - - v8::Local<v8::Function> createCaptor(String* value) - { - return StringCapturingFunction::createFunction(getScriptState(), value); - } - - StringStream* construct(MockStrategy* strategy) - { - Checkpoint checkpoint; - { - InSequence s; - EXPECT_CALL(checkpoint, Call(0)); - EXPECT_CALL(*strategy, shouldApplyBackpressure(0, _)).WillOnce(Return(true)); - EXPECT_CALL(checkpoint, Call(1)); - } - StringStream* stream = new StringStream(m_underlyingSource, strategy); - checkpoint.Call(0); - stream->didSourceStart(); - checkpoint.Call(1); - return stream; - } - StringStream* construct() - { - Checkpoint checkpoint; - { - InSequence s; - EXPECT_CALL(checkpoint, Call(0)); - EXPECT_CALL(*m_underlyingSource, pullSource()).Times(1); - EXPECT_CALL(checkpoint, Call(1)); - } - StringStream* stream = new StringStream(m_underlyingSource, new PermissiveStrategy); - checkpoint.Call(0); - stream->didSourceStart(); - checkpoint.Call(1); - return stream; - } - - std::unique_ptr<DummyPageHolder> m_page; - Persistent<MockUnderlyingSource> m_underlyingSource; -}; - -TEST_F(ReadableStreamTest, Start) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - Checkpoint checkpoint; - { - InSequence s; - EXPECT_CALL(checkpoint, Call(0)); - EXPECT_CALL(*m_underlyingSource, pullSource()).Times(1); - EXPECT_CALL(checkpoint, Call(1)); - } - - StringStream* stream = new StringStream(m_underlyingSource); - EXPECT_FALSE(exceptionState.hadException()); - EXPECT_FALSE(stream->isStarted()); - EXPECT_FALSE(stream->isDraining()); - EXPECT_FALSE(stream->isPulling()); - EXPECT_FALSE(stream->isDisturbed()); - EXPECT_EQ(stream->stateInternal(), ReadableStream::Readable); - - checkpoint.Call(0); - stream->didSourceStart(); - checkpoint.Call(1); - - EXPECT_TRUE(stream->isStarted()); - EXPECT_FALSE(stream->isDraining()); - EXPECT_TRUE(stream->isPulling()); - EXPECT_EQ(stream->stateInternal(), ReadableStream::Readable); - - // We need to call |error| in order to make - // ActiveDOMObject::hasPendingActivity return false. - stream->error(DOMException::create(AbortError, "done")); -} - -TEST_F(ReadableStreamTest, StartFail) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - StringStream* stream = new StringStream(m_underlyingSource); - EXPECT_FALSE(exceptionState.hadException()); - EXPECT_FALSE(stream->isStarted()); - EXPECT_FALSE(stream->isDraining()); - EXPECT_FALSE(stream->isPulling()); - EXPECT_EQ(stream->stateInternal(), ReadableStream::Readable); - - stream->error(DOMException::create(NotFoundError)); - - EXPECT_FALSE(stream->isStarted()); - EXPECT_FALSE(stream->isDraining()); - EXPECT_FALSE(stream->isPulling()); - EXPECT_EQ(stream->stateInternal(), ReadableStream::Errored); -} - -TEST_F(ReadableStreamTest, ErrorAndEnqueue) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - StringStream* stream = construct(); - - stream->error(DOMException::create(NotFoundError, "error")); - EXPECT_EQ(ReadableStream::Errored, stream->stateInternal()); - - bool result = stream->enqueue("hello"); - EXPECT_FALSE(result); - EXPECT_EQ(ReadableStream::Errored, stream->stateInternal()); -} - -TEST_F(ReadableStreamTest, CloseAndEnqueue) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - StringStream* stream = construct(); - - stream->close(); - EXPECT_EQ(ReadableStream::Closed, stream->stateInternal()); - - bool result = stream->enqueue("hello"); - EXPECT_FALSE(result); - EXPECT_EQ(ReadableStream::Closed, stream->stateInternal()); -} - -TEST_F(ReadableStreamTest, CloseWhenErrored) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - StringStream* stream = construct(); - EXPECT_EQ(ReadableStream::Readable, stream->stateInternal()); - - stream->error(DOMException::create(NotFoundError, "error")); - stream->close(); - - EXPECT_EQ(ReadableStream::Errored, stream->stateInternal()); -} - -TEST_F(ReadableStreamTest, ReadQueue) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - StringStream* stream = construct(); - Checkpoint checkpoint; - - { - InSequence s; - EXPECT_CALL(checkpoint, Call(0)); - EXPECT_CALL(*m_underlyingSource, pullSource()).Times(1); - EXPECT_CALL(checkpoint, Call(1)); - } - - Deque<std::pair<String, size_t>> queue; - - EXPECT_TRUE(stream->enqueue("hello")); - EXPECT_TRUE(stream->enqueue("bye")); - EXPECT_EQ(ReadableStream::Readable, stream->stateInternal()); - EXPECT_FALSE(stream->isPulling()); - - checkpoint.Call(0); - EXPECT_FALSE(stream->isDisturbed()); - stream->readInternal(queue); - EXPECT_TRUE(stream->isDisturbed()); - checkpoint.Call(1); - ASSERT_EQ(2u, queue.size()); - - EXPECT_EQ(std::make_pair(String("hello"), static_cast<size_t>(5)), queue[0]); - EXPECT_EQ(std::make_pair(String("bye"), static_cast<size_t>(3)), queue[1]); - - EXPECT_EQ(ReadableStream::Readable, stream->stateInternal()); - EXPECT_TRUE(stream->isPulling()); - EXPECT_FALSE(stream->isDraining()); -} - -TEST_F(ReadableStreamTest, CloseWhenReadable) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - StringStream* stream = construct(); - - EXPECT_TRUE(stream->enqueue("hello")); - EXPECT_TRUE(stream->enqueue("bye")); - stream->close(); - EXPECT_FALSE(stream->enqueue("should be ignored")); - - EXPECT_EQ(ReadableStream::Readable, stream->stateInternal()); - EXPECT_FALSE(stream->isPulling()); - EXPECT_TRUE(stream->isDraining()); - - stream->read(getScriptState()); - - v8::MicrotasksScope::PerformCheckpoint(isolate()); - - EXPECT_EQ(ReadableStream::Readable, stream->stateInternal()); - EXPECT_FALSE(stream->isPulling()); - EXPECT_TRUE(stream->isDraining()); - - stream->read(getScriptState()); - - EXPECT_EQ(ReadableStream::Closed, stream->stateInternal()); - EXPECT_FALSE(stream->isPulling()); - EXPECT_TRUE(stream->isDraining()); -} - -TEST_F(ReadableStreamTest, CancelWhenClosed) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - StringStream* stream = construct(); - String onFulfilled, onRejected; - stream->close(); - EXPECT_EQ(ReadableStream::Closed, stream->stateInternal()); - - EXPECT_FALSE(stream->isDisturbed()); - ScriptPromise promise = stream->cancel(getScriptState(), ScriptValue()); - EXPECT_TRUE(stream->isDisturbed()); - EXPECT_EQ(ReadableStream::Closed, stream->stateInternal()); - - promise.then(createCaptor(&onFulfilled), createCaptor(&onRejected)); - EXPECT_TRUE(onFulfilled.isNull()); - EXPECT_TRUE(onRejected.isNull()); - - v8::MicrotasksScope::PerformCheckpoint(isolate()); - EXPECT_EQ("undefined", onFulfilled); - EXPECT_TRUE(onRejected.isNull()); -} - -TEST_F(ReadableStreamTest, CancelWhenErrored) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - StringStream* stream = construct(); - String onFulfilled, onRejected; - stream->error(DOMException::create(NotFoundError, "error")); - EXPECT_EQ(ReadableStream::Errored, stream->stateInternal()); - - EXPECT_FALSE(stream->isDisturbed()); - ScriptPromise promise = stream->cancel(getScriptState(), ScriptValue()); - EXPECT_TRUE(stream->isDisturbed()); - EXPECT_EQ(ReadableStream::Errored, stream->stateInternal()); - - promise.then(createCaptor(&onFulfilled), createCaptor(&onRejected)); - EXPECT_TRUE(onFulfilled.isNull()); - EXPECT_TRUE(onRejected.isNull()); - - v8::MicrotasksScope::PerformCheckpoint(isolate()); - EXPECT_TRUE(onFulfilled.isNull()); - EXPECT_EQ("NotFoundError: error", onRejected); -} - -TEST_F(ReadableStreamTest, CancelWhenReadable) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - StringStream* stream = construct(); - String onFulfilled, onRejected; - String onCancelFulfilled, onCancelRejected; - ScriptValue reason(getScriptState(), v8String(getScriptState()->isolate(), "reason")); - ScriptPromise promise = ScriptPromise::cast(getScriptState(), v8String(getScriptState()->isolate(), "hello")); - - { - InSequence s; - EXPECT_CALL(*m_underlyingSource, cancelSource(getScriptState(), reason)).WillOnce(ReturnPointee(&promise)); - } - - stream->enqueue("hello"); - EXPECT_EQ(ReadableStream::Readable, stream->stateInternal()); - - EXPECT_FALSE(stream->isDisturbed()); - ScriptPromise cancelResult = stream->cancel(getScriptState(), reason); - EXPECT_TRUE(stream->isDisturbed()); - cancelResult.then(createCaptor(&onCancelFulfilled), createCaptor(&onCancelRejected)); - - EXPECT_NE(promise, cancelResult); - EXPECT_EQ(ReadableStream::Closed, stream->stateInternal()); - - EXPECT_TRUE(onCancelFulfilled.isNull()); - EXPECT_TRUE(onCancelRejected.isNull()); - - v8::MicrotasksScope::PerformCheckpoint(isolate()); - EXPECT_EQ("undefined", onCancelFulfilled); - EXPECT_TRUE(onCancelRejected.isNull()); -} - -TEST_F(ReadableStreamTest, CancelWhenLocked) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - String onFulfilled, onRejected; - StringStream* stream = construct(); - ReadableStreamReader* reader = stream->getReader(getScriptState()->getExecutionContext(), exceptionState); - - EXPECT_TRUE(reader->isActive()); - EXPECT_FALSE(exceptionState.hadException()); - EXPECT_EQ(ReadableStream::Readable, stream->stateInternal()); - - EXPECT_FALSE(stream->isDisturbed()); - stream->cancel(getScriptState(), ScriptValue(getScriptState(), v8::Undefined(isolate()))).then(createCaptor(&onFulfilled), createCaptor(&onRejected)); - EXPECT_FALSE(stream->isDisturbed()); - - EXPECT_TRUE(onFulfilled.isNull()); - EXPECT_TRUE(onRejected.isNull()); - - v8::MicrotasksScope::PerformCheckpoint(isolate()); - - EXPECT_TRUE(onFulfilled.isNull()); - EXPECT_EQ("TypeError: this stream is locked to a ReadableStreamReader", onRejected); - EXPECT_TRUE(reader->isActive()); - EXPECT_EQ(ReadableStream::Readable, stream->stateInternal()); -} - -TEST_F(ReadableStreamTest, ReadableArrayBufferStreamCompileTest) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - // This test tests if ReadableStreamImpl<DOMArrayBuffer> can be - // instantiated. - new ReadableStreamImpl<ReadableStreamChunkTypeTraits<DOMArrayBuffer>>(m_underlyingSource); -} - -TEST_F(ReadableStreamTest, ReadableArrayBufferViewStreamCompileTest) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - // This test tests if ReadableStreamImpl<DOMArrayBufferVIew> can be - // instantiated. - new ReadableStreamImpl<ReadableStreamChunkTypeTraits<DOMArrayBufferView>>(m_underlyingSource); -} - -TEST_F(ReadableStreamTest, BackpressureOnEnqueueing) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - auto strategy = MockStrategy::create(); - Checkpoint checkpoint; - - StringStream* stream = construct(strategy); - EXPECT_EQ(ReadableStream::Readable, stream->stateInternal()); - - { - InSequence s; - EXPECT_CALL(checkpoint, Call(0)); - EXPECT_CALL(*strategy, size(String("hello"), stream)).WillOnce(Return(1)); - EXPECT_CALL(*strategy, shouldApplyBackpressure(1, stream)).WillOnce(Return(false)); - EXPECT_CALL(checkpoint, Call(1)); - EXPECT_CALL(checkpoint, Call(2)); - EXPECT_CALL(*strategy, size(String("world"), stream)).WillOnce(Return(2)); - EXPECT_CALL(*strategy, shouldApplyBackpressure(3, stream)).WillOnce(Return(true)); - EXPECT_CALL(checkpoint, Call(3)); - } - checkpoint.Call(0); - bool result = stream->enqueue("hello"); - checkpoint.Call(1); - EXPECT_TRUE(result); - - checkpoint.Call(2); - result = stream->enqueue("world"); - checkpoint.Call(3); - EXPECT_FALSE(result); - - stream->error(DOMException::create(AbortError, "done")); -} - -TEST_F(ReadableStreamTest, BackpressureOnReading) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - auto strategy = MockStrategy::create(); - Checkpoint checkpoint; - - StringStream* stream = construct(strategy); - EXPECT_EQ(ReadableStream::Readable, stream->stateInternal()); - - { - InSequence s; - EXPECT_CALL(*strategy, size(String("hello"), stream)).WillOnce(Return(2)); - EXPECT_CALL(*strategy, shouldApplyBackpressure(2, stream)).WillOnce(Return(false)); - EXPECT_CALL(*strategy, size(String("world"), stream)).WillOnce(Return(3)); - EXPECT_CALL(*strategy, shouldApplyBackpressure(5, stream)).WillOnce(Return(false)); - - EXPECT_CALL(checkpoint, Call(0)); - EXPECT_CALL(*strategy, shouldApplyBackpressure(3, stream)).WillOnce(Return(false)); - EXPECT_CALL(*m_underlyingSource, pullSource()).Times(1); - EXPECT_CALL(checkpoint, Call(1)); - // shouldApplyBackpressure and pullSource are not called because the - // stream is pulling. - EXPECT_CALL(checkpoint, Call(2)); - EXPECT_CALL(*strategy, size(String("foo"), stream)).WillOnce(Return(4)); - EXPECT_CALL(*strategy, shouldApplyBackpressure(4, stream)).WillOnce(Return(true)); - EXPECT_CALL(*strategy, size(String("bar"), stream)).WillOnce(Return(5)); - EXPECT_CALL(*strategy, shouldApplyBackpressure(9, stream)).WillOnce(Return(true)); - EXPECT_CALL(checkpoint, Call(3)); - EXPECT_CALL(*strategy, shouldApplyBackpressure(5, stream)).WillOnce(Return(true)); - EXPECT_CALL(checkpoint, Call(4)); - } - stream->enqueue("hello"); - stream->enqueue("world"); - - checkpoint.Call(0); - stream->read(getScriptState()); - checkpoint.Call(1); - stream->read(getScriptState()); - checkpoint.Call(2); - stream->enqueue("foo"); - stream->enqueue("bar"); - checkpoint.Call(3); - stream->read(getScriptState()); - checkpoint.Call(4); - - stream->error(DOMException::create(AbortError, "done")); -} - -// Note: Detailed tests are on ReadableStreamReaderTest. -TEST_F(ReadableStreamTest, ReadableStreamReader) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - StringStream* stream = construct(); - ReadableStreamReader* reader = stream->getReader(getScriptState()->getExecutionContext(), exceptionState); - - ASSERT_TRUE(reader); - EXPECT_FALSE(exceptionState.hadException()); - EXPECT_TRUE(reader->isActive()); - EXPECT_TRUE(stream->isLockedTo(reader)); - - ReadableStreamReader* another = stream->getReader(getScriptState()->getExecutionContext(), exceptionState); - ASSERT_EQ(nullptr, another); - EXPECT_TRUE(exceptionState.hadException()); - EXPECT_TRUE(reader->isActive()); - EXPECT_TRUE(stream->isLockedTo(reader)); -} - -TEST_F(ReadableStreamTest, GetClosedReader) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - StringStream* stream = construct(); - stream->close(); - ReadableStreamReader* reader = stream->getReader(getScriptState()->getExecutionContext(), exceptionState); - - ASSERT_TRUE(reader); - EXPECT_FALSE(exceptionState.hadException()); - - String onFulfilled, onRejected; - reader->closed(getScriptState()).then(createCaptor(&onFulfilled), createCaptor(&onRejected)); - - EXPECT_TRUE(reader->isActive()); - EXPECT_TRUE(onFulfilled.isNull()); - EXPECT_TRUE(onRejected.isNull()); - - v8::MicrotasksScope::PerformCheckpoint(isolate()); - EXPECT_EQ("undefined", onFulfilled); - EXPECT_TRUE(onRejected.isNull()); -} - -TEST_F(ReadableStreamTest, GetErroredReader) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - StringStream* stream = construct(); - stream->error(DOMException::create(SyntaxError, "some error")); - ReadableStreamReader* reader = stream->getReader(getScriptState()->getExecutionContext(), exceptionState); - - ASSERT_TRUE(reader); - EXPECT_FALSE(exceptionState.hadException()); - - String onFulfilled, onRejected; - reader->closed(getScriptState()).then(createCaptor(&onFulfilled), createCaptor(&onRejected)); - - EXPECT_TRUE(reader->isActive()); - EXPECT_TRUE(onFulfilled.isNull()); - EXPECT_TRUE(onRejected.isNull()); - - v8::MicrotasksScope::PerformCheckpoint(isolate()); - EXPECT_TRUE(onFulfilled.isNull()); - EXPECT_EQ("SyntaxError: some error", onRejected); -} - -TEST_F(ReadableStreamTest, StrictStrategy) -{ - ScriptState::Scope scope(getScriptState()); - ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", getScriptState()->context()->Global(), isolate()); - Checkpoint checkpoint; - { - InSequence s; - EXPECT_CALL(checkpoint, Call(0)); - EXPECT_CALL(checkpoint, Call(1)); - EXPECT_CALL(*m_underlyingSource, pullSource()); - EXPECT_CALL(checkpoint, Call(2)); - EXPECT_CALL(checkpoint, Call(3)); - EXPECT_CALL(*m_underlyingSource, pullSource()); - EXPECT_CALL(checkpoint, Call(4)); - EXPECT_CALL(checkpoint, Call(5)); - EXPECT_CALL(checkpoint, Call(6)); - EXPECT_CALL(checkpoint, Call(7)); - EXPECT_CALL(checkpoint, Call(8)); - EXPECT_CALL(checkpoint, Call(9)); - EXPECT_CALL(*m_underlyingSource, pullSource()); - } - StringStream* stream = new StringStream(m_underlyingSource, new StringStream::StrictStrategy); - ReadableStreamReader* reader = stream->getReader(getScriptState()->getExecutionContext(), exceptionState); - - checkpoint.Call(0); - stream->didSourceStart(); - - checkpoint.Call(1); - EXPECT_FALSE(stream->isPulling()); - reader->read(getScriptState()); - EXPECT_TRUE(stream->isPulling()); - checkpoint.Call(2); - stream->enqueue("hello"); - EXPECT_FALSE(stream->isPulling()); - checkpoint.Call(3); - reader->read(getScriptState()); - EXPECT_TRUE(stream->isPulling()); - checkpoint.Call(4); - reader->read(getScriptState()); - EXPECT_TRUE(stream->isPulling()); - checkpoint.Call(5); - stream->enqueue("hello"); - EXPECT_FALSE(stream->isPulling()); - checkpoint.Call(6); - stream->enqueue("hello"); - EXPECT_FALSE(stream->isPulling()); - checkpoint.Call(7); - stream->enqueue("hello"); - EXPECT_FALSE(stream->isPulling()); - checkpoint.Call(8); - reader->read(getScriptState()); - EXPECT_FALSE(stream->isPulling()); - checkpoint.Call(9); - reader->read(getScriptState()); - EXPECT_TRUE(stream->isPulling()); - - stream->error(DOMException::create(AbortError, "done")); -} - -} // namespace blink
diff --git a/third_party/WebKit/Source/core/streams/UnderlyingSource.h b/third_party/WebKit/Source/core/streams/UnderlyingSource.h deleted file mode 100644 index 14b9d843..0000000 --- a/third_party/WebKit/Source/core/streams/UnderlyingSource.h +++ /dev/null
@@ -1,29 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UnderlyingSource_h -#define UnderlyingSource_h - -#include "bindings/core/v8/ScriptPromise.h" -#include "bindings/core/v8/ScriptValue.h" -#include "core/CoreExport.h" -#include "platform/heap/Heap.h" - -namespace blink { - -class ScriptState; - -class CORE_EXPORT UnderlyingSource : public GarbageCollectedMixin { -public: - virtual ~UnderlyingSource() { } - - virtual void pullSource() = 0; - virtual ScriptPromise cancelSource(ScriptState*, ScriptValue reason) = 0; - DEFINE_INLINE_VIRTUAL_TRACE() { } -}; - -} // namespace blink - -#endif // UnderlyingSource_h -
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.cpp b/third_party/WebKit/Source/core/style/ComputedStyle.cpp index 984ff42..2068109 100644 --- a/third_party/WebKit/Source/core/style/ComputedStyle.cpp +++ b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
@@ -52,6 +52,7 @@ #include "platform/transforms/TranslateTransformOperation.h" #include "wtf/MathExtras.h" #include "wtf/PtrUtil.h" +#include "wtf/SaturatedArithmetic.h" #include <algorithm> #include <memory> @@ -666,7 +667,7 @@ return true; } - if ((visibility() == COLLAPSE) != (other.visibility() == COLLAPSE)) + if ((visibility() == EVisibility::Collapse) != (other.visibility() == EVisibility::Collapse)) return true; if (hasPseudoStyle(PseudoIdScrollbar) != other.hasPseudoStyle(PseudoIdScrollbar)) @@ -1534,6 +1535,13 @@ m_rareInheritedData.access()->appliedTextDecorations = nullptr; } +void ComputedStyle::restoreParentTextDecorations(const ComputedStyle& parentStyle) +{ + m_inheritedData.m_textUnderline = parentStyle.m_inheritedData.m_textUnderline; + if (m_rareInheritedData->appliedTextDecorations != parentStyle.m_rareInheritedData->appliedTextDecorations) + m_rareInheritedData.access()->appliedTextDecorations = parentStyle.m_rareInheritedData->appliedTextDecorations; +} + void ComputedStyle::clearMultiCol() { m_rareNonInheritedData.access()->m_multiCol = nullptr; @@ -1784,7 +1792,7 @@ return 0; if (outlineStyleIsAuto()) return GraphicsContext::focusRingOutsetExtent(outlineOffset(), outlineWidth()); - return std::max(0, outlineWidth() + outlineOffset()); + return std::max(0, saturatedAddition(outlineWidth(), outlineOffset())); } bool ComputedStyle::columnRuleEquivalent(const ComputedStyle* otherStyle) const
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.h b/third_party/WebKit/Source/core/style/ComputedStyle.h index 99a0ddb..3657eae 100644 --- a/third_party/WebKit/Source/core/style/ComputedStyle.h +++ b/third_party/WebKit/Source/core/style/ComputedStyle.h
@@ -298,7 +298,7 @@ m_inheritedData.m_captionSide = initialCaptionSide(); m_inheritedData.m_listStyleType = initialListStyleType(); m_inheritedData.m_listStylePosition = initialListStylePosition(); - m_inheritedData.m_visibility = initialVisibility(); + m_inheritedData.m_visibility = static_cast<unsigned>(initialVisibility()); m_inheritedData.m_textAlign = initialTextAlign(); m_inheritedData.m_textTransform = initialTextTransform(); m_inheritedData.m_textUnderline = false; @@ -1468,9 +1468,9 @@ void setTextTransform(ETextTransform v) { m_inheritedData.m_textTransform = v; } // visibility - static EVisibility initialVisibility() { return VISIBLE; } + static EVisibility initialVisibility() { return EVisibility::Visible; } EVisibility visibility() const { return static_cast<EVisibility>(m_inheritedData.m_visibility); } - void setVisibility(EVisibility v) { m_inheritedData.m_visibility = v; } + void setVisibility(EVisibility v) { m_inheritedData.m_visibility = static_cast<unsigned>(v); } // white-space inherited static EWhiteSpace initialWhiteSpace() { return NORMAL; } @@ -2161,11 +2161,15 @@ // Text decoration utility functions. void applyTextDecorations(); void clearAppliedTextDecorations(); + void restoreParentTextDecorations(const ComputedStyle& parentStyle); const Vector<AppliedTextDecoration>& appliedTextDecorations() const; TextDecoration textDecorationsInEffect() const; // Overflow utility functions. + EOverflow overflowInlineDirection() const { return isHorizontalWritingMode() ? overflowX() : overflowY(); } + EOverflow overflowBlockDirection() const { return isHorizontalWritingMode() ? overflowY() : overflowX(); } + // It's sufficient to just check one direction, since it's illegal to have visible on only one overflow value. bool isOverflowVisible() const { DCHECK(overflowX() != OverflowVisible || overflowX() == overflowY()); return overflowX() == OverflowVisible; } bool isOverflowPaged() const { return overflowY() == OverflowPagedX || overflowY() == OverflowPagedY; } @@ -2317,6 +2321,7 @@ // Border utility functions. bool borderObscuresBackground() const; void getBorderEdgeInfo(BorderEdge edges[], bool includeLogicalLeftEdge = true, bool includeLogicalRightEdge = true) const; + bool hasBoxDecorations() const { return hasBorderDecoration() @@ -2329,6 +2334,14 @@ || resize() != RESIZE_NONE; } + // "Box decoration background" includes all box decorations and backgrounds + // that are painted as the background of the object. It includes borders, + // box-shadows, background-color and background-image, etc. + bool hasBoxDecorationBackground() const + { + return hasBackground() || hasBorderDecoration() || hasAppearance() || boxShadow(); + } + // Background utility functions. FillLayer& accessBackgroundLayers() { return m_background.access()->m_background; } const FillLayer& backgroundLayers() const { return m_background->background(); }
diff --git a/third_party/WebKit/Source/core/style/ComputedStyleConstants.h b/third_party/WebKit/Source/core/style/ComputedStyleConstants.h index f9b57ee..57a6689 100644 --- a/third_party/WebKit/Source/core/style/ComputedStyleConstants.h +++ b/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
@@ -30,6 +30,11 @@ namespace blink { +// TODO(sashab): Change these enums to enum classes with an unsigned underlying +// type. Enum classes provide better type safety, and forcing an unsigned +// underlying type prevents msvc from interpreting enums as negative numbers. +// See: crbug.com/628043 + // Sides used when drawing borders and outlines. The values should run clockwise from top. enum BoxSide { BSTop, @@ -386,7 +391,9 @@ enum EListStylePosition { ListStylePositionOutside, ListStylePositionInside }; -enum EVisibility { VISIBLE, HIDDEN, COLLAPSE }; +// TODO(sashab): Add a static_assert when this is used in bitfields to ensure it +// uses unsigned as the underlying type. +enum class EVisibility : unsigned { Visible, Hidden, Collapse }; enum ECursor { // The following must match the order in CSSValueKeywords.in.
diff --git a/third_party/WebKit/Source/core/style/StyleBoxData.h b/third_party/WebKit/Source/core/style/StyleBoxData.h index 6086d373..0c556009 100644 --- a/third_party/WebKit/Source/core/style/StyleBoxData.h +++ b/third_party/WebKit/Source/core/style/StyleBoxData.h
@@ -25,6 +25,7 @@ #ifndef StyleBoxData_h #define StyleBoxData_h +#include "core/CoreExport.h" #include "core/style/ComputedStyleConstants.h" #include "platform/Length.h" #include "wtf/PassRefPtr.h" @@ -35,7 +36,7 @@ // TODO(sashab): Move this into a private class on ComputedStyle, and remove // all methods on it, merging them into copy/creation methods on ComputedStyle // instead. Keep the allocation logic, only allocating a new object if needed. -class StyleBoxData : public RefCounted<StyleBoxData> { +class CORE_EXPORT StyleBoxData : public RefCounted<StyleBoxData> { public: static PassRefPtr<StyleBoxData> create() { return adoptRef(new StyleBoxData); } PassRefPtr<StyleBoxData> copy() const { return adoptRef(new StyleBoxData(*this)); }
diff --git a/third_party/WebKit/Source/core/svg/SVGUseElement.cpp b/third_party/WebKit/Source/core/svg/SVGUseElement.cpp index c8a31ffc..538be62 100644 --- a/third_party/WebKit/Source/core/svg/SVGUseElement.cpp +++ b/third_party/WebKit/Source/core/svg/SVGUseElement.cpp
@@ -515,7 +515,7 @@ return nullptr; const ComputedStyle* style = element.layoutObject()->style(); - if (!style || style->visibility() != VISIBLE) + if (!style || style->visibility() != EVisibility::Visible) return nullptr; // Spec: "If a <use> element is a child of a clipPath element, it must directly
diff --git a/third_party/WebKit/Source/core/svg/SVGViewElement.cpp b/third_party/WebKit/Source/core/svg/SVGViewElement.cpp index 7d0ed4f9..45c5126 100644 --- a/third_party/WebKit/Source/core/svg/SVGViewElement.cpp +++ b/third_party/WebKit/Source/core/svg/SVGViewElement.cpp
@@ -20,6 +20,8 @@ #include "core/svg/SVGViewElement.h" +#include "core/frame/UseCounter.h" + namespace blink { inline SVGViewElement::SVGViewElement(Document& document) @@ -28,6 +30,7 @@ , m_viewTarget(SVGStaticStringList::create(this, SVGNames::viewTargetAttr)) { addToPropertyMap(m_viewTarget); + UseCounter::count(document, UseCounter::SVGViewElement); } DEFINE_NODE_FACTORY(SVGViewElement)
diff --git a/third_party/WebKit/Source/core/svg/animation/SMILTimeContainer.cpp b/third_party/WebKit/Source/core/svg/animation/SMILTimeContainer.cpp index fde1701..32ccfa0 100644 --- a/third_party/WebKit/Source/core/svg/animation/SMILTimeContainer.cpp +++ b/third_party/WebKit/Source/core/svg/animation/SMILTimeContainer.cpp
@@ -26,7 +26,7 @@ #include "core/svg/animation/SMILTimeContainer.h" #include "core/animation/AnimationClock.h" -#include "core/animation/AnimationTimeline.h" +#include "core/animation/DocumentTimeline.h" #include "core/dom/ElementTraversal.h" #include "core/frame/FrameView.h" #include "core/frame/Settings.h"
diff --git a/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp b/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp index 6e9bfe2..4a867cb 100644 --- a/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp +++ b/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp
@@ -27,7 +27,7 @@ #include "core/svg/graphics/SVGImage.h" -#include "core/animation/AnimationTimeline.h" +#include "core/animation/DocumentTimeline.h" #include "core/dom/NodeTraversal.h" #include "core/dom/shadow/FlatTreeTraversal.h" #include "core/frame/Deprecation.h"
diff --git a/third_party/WebKit/Source/core/svg/graphics/SVGImageTest.cpp b/third_party/WebKit/Source/core/svg/graphics/SVGImageTest.cpp index 465a932..a173e77 100644 --- a/third_party/WebKit/Source/core/svg/graphics/SVGImageTest.cpp +++ b/third_party/WebKit/Source/core/svg/graphics/SVGImageTest.cpp
@@ -43,6 +43,7 @@ std::unique_ptr<WebTaskRunner> clone() override { return nullptr; } double virtualTimeSeconds() const override { return 0.0; } double monotonicallyIncreasingVirtualTimeSeconds() const override { return m_time; } + SingleThreadTaskRunner* taskRunner() override { return nullptr; } double m_time; Task* m_currentTask;
diff --git a/third_party/WebKit/Source/core/testing/Internals.cpp b/third_party/WebKit/Source/core/testing/Internals.cpp index fa5e387..618dd6a 100644 --- a/third_party/WebKit/Source/core/testing/Internals.cpp +++ b/third_party/WebKit/Source/core/testing/Internals.cpp
@@ -37,7 +37,7 @@ #include "bindings/core/v8/V8ThrowException.h" #include "core/HTMLNames.h" #include "core/SVGNames.h" -#include "core/animation/AnimationTimeline.h" +#include "core/animation/DocumentTimeline.h" #include "core/css/StyleSheetContents.h" #include "core/css/resolver/StyleResolver.h" #include "core/css/resolver/StyleResolverStats.h" @@ -2618,4 +2618,12 @@ return String(); } +ClientRect* Internals::visualRect(Node* node) +{ + if (!node || !node->layoutObject()) + return ClientRect::create(); + + return ClientRect::create(FloatRect(node->layoutObject()->visualRect())); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/testing/Internals.h b/third_party/WebKit/Source/core/testing/Internals.h index 674cd8d6..9ada88e8 100644 --- a/third_party/WebKit/Source/core/testing/Internals.h +++ b/third_party/WebKit/Source/core/testing/Internals.h
@@ -400,6 +400,9 @@ // or -1 if the node does not have a scrollable area. String getProgrammaticScrollAnimationState(Node*) const; + // Returns the visual rect of a node's LayoutObject. + ClientRect* visualRect(Node*); + private: explicit Internals(ScriptState*); Document* contextDocument() const;
diff --git a/third_party/WebKit/Source/core/testing/Internals.idl b/third_party/WebKit/Source/core/testing/Internals.idl index 64012a1..921e6ec 100644 --- a/third_party/WebKit/Source/core/testing/Internals.idl +++ b/third_party/WebKit/Source/core/testing/Internals.idl
@@ -350,4 +350,6 @@ DOMString getScrollAnimationState(Node node); DOMString getProgrammaticScrollAnimationState(Node node); + + ClientRect visualRect(Node node); };
diff --git a/third_party/WebKit/Source/core/workers/DedicatedWorkerThread.cpp b/third_party/WebKit/Source/core/workers/DedicatedWorkerThread.cpp index 371c153..5e2d388 100644 --- a/third_party/WebKit/Source/core/workers/DedicatedWorkerThread.cpp +++ b/third_party/WebKit/Source/core/workers/DedicatedWorkerThread.cpp
@@ -61,11 +61,6 @@ return DedicatedWorkerGlobalScope::create(this, std::move(startupData), m_timeOrigin); } -ConsoleMessageStorage* DedicatedWorkerThread::consoleMessageStorage() -{ - return toWorkerGlobalScope(globalScope())->consoleMessageStorage(); -} - void DedicatedWorkerThread::postInitialize() { // Notify the parent object of our current active state before the event
diff --git a/third_party/WebKit/Source/core/workers/DedicatedWorkerThread.h b/third_party/WebKit/Source/core/workers/DedicatedWorkerThread.h index c45a7ca..84ecd4e 100644 --- a/third_party/WebKit/Source/core/workers/DedicatedWorkerThread.h +++ b/third_party/WebKit/Source/core/workers/DedicatedWorkerThread.h
@@ -44,7 +44,6 @@ ~DedicatedWorkerThread() override; WorkerBackingThread& workerBackingThread() override { return *m_workerBackingThread; } - ConsoleMessageStorage* consoleMessageStorage() final; InProcessWorkerObjectProxy& workerObjectProxy() const { return m_workerObjectProxy; } protected:
diff --git a/third_party/WebKit/Source/core/workers/SharedWorkerThread.cpp b/third_party/WebKit/Source/core/workers/SharedWorkerThread.cpp index 3f6fc676..3a4cd8a 100644 --- a/third_party/WebKit/Source/core/workers/SharedWorkerThread.cpp +++ b/third_party/WebKit/Source/core/workers/SharedWorkerThread.cpp
@@ -59,9 +59,4 @@ return SharedWorkerGlobalScope::create(m_name, this, std::move(startupData)); } -ConsoleMessageStorage* SharedWorkerThread::consoleMessageStorage() -{ - return toWorkerGlobalScope(globalScope())->consoleMessageStorage(); -} - } // namespace blink
diff --git a/third_party/WebKit/Source/core/workers/SharedWorkerThread.h b/third_party/WebKit/Source/core/workers/SharedWorkerThread.h index 002c791..33dc26b 100644 --- a/third_party/WebKit/Source/core/workers/SharedWorkerThread.h +++ b/third_party/WebKit/Source/core/workers/SharedWorkerThread.h
@@ -45,7 +45,6 @@ ~SharedWorkerThread() override; WorkerBackingThread& workerBackingThread() override { return *m_workerBackingThread; } - ConsoleMessageStorage* consoleMessageStorage() final; protected: WorkerOrWorkletGlobalScope* createWorkerGlobalScope(std::unique_ptr<WorkerThreadStartupData>) override;
diff --git a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp index a272b97..4d5192d 100644 --- a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp +++ b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
@@ -259,7 +259,7 @@ { DCHECK(isContextThread()); thread()->workerReportingProxy().reportConsoleMessage(consoleMessage->source(), consoleMessage->level(), consoleMessage->message(), consoleMessage->location()); - m_consoleMessageStorage->addConsoleMessage(this, consoleMessage); + thread()->consoleMessageStorage()->addConsoleMessage(this, consoleMessage); } WorkerEventQueue* WorkerGlobalScope::getEventQueue() const @@ -297,7 +297,6 @@ , m_workerClients(workerClients) , m_timers(Platform::current()->currentThread()->scheduler()->timerTaskRunner()->clone()) , m_timeOrigin(timeOrigin) - , m_consoleMessageStorage(new ConsoleMessageStorage()) , m_lastPendingErrorEventId(0) { setSecurityOrigin(SecurityOrigin::create(url)); @@ -349,7 +348,6 @@ visitor->trace(m_eventQueue); visitor->trace(m_workerClients); visitor->trace(m_timers); - visitor->trace(m_consoleMessageStorage); visitor->trace(m_eventListeners); visitor->trace(m_pendingErrorEvents); ExecutionContext::trace(visitor);
diff --git a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h index 22934d7..1c7cdd4c 100644 --- a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h +++ b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
@@ -128,7 +128,6 @@ WorkerOrWorkletScriptController* scriptController() final { return m_scriptController.get(); } WorkerClients* clients() { return m_workerClients.get(); } - ConsoleMessageStorage* consoleMessageStorage() { return m_consoleMessageStorage.get(); } DECLARE_VIRTUAL_TRACE(); @@ -175,8 +174,6 @@ const double m_timeOrigin; - Member<ConsoleMessageStorage> m_consoleMessageStorage; - HeapListHashSet<Member<V8AbstractEventListener>> m_eventListeners; HeapHashMap<int, Member<ErrorEvent>> m_pendingErrorEvents;
diff --git a/third_party/WebKit/Source/core/workers/WorkerThread.cpp b/third_party/WebKit/Source/core/workers/WorkerThread.cpp index a65ac133..8b7022d 100644 --- a/third_party/WebKit/Source/core/workers/WorkerThread.cpp +++ b/third_party/WebKit/Source/core/workers/WorkerThread.cpp
@@ -31,6 +31,7 @@ #include "bindings/core/v8/V8GCController.h" #include "bindings/core/v8/V8IdleTaskRunner.h" #include "bindings/core/v8/WorkerOrWorkletScriptController.h" +#include "core/inspector/ConsoleMessageStorage.h" #include "core/inspector/InspectorInstrumentation.h" #include "core/inspector/InspectorTaskRunner.h" #include "core/inspector/WorkerInspectorController.h" @@ -492,6 +493,7 @@ // Optimize for memory usage instead of latency for the worker isolate. isolate()->IsolateInBackgroundNotification(); + m_consoleMessageStorage = new ConsoleMessageStorage(); m_globalScope = createWorkerGlobalScope(std::move(startupData)); m_workerInspectorController = WorkerInspectorController::create(this); if (m_globalScope->isWorkerGlobalScope()) @@ -563,6 +565,7 @@ m_workerInspectorController->dispose(); m_workerInspectorController.clear(); } + m_consoleMessageStorage.clear(); workerBackingThread().backingThread().removeTaskObserver(m_microtaskRunner.get()); }
diff --git a/third_party/WebKit/Source/core/workers/WorkerThread.h b/third_party/WebKit/Source/core/workers/WorkerThread.h index ffdf714..834fda0 100644 --- a/third_party/WebKit/Source/core/workers/WorkerThread.h +++ b/third_party/WebKit/Source/core/workers/WorkerThread.h
@@ -109,7 +109,7 @@ static void terminateAndWaitForAllWorkers(); virtual WorkerBackingThread& workerBackingThread() = 0; - virtual ConsoleMessageStorage* consoleMessageStorage() = 0; + ConsoleMessageStorage* consoleMessageStorage() const { return m_consoleMessageStorage.get(); } virtual bool shouldAttachThreadDebugger() const { return true; } v8::Isolate* isolate(); @@ -238,6 +238,7 @@ // |m_runningDebuggerTask|, |m_exitCode| and |m_microtaskRunner|. Mutex m_threadStateMutex; + Persistent<ConsoleMessageStorage> m_consoleMessageStorage; Persistent<WorkerOrWorkletGlobalScope> m_globalScope; Persistent<WorkerInspectorController> m_workerInspectorController;
diff --git a/third_party/WebKit/Source/core/workers/WorkerThreadTestHelper.h b/third_party/WebKit/Source/core/workers/WorkerThreadTestHelper.h index 2bd9a65..e46d804 100644 --- a/third_party/WebKit/Source/core/workers/WorkerThreadTestHelper.h +++ b/third_party/WebKit/Source/core/workers/WorkerThreadTestHelper.h
@@ -93,7 +93,6 @@ ~WorkerThreadForTest() override { } WorkerBackingThread& workerBackingThread() override { return *m_workerBackingThread; } - ConsoleMessageStorage* consoleMessageStorage() final { return toWorkerGlobalScope(globalScope())->consoleMessageStorage(); } WorkerOrWorkletGlobalScope* createWorkerGlobalScope(std::unique_ptr<WorkerThreadStartupData>) override;
diff --git a/third_party/WebKit/Source/devtools/devtools.gypi b/third_party/WebKit/Source/devtools/devtools.gypi index 1f04b761..330a1e6 100644 --- a/third_party/WebKit/Source/devtools/devtools.gypi +++ b/third_party/WebKit/Source/devtools/devtools.gypi
@@ -653,7 +653,6 @@ 'front_end/source_frame/cmdevtools.css', 'front_end/source_frame/fontView.css', 'front_end/source_frame/imageView.css', - 'front_end/source_frame/CodeMirrorDictionary.js', 'front_end/source_frame/CodeMirrorTextEditor.js', 'front_end/source_frame/CodeMirrorUtils.js', 'front_end/source_frame/FontView.js',
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes b/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes index a4571301..f3169eb 100644 --- a/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes +++ b/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes
@@ -3,7 +3,7 @@ "breakpointConditional.svg": "4cf90210b2af2ed84db2f60b07bcde28", "errorWave.svg": "e183fa242a22ed4784a92f6becbc2c45", "settingsListRemove.svg": "ce9e7c5c5cdaef28e6ee51d9478d5485", - "toolbarButtonGlyphs.svg": "8e895729ba7499dc478860a078c21696", + "toolbarButtonGlyphs.svg": "337f27abe1f69c6e5501ec2412476bf7", "breakpoint.svg": "69cd92d807259c022791112809b97799", "search.svg": "fc990dd3836aec510d7ca1f36c2a3142" } \ No newline at end of file
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes b/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes index a4571301..f3169eb 100644 --- a/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes +++ b/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes
@@ -3,7 +3,7 @@ "breakpointConditional.svg": "4cf90210b2af2ed84db2f60b07bcde28", "errorWave.svg": "e183fa242a22ed4784a92f6becbc2c45", "settingsListRemove.svg": "ce9e7c5c5cdaef28e6ee51d9478d5485", - "toolbarButtonGlyphs.svg": "8e895729ba7499dc478860a078c21696", + "toolbarButtonGlyphs.svg": "337f27abe1f69c6e5501ec2412476bf7", "breakpoint.svg": "69cd92d807259c022791112809b97799", "search.svg": "fc990dd3836aec510d7ca1f36c2a3142" } \ No newline at end of file
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/src/toolbarButtonGlyphs.svg b/third_party/WebKit/Source/devtools/front_end/Images/src/toolbarButtonGlyphs.svg index a359ac29..ecd70de 100644 --- a/third_party/WebKit/Source/devtools/front_end/Images/src/toolbarButtonGlyphs.svg +++ b/third_party/WebKit/Source/devtools/front_end/Images/src/toolbarButtonGlyphs.svg
@@ -21,9 +21,9 @@ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><sodipodi:namedview showgrid="true" id="namedview3397" - inkscape:zoom="3.3551137" - inkscape:cx="162.39793" - inkscape:cy="66.119008" + inkscape:zoom="13.420455" + inkscape:cx="217.56822" + inkscape:cy="49.153235" inkscape:window-width="1766" inkscape:window-height="1118" inkscape:window-x="238" @@ -739,7 +739,8 @@ id="path3963" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc" /><g - id="g3234"><path + id="g3234" + transform="translate(1,0)"><path style="fill:url(#linearGradient3239)" inkscape:connector-curvature="0" id="path3699-5" @@ -1071,4 +1072,9 @@ style="fill:#5b5b5b" inkscape:connector-curvature="0" d="M 10.192064,11.106277 C 9.4413335,11.667599 8.509485,12 7.5,12 5.0147186,12 3,9.9852814 3,7.5 3,5.0147186 5.0147186,3 7.5,3 9.9852814,3 12,5.0147186 12,7.5 c 0,1.1153728 -0.405792,2.1359679 -1.077795,2.922205 l 2.345562,2.345562 -0.707107,0.707107 -2.368596,-2.368597 z M 7.5,11 C 9.4329966,11 11,9.4329966 11,7.5 11,5.5670034 9.4329966,4 7.5,4 5.5670034,4 4,5.5670034 4,7.5 4,9.4329966 5.5670034,11 7.5,11 z" - id="path3730" /></g></g></svg> \ No newline at end of file + id="path3730" /></g></g><path + inkscape:connector-curvature="0" + id="path3660" + d="m 236,115 4,0 0,2 5,-4.5 -5,-4.5 0,2 -4,0 z" + style="fill:#4688f1;fill-opacity:1" + sodipodi:nodetypes="cccccccc" /></svg> \ No newline at end of file
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs.png b/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs.png index 769fee0b..6982b00 100644 --- a/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs.png +++ b/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs.png Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs_2x.png b/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs_2x.png index 67d61f51..ddf5f38 100644 --- a/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs_2x.png +++ b/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs_2x.png Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/common/TextDictionary.js b/third_party/WebKit/Source/devtools/front_end/common/TextDictionary.js index 76abb69..f7817fb 100644 --- a/third_party/WebKit/Source/devtools/front_end/common/TextDictionary.js +++ b/third_party/WebKit/Source/devtools/front_end/common/TextDictionary.js
@@ -33,7 +33,8 @@ */ WebInspector.TextDictionary = function() { - this._words = {}; + /** @type {!Map<string, number>} */ + this._words = new Map(); } WebInspector.TextDictionary.prototype = { @@ -42,10 +43,9 @@ */ addWord: function(word) { - if (!this._words[word]) - this._words[word] = 1; - else - ++this._words[word]; + var count = this._words.get(word) || 0; + ++count; + this._words.set(word, count); }, /** @@ -53,12 +53,15 @@ */ removeWord: function(word) { - if (!this._words[word]) + var count = this._words.get(word) || 0; + if (!count) return; - if (this._words[word] === 1) - delete this._words[word]; - else - --this._words[word]; + if (count === 1) { + this._words.delete(word); + return; + } + --count; + this._words.set(word, count); }, /** @@ -68,9 +71,9 @@ wordsWithPrefix: function(prefix) { var words = []; - for (var i in this._words) { - if (i.startsWith(prefix)) - words.push(i); + for (var word of this._words.keys()) { + if (word.startsWith(prefix)) + words.push(word); } return words; }, @@ -81,7 +84,7 @@ */ hasWord: function(word) { - return !!this._words[word]; + return this._words.has(word); }, /** @@ -90,11 +93,11 @@ */ wordCount: function(word) { - return this._words[word] ? this._words[word] : 0; + return this._words.get(word) || 0; }, reset: function() { - this._words = {}; + this._words.clear(); } }
diff --git a/third_party/WebKit/Source/devtools/front_end/source_frame/CodeMirrorDictionary.js b/third_party/WebKit/Source/devtools/front_end/source_frame/CodeMirrorDictionary.js deleted file mode 100644 index a110a50..0000000 --- a/third_party/WebKit/Source/devtools/front_end/source_frame/CodeMirrorDictionary.js +++ /dev/null
@@ -1,146 +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. - -/** - * @constructor - * @param {!CodeMirror} codeMirror - * @param {string=} additionalWordChars - */ -WebInspector.CodeMirrorDictionary = function(codeMirror, additionalWordChars) -{ - this._codeMirror = codeMirror; - this._additionalWordChars = new Set(/** @type {!Iterable} */ (additionalWordChars)); - this._dictionary = new WebInspector.TextDictionary(); - this._addText(this._codeMirror.getValue()); - - this._changes = this._changes.bind(this); - this._beforeChange = this._beforeChange.bind(this); - this._codeMirror.on("beforeChange", this._beforeChange); - this._codeMirror.on("changes", this._changes); -} - -WebInspector.CodeMirrorDictionary.prototype = { - /** - * @param {!CodeMirror} codeMirror - * @param {!CodeMirror.BeforeChangeObject} changeObject - */ - _beforeChange: function(codeMirror, changeObject) - { - this._updatedLines = this._updatedLines || {}; - for (var i = changeObject.from.line; i <= changeObject.to.line; ++i) - this._updatedLines[i] = this._codeMirror.getLine(i); - }, - - /** - * @param {!CodeMirror} codeMirror - * @param {!Array.<!CodeMirror.ChangeObject>} changes - */ - _changes: function(codeMirror, changes) - { - if (!changes.length || !this._updatedLines) - return; - - for (var lineNumber in this._updatedLines) - this._removeText(this._updatedLines[lineNumber]); - delete this._updatedLines; - - var linesToUpdate = {}; - for (var changeIndex = 0; changeIndex < changes.length; ++changeIndex) { - var changeObject = changes[changeIndex]; - var editInfo = WebInspector.CodeMirrorUtils.changeObjectToEditOperation(changeObject); - for (var i = editInfo.newRange.startLine; i <= editInfo.newRange.endLine; ++i) - linesToUpdate[i] = this._codeMirror.getLine(i); - } - for (var lineNumber in linesToUpdate) - this._addText(linesToUpdate[lineNumber]); - }, - - /** - * @param {string} word - * @return {boolean} - */ - _validWord: function(word) - { - return !!word.length && (word[0] < "0" || word[0] > "9"); - }, - - /** - * @param {string} text - */ - _addText: function(text) - { - WebInspector.TextUtils.textToWords(text, this.isWordChar.bind(this), addWord.bind(this)); - - /** - * @param {string} word - * @this {WebInspector.CodeMirrorDictionary} - */ - function addWord(word) - { - if (this._validWord(word)) - this._dictionary.addWord(word); - } - }, - - /** - * @param {string} text - */ - _removeText: function(text) - { - WebInspector.TextUtils.textToWords(text, this.isWordChar.bind(this), removeWord.bind(this)); - - /** - * @param {string} word - * @this {WebInspector.CodeMirrorDictionary} - */ - function removeWord(word) - { - if (this._validWord(word)) - this._dictionary.removeWord(word); - } - }, - - /** - * @param {string} char - * @return {boolean} - */ - isWordChar: function(char) - { - return WebInspector.TextUtils.isWordChar(char) || this._additionalWordChars.has(char); - }, - - /** - * @param {string} prefix - * @return {!Array.<string>} - */ - wordsWithPrefix: function(prefix) - { - return this._dictionary.wordsWithPrefix(prefix); - }, - - /** - * @param {string} word - * @return {boolean} - */ - hasWord: function(word) - { - return this._dictionary.hasWord(word); - }, - - /** - * @param {string} word - * @return {number} - */ - wordCount: function(word) - { - return this._dictionary.wordCount(word); - }, - - dispose: function() - { - this._codeMirror.off("beforeChange", this._beforeChange); - this._codeMirror.off("changes", this._changes); - this._dictionary.reset(); - }, -}
diff --git a/third_party/WebKit/Source/devtools/front_end/source_frame/CodeMirrorTextEditor.js b/third_party/WebKit/Source/devtools/front_end/source_frame/CodeMirrorTextEditor.js index b6583fa..baa31c1 100644 --- a/third_party/WebKit/Source/devtools/front_end/source_frame/CodeMirrorTextEditor.js +++ b/third_party/WebKit/Source/devtools/front_end/source_frame/CodeMirrorTextEditor.js
@@ -148,15 +148,11 @@ this._shouldClearHistory = true; this._lineSeparator = "\n"; - this._autocompleteController = new WebInspector.TextEditorAutocompleteController(this, this._codeMirror); this._tokenHighlighter = new WebInspector.CodeMirrorTextEditor.TokenHighlighter(this, this._codeMirror); this._blockIndentController = new WebInspector.CodeMirrorTextEditor.BlockIndentController(this._codeMirror); this._fixWordMovement = new WebInspector.CodeMirrorTextEditor.FixWordMovement(this._codeMirror); this._selectNextOccurrenceController = new WebInspector.CodeMirrorTextEditor.SelectNextOccurrenceController(this, this._codeMirror); - WebInspector.moduleSetting("textEditorAutocompletion").addChangeListener(this._enableAutocompletionIfNeeded, this); - this._enableAutocompletionIfNeeded(); - this._codeMirror.on("changes", this._changes.bind(this)); this._codeMirror.on("gutterClick", this._gutterClick.bind(this)); this._codeMirror.on("cursorActivity", this._cursorActivity.bind(this)); @@ -196,7 +192,9 @@ */ WebInspector.CodeMirrorTextEditor.autocompleteCommand = function(codeMirror) { - codeMirror._codeMirrorTextEditor._autocompleteController.autocomplete(); + var autocompleteController = codeMirror._codeMirrorTextEditor._autocompleteController; + if (autocompleteController) + autocompleteController.autocomplete(); } CodeMirror.commands.autocomplete = WebInspector.CodeMirrorTextEditor.autocompleteCommand; @@ -296,7 +294,9 @@ codemirror.execCommand("undo"); var cursor = codemirror.getCursor("start"); codemirror._codeMirrorTextEditor._innerRevealLine(cursor.line, scrollInfo); - codemirror._codeMirrorTextEditor._autocompleteController.finishAutocomplete(); + var autocompleteController = codemirror._codeMirrorTextEditor._autocompleteController; + if (autocompleteController) + autocompleteController.finishAutocomplete(); } /** @@ -308,7 +308,9 @@ codemirror.execCommand("redo"); var cursor = codemirror.getCursor("start"); codemirror._codeMirrorTextEditor._innerRevealLine(cursor.line, scrollInfo); - codemirror._codeMirrorTextEditor._autocompleteController.finishAutocomplete(); + var autocompleteController = codemirror._codeMirrorTextEditor._autocompleteController; + if (autocompleteController) + autocompleteController.finishAutocomplete(); } /** @@ -409,20 +411,6 @@ WebInspector.CodeMirrorTextEditor.prototype = { - /** - * @param {string=} additionalWordChars - * @return {!WebInspector.CodeMirrorDictionary} - */ - createTextDictionary: function(additionalWordChars) - { - return new WebInspector.CodeMirrorDictionary(this._codeMirror, additionalWordChars); - }, - - _enableAutocompletionIfNeeded: function() - { - this._autocompleteController.setEnabled(WebInspector.moduleSetting("textEditorAutocompletion").get()); - }, - _onKeyHandled: function() { WebInspector.shortcutRegistry.dismissPendingShortcutAction(); @@ -601,7 +589,6 @@ WebInspector.moduleSetting("textEditorAutoDetectIndent").removeChangeListener(this._onUpdateEditorIndentation, this); WebInspector.moduleSetting("showWhitespacesInEditor").removeChangeListener(this._updateCodeMirrorMode, this); WebInspector.moduleSetting("textEditorBracketMatching").removeChangeListener(this._enableBracketMatchingIfNeeded, this); - WebInspector.moduleSetting("textEditorAutocompletion").removeChangeListener(this._enableAutocompletionIfNeeded, this); }, _enableBracketMatchingIfNeeded: function() @@ -742,7 +729,7 @@ _handleKeyDown: function(e) { - if (this._autocompleteController.keyDown(e)) + if (this._autocompleteController && this._autocompleteController.keyDown(e)) e.consume(true); }, @@ -753,11 +740,17 @@ }, /** - * @param {!WebInspector.TextEditorAutocompleteDelegate} delegate + * @param {?WebInspector.AutocompleteConfig} config */ - setAutocompleteDelegate: function(delegate) + configureAutocomplete: function(config) { - this._autocompleteController.setDelegate(delegate); + if (this._autocompleteController) { + this._autocompleteController.dispose(); + delete this._autocompleteController; + } + + if (config) + this._autocompleteController = new WebInspector.TextEditorAutocompleteController(this, this._codeMirror, config); }, /** @@ -1339,7 +1332,8 @@ */ onResize: function() { - this._autocompleteController.finishAutocomplete(); + if (this._autocompleteController) + this._autocompleteController.finishAutocomplete(); this._resizeEditor(); this._editorSizeInSync = true; if (this._selectionSetScheduled) { @@ -1593,7 +1587,7 @@ { this._muteTextChangedEvent = true; if (text.length > WebInspector.CodeMirrorTextEditor.MaxEditableTextSize) { - this._autocompleteController.setEnabled(false); + this.configureAutocomplete(null); this.setReadOnly(true); }
diff --git a/third_party/WebKit/Source/devtools/front_end/source_frame/TextEditorAutocompleteController.js b/third_party/WebKit/Source/devtools/front_end/source_frame/TextEditorAutocompleteController.js index 7451eec..2cc0c17 100644 --- a/third_party/WebKit/Source/devtools/front_end/source_frame/TextEditorAutocompleteController.js +++ b/third_party/WebKit/Source/devtools/front_end/source_frame/TextEditorAutocompleteController.js
@@ -7,20 +7,23 @@ * @implements {WebInspector.SuggestBoxDelegate} * @param {!WebInspector.CodeMirrorTextEditor} textEditor * @param {!CodeMirror} codeMirror + * @param {!WebInspector.AutocompleteConfig} config */ -WebInspector.TextEditorAutocompleteController = function(textEditor, codeMirror) +WebInspector.TextEditorAutocompleteController = function(textEditor, codeMirror, config) { this._textEditor = textEditor; this._codeMirror = codeMirror; + this._config = config; + this._initialized = false; this._onScroll = this._onScroll.bind(this); this._onCursorActivity = this._onCursorActivity.bind(this); this._changes = this._changes.bind(this); this._blur = this._blur.bind(this); + this._beforeChange = this._beforeChange.bind(this); + this._mouseDown = this.finishAutocomplete.bind(this); this._codeMirror.on("changes", this._changes); - this._enabled = true; - this._initialized = false; this._hintElement = createElementWithClass("span", "auto-complete-text"); } @@ -32,35 +35,101 @@ this._initialized = true; this._codeMirror.on("scroll", this._onScroll); this._codeMirror.on("cursorActivity", this._onCursorActivity); - this._codeMirror.on("mousedown", this.finishAutocomplete.bind(this)); + this._codeMirror.on("mousedown", this._mouseDown); this._codeMirror.on("blur", this._blur); - this._delegate.initialize(this._textEditor); + if (this._config.isWordChar) { + this._codeMirror.on("beforeChange", this._beforeChange); + this._dictionary = new WebInspector.TextDictionary(); + this._addWordsFromText(this._codeMirror.getValue()); + } + }, + + dispose: function() + { + this._codeMirror.off("changes", this._changes); + if (this._initialized) { + this._codeMirror.off("scroll", this._onScroll); + this._codeMirror.off("cursorActivity", this._onCursorActivity); + this._codeMirror.off("mousedown", this._mouseDown); + this._codeMirror.off("blur", this._blur); + } + if (this._dictionary) { + this._codeMirror.off("beforeChange", this._beforeChange); + this._dictionary.reset(); + } }, /** - * @param {!WebInspector.TextEditorAutocompleteDelegate} delegate + * @param {!CodeMirror} codeMirror + * @param {!CodeMirror.BeforeChangeObject} changeObject */ - setDelegate: function(delegate) + _beforeChange: function(codeMirror, changeObject) { - if (this._delegate) - this._delegate.dispose(); - this._delegate = delegate; + this._updatedLines = this._updatedLines || {}; + for (var i = changeObject.from.line; i <= changeObject.to.line; ++i) + this._updatedLines[i] = this._codeMirror.getLine(i); }, /** - * @param {boolean} enabled + * @param {string} text */ - setEnabled: function(enabled) + _addWordsFromText: function(text) { - if (enabled === this._enabled) - return; - this._enabled = enabled; - if (!this._delegate) - return; - if (!enabled) - this._delegate.dispose(); - else - this._delegate.initialize(); + WebInspector.TextUtils.textToWords(text, /** @type {function(string):boolean} */ (this._config.isWordChar), addWord.bind(this)); + + /** + * @param {string} word + * @this {WebInspector.TextEditorAutocompleteController} + */ + function addWord(word) + { + if (word.length && (word[0] < "0" || word[0] > "9")) + this._dictionary.addWord(word); + } + }, + + /** + * @param {string} text + */ + _removeWordsFromText: function(text) + { + WebInspector.TextUtils.textToWords(text, /** @type {function(string):boolean} */ (this._config.isWordChar), (word) => this._dictionary.removeWord(word)); + }, + + /** + * @param {number} lineNumber + * @param {number} columnNumber + * @return {?WebInspector.TextRange} + */ + _substituteRange: function(lineNumber, columnNumber) + { + var range = this._config.substituteRangeCallback ? this._config.substituteRangeCallback(lineNumber, columnNumber) : null; + if (!range && this._config.isWordChar) + range = this._textEditor.wordRangeForCursorPosition(lineNumber, columnNumber, this._config.isWordChar); + return range; + }, + + /** + * @param {!WebInspector.TextRange} prefixRange + * @param {!WebInspector.TextRange} substituteRange + * @return {!Promise.<!WebInspector.SuggestBox.Suggestions>} + */ + _wordsWithPrefix: function(prefixRange, substituteRange) + { + var external = this._config.suggestionsCallback ? this._config.suggestionsCallback(prefixRange, substituteRange) : null; + if (external) + return external; + + if (!this._dictionary || prefixRange.startColumn === prefixRange.endColumn) + return Promise.resolve([]); + + var completions = this._dictionary.wordsWithPrefix(this._textEditor.copyRange(prefixRange)); + var substituteWord = this._textEditor.copyRange(substituteRange); + if (this._dictionary.wordCount(substituteWord) === 1) + completions = completions.filter((word) => word !== substituteWord); + + completions.sort((a, b) => this._dictionary.wordCount(b) - this._dictionary.wordCount(a) || a.length - b.length); + return Promise.resolve(completions.map(item => ({ title: item }))); }, /** @@ -69,8 +138,25 @@ */ _changes: function(codeMirror, changes) { - if (!changes.length || !this._enabled || !this._delegate) + if (!changes.length) return; + + if (this._dictionary && this._updatedLines) { + for (var lineNumber in this._updatedLines) + this._removeWordsFromText(this._updatedLines[lineNumber]); + delete this._updatedLines; + + var linesToUpdate = {}; + for (var changeIndex = 0; changeIndex < changes.length; ++changeIndex) { + var changeObject = changes[changeIndex]; + var editInfo = WebInspector.CodeMirrorUtils.changeObjectToEditOperation(changeObject); + for (var i = editInfo.newRange.startLine; i <= editInfo.newRange.endLine; ++i) + linesToUpdate[i] = this._codeMirror.getLine(i); + } + for (var lineNumber in linesToUpdate) + this._addWordsFromText(linesToUpdate[lineNumber]); + } + var singleCharInput = false; var singleCharDelete = false; var cursor = this._codeMirror.getCursor("head"); @@ -123,7 +209,7 @@ return true; var mainSelectionContext = this._textEditor.copyRange(mainSelection); for (var i = 0; i < selections.length; ++i) { - var wordRange = this._delegate.substituteRange(this._textEditor, selections[i].head.line, selections[i].head.ch); + var wordRange = this._substituteRange(selections[i].head.line, selections[i].head.ch); if (!wordRange) return false; var context = this._textEditor.copyRange(wordRange); @@ -135,8 +221,6 @@ autocomplete: function() { - if (!this._enabled || !this._delegate) - return; this._initializeIfNeeded(); if (this._codeMirror.somethingSelected()) { this.finishAutocomplete(); @@ -144,7 +228,7 @@ } var cursor = this._codeMirror.getCursor("head"); - var substituteRange = this._delegate.substituteRange(this._textEditor, cursor.line, cursor.ch); + var substituteRange = this._substituteRange(cursor.line, cursor.ch); if (!substituteRange || !this._validateSelectionsContexts(substituteRange)) { this.finishAutocomplete(); return; @@ -157,7 +241,7 @@ if (this._suggestBox) hadSuggestBox = true; - this._delegate.wordsWithPrefix(this._textEditor, prefixRange, substituteRange).then(wordsAcquired.bind(this)); + this._wordsWithPrefix(prefixRange, substituteRange).then(wordsAcquired.bind(this)); /** * @param {!WebInspector.SuggestBox.Suggestions} wordsWithPrefix @@ -328,109 +412,10 @@ } /** - * @interface - */ -WebInspector.TextEditorAutocompleteDelegate = function() {} - -WebInspector.TextEditorAutocompleteDelegate.prototype = { - /** - * @param {!WebInspector.CodeMirrorTextEditor} editor - * @param {number} lineNumber - * @param {number} columnNumber - * @return {?WebInspector.TextRange} - */ - substituteRange: function(editor, lineNumber, columnNumber) {}, - - /** - * @param {!WebInspector.CodeMirrorTextEditor} editor - * @param {!WebInspector.TextRange} prefixRange - * @param {!WebInspector.TextRange} substituteRange - * @return {!Promise.<!WebInspector.SuggestBox.Suggestions>} - */ - wordsWithPrefix: function(editor, prefixRange, substituteRange) {}, - - /** - * @param {!WebInspector.CodeMirrorTextEditor} editor - */ - initialize: function(editor) {}, - - dispose: function() {} -} - -/** - * @constructor - * @implements {WebInspector.TextEditorAutocompleteDelegate} - * @param {string=} additionalWordChars - */ -WebInspector.SimpleAutocompleteDelegate = function(additionalWordChars) -{ - this._additionalWordChars = additionalWordChars; -} - -WebInspector.SimpleAutocompleteDelegate.prototype = { - /** - * @override - * @param {!WebInspector.CodeMirrorTextEditor} editor - */ - initialize: function(editor) - { - if (this._dictionary) - this._dictionary.dispose(); - this._dictionary = editor.createTextDictionary(this._additionalWordChars); - }, - - /** - * @override - */ - dispose: function() - { - if (this._dictionary) { - this._dictionary.dispose(); - delete this._dictionary; - } - }, - - /** - * @override - * @param {!WebInspector.CodeMirrorTextEditor} editor - * @param {number} lineNumber - * @param {number} columnNumber - * @return {?WebInspector.TextRange} - */ - substituteRange: function(editor, lineNumber, columnNumber) - { - return editor.wordRangeForCursorPosition(lineNumber, columnNumber, this._dictionary.isWordChar.bind(this._dictionary)); - }, - - /** - * @override - * @param {!WebInspector.CodeMirrorTextEditor} editor - * @param {!WebInspector.TextRange} prefixRange - * @param {!WebInspector.TextRange} substituteRange - * @return {!Promise.<!WebInspector.SuggestBox.Suggestions>} - */ - wordsWithPrefix: function(editor, prefixRange, substituteRange) - { - if (prefixRange.startColumn === prefixRange.endColumn) - return Promise.resolve([]); - - var dictionary = this._dictionary; - var completions = dictionary.wordsWithPrefix(editor.copyRange(prefixRange)); - var substituteWord = editor.copyRange(substituteRange); - if (dictionary.wordCount(substituteWord) === 1) - completions = completions.filter(excludeFilter.bind(null, substituteWord)); - - completions.sort(sortSuggestions); - return Promise.resolve(completions.map(item => ({ title: item }))); - - function sortSuggestions(a, b) - { - return dictionary.wordCount(b) - dictionary.wordCount(a) || a.length - b.length; - } - - function excludeFilter(excludeWord, word) - { - return word !== excludeWord; - } - } -} + * @typedef {{ + * substituteRangeCallback: ((function(number, number):?WebInspector.TextRange)|undefined), + * suggestionsCallback: ((function(!WebInspector.TextRange, !WebInspector.TextRange):?Promise.<!WebInspector.SuggestBox.Suggestions>)|undefined), + * isWordChar: ((function(string):boolean)|undefined) + * }} + **/ +WebInspector.AutocompleteConfig;
diff --git a/third_party/WebKit/Source/devtools/front_end/source_frame/module.json b/third_party/WebKit/Source/devtools/front_end/source_frame/module.json index 94ff6fe..969b132 100644 --- a/third_party/WebKit/Source/devtools/front_end/source_frame/module.json +++ b/third_party/WebKit/Source/devtools/front_end/source_frame/module.json
@@ -44,7 +44,6 @@ "../cm/activeline.js", "CodeMirrorUtils.js", - "CodeMirrorDictionary.js", "TextEditorAutocompleteController.js", "CodeMirrorTextEditor.js", "FontView.js",
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/CSSSourceFrame.js b/third_party/WebKit/Source/devtools/front_end/sources/CSSSourceFrame.js index 743ac7f6..88a9384 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/CSSSourceFrame.js +++ b/third_party/WebKit/Source/devtools/front_end/sources/CSSSourceFrame.js
@@ -36,10 +36,13 @@ WebInspector.CSSSourceFrame = function(uiSourceCode) { WebInspector.UISourceCodeFrame.call(this, uiSourceCode); - this.textEditor.setAutocompleteDelegate(new WebInspector.CSSSourceFrame.AutocompleteDelegate()); this._registerShortcuts(); this._swatchPopoverHelper = new WebInspector.SwatchPopoverHelper(); this._muteColorProcessing = false; + this.configureAutocomplete({ + suggestionsCallback: this._cssSuggestions.bind(this), + isWordChar: this._isWordChar.bind(this) + }); } /** @type {number} */ @@ -251,6 +254,68 @@ this._swatchPopoverHelper.hide(true); }, + /** + * @param {string} char + * @return {boolean} + */ + _isWordChar: function(char) + { + return WebInspector.TextUtils.isWordChar(char) || char === "." || char === "-" || char === "$"; + }, + + /** + * @param {!WebInspector.TextRange} prefixRange + * @param {!WebInspector.TextRange} substituteRange + * @return {?Promise.<!WebInspector.SuggestBox.Suggestions>} + */ + _cssSuggestions: function(prefixRange, substituteRange) + { + var prefix = this._textEditor.copyRange(prefixRange); + if (prefix.startsWith("$")) + return null; + + var propertyToken = this._backtrackPropertyToken(prefixRange.startLine, prefixRange.startColumn - 1); + if (!propertyToken) + return null; + + var line = this._textEditor.line(prefixRange.startLine); + var tokenContent = line.substring(propertyToken.startColumn, propertyToken.endColumn); + var propertyValues = WebInspector.cssMetadata().propertyValues(tokenContent); + return Promise.resolve(propertyValues.filter(value => value.startsWith(prefix)).map(value => ({title: value}))); + }, + + /** + * @param {number} lineNumber + * @param {number} columnNumber + * @return {?{startColumn: number, endColumn: number, type: string}} + */ + _backtrackPropertyToken: function(lineNumber, columnNumber) + { + var backtrackDepth = 10; + var tokenPosition = columnNumber; + var line = this._textEditor.line(lineNumber); + var seenColon = false; + + for (var i = 0; i < backtrackDepth && tokenPosition >= 0; ++i) { + var token = this._textEditor.tokenAtTextPosition(lineNumber, tokenPosition); + if (!token) + return null; + if (token.type === "css-property") + return seenColon ? token : null; + if (token.type && !(token.type.indexOf("whitespace") !== -1 || token.type.startsWith("css-comment"))) + return null; + + if (!token.type && line.substring(token.startColumn, token.endColumn) === ":") { + if (!seenColon) + seenColon = true; + else + return null; + } + tokenPosition = token.startColumn - 1; + } + return null; + }, + __proto__: WebInspector.UISourceCodeFrame.prototype } @@ -266,100 +331,3 @@ this.color = color; this.textRange = new WebInspector.TextRange(lineNumber, startColumn, lineNumber, startColumn + textLength); } - -/** - * @constructor - * @implements {WebInspector.TextEditorAutocompleteDelegate} - */ -WebInspector.CSSSourceFrame.AutocompleteDelegate = function() -{ - this._simpleDelegate = new WebInspector.SimpleAutocompleteDelegate(".-$"); -} - -WebInspector.CSSSourceFrame._backtrackDepth = 10; - -WebInspector.CSSSourceFrame.AutocompleteDelegate.prototype = { - /** - * @override - * @param {!WebInspector.CodeMirrorTextEditor} editor - */ - initialize: function(editor) - { - this._simpleDelegate.initialize(editor); - }, - - /** - * @override - */ - dispose: function() - { - this._simpleDelegate.dispose(); - }, - - /** - * @override - * @param {!WebInspector.CodeMirrorTextEditor} editor - * @param {number} lineNumber - * @param {number} columnNumber - * @return {?WebInspector.TextRange} - */ - substituteRange: function(editor, lineNumber, columnNumber) - { - return this._simpleDelegate.substituteRange(editor, lineNumber, columnNumber); - }, - - /** - * @param {!WebInspector.CodeMirrorTextEditor} editor - * @param {number} lineNumber - * @param {number} columnNumber - * @return {?{startColumn: number, endColumn: number, type: string}} - */ - _backtrackPropertyToken: function(editor, lineNumber, columnNumber) - { - var tokenPosition = columnNumber; - var line = editor.line(lineNumber); - var seenColumn = false; - - for (var i = 0; i < WebInspector.CSSSourceFrame._backtrackDepth && tokenPosition >= 0; ++i) { - var token = editor.tokenAtTextPosition(lineNumber, tokenPosition); - if (!token) - return null; - if (token.type === "css-property") - return seenColumn ? token : null; - if (token.type && !(token.type.indexOf("whitespace") !== -1 || token.type.startsWith("css-comment"))) - return null; - - if (!token.type && line.substring(token.startColumn, token.endColumn) === ":") { - if (!seenColumn) - seenColumn = true; - else - return null; - } - tokenPosition = token.startColumn - 1; - } - return null; - }, - - /** - * @override - * @param {!WebInspector.CodeMirrorTextEditor} editor - * @param {!WebInspector.TextRange} prefixRange - * @param {!WebInspector.TextRange} substituteRange - * @return {!Promise.<!WebInspector.SuggestBox.Suggestions>} - */ - wordsWithPrefix: function(editor, prefixRange, substituteRange) - { - var prefix = editor.copyRange(prefixRange); - if (prefix.startsWith("$")) - return this._simpleDelegate.wordsWithPrefix(editor, prefixRange, substituteRange); - - var propertyToken = this._backtrackPropertyToken(editor, prefixRange.startLine, prefixRange.startColumn - 1); - if (!propertyToken) - return this._simpleDelegate.wordsWithPrefix(editor, prefixRange, substituteRange); - - var line = editor.line(prefixRange.startLine); - var tokenContent = line.substring(propertyToken.startColumn, propertyToken.endColumn); - var propertyValues = WebInspector.cssMetadata().propertyValues(tokenContent); - return Promise.resolve(propertyValues.filter(value => value.startsWith(prefix)).map(value => ({title: value}))); - } -}
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js b/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js index db904e23..f093016 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js +++ b/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js
@@ -81,6 +81,7 @@ this._sourcesView.addEventListener(WebInspector.SourcesView.Events.EditorClosed, this._editorClosed.bind(this)); this._sourcesView.registerShortcuts(this.registerShortcuts.bind(this)); this.editorView.setMainWidget(this._sourcesView); + this._editorChanged(this._sourcesView.currentUISourceCode()); this.sidebarPanes = {}; this.sidebarPanes.threads = null;
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/UISourceCodeFrame.js b/third_party/WebKit/Source/devtools/front_end/sources/UISourceCodeFrame.js index b63c582..17b212f 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/UISourceCodeFrame.js +++ b/third_party/WebKit/Source/devtools/front_end/sources/UISourceCodeFrame.js
@@ -38,7 +38,11 @@ if (Runtime.experiments.isEnabled("sourceDiff")) this._diff = new WebInspector.SourceCodeDiff(uiSourceCode.requestOriginalContent(), this.textEditor); - this.textEditor.setAutocompleteDelegate(new WebInspector.SimpleAutocompleteDelegate()); + + /** @type {?WebInspector.AutocompleteConfig} */ + this._autocompleteConfig = {isWordChar: WebInspector.TextUtils.isWordChar}; + WebInspector.moduleSetting("textEditorAutocompletion").addChangeListener(this._updateAutocomplete, this); + this._updateAutocomplete(); this._rowMessageBuckets = {}; /** @type {!Set<string>} */ @@ -195,6 +199,20 @@ { }, + _updateAutocomplete: function() + { + this._textEditor.configureAutocomplete(WebInspector.moduleSetting("textEditorAutocompletion").get() ? this._autocompleteConfig : null); + }, + + /** + * @param {?WebInspector.AutocompleteConfig} config + */ + configureAutocomplete: function(config) + { + this._autocompleteConfig = config; + this._updateAutocomplete(); + }, + /** * @param {string} content */ @@ -249,6 +267,7 @@ dispose: function() { this._textEditor.dispose(); + WebInspector.moduleSetting("textEditorAutocompletion").removeChangeListener(this._updateAutocomplete, this); this.detach(); },
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/sourcesPanel.css b/third_party/WebKit/Source/devtools/front_end/sources/sourcesPanel.css index efa5287f..2180da2 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/sourcesPanel.css +++ b/third_party/WebKit/Source/devtools/front_end/sources/sourcesPanel.css
@@ -254,6 +254,7 @@ .scope-chain-sidebar-pane-section { padding: 2px 4px 2px 4px; + flex: none; } .hidden-callframes-message { @@ -266,4 +267,4 @@ .event-listeners-sidebar-pane .toolbar { border-bottom: 1px solid #eee; -} \ No newline at end of file +}
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/uiList.css b/third_party/WebKit/Source/devtools/front_end/sources/uiList.css index 654def1..af8b8f77 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/uiList.css +++ b/third_party/WebKit/Source/devtools/front_end/sources/uiList.css
@@ -5,23 +5,13 @@ */ .list-item { - padding: 2px 8px 3px 8px; + padding: 0 8px 0 0; position: relative; - min-height: 26px; + min-height: 18px; white-space: nowrap; - line-height: 21px; -} - -.list-item:nth-of-type(2n) { - background-color: #f8f8f8; -} - -.list-item.selected { - background-color: #dadada; -} - -.list-item.selected > .title { - font-weight: bold; + line-height: 20px; + border-bottom: 1px solid #eee; + background-position: -235px -107px; } .list-item:not(.ignore-hover):hover { @@ -29,14 +19,14 @@ } .list-item > .title { - font-weight: normal; word-wrap: break-word; white-space: normal; + margin-left: 17px; } .list-item > .subtitle { margin-left: 5px; - color: rgba(0, 0, 0, 0.7); + color: #888; text-overflow: ellipsis; overflow: hidden; float: right; @@ -61,3 +51,21 @@ opacity: 0.6; font-style: italic; } + +.list-item.selected::before { + background-image: url(Images/toolbarButtonGlyphs.png); + background-size: 352px 168px; + background-position: -235px -107px; + content: ""; + position: absolute; + top: 5px; + left: 4px; + width: 10px; + height: 10px; +} + +@media (-webkit-min-device-pixel-ratio: 1.5) { +.list-item.selected::before { + background-image: url(Images/toolbarButtonGlyphs_2x.png); +} +} /* media */
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/smallIcon.css b/third_party/WebKit/Source/devtools/front_end/ui/smallIcon.css index d84aaa2..64eea1d 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/smallIcon.css +++ b/third_party/WebKit/Source/devtools/front_end/ui/smallIcon.css
@@ -42,7 +42,7 @@ } div.revokedError-icon { - background-position: -245px -107px; + background-position: -246px -107px; } div.warning-icon {
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/suggestBox.css b/third_party/WebKit/Source/devtools/front_end/ui/suggestBox.css index e33ff52c..beb98f9 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/suggestBox.css +++ b/third_party/WebKit/Source/devtools/front_end/ui/suggestBox.css
@@ -65,7 +65,6 @@ .suggest-box { background-color: #FFFFFF; - border: 1px solid rgb(66%, 66%, 66%); pointer-events: auto; margin-left: -3px; overflow-x: hidden; @@ -73,11 +72,7 @@ display: flex; flex-direction: column; flex: 0 0 auto; - border-radius: 5px 5px 5px 0; -} - -:host(.under-anchor) .suggest-box { - border-radius: 0 5px 5px 5px; + box-shadow: 0 0 2px hsla(0, 0%, 0%, 0.3); } .suggest-box .suggest-box-content-item {
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/viewContainers.css b/third_party/WebKit/Source/devtools/front_end/ui/viewContainers.css index a0a595620..086f5cd5 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/viewContainers.css +++ b/third_party/WebKit/Source/devtools/front_end/ui/viewContainers.css
@@ -35,7 +35,7 @@ display: flex; align-items: center; background-color: #eee; - height: 26px; + height: 22px; padding: 0 5px; border-top: 1px solid #dadada; white-space: nowrap; @@ -49,6 +49,10 @@ border-bottom: 1px solid #ddd; } +.expandable-view-title .toolbar { + margin-top: -3px; +} + .expandable-view-title:not(.expanded) .toolbar { display: none; }
diff --git a/third_party/WebKit/Source/devtools/front_end/workspace/IsolatedFileSystemManager.js b/third_party/WebKit/Source/devtools/front_end/workspace/IsolatedFileSystemManager.js index 837526e7..348655a2 100644 --- a/third_party/WebKit/Source/devtools/front_end/workspace/IsolatedFileSystemManager.js +++ b/third_party/WebKit/Source/devtools/front_end/workspace/IsolatedFileSystemManager.js
@@ -34,12 +34,12 @@ */ WebInspector.IsolatedFileSystemManager = function() { - /** @type {!Object.<string, !WebInspector.IsolatedFileSystem>} */ - this._fileSystems = {}; - /** @type {!Object.<number, function(!Array.<string>)>} */ - this._callbacks = {}; - /** @type {!Object.<number, !WebInspector.Progress>} */ - this._progresses = {}; + /** @type {!Map<string, !WebInspector.IsolatedFileSystem>} */ + this._fileSystems = new Map(); + /** @type {!Map<number, function(!Array.<string>)>} */ + this._callbacks = new Map(); + /** @type {!Map<number, !WebInspector.Progress>} */ + this._progresses = new Map(); InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.FileSystemsLoaded, this._onFileSystemsLoaded, this); InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.FileSystemRemoved, this._onFileSystemRemoved, this); @@ -156,7 +156,7 @@ { if (!fileSystem) return; - this._fileSystems[fileSystemPath] = fileSystem; + this._fileSystems.set(fileSystemPath, fileSystem); this.dispatchEventToListeners(WebInspector.IsolatedFileSystemManager.Events.FileSystemAdded, fileSystem); } }, @@ -198,12 +198,12 @@ _fileSystemRemoved: function(embedderPath) { var fileSystemPath = WebInspector.IsolatedFileSystemManager.normalizePath(embedderPath); - var isolatedFileSystem = this._fileSystems[fileSystemPath]; - delete this._fileSystems[fileSystemPath]; - if (isolatedFileSystem) { - isolatedFileSystem.fileSystemRemoved(); - this.dispatchEventToListeners(WebInspector.IsolatedFileSystemManager.Events.FileSystemRemoved, isolatedFileSystem); - } + var isolatedFileSystem = this._fileSystems.get(fileSystemPath); + if (!isolatedFileSystem) + return; + this._fileSystems.delete(fileSystemPath); + isolatedFileSystem.fileSystemRemoved(); + this.dispatchEventToListeners(WebInspector.IsolatedFileSystemManager.Events.FileSystemRemoved, isolatedFileSystem); }, /** @@ -211,7 +211,7 @@ */ fileSystemPaths: function() { - return Object.keys(this._fileSystems); + return this._fileSystems.keysArray(); }, /** @@ -220,7 +220,7 @@ */ fileSystem: function(fileSystemPath) { - return this._fileSystems[fileSystemPath]; + return this._fileSystems.get(fileSystemPath) || null; }, _initExcludePatterSetting: function() @@ -279,7 +279,7 @@ registerCallback: function(callback) { var requestId = ++WebInspector.IsolatedFileSystemManager._lastRequestId; - this._callbacks[requestId] = callback; + this._callbacks.set(requestId, callback); return requestId; }, @@ -290,7 +290,7 @@ registerProgress: function(progress) { var requestId = ++WebInspector.IsolatedFileSystemManager._lastRequestId; - this._progresses[requestId] = progress; + this._progresses.set(requestId, progress); return requestId; }, @@ -302,7 +302,7 @@ var requestId = /** @type {number} */ (event.data["requestId"]); var totalWork = /** @type {number} */ (event.data["totalWork"]); - var progress = this._progresses[requestId]; + var progress = this._progresses.get(requestId); if (!progress) return; progress.setTotalWork(totalWork); @@ -316,7 +316,7 @@ var requestId = /** @type {number} */ (event.data["requestId"]); var worked = /** @type {number} */ (event.data["worked"]); - var progress = this._progresses[requestId]; + var progress = this._progresses.get(requestId); if (!progress) return; progress.worked(worked); @@ -333,11 +333,11 @@ { var requestId = /** @type {number} */ (event.data["requestId"]); - var progress = this._progresses[requestId]; + var progress = this._progresses.get(requestId); if (!progress) return; progress.done(); - delete this._progresses[requestId]; + this._progresses.delete(requestId); }, /** @@ -348,11 +348,11 @@ var requestId = /** @type {number} */ (event.data["requestId"]); var files = /** @type {!Array.<string>} */ (event.data["files"]); - var callback = this._callbacks[requestId]; + var callback = this._callbacks.get(requestId); if (!callback) return; callback.call(null, files); - delete this._callbacks[requestId]; + this._callbacks.delete(requestId); }, dispose: function()
diff --git a/third_party/WebKit/Source/devtools/scripts/check_injected_script_source.py b/third_party/WebKit/Source/devtools/scripts/check_injected_script_source.py index c3da9aa..9a220bc 100755 --- a/third_party/WebKit/Source/devtools/scripts/check_injected_script_source.py +++ b/third_party/WebKit/Source/devtools/scripts/check_injected_script_source.py
@@ -49,7 +49,7 @@ global_functions = "|".join([ "eval", "uneval", "isFinite", "isNaN", "parseFloat", "parseInt", "decodeURI", "decodeURIComponent", - "encodeURI", "encodeURIComponent", "escape", "unescape", + "encodeURI", "encodeURIComponent", "escape", "unescape", "Map", "Set" ]) # Black list: @@ -63,7 +63,7 @@ errors_found = False for i, line in enumerate(lines): - if line.find("suppressBlacklist"): + if line.find("suppressBlacklist") != -1: continue for match in re.finditer(black_list_call_regex, line): errors_found = True
diff --git a/third_party/WebKit/Source/devtools/scripts/compile_frontend.py b/third_party/WebKit/Source/devtools/scripts/compile_frontend.py index 449ff3b6..aed1a8f 100755 --- a/third_party/WebKit/Source/devtools/scripts/compile_frontend.py +++ b/third_party/WebKit/Source/devtools/scripts/compile_frontend.py
@@ -30,7 +30,6 @@ from modular_build import read_file, write_file import os import os.path as path -import generate_injected_script_externs import generate_protocol_externs import modular_build import re
diff --git a/third_party/WebKit/Source/devtools/scripts/generate_injected_script_externs.py b/third_party/WebKit/Source/devtools/scripts/generate_injected_script_externs.py deleted file mode 100755 index 91e5a63..0000000 --- a/third_party/WebKit/Source/devtools/scripts/generate_injected_script_externs.py +++ /dev/null
@@ -1,213 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2014 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import re - -interface_name_map = { - 'InjectedScriptHost': 'InjectedScriptHostClass' -} - -type_map = { - 'any': '*', - 'DOMString': 'string', - 'short': 'number', - 'unsigned short': 'number', - 'long': 'number', - 'unsigned long': 'number', - 'boolean': 'boolean', - 'object': 'Object', - 'void': '' -} - -idl_type_exprs = [ - r'any', - r'DOMString', - r'short', - r'unsigned\s+short', - r'long', - r'unsigned\s+long', - r'boolean', - r'object', - r'void', - r'\w+' # Non IDL-specific object types. -] - -# Groups: -# 1: type name -# 2: array (optional) -# 3: nullable (optional) -type_expr = r'\b(' + r'|'.join(idl_type_exprs) + r')\b(\[\])?(\?)?' - -# Groups: -# 1: return type -# 2: array (optional) -# 3: nullable (optional) -# 4: method name -# 5: method arguments -method_expr = r'^\s*(?:\[.+\])?\s+' + type_expr + r'\s+(\w+)\s*\(([^)]*)\)\s*;\s*$' -method_regex = re.compile(method_expr) - -# Groups: -# 1: type name -# 2: array (optional) -# 3: nullable (optional) -# 4: attribute name -attribute_expr = r'^\s*(?:\[.+\]\s+)?(?:\breadonly\s+)?\battribute\s+' + type_expr + r'\s+(\w+)\s*;' -attribute_regex = re.compile(attribute_expr) - -# Groups: -# 1: optional (optional) -# 2: type name -# 3: array (optional) -# 4: nullable (optional) -# 5: arg name -arg_regex = re.compile(r'\s*(?:\[[^]]+\]\s*)?(\boptional\s+)?' + type_expr + r'\s+(\w+)') - -interface_regex = r'\binterface\s+(\w+)' - -other_externs = """ -/** @type {!Window} */ -var inspectedWindow; -/** @type {number} */ -var injectedScriptId; -""" - - -class Type: - def __init__(self, type_name, is_array, is_nullable): - self.type_name = re.sub(r'\s+', ' ', type_name) - self.is_array = is_array - self.is_nullable = is_nullable - - def as_js_type(self): - if self.type_name == 'void': - return '' - result = '' - if self.is_nullable: - result = '?' - elif self._is_object_type(): - result = '!' - if self.is_array: - result += 'Array.<%s>' % Type(self.type_name, False, False).as_js_type() - else: - result += type_map.get(self.type_name, self.type_name) - return result - - def _is_object_type(self): - return self.is_array or self.type_name == 'object' or not type_map.get(self.type_name) - - -class Attribute: - def __init__(self, type, name): - self.type = type - self.name = name - - -class Argument: - def __init__(self, type, optional, name): - self.type = type - self.optional = optional - self.name = name - - def as_js_param_type(self): - result = self.type.as_js_type() - if self.optional: - result += '=' - return result - - -class Method: - def __init__(self, return_type, name, args): - self.return_type = return_type - self.name = name - self.args = args - - def js_argument_names(self): - result = [] - for arg in self.args: - result.append(arg.name) - return ', '.join(result) - - -class Interface: - def __init__(self, name, methods, attributes): - self.name = name - self.methods = methods - self.attributes = attributes - - -def parse_args(text): - arguments = [] - for (optional, type_name, is_array, is_nullable, arg_name) in re.findall(arg_regex, text): - arguments.append(Argument(Type(type_name, is_array, is_nullable), optional != '', arg_name)) - return arguments - - -def read_interface(idl): - methods = [] - attributes = [] - with open(idl, "r") as input_file: - for line in input_file.readlines(): - match = re.search(method_regex, line) - if match: - return_type = Type(match.group(1), match.group(2) is not None, match.group(3) is not None) - name = match.group(4) - methods.append(Method(return_type, name, parse_args(match.group(5)))) - continue - match = re.search(attribute_regex, line) - if match: - type = Type(match.group(1), match.group(2) is not None, match.group(3) is not None) - name = match.group(4) - attributes.append(Attribute(type, name)) - continue - match = re.search(interface_regex, line) - if match: - interface_name = match.group(1) - return Interface(interface_name, methods, attributes) - - -def generate_injected_script_externs(input_idls, output): - for idl in input_idls: - ifc = read_interface(idl) - interface_name = interface_name_map.get(ifc.name, ifc.name) - output.write('/** @interface */\nfunction %s()\n{\n' % interface_name) - for attribute in ifc.attributes: - output.write(' /** @type {%s} */\n' % attribute.type.as_js_type()) - output.write(' this.%s;\n' % attribute.name) - output.write('}\n') - for method in ifc.methods: - output.write('\n/**\n') - for arg in method.args: - output.write(' * @param {%s} %s\n' % (arg.as_js_param_type(), arg.name)) - return_type = method.return_type.as_js_type() - if return_type: - output.write(' * @return {%s}\n' % return_type) - output.write(' */\n') - output.write('%s.prototype.%s = function(%s) {}\n' % (interface_name, method.name, method.js_argument_names())) - if interface_name != ifc.name: - output.write('\n/** @type {!%s} */\nvar %s;\n' % (interface_name, ifc.name)) - output.write('\n') - output.write(other_externs) - - -def generate_injected_script_externs_to_file(input_idls, output_name): - with open(output_name, 'w') as output: - generate_injected_script_externs(input_idls, output) - - -def main(argv): - import os.path - program_name = os.path.basename(__file__) - if len(argv) < 3: - sys.stderr.write("Usage: %s IDL_1 ... IDL_N OUTPUT_FILE\n" % program_name) - exit(1) - input_idls = argv[1:-1] - generate_injected_script_externs_to_file(input_idls, argv[-1]) - - -if __name__ == "__main__": - import sys - sys.exit(main(sys.argv))
diff --git a/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp index e8e1224..ec779e1 100644 --- a/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp +++ b/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp
@@ -598,7 +598,7 @@ return IgnoreObject; } - if (m_layoutObject->style()->visibility() != VISIBLE) { + if (m_layoutObject->style()->visibility() != EVisibility::Visible) { // aria-hidden is meant to override visibility as the determinant in AX hierarchy inclusion. if (equalIgnoringCase(getAttribute(aria_hiddenAttr), "false")) return DefaultBehavior;
diff --git a/third_party/WebKit/Source/modules/accessibility/AXMediaControls.cpp b/third_party/WebKit/Source/modules/accessibility/AXMediaControls.cpp index 309e230..1120eb9 100644 --- a/third_party/WebKit/Source/modules/accessibility/AXMediaControls.cpp +++ b/third_party/WebKit/Source/modules/accessibility/AXMediaControls.cpp
@@ -141,7 +141,7 @@ bool AccessibilityMediaControl::computeAccessibilityIsIgnored(IgnoredReasons* ignoredReasons) const { - if (!m_layoutObject || !m_layoutObject->style() || m_layoutObject->style()->visibility() != VISIBLE || controlType() == MediaTimelineContainer) + if (!m_layoutObject || !m_layoutObject->style() || m_layoutObject->style()->visibility() != EVisibility::Visible || controlType() == MediaTimelineContainer) return true; return accessibilityIsIgnoredByDefault(ignoredReasons); @@ -250,7 +250,7 @@ bool AccessibilityMediaTimeDisplay::computeAccessibilityIsIgnored(IgnoredReasons* ignoredReasons) const { - if (!m_layoutObject || !m_layoutObject->style() || m_layoutObject->style()->visibility() != VISIBLE) + if (!m_layoutObject || !m_layoutObject->style() || m_layoutObject->style()->visibility() != EVisibility::Visible) return true; if (!m_layoutObject->style()->width().value())
diff --git a/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp index 244c2c3a..1db628f1 100644 --- a/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp +++ b/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp
@@ -2072,7 +2072,6 @@ case MenuItemRole: case MenuItemCheckBoxRole: case MenuItemRadioRole: - case ListItemRole: return toElement(node); default: break;
diff --git a/third_party/WebKit/Source/modules/accessibility/AXObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXObject.cpp index cbf02e1e..9dad88c 100644 --- a/third_party/WebKit/Source/modules/accessibility/AXObject.cpp +++ b/third_party/WebKit/Source/modules/accessibility/AXObject.cpp
@@ -761,7 +761,7 @@ return false; if (getLayoutObject()) - return getLayoutObject()->style()->visibility() != VISIBLE; + return getLayoutObject()->style()->visibility() != EVisibility::Visible; // This is an obscure corner case: if a node has no LayoutObject, that means it's not rendered, // but we still may be exploring it as part of a text alternative calculation, for example if it @@ -771,7 +771,7 @@ Document* doc = getDocument(); if (doc && doc->frame() && getNode() && getNode()->isElementNode()) { RefPtr<ComputedStyle> style = doc->ensureStyleResolver().styleForElement(toElement(getNode())); - return style->display() == NONE || style->visibility() != VISIBLE; + return style->display() == NONE || style->visibility() != EVisibility::Visible; } return false;
diff --git a/third_party/WebKit/Source/modules/cachestorage/Cache.cpp b/third_party/WebKit/Source/modules/cachestorage/Cache.cpp index 021769f3..260b762 100644 --- a/third_party/WebKit/Source/modules/cachestorage/Cache.cpp +++ b/third_party/WebKit/Source/modules/cachestorage/Cache.cpp
@@ -493,6 +493,10 @@ ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); const ScriptPromise promise = resolver->promise(); + if (request->method() != HTTPNames::GET && !options.ignoreMethod()) { + resolver->resolve(); + return promise; + } m_webCache->dispatchMatch(new CacheMatchCallbacks(resolver), webRequest, toWebQueryParams(options)); return promise; } @@ -513,6 +517,10 @@ ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); const ScriptPromise promise = resolver->promise(); + if (request->method() != HTTPNames::GET && !options.ignoreMethod()) { + resolver->resolve(HeapVector<Member<Response>>()); + return promise; + } m_webCache->dispatchMatchAll(new CacheWithResponsesCallbacks(resolver), webRequest, toWebQueryParams(options)); return promise; } @@ -549,6 +557,10 @@ ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); const ScriptPromise promise = resolver->promise(); + if (request->method() != HTTPNames::GET && !options.ignoreMethod()) { + resolver->resolve(false); + return promise; + } m_webCache->dispatchBatch(new CacheDeleteCallback(resolver), batchOperations); return promise; } @@ -607,7 +619,7 @@ { ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); const ScriptPromise promise = resolver->promise(); - m_webCache->dispatchKeys(new CacheWithRequestsCallbacks(resolver), 0, WebServiceWorkerCache::QueryParams()); + m_webCache->dispatchKeys(new CacheWithRequestsCallbacks(resolver), WebServiceWorkerRequest(), WebServiceWorkerCache::QueryParams()); return promise; } @@ -619,7 +631,11 @@ ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); const ScriptPromise promise = resolver->promise(); - m_webCache->dispatchKeys(new CacheWithRequestsCallbacks(resolver), 0, toWebQueryParams(options)); + if (request->method() != HTTPNames::GET && !options.ignoreMethod()) { + resolver->resolve(HeapVector<Member<Request>>()); + return promise; + } + m_webCache->dispatchKeys(new CacheWithRequestsCallbacks(resolver), webRequest, toWebQueryParams(options)); return promise; }
diff --git a/third_party/WebKit/Source/modules/cachestorage/CacheStorage.cpp b/third_party/WebKit/Source/modules/cachestorage/CacheStorage.cpp index ec8460c..526ed8a 100644 --- a/third_party/WebKit/Source/modules/cachestorage/CacheStorage.cpp +++ b/third_party/WebKit/Source/modules/cachestorage/CacheStorage.cpp
@@ -320,6 +320,11 @@ ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); const ScriptPromise promise = resolver->promise(); + if (request->method() != HTTPNames::GET && !options.ignoreMethod()) { + resolver->resolve(); + return promise; + } + if (m_webCacheStorage) m_webCacheStorage->dispatchMatch(new MatchCallbacks(resolver), webRequest, Cache::toWebQueryParams(options)); else
diff --git a/third_party/WebKit/Source/modules/cachestorage/CacheTest.cpp b/third_party/WebKit/Source/modules/cachestorage/CacheTest.cpp index 0d39207..17a4d7c 100644 --- a/third_party/WebKit/Source/modules/cachestorage/CacheTest.cpp +++ b/third_party/WebKit/Source/modules/cachestorage/CacheTest.cpp
@@ -131,11 +131,11 @@ return callbacks->onError(m_error); } - void dispatchKeys(CacheWithRequestsCallbacks* callbacks, const WebServiceWorkerRequest* webRequest, const QueryParams& queryParams) override + void dispatchKeys(CacheWithRequestsCallbacks* callbacks, const WebServiceWorkerRequest& webRequest, const QueryParams& queryParams) override { m_lastErrorWebCacheMethodCalled = "dispatchKeys"; - if (webRequest) { - checkUrlIfProvided(webRequest->url()); + if (!webRequest.url().isEmpty()) { + checkUrlIfProvided(webRequest.url()); checkQueryParamsIfProvided(queryParams); } @@ -513,7 +513,7 @@ KeysTestCache(WebVector<WebServiceWorkerRequest>& requests) : m_requests(requests) { } - void dispatchKeys(CacheWithRequestsCallbacks* callbacks, const WebServiceWorkerRequest* webRequest, const QueryParams& queryParams) override + void dispatchKeys(CacheWithRequestsCallbacks* callbacks, const WebServiceWorkerRequest& webRequest, const QueryParams& queryParams) override { std::unique_ptr<CacheWithRequestsCallbacks> ownedCallbacks(wrapUnique(callbacks)); return callbacks->onSuccess(m_requests);
diff --git a/third_party/WebKit/Source/modules/cachestorage/InspectorCacheStorageAgent.cpp b/third_party/WebKit/Source/modules/cachestorage/InspectorCacheStorageAgent.cpp index 07fefac..de7b57d 100644 --- a/third_party/WebKit/Source/modules/cachestorage/InspectorCacheStorageAgent.cpp +++ b/third_party/WebKit/Source/modules/cachestorage/InspectorCacheStorageAgent.cpp
@@ -299,7 +299,7 @@ void onSuccess(std::unique_ptr<WebServiceWorkerCache> cache) override { auto* cacheRequest = new GetCacheKeysForRequestData(m_params, wrapUnique(cache.release()), std::move(m_callback)); - cacheRequest->cache()->dispatchKeys(cacheRequest, nullptr, WebServiceWorkerCache::QueryParams()); + cacheRequest->cache()->dispatchKeys(cacheRequest, WebServiceWorkerRequest(), WebServiceWorkerCache::QueryParams()); } void onError(WebServiceWorkerCacheError error) override
diff --git a/third_party/WebKit/Source/modules/canvas/HTMLCanvasElementModule.cpp b/third_party/WebKit/Source/modules/canvas/HTMLCanvasElementModule.cpp index 2e1ddde..e673f25d 100644 --- a/third_party/WebKit/Source/modules/canvas/HTMLCanvasElementModule.cpp +++ b/third_party/WebKit/Source/modules/canvas/HTMLCanvasElementModule.cpp
@@ -22,7 +22,7 @@ OffscreenCanvas* HTMLCanvasElementModule::transferControlToOffscreen(HTMLCanvasElement& canvas, ExceptionState& exceptionState) { if (!canvas.createSurfaceLayer()) { - exceptionState.throwDOMException(V8GeneralError, "Offscreen canvas creation failed due to an internal timeout."); + exceptionState.throwDOMException(V8Error, "Offscreen canvas creation failed due to an internal timeout."); return nullptr; }
diff --git a/third_party/WebKit/Source/modules/compositorworker/AbstractAnimationWorkletThread.cpp b/third_party/WebKit/Source/modules/compositorworker/AbstractAnimationWorkletThread.cpp new file mode 100644 index 0000000..c7cd7a86 --- /dev/null +++ b/third_party/WebKit/Source/modules/compositorworker/AbstractAnimationWorkletThread.cpp
@@ -0,0 +1,135 @@ +// 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 "modules/compositorworker/AbstractAnimationWorkletThread.h" + +#include "core/workers/WorkerBackingThread.h" +#include "platform/CrossThreadFunctional.h" +#include "platform/WaitableEvent.h" +#include "platform/WebThreadSupportingGC.h" +#include "public/platform/Platform.h" +#include "wtf/Assertions.h" +#include "wtf/PtrUtil.h" +#include <memory> + +namespace blink { + +namespace { + +// This is a singleton class holding the animation worklet thread in this +// renderer process. BackingThreadHolder::m_thread is cleared by +// ModulesInitializer::shutdown. +// See WorkerThread::terminateAndWaitForAllWorkers for the process shutdown +// case. +class BackingThreadHolder { +public: + static BackingThreadHolder& instance() + { + MutexLocker locker(holderInstanceMutex()); + return *s_instance; + } + + static void ensureInstance() + { + if (!s_instance) + s_instance = new BackingThreadHolder; + } + + static void clear() + { + MutexLocker locker(holderInstanceMutex()); + if (s_instance) { + s_instance->shutdownAndWait(); + delete s_instance; + s_instance = nullptr; + } + } + + static void createForTest() + { + MutexLocker locker(holderInstanceMutex()); + DCHECK_EQ(nullptr, s_instance); + s_instance = new BackingThreadHolder(WorkerBackingThread::createForTest(Platform::current()->compositorThread())); + } + + WorkerBackingThread* thread() { return m_thread.get(); } + +private: + BackingThreadHolder(std::unique_ptr<WorkerBackingThread> useBackingThread = nullptr) + : m_thread(useBackingThread ? std::move(useBackingThread) : WorkerBackingThread::create(Platform::current()->compositorThread())) + { + DCHECK(isMainThread()); + m_thread->backingThread().postTask(BLINK_FROM_HERE, crossThreadBind(&BackingThreadHolder::initializeOnThread, crossThreadUnretained(this))); + } + + static Mutex& holderInstanceMutex() + { + DEFINE_THREAD_SAFE_STATIC_LOCAL(Mutex, holderMutex, new Mutex); + return holderMutex; + } + + void initializeOnThread() + { + MutexLocker locker(holderInstanceMutex()); + DCHECK(!m_initialized); + m_thread->initialize(); + m_initialized = true; + } + + void shutdownAndWait() + { + DCHECK(isMainThread()); + WaitableEvent doneEvent; + m_thread->backingThread().postTask(BLINK_FROM_HERE, crossThreadBind(&BackingThreadHolder::shutdownOnThread, crossThreadUnretained(this), crossThreadUnretained(&doneEvent))); + doneEvent.wait(); + } + + void shutdownOnThread(WaitableEvent* doneEvent) + { + m_thread->shutdown(); + doneEvent->signal(); + } + + std::unique_ptr<WorkerBackingThread> m_thread; + bool m_initialized = false; + + static BackingThreadHolder* s_instance; +}; + +BackingThreadHolder* BackingThreadHolder::s_instance = nullptr; + +} // namespace + +AbstractAnimationWorkletThread::AbstractAnimationWorkletThread(PassRefPtr<WorkerLoaderProxy> workerLoaderProxy, WorkerReportingProxy& workerReportingProxy) + : WorkerThread(workerLoaderProxy, workerReportingProxy) +{ +} + +AbstractAnimationWorkletThread::~AbstractAnimationWorkletThread() +{ +} + +WorkerBackingThread& AbstractAnimationWorkletThread::workerBackingThread() +{ + return *BackingThreadHolder::instance().thread(); +} + +void AbstractAnimationWorkletThread::ensureSharedBackingThread() +{ + DCHECK(isMainThread()); + BackingThreadHolder::ensureInstance(); +} + +void AbstractAnimationWorkletThread::clearSharedBackingThread() +{ + DCHECK(isMainThread()); + BackingThreadHolder::clear(); +} + +void AbstractAnimationWorkletThread::createSharedBackingThreadForTest() +{ + BackingThreadHolder::createForTest(); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/modules/compositorworker/AbstractAnimationWorkletThread.h b/third_party/WebKit/Source/modules/compositorworker/AbstractAnimationWorkletThread.h new file mode 100644 index 0000000..deb0f5a --- /dev/null +++ b/third_party/WebKit/Source/modules/compositorworker/AbstractAnimationWorkletThread.h
@@ -0,0 +1,39 @@ +// 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 AbstractAnimationWorkletThread_h +#define AbstractAnimationWorkletThread_h + +#include "core/workers/WorkerLoaderProxy.h" +#include "core/workers/WorkerThread.h" +#include "modules/ModulesExport.h" +#include <memory> + +namespace blink { + +class WorkerReportingProxy; + +// TODO(ikilpatrick): Remove this class up to AnimationWorkletThread once we no +// longer have CompositorWorker. +class MODULES_EXPORT AbstractAnimationWorkletThread : public WorkerThread { +public: + ~AbstractAnimationWorkletThread() override; + + WorkerBackingThread& workerBackingThread() override; + bool shouldAttachThreadDebugger() const override { return false; } + + static void ensureSharedBackingThread(); + static void createSharedBackingThreadForTest(); + + static void clearSharedBackingThread(); + +protected: + AbstractAnimationWorkletThread(PassRefPtr<WorkerLoaderProxy>, WorkerReportingProxy&); + + bool isOwningBackingThread() const override { return false; } +}; + +} // namespace blink + +#endif // AbstractAnimationWorkletThread_h
diff --git a/third_party/WebKit/Source/modules/compositorworker/AnimationWorkletThread.cpp b/third_party/WebKit/Source/modules/compositorworker/AnimationWorkletThread.cpp new file mode 100644 index 0000000..45c73b5 --- /dev/null +++ b/third_party/WebKit/Source/modules/compositorworker/AnimationWorkletThread.cpp
@@ -0,0 +1,36 @@ +// 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 "modules/compositorworker/AnimationWorkletThread.h" + +#include "core/workers/WorkerThreadStartupData.h" +#include "platform/TraceEvent.h" +#include "wtf/PtrUtil.h" + +namespace blink { + +std::unique_ptr<AnimationWorkletThread> AnimationWorkletThread::create(PassRefPtr<WorkerLoaderProxy> workerLoaderProxy, WorkerReportingProxy& workerReportingProxy) +{ + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("animation-worklet"), "AnimationWorkletThread::create"); + DCHECK(isMainThread()); + return wrapUnique(new AnimationWorkletThread(workerLoaderProxy, workerReportingProxy)); +} + +AnimationWorkletThread::AnimationWorkletThread(PassRefPtr<WorkerLoaderProxy> workerLoaderProxy, WorkerReportingProxy& workerReportingProxy) + : AbstractAnimationWorkletThread(workerLoaderProxy, workerReportingProxy) +{ +} + +AnimationWorkletThread::~AnimationWorkletThread() +{ +} + +WorkerOrWorkletGlobalScope* AnimationWorkletThread::createWorkerGlobalScope(std::unique_ptr<WorkerThreadStartupData> startupData) +{ + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("animation-worklet"), "AnimationWorkletThread::createWorkerGlobalScope"); + // TODO(ikilpatrick): implement. + return nullptr; +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/modules/compositorworker/AnimationWorkletThread.h b/third_party/WebKit/Source/modules/compositorworker/AnimationWorkletThread.h new file mode 100644 index 0000000..39b5a3c6 --- /dev/null +++ b/third_party/WebKit/Source/modules/compositorworker/AnimationWorkletThread.h
@@ -0,0 +1,30 @@ +// 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 AnimationWorkletThread_h +#define AnimationWorkletThread_h + +#include "modules/ModulesExport.h" +#include "modules/compositorworker/AbstractAnimationWorkletThread.h" +#include <memory> + +namespace blink { + +class WorkerReportingProxy; + +class MODULES_EXPORT AnimationWorkletThread final : public AbstractAnimationWorkletThread { +public: + static std::unique_ptr<AnimationWorkletThread> create(PassRefPtr<WorkerLoaderProxy>, WorkerReportingProxy&); + ~AnimationWorkletThread() override; + +protected: + WorkerOrWorkletGlobalScope* createWorkerGlobalScope(std::unique_ptr<WorkerThreadStartupData>) final; + +private: + AnimationWorkletThread(PassRefPtr<WorkerLoaderProxy>, WorkerReportingProxy&); +}; + +} // namespace blink + +#endif // AnimationWorkletThread_h
diff --git a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.cpp b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.cpp index dcf5b79..ec0872e 100644 --- a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.cpp +++ b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.cpp
@@ -4,109 +4,15 @@ #include "modules/compositorworker/CompositorWorkerThread.h" -#include "bindings/core/v8/V8GCController.h" -#include "bindings/core/v8/V8Initializer.h" #include "core/workers/InProcessWorkerObjectProxy.h" -#include "core/workers/WorkerBackingThread.h" #include "core/workers/WorkerThreadStartupData.h" #include "modules/compositorworker/CompositorWorkerGlobalScope.h" -#include "platform/CrossThreadFunctional.h" #include "platform/TraceEvent.h" -#include "platform/WaitableEvent.h" -#include "platform/WebThreadSupportingGC.h" -#include "public/platform/Platform.h" #include "wtf/Assertions.h" -#include "wtf/PtrUtil.h" #include <memory> namespace blink { -namespace { - -// This is a singleton class holding the compositor worker thread in this -// renderer process. BackingThreadHolder::m_thread is cleared by -// ModulesInitializer::shutdown. -// See WorkerThread::terminateAndWaitForAllWorkers for the process shutdown -// case. -class BackingThreadHolder { -public: - static BackingThreadHolder& instance() - { - MutexLocker locker(holderInstanceMutex()); - return *s_instance; - } - - static void ensureInstance() - { - if (!s_instance) - s_instance = new BackingThreadHolder; - } - - static void clear() - { - MutexLocker locker(holderInstanceMutex()); - if (s_instance) { - s_instance->shutdownAndWait(); - delete s_instance; - s_instance = nullptr; - } - } - - static void createForTest() - { - MutexLocker locker(holderInstanceMutex()); - DCHECK_EQ(nullptr, s_instance); - s_instance = new BackingThreadHolder(WorkerBackingThread::createForTest(Platform::current()->compositorThread())); - } - - WorkerBackingThread* thread() { return m_thread.get(); } - -private: - BackingThreadHolder(std::unique_ptr<WorkerBackingThread> useBackingThread = nullptr) - : m_thread(useBackingThread ? std::move(useBackingThread) : WorkerBackingThread::create(Platform::current()->compositorThread())) - { - DCHECK(isMainThread()); - m_thread->backingThread().postTask(BLINK_FROM_HERE, crossThreadBind(&BackingThreadHolder::initializeOnThread, crossThreadUnretained(this))); - } - - static Mutex& holderInstanceMutex() - { - DEFINE_THREAD_SAFE_STATIC_LOCAL(Mutex, holderMutex, new Mutex); - return holderMutex; - } - - void initializeOnThread() - { - MutexLocker locker(holderInstanceMutex()); - DCHECK(!m_initialized); - m_thread->initialize(); - m_initialized = true; - } - - void shutdownAndWait() - { - DCHECK(isMainThread()); - WaitableEvent doneEvent; - m_thread->backingThread().postTask(BLINK_FROM_HERE, crossThreadBind(&BackingThreadHolder::shutdownOnThread, crossThreadUnretained(this), crossThreadUnretained(&doneEvent))); - doneEvent.wait(); - } - - void shutdownOnThread(WaitableEvent* doneEvent) - { - m_thread->shutdown(); - doneEvent->signal(); - } - - std::unique_ptr<WorkerBackingThread> m_thread; - bool m_initialized = false; - - static BackingThreadHolder* s_instance; -}; - -BackingThreadHolder* BackingThreadHolder::s_instance = nullptr; - -} // namespace - std::unique_ptr<CompositorWorkerThread> CompositorWorkerThread::create(PassRefPtr<WorkerLoaderProxy> workerLoaderProxy, InProcessWorkerObjectProxy& workerObjectProxy, double timeOrigin) { TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("compositor-worker"), "CompositorWorkerThread::create"); @@ -115,7 +21,7 @@ } CompositorWorkerThread::CompositorWorkerThread(PassRefPtr<WorkerLoaderProxy> workerLoaderProxy, InProcessWorkerObjectProxy& workerObjectProxy, double timeOrigin) - : WorkerThread(workerLoaderProxy, workerObjectProxy) + : AbstractAnimationWorkletThread(workerLoaderProxy, workerObjectProxy) , m_workerObjectProxy(workerObjectProxy) , m_timeOrigin(timeOrigin) { @@ -125,37 +31,10 @@ { } -WorkerBackingThread& CompositorWorkerThread::workerBackingThread() -{ - return *BackingThreadHolder::instance().thread(); -} - WorkerOrWorkletGlobalScope* CompositorWorkerThread::createWorkerGlobalScope(std::unique_ptr<WorkerThreadStartupData> startupData) { TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("compositor-worker"), "CompositorWorkerThread::createWorkerGlobalScope"); return CompositorWorkerGlobalScope::create(this, std::move(startupData), m_timeOrigin); } -ConsoleMessageStorage* CompositorWorkerThread::consoleMessageStorage() -{ - return toWorkerGlobalScope(globalScope())->consoleMessageStorage(); -} - -void CompositorWorkerThread::ensureSharedBackingThread() -{ - DCHECK(isMainThread()); - BackingThreadHolder::ensureInstance(); -} - -void CompositorWorkerThread::clearSharedBackingThread() -{ - DCHECK(isMainThread()); - BackingThreadHolder::clear(); -} - -void CompositorWorkerThread::createSharedBackingThreadForTest() -{ - BackingThreadHolder::createForTest(); -} - } // namespace blink
diff --git a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.h b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.h index e8f7de7..1049f06 100644 --- a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.h +++ b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.h
@@ -5,36 +5,27 @@ #ifndef CompositorWorkerThread_h #define CompositorWorkerThread_h -#include "core/workers/WorkerThread.h" #include "modules/ModulesExport.h" +#include "modules/compositorworker/AbstractAnimationWorkletThread.h" #include <memory> namespace blink { class InProcessWorkerObjectProxy; -class MODULES_EXPORT CompositorWorkerThread final : public WorkerThread { +class MODULES_EXPORT CompositorWorkerThread final : public AbstractAnimationWorkletThread { public: static std::unique_ptr<CompositorWorkerThread> create(PassRefPtr<WorkerLoaderProxy>, InProcessWorkerObjectProxy&, double timeOrigin); ~CompositorWorkerThread() override; InProcessWorkerObjectProxy& workerObjectProxy() const { return m_workerObjectProxy; } - WorkerBackingThread& workerBackingThread() override; - ConsoleMessageStorage* consoleMessageStorage() final; - bool shouldAttachThreadDebugger() const override { return false; } - - static void ensureSharedBackingThread(); - static void createSharedBackingThreadForTest(); - - static void clearSharedBackingThread(); protected: - CompositorWorkerThread(PassRefPtr<WorkerLoaderProxy>, InProcessWorkerObjectProxy&, double timeOrigin); - WorkerOrWorkletGlobalScope* createWorkerGlobalScope(std::unique_ptr<WorkerThreadStartupData>) override; - bool isOwningBackingThread() const override { return false; } private: + CompositorWorkerThread(PassRefPtr<WorkerLoaderProxy>, InProcessWorkerObjectProxy&, double timeOrigin); + InProcessWorkerObjectProxy& m_workerObjectProxy; double m_timeOrigin; };
diff --git a/third_party/WebKit/Source/modules/compositorworker/OWNERS b/third_party/WebKit/Source/modules/compositorworker/OWNERS index ab4484b..95bfcce 100644 --- a/third_party/WebKit/Source/modules/compositorworker/OWNERS +++ b/third_party/WebKit/Source/modules/compositorworker/OWNERS
@@ -1,2 +1,5 @@ +flackr@chromium.org + # for Worker related changes kinuko@chromium.org +nhiroki@chromium.org
diff --git a/third_party/WebKit/Source/modules/fetch/BodyStreamBuffer.cpp b/third_party/WebKit/Source/modules/fetch/BodyStreamBuffer.cpp index ea9bebe..27d7194e2 100644 --- a/third_party/WebKit/Source/modules/fetch/BodyStreamBuffer.cpp +++ b/third_party/WebKit/Source/modules/fetch/BodyStreamBuffer.cpp
@@ -17,7 +17,6 @@ #include "modules/fetch/DataConsumerHandleUtil.h" #include "modules/fetch/DataConsumerTee.h" #include "modules/fetch/ReadableStreamDataConsumerHandle.h" -#include "platform/RuntimeEnabledFeatures.h" #include "platform/blob/BlobData.h" #include "platform/network/EncodedFormData.h" #include <memory> @@ -105,34 +104,29 @@ , m_reader(m_handle->obtainFetchDataReader(this)) , m_madeFromReadableStream(false) { - if (RuntimeEnabledFeatures::responseBodyWithV8ExtraStreamEnabled()) { - if (isTerminating(scriptState)) { - m_reader = nullptr; - m_handle = nullptr; - return; - } - v8::Local<v8::Value> bodyValue = toV8(this, scriptState); - if (bodyValue.IsEmpty()) { - DCHECK(isTerminating(scriptState)); - m_reader = nullptr; - m_handle = nullptr; - return; - } - ASSERT(bodyValue->IsObject()); - v8::Local<v8::Object> body = bodyValue.As<v8::Object>(); - - ScriptValue readableStream = ReadableStreamOperations::createReadableStream( - scriptState, this, ReadableStreamOperations::createCountQueuingStrategy(scriptState, 0)); - if (isTerminating(scriptState)) { - m_reader = nullptr; - m_handle = nullptr; - return; - } - V8HiddenValue::setHiddenValue(scriptState, body, V8HiddenValue::internalBodyStream(scriptState->isolate()), readableStream.v8Value()); - } else { - m_stream = new ReadableByteStream(this, new ReadableByteStream::StrictStrategy); - m_stream->didSourceStart(); + if (isTerminating(scriptState)) { + m_reader = nullptr; + m_handle = nullptr; + return; } + v8::Local<v8::Value> bodyValue = toV8(this, scriptState); + if (bodyValue.IsEmpty()) { + DCHECK(isTerminating(scriptState)); + m_reader = nullptr; + m_handle = nullptr; + return; + } + DCHECK(bodyValue->IsObject()); + v8::Local<v8::Object> body = bodyValue.As<v8::Object>(); + + ScriptValue readableStream = ReadableStreamOperations::createReadableStream( + scriptState, this, ReadableStreamOperations::createCountQueuingStrategy(scriptState, 0)); + if (isTerminating(scriptState)) { + m_reader = nullptr; + m_handle = nullptr; + return; + } + V8HiddenValue::setHiddenValue(scriptState, body, V8HiddenValue::internalBodyStream(scriptState->isolate()), readableStream.v8Value()); } BodyStreamBuffer::BodyStreamBuffer(ScriptState* scriptState, ScriptValue stream) @@ -140,7 +134,6 @@ , m_scriptState(scriptState) , m_madeFromReadableStream(true) { - DCHECK(RuntimeEnabledFeatures::responseBodyWithV8ExtraStreamEnabled()); DCHECK(ReadableStreamOperations::isReadableStream(scriptState, stream)); if (isTerminating(scriptState)) return; @@ -158,19 +151,16 @@ ScriptValue BodyStreamBuffer::stream() { ScriptState::Scope scope(m_scriptState.get()); - if (RuntimeEnabledFeatures::responseBodyWithV8ExtraStreamEnabled()) { - if (isTerminating(m_scriptState.get())) - return ScriptValue(); - v8::Local<v8::Value> bodyValue = toV8(this, m_scriptState.get()); - if (bodyValue.IsEmpty()) { - DCHECK(isTerminating(m_scriptState.get())); - return ScriptValue(); - } - ASSERT(bodyValue->IsObject()); - v8::Local<v8::Object> body = bodyValue.As<v8::Object>(); - return ScriptValue(m_scriptState.get(), V8HiddenValue::getHiddenValue(m_scriptState.get(), body, V8HiddenValue::internalBodyStream(m_scriptState->isolate()))); + if (isTerminating(m_scriptState.get())) + return ScriptValue(); + v8::Local<v8::Value> bodyValue = toV8(this, m_scriptState.get()); + if (bodyValue.IsEmpty()) { + DCHECK(isTerminating(m_scriptState.get())); + return ScriptValue(); } - return ScriptValue(m_scriptState.get(), toV8(m_stream, m_scriptState.get())); + DCHECK(bodyValue->IsObject()); + v8::Local<v8::Object> body = bodyValue.As<v8::Object>(); + return ScriptValue(m_scriptState.get(), V8HiddenValue::getHiddenValue(m_scriptState.get(), body, V8HiddenValue::internalBodyStream(m_scriptState->isolate()))); } PassRefPtr<BlobDataHandle> BodyStreamBuffer::drainAsBlobDataHandle(FetchDataConsumerHandle::Reader::BlobSizePolicy policy) @@ -239,20 +229,6 @@ *branch2 = new BodyStreamBuffer(m_scriptState.get(), std::move(handle2)); } -void BodyStreamBuffer::pullSource() -{ - ASSERT(!m_streamNeedsMore); - m_streamNeedsMore = true; - processData(); -} - -ScriptPromise BodyStreamBuffer::cancelSource(ScriptState* scriptState, ScriptValue) -{ - ASSERT(scriptState == m_scriptState.get()); - close(); - return ScriptPromise::castUndefined(scriptState); -} - ScriptPromise BodyStreamBuffer::pull(ScriptState* scriptState) { ASSERT(!m_streamNeedsMore); @@ -300,10 +276,7 @@ { if (m_loader) return true; - if (RuntimeEnabledFeatures::responseBodyWithV8ExtraStreamEnabled()) - return UnderlyingSourceBase::hasPendingActivity(); - - return m_stream->stateInternal() == ReadableStream::Readable && m_stream->isLocked(); + return UnderlyingSourceBase::hasPendingActivity(); } void BodyStreamBuffer::stop() @@ -315,47 +288,32 @@ bool BodyStreamBuffer::isStreamReadable() { - if (RuntimeEnabledFeatures::responseBodyWithV8ExtraStreamEnabled()) { - ScriptState::Scope scope(m_scriptState.get()); - return ReadableStreamOperations::isReadable(m_scriptState.get(), stream()); - } - return m_stream->stateInternal() == ReadableStream::Readable; + ScriptState::Scope scope(m_scriptState.get()); + return ReadableStreamOperations::isReadable(m_scriptState.get(), stream()); } bool BodyStreamBuffer::isStreamClosed() { - if (RuntimeEnabledFeatures::responseBodyWithV8ExtraStreamEnabled()) { - ScriptState::Scope scope(m_scriptState.get()); - return ReadableStreamOperations::isClosed(m_scriptState.get(), stream()); - } - return m_stream->stateInternal() == ReadableStream::Closed; + ScriptState::Scope scope(m_scriptState.get()); + return ReadableStreamOperations::isClosed(m_scriptState.get(), stream()); } bool BodyStreamBuffer::isStreamErrored() { - if (RuntimeEnabledFeatures::responseBodyWithV8ExtraStreamEnabled()) { - ScriptState::Scope scope(m_scriptState.get()); - return ReadableStreamOperations::isErrored(m_scriptState.get(), stream()); - } - return m_stream->stateInternal() == ReadableStream::Errored; + ScriptState::Scope scope(m_scriptState.get()); + return ReadableStreamOperations::isErrored(m_scriptState.get(), stream()); } bool BodyStreamBuffer::isStreamLocked() { - if (RuntimeEnabledFeatures::responseBodyWithV8ExtraStreamEnabled()) { - ScriptState::Scope scope(m_scriptState.get()); - return ReadableStreamOperations::isLocked(m_scriptState.get(), stream()); - } - return m_stream->isLocked(); + ScriptState::Scope scope(m_scriptState.get()); + return ReadableStreamOperations::isLocked(m_scriptState.get(), stream()); } bool BodyStreamBuffer::isStreamDisturbed() { - if (RuntimeEnabledFeatures::responseBodyWithV8ExtraStreamEnabled()) { - ScriptState::Scope scope(m_scriptState.get()); - return ReadableStreamOperations::isDisturbed(m_scriptState.get(), stream()); - } - return m_stream->isDisturbed(); + ScriptState::Scope scope(m_scriptState.get()); + return ReadableStreamOperations::isDisturbed(m_scriptState.get(), stream()); } void BodyStreamBuffer::closeAndLockAndDisturb() @@ -366,34 +324,22 @@ close(); } - if (RuntimeEnabledFeatures::responseBodyWithV8ExtraStreamEnabled()) { - ScriptState::Scope scope(m_scriptState.get()); - NonThrowableExceptionState exceptionState; - ScriptValue reader = ReadableStreamOperations::getReader(m_scriptState.get(), stream(), exceptionState); - ReadableStreamOperations::defaultReaderRead(m_scriptState.get(), reader); - } else { - NonThrowableExceptionState exceptionState; - m_stream->getBytesReader(m_scriptState->getExecutionContext(), exceptionState); - m_stream->setIsDisturbed(); - } + ScriptState::Scope scope(m_scriptState.get()); + NonThrowableExceptionState exceptionState; + ScriptValue reader = ReadableStreamOperations::getReader(m_scriptState.get(), stream(), exceptionState); + ReadableStreamOperations::defaultReaderRead(m_scriptState.get(), reader); } void BodyStreamBuffer::close() { - if (RuntimeEnabledFeatures::responseBodyWithV8ExtraStreamEnabled()) - controller()->close(); - else - m_stream->close(); + controller()->close(); m_reader = nullptr; m_handle = nullptr; } void BodyStreamBuffer::error() { - if (RuntimeEnabledFeatures::responseBodyWithV8ExtraStreamEnabled()) - controller()->error(DOMException::create(NetworkError, "network error")); - else - m_stream->error(DOMException::create(NetworkError, "network error")); + controller()->error(DOMException::create(NetworkError, "network error")); m_reader = nullptr; m_handle = nullptr; } @@ -408,12 +354,8 @@ switch (result) { case WebDataConsumerHandle::Ok: { DOMUint8Array* array = DOMUint8Array::create(static_cast<const unsigned char*>(buffer), available); - if (RuntimeEnabledFeatures::responseBodyWithV8ExtraStreamEnabled()) { - controller()->enqueue(array); - m_streamNeedsMore = controller()->desiredSize() > 0; - } else { - m_streamNeedsMore = m_stream->enqueue(array); - } + controller()->enqueue(array); + m_streamNeedsMore = controller()->desiredSize() > 0; m_reader->endRead(available); break; }
diff --git a/third_party/WebKit/Source/modules/fetch/BodyStreamBuffer.h b/third_party/WebKit/Source/modules/fetch/BodyStreamBuffer.h index 403b0b1..707ab66 100644 --- a/third_party/WebKit/Source/modules/fetch/BodyStreamBuffer.h +++ b/third_party/WebKit/Source/modules/fetch/BodyStreamBuffer.h
@@ -8,9 +8,6 @@ #include "bindings/core/v8/ScriptPromise.h" #include "bindings/core/v8/ScriptValue.h" #include "core/dom/DOMException.h" -#include "core/streams/ReadableByteStream.h" -#include "core/streams/ReadableByteStreamReader.h" -#include "core/streams/UnderlyingSource.h" #include "core/streams/UnderlyingSourceBase.h" #include "modules/ModulesExport.h" #include "modules/fetch/FetchDataConsumerHandle.h" @@ -24,7 +21,7 @@ class EncodedFormData; class ScriptState; -class MODULES_EXPORT BodyStreamBuffer final : public UnderlyingSourceBase, public UnderlyingSource, public WebDataConsumerHandle::Client { +class MODULES_EXPORT BodyStreamBuffer final : public UnderlyingSourceBase, public WebDataConsumerHandle::Client { WTF_MAKE_NONCOPYABLE(BodyStreamBuffer); USING_GARBAGE_COLLECTED_MIXIN(BodyStreamBuffer); public: @@ -45,10 +42,6 @@ void startLoading(FetchDataLoader*, FetchDataLoader::Client* /* client */); void tee(BodyStreamBuffer**, BodyStreamBuffer**); - // UnderlyingSource - void pullSource() override; - ScriptPromise cancelSource(ScriptState*, ScriptValue reason) override; - // UnderlyingSourceBase ScriptPromise pull(ScriptState*) override; ScriptPromise cancel(ScriptState*, ScriptValue reason) override; @@ -68,10 +61,8 @@ DEFINE_INLINE_TRACE() { - visitor->trace(m_stream); visitor->trace(m_loader); UnderlyingSourceBase::trace(visitor); - UnderlyingSource::trace(visitor); } private: @@ -87,7 +78,6 @@ RefPtr<ScriptState> m_scriptState; std::unique_ptr<FetchDataConsumerHandle> m_handle; std::unique_ptr<FetchDataConsumerHandle::Reader> m_reader; - Member<ReadableByteStream> m_stream; // We need this member to keep it alive while loading. Member<FetchDataLoader> m_loader; bool m_streamNeedsMore = false;
diff --git a/third_party/WebKit/Source/modules/fetch/BodyStreamBufferTest.cpp b/third_party/WebKit/Source/modules/fetch/BodyStreamBufferTest.cpp index 83ed30b..ef277f8 100644 --- a/third_party/WebKit/Source/modules/fetch/BodyStreamBufferTest.cpp +++ b/third_party/WebKit/Source/modules/fetch/BodyStreamBufferTest.cpp
@@ -500,7 +500,7 @@ BodyStreamBuffer* buffer = new BodyStreamBuffer(scope.getScriptState(), std::move(handle)); checkpoint.Call(1); ScriptValue reason(scope.getScriptState(), v8String(scope.getScriptState()->isolate(), "reason")); - buffer->cancelSource(scope.getScriptState(), reason); + buffer->cancel(scope.getScriptState(), reason); checkpoint.Call(2); }
diff --git a/third_party/WebKit/Source/modules/fetch/FetchRequestData.cpp b/third_party/WebKit/Source/modules/fetch/FetchRequestData.cpp index 0776cae1..811ef0d 100644 --- a/third_party/WebKit/Source/modules/fetch/FetchRequestData.cpp +++ b/third_party/WebKit/Source/modules/fetch/FetchRequestData.cpp
@@ -8,7 +8,6 @@ #include "core/dom/ExecutionContext.h" #include "core/fetch/ResourceLoaderOptions.h" #include "core/loader/ThreadableLoader.h" -#include "core/streams/ReadableStream.h" #include "modules/credentialmanager/PasswordCredential.h" #include "modules/fetch/BodyStreamBuffer.h" #include "modules/fetch/DataConsumerHandleUtil.h"
diff --git a/third_party/WebKit/Source/modules/fetch/Response.cpp b/third_party/WebKit/Source/modules/fetch/Response.cpp index 76af6c3b7..356e6b6b 100644 --- a/third_party/WebKit/Source/modules/fetch/Response.cpp +++ b/third_party/WebKit/Source/modules/fetch/Response.cpp
@@ -26,7 +26,6 @@ #include "modules/fetch/FetchFormDataConsumerHandle.h" #include "modules/fetch/ReadableStreamDataConsumerHandle.h" #include "modules/fetch/ResponseInit.h" -#include "platform/RuntimeEnabledFeatures.h" #include "platform/network/EncodedFormData.h" #include "platform/network/HTTPHeaderMap.h" #include "public/platform/modules/serviceworker/WebServiceWorkerResponse.h" @@ -149,21 +148,8 @@ RefPtr<EncodedFormData> formData = V8URLSearchParams::toImpl(body.As<v8::Object>())->toEncodedFormData(); bodyBuffer = new BodyStreamBuffer(scriptState, FetchFormDataConsumerHandle::create(executionContext, formData.release())); contentType = "application/x-www-form-urlencoded;charset=UTF-8"; - } else if (RuntimeEnabledFeatures::responseConstructedWithReadableStreamEnabled() && ReadableStreamOperations::isReadableStream(scriptState, bodyValue)) { - if (RuntimeEnabledFeatures::responseBodyWithV8ExtraStreamEnabled()) { - bodyBuffer = new BodyStreamBuffer(scriptState, bodyValue); - } else { - std::unique_ptr<FetchDataConsumerHandle> bodyHandle; - reader = ReadableStreamOperations::getReader(scriptState, bodyValue, exceptionState); - if (exceptionState.hadException()) { - reader = ScriptValue(); - bodyHandle = createFetchDataConsumerHandleFromWebHandle(createUnexpectedErrorDataConsumerHandle()); - exceptionState.clearException(); - } else { - bodyHandle = ReadableStreamDataConsumerHandle::create(scriptState, reader); - } - bodyBuffer = new BodyStreamBuffer(scriptState, std::move(bodyHandle)); - } + } else if (ReadableStreamOperations::isReadableStream(scriptState, bodyValue)) { + bodyBuffer = new BodyStreamBuffer(scriptState, bodyValue); } else { String string = toUSVString(isolate, body, exceptionState); if (exceptionState.hadException())
diff --git a/third_party/WebKit/Source/modules/modules.gypi b/third_party/WebKit/Source/modules/modules.gypi index 4af94b2..0f45df5 100644 --- a/third_party/WebKit/Source/modules/modules.gypi +++ b/third_party/WebKit/Source/modules/modules.gypi
@@ -943,8 +943,12 @@ 'canvas2d/HitRegion.cpp', 'canvas2d/HitRegion.h', 'canvas2d/Path2D.h', + 'compositorworker/AbstractAnimationWorkletThread.cpp', + 'compositorworker/AbstractAnimationWorkletThread.h', 'compositorworker/AnimationWorklet.cpp', 'compositorworker/AnimationWorklet.h', + 'compositorworker/AnimationWorkletThread.cpp', + 'compositorworker/AnimationWorkletThread.h', 'compositorworker/CompositorWorker.cpp', 'compositorworker/CompositorWorker.h', 'compositorworker/CompositorWorkerGlobalScope.cpp',
diff --git a/third_party/WebKit/Source/modules/plugins/PluginOcclusionSupport.cpp b/third_party/WebKit/Source/modules/plugins/PluginOcclusionSupport.cpp index adf3a3e..34076a3 100644 --- a/third_party/WebKit/Source/modules/plugins/PluginOcclusionSupport.cpp +++ b/third_party/WebKit/Source/modules/plugins/PluginOcclusionSupport.cpp
@@ -115,7 +115,7 @@ static bool intersectsRect(const LayoutObject* renderer, const IntRect& rect) { return renderer->absoluteBoundingBoxRectIgnoringTransforms().intersects(rect) - && (!renderer->style() || renderer->style()->visibility() == VISIBLE); + && (!renderer->style() || renderer->style()->visibility() == EVisibility::Visible); } static void addToOcclusions(const LayoutBox* renderer, Vector<IntRect>& occlusions)
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerThread.cpp b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerThread.cpp index 07d58e5..9621525 100644 --- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerThread.cpp +++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerThread.cpp
@@ -58,9 +58,4 @@ return ServiceWorkerGlobalScope::create(this, std::move(startupData)); } -ConsoleMessageStorage* ServiceWorkerThread::consoleMessageStorage() -{ - return toWorkerGlobalScope(globalScope())->consoleMessageStorage(); -} - } // namespace blink
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerThread.h b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerThread.h index 878c77d9..1a3718f 100644 --- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerThread.h +++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerThread.h
@@ -45,7 +45,6 @@ ~ServiceWorkerThread() override; WorkerBackingThread& workerBackingThread() override { return *m_workerBackingThread; } - ConsoleMessageStorage* consoleMessageStorage() final; protected: WorkerOrWorkletGlobalScope* createWorkerGlobalScope(std::unique_ptr<WorkerThreadStartupData>) override;
diff --git a/third_party/WebKit/Source/modules/vibration/NavigatorVibration.cpp b/third_party/WebKit/Source/modules/vibration/NavigatorVibration.cpp index 9ca5c36c..50e5ce2 100644 --- a/third_party/WebKit/Source/modules/vibration/NavigatorVibration.cpp +++ b/third_party/WebKit/Source/modules/vibration/NavigatorVibration.cpp
@@ -92,7 +92,7 @@ UseCounter::count(&frame, UseCounter::NavigatorVibrate); if (!frame.isMainFrame()) { UseCounter::count(&frame, UseCounter::NavigatorVibrateSubFrame); - if (frame.isCrossOrigin()) { + if (frame.isCrossOriginSubframe()) { if (userGesture) type = NavigatorVibrationType::CrossOriginSubFrameWithUserGesture; else
diff --git a/third_party/WebKit/Source/modules/worklet/OWNERS b/third_party/WebKit/Source/modules/worklet/OWNERS index e67a8c32..d919566 100644 --- a/third_party/WebKit/Source/modules/worklet/OWNERS +++ b/third_party/WebKit/Source/modules/worklet/OWNERS
@@ -1 +1,2 @@ kinuko@chromium.org +nhiroki@chromium.org
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn index 7f6aa29..ffa75b7 100644 --- a/third_party/WebKit/Source/platform/BUILD.gn +++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -611,6 +611,31 @@ include_dirs = [ "$root_gen_dir/blink" ] } +test("blink_platform_perftests") { + sources = [ + "scheduler/base/task_queue_manager_delegate_for_test.cc", + "scheduler/base/task_queue_manager_delegate_for_test.h", + "scheduler/base/task_queue_manager_perftest.cc", + ] + + configs += [ + # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. + "//build/config/compiler:no_size_t_to_int_warning", + "//third_party/WebKit/Source/wtf:wtf_config", + "//third_party/WebKit/Source:config", + ] + + deps = [ + ":blink_common", + ":platform", + "//base", + "//base/test:test_support", + "//base/test:test_support_perf", + "//testing/gtest", + "//testing/perf", + ] +} + group("blink_platform_unittests_data") { data = [ "testing/data/",
diff --git a/third_party/WebKit/Source/platform/PlatformWheelEvent.h b/third_party/WebKit/Source/platform/PlatformWheelEvent.h index e6c8890..66d3eca 100644 --- a/third_party/WebKit/Source/platform/PlatformWheelEvent.h +++ b/third_party/WebKit/Source/platform/PlatformWheelEvent.h
@@ -69,8 +69,6 @@ #if OS(MACOSX) , m_phase(PlatformWheelEventPhaseNone) , m_momentumPhase(PlatformWheelEventPhaseNone) - , m_canRubberbandLeft(true) - , m_canRubberbandRight(true) #endif { } @@ -95,8 +93,6 @@ #if OS(MACOSX) PlatformWheelEventPhase phase() const { return m_phase; } PlatformWheelEventPhase momentumPhase() const { return m_momentumPhase; } - bool canRubberbandLeft() const { return m_canRubberbandLeft; } - bool canRubberbandRight() const { return m_canRubberbandRight; } #endif protected: @@ -114,8 +110,6 @@ #if OS(MACOSX) PlatformWheelEventPhase m_phase; PlatformWheelEventPhase m_momentumPhase; - bool m_canRubberbandLeft; - bool m_canRubberbandRight; #endif };
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in index e4aac0a..0b860b9 100644 --- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in +++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
@@ -40,6 +40,7 @@ EnableCanvas2dDynamicRenderingModeSwitching status=experimental Canvas2dImageChromium status=experimental ClientHints status=stable +CompositeOpaqueScrollers CompositedSelectionUpdate CompositorWorker status=experimental ContextMenu status=test @@ -173,8 +174,6 @@ RenderingPipelineThrottling status=stable RenderUnicodeControlCharacters status=experimental RequestIdleCallback status=stable -ResponseConstructedWithReadableStream status=stable -ResponseBodyWithV8ExtraStream status=stable ResizeObserver status=experimental RTCPeerConnectionNewGetStats status=test SandboxBlocksModals status=stable @@ -210,6 +209,7 @@ SpeculativeLaunchServiceWorker StorageEstimate status=experimental Suborigins status=test +TimerThrottlingForBackgroundTabs status=stable // Many websites disable mouse support when touch APIs are available. We'd // like to enable this always but can't until more websites fix this bug. // Chromium sets this conditionally (eg. based on the presence of a
diff --git a/third_party/WebKit/Source/platform/TimerTest.cpp b/third_party/WebKit/Source/platform/TimerTest.cpp index 0c226680..bd37098 100644 --- a/third_party/WebKit/Source/platform/TimerTest.cpp +++ b/third_party/WebKit/Source/platform/TimerTest.cpp
@@ -111,6 +111,12 @@ return gCurrentTimeSecs; } + base::SingleThreadTaskRunner* taskRunner() override + { + ASSERT_NOT_REACHED(); + return nullptr; + } + std::priority_queue<DelayedTask>* m_timerTasks; // NOT OWNED }; @@ -194,7 +200,7 @@ } void shutdown() override {} - std::unique_ptr<WebViewScheduler> createWebViewScheduler(blink::WebView*) override { return nullptr; } + std::unique_ptr<WebViewScheduler> createWebViewScheduler(InterventionReporter*) override { return nullptr; } void suspendTimerQueue() override { } void resumeTimerQueue() override { } void addPendingNavigation(WebScheduler::NavigatingFrameType) override { }
diff --git a/third_party/WebKit/Source/platform/animation/CompositorFilterAnimationCurve.cpp b/third_party/WebKit/Source/platform/animation/CompositorFilterAnimationCurve.cpp index 778d2c2a..df10488 100644 --- a/third_party/WebKit/Source/platform/animation/CompositorFilterAnimationCurve.cpp +++ b/third_party/WebKit/Source/platform/animation/CompositorFilterAnimationCurve.cpp
@@ -9,8 +9,6 @@ #include "cc/output/filter_operations.h" #include "platform/graphics/CompositorFilterOperations.h" -using blink::CompositorFilterKeyframe; - namespace blink { CompositorFilterAnimationCurve::CompositorFilterAnimationCurve() @@ -22,15 +20,7 @@ { } -void CompositorFilterAnimationCurve::addLinearKeyframe(const CompositorFilterKeyframe& keyframe) -{ - const cc::FilterOperations& filterOperations = keyframe.value().asFilterOperations(); - m_curve->AddKeyframe(cc::FilterKeyframe::Create( - base::TimeDelta::FromSecondsD(keyframe.time()), filterOperations, nullptr)); - -} - -void CompositorFilterAnimationCurve::addCubicBezierKeyframe(const CompositorFilterKeyframe& keyframe, const TimingFunction& timingFunction) +void CompositorFilterAnimationCurve::addKeyframe(const CompositorFilterKeyframe& keyframe, const TimingFunction& timingFunction) { const cc::FilterOperations& filterOperations = keyframe.value().asFilterOperations(); m_curve->AddKeyframe(cc::FilterKeyframe::Create( @@ -38,25 +28,7 @@ timingFunction.cloneToCC())); } -void CompositorFilterAnimationCurve::addStepsKeyframe(const CompositorFilterKeyframe& keyframe, const TimingFunction& timingFunction) -{ - const cc::FilterOperations& filterOperations = keyframe.value().asFilterOperations(); - m_curve->AddKeyframe(cc::FilterKeyframe::Create( - base::TimeDelta::FromSecondsD(keyframe.time()), filterOperations, - timingFunction.cloneToCC())); -} - -void CompositorFilterAnimationCurve::setLinearTimingFunction() -{ - m_curve->SetTimingFunction(nullptr); -} - -void CompositorFilterAnimationCurve::setCubicBezierTimingFunction(const TimingFunction& timingFunction) -{ - m_curve->SetTimingFunction(timingFunction.cloneToCC()); -} - -void CompositorFilterAnimationCurve::setStepsTimingFunction(const TimingFunction& timingFunction) +void CompositorFilterAnimationCurve::setTimingFunction(const TimingFunction& timingFunction) { m_curve->SetTimingFunction(timingFunction.cloneToCC()); }
diff --git a/third_party/WebKit/Source/platform/animation/CompositorFilterAnimationCurve.h b/third_party/WebKit/Source/platform/animation/CompositorFilterAnimationCurve.h index 820d825..a2d95ee9 100644 --- a/third_party/WebKit/Source/platform/animation/CompositorFilterAnimationCurve.h +++ b/third_party/WebKit/Source/platform/animation/CompositorFilterAnimationCurve.h
@@ -33,13 +33,8 @@ } ~CompositorFilterAnimationCurve() override; - void addLinearKeyframe(const CompositorFilterKeyframe&); - void addCubicBezierKeyframe(const CompositorFilterKeyframe&, const TimingFunction&); - void addStepsKeyframe(const CompositorFilterKeyframe&, const TimingFunction&); - - void setLinearTimingFunction(); - void setCubicBezierTimingFunction(const TimingFunction&); - void setStepsTimingFunction(const TimingFunction&); + void addKeyframe(const CompositorFilterKeyframe&, const TimingFunction&); + void setTimingFunction(const TimingFunction&); // blink::CompositorAnimationCurve implementation. std::unique_ptr<cc::AnimationCurve> cloneToAnimationCurve() const override;
diff --git a/third_party/WebKit/Source/platform/animation/CompositorFloatAnimationCurve.cpp b/third_party/WebKit/Source/platform/animation/CompositorFloatAnimationCurve.cpp index 52241c5..88874c1 100644 --- a/third_party/WebKit/Source/platform/animation/CompositorFloatAnimationCurve.cpp +++ b/third_party/WebKit/Source/platform/animation/CompositorFloatAnimationCurve.cpp
@@ -10,8 +10,6 @@ #include "wtf/PtrUtil.h" #include <memory> -using blink::CompositorFloatKeyframe; - namespace blink { CompositorFloatAnimationCurve::CompositorFloatAnimationCurve() @@ -73,38 +71,14 @@ return !m_curve->keyframes_for_testing()[index]->timing_function(); } -void CompositorFloatAnimationCurve::addLinearKeyframe(const CompositorFloatKeyframe& keyframe) -{ - m_curve->AddKeyframe( - cc::FloatKeyframe::Create(base::TimeDelta::FromSecondsD(keyframe.time), - keyframe.value, nullptr)); -} - -void CompositorFloatAnimationCurve::addCubicBezierKeyframe(const CompositorFloatKeyframe& keyframe, const TimingFunction& timingFunction) +void CompositorFloatAnimationCurve::addKeyframe(const CompositorFloatKeyframe& keyframe, const TimingFunction& timingFunction) { m_curve->AddKeyframe(cc::FloatKeyframe::Create( base::TimeDelta::FromSecondsD(keyframe.time), keyframe.value, timingFunction.cloneToCC())); } -void CompositorFloatAnimationCurve::addStepsKeyframe(const CompositorFloatKeyframe& keyframe, const TimingFunction& timingFunction) -{ - m_curve->AddKeyframe(cc::FloatKeyframe::Create( - base::TimeDelta::FromSecondsD(keyframe.time), keyframe.value, - timingFunction.cloneToCC())); -} - -void CompositorFloatAnimationCurve::setLinearTimingFunction() -{ - m_curve->SetTimingFunction(nullptr); -} - -void CompositorFloatAnimationCurve::setCubicBezierTimingFunction(const TimingFunction& timingFunction) -{ - m_curve->SetTimingFunction(timingFunction.cloneToCC()); -} - -void CompositorFloatAnimationCurve::setStepsTimingFunction(const TimingFunction& timingFunction) +void CompositorFloatAnimationCurve::setTimingFunction(const TimingFunction& timingFunction) { m_curve->SetTimingFunction(timingFunction.cloneToCC()); }
diff --git a/third_party/WebKit/Source/platform/animation/CompositorFloatAnimationCurve.h b/third_party/WebKit/Source/platform/animation/CompositorFloatAnimationCurve.h index 1d3cf61..00b6312f 100644 --- a/third_party/WebKit/Source/platform/animation/CompositorFloatAnimationCurve.h +++ b/third_party/WebKit/Source/platform/animation/CompositorFloatAnimationCurve.h
@@ -44,13 +44,8 @@ CubicBezierTimingFunction::EaseType getKeyframeEaseTypeForTesting(unsigned long index) const; bool keyframeHasLinearTimingFunctionForTesting(unsigned long index) const; - void addLinearKeyframe(const CompositorFloatKeyframe&); - void addCubicBezierKeyframe(const CompositorFloatKeyframe&, const TimingFunction&); - void addStepsKeyframe(const CompositorFloatKeyframe&, const TimingFunction&); - - void setLinearTimingFunction(); - void setCubicBezierTimingFunction(const TimingFunction&); - void setStepsTimingFunction(const TimingFunction&); + void addKeyframe(const CompositorFloatKeyframe&, const TimingFunction&); + void setTimingFunction(const TimingFunction&); float getValue(double time) const;
diff --git a/third_party/WebKit/Source/platform/animation/CompositorFloatAnimationCurveTest.cpp b/third_party/WebKit/Source/platform/animation/CompositorFloatAnimationCurveTest.cpp index 128ab131..7cb88f5 100644 --- a/third_party/WebKit/Source/platform/animation/CompositorFloatAnimationCurveTest.cpp +++ b/third_party/WebKit/Source/platform/animation/CompositorFloatAnimationCurveTest.cpp
@@ -19,7 +19,7 @@ TEST(WebFloatAnimationCurveTest, OneFloatKeyframe) { std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create(); - curve->addLinearKeyframe(CompositorFloatKeyframe(0, 2)); + curve->addKeyframe(CompositorFloatKeyframe(0, 2), *LinearTimingFunction::shared()); EXPECT_FLOAT_EQ(2, curve->getValue(-1)); EXPECT_FLOAT_EQ(2, curve->getValue(0)); EXPECT_FLOAT_EQ(2, curve->getValue(0.5)); @@ -31,8 +31,8 @@ TEST(WebFloatAnimationCurveTest, TwoFloatKeyframe) { std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create(); - curve->addLinearKeyframe(CompositorFloatKeyframe(0, 2)); - curve->addLinearKeyframe(CompositorFloatKeyframe(1, 4)); + curve->addKeyframe(CompositorFloatKeyframe(0, 2), *LinearTimingFunction::shared()); + curve->addKeyframe(CompositorFloatKeyframe(1, 4), *LinearTimingFunction::shared()); EXPECT_FLOAT_EQ(2, curve->getValue(-1)); EXPECT_FLOAT_EQ(2, curve->getValue(0)); EXPECT_FLOAT_EQ(3, curve->getValue(0.5)); @@ -44,9 +44,9 @@ TEST(WebFloatAnimationCurveTest, ThreeFloatKeyframe) { std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create(); - curve->addLinearKeyframe(CompositorFloatKeyframe(0, 2)); - curve->addLinearKeyframe(CompositorFloatKeyframe(1, 4)); - curve->addLinearKeyframe(CompositorFloatKeyframe(2, 8)); + curve->addKeyframe(CompositorFloatKeyframe(0, 2), *LinearTimingFunction::shared()); + curve->addKeyframe(CompositorFloatKeyframe(1, 4), *LinearTimingFunction::shared()); + curve->addKeyframe(CompositorFloatKeyframe(2, 8), *LinearTimingFunction::shared()); EXPECT_FLOAT_EQ(2, curve->getValue(-1)); EXPECT_FLOAT_EQ(2, curve->getValue(0)); EXPECT_FLOAT_EQ(3, curve->getValue(0.5)); @@ -60,10 +60,10 @@ TEST(WebFloatAnimationCurveTest, RepeatedFloatKeyTimes) { std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create(); - curve->addLinearKeyframe(CompositorFloatKeyframe(0, 4)); - curve->addLinearKeyframe(CompositorFloatKeyframe(1, 4)); - curve->addLinearKeyframe(CompositorFloatKeyframe(1, 6)); - curve->addLinearKeyframe(CompositorFloatKeyframe(2, 6)); + curve->addKeyframe(CompositorFloatKeyframe(0, 4), *LinearTimingFunction::shared()); + curve->addKeyframe(CompositorFloatKeyframe(1, 4), *LinearTimingFunction::shared()); + curve->addKeyframe(CompositorFloatKeyframe(1, 6), *LinearTimingFunction::shared()); + curve->addKeyframe(CompositorFloatKeyframe(2, 6), *LinearTimingFunction::shared()); EXPECT_FLOAT_EQ(4, curve->getValue(-1)); EXPECT_FLOAT_EQ(4, curve->getValue(0)); @@ -82,9 +82,9 @@ TEST(WebFloatAnimationCurveTest, UnsortedKeyframes) { std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create(); - curve->addLinearKeyframe(CompositorFloatKeyframe(2, 8)); - curve->addLinearKeyframe(CompositorFloatKeyframe(0, 2)); - curve->addLinearKeyframe(CompositorFloatKeyframe(1, 4)); + curve->addKeyframe(CompositorFloatKeyframe(2, 8), *LinearTimingFunction::shared()); + curve->addKeyframe(CompositorFloatKeyframe(0, 2), *LinearTimingFunction::shared()); + curve->addKeyframe(CompositorFloatKeyframe(1, 4), *LinearTimingFunction::shared()); EXPECT_FLOAT_EQ(2, curve->getValue(-1)); EXPECT_FLOAT_EQ(2, curve->getValue(0)); @@ -99,8 +99,9 @@ TEST(WebFloatAnimationCurveTest, CubicBezierTimingFunction) { std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create(); - curve->addCubicBezierKeyframe(CompositorFloatKeyframe(0, 0), *CubicBezierTimingFunction::create(0.25, 0, 0.75, 1)); - curve->addLinearKeyframe(CompositorFloatKeyframe(1, 1)); + RefPtr<CubicBezierTimingFunction> cubic = CubicBezierTimingFunction::create(0.25, 0, 0.75, 1); + curve->addKeyframe(CompositorFloatKeyframe(0, 0), *cubic); + curve->addKeyframe(CompositorFloatKeyframe(1, 1), *LinearTimingFunction::shared()); EXPECT_FLOAT_EQ(0, curve->getValue(0)); EXPECT_LT(0, curve->getValue(0.25)); @@ -115,8 +116,8 @@ TEST(WebFloatAnimationCurveTest, EaseTimingFunction) { std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create(); - curve->addCubicBezierKeyframe(CompositorFloatKeyframe(0, 0), *CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseType::EASE)); - curve->addLinearKeyframe(CompositorFloatKeyframe(1, 1)); + curve->addKeyframe(CompositorFloatKeyframe(0, 0), *CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseType::EASE)); + curve->addKeyframe(CompositorFloatKeyframe(1, 1), *LinearTimingFunction::shared()); std::unique_ptr<cc::TimingFunction> timingFunction( cc::CubicBezierTimingFunction::CreatePreset(CubicBezierTimingFunction::EaseType::EASE)); @@ -130,8 +131,8 @@ TEST(WebFloatAnimationCurveTest, LinearTimingFunction) { std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create(); - curve->addLinearKeyframe(CompositorFloatKeyframe(0, 0)); - curve->addLinearKeyframe(CompositorFloatKeyframe(1, 1)); + curve->addKeyframe(CompositorFloatKeyframe(0, 0), *LinearTimingFunction::shared()); + curve->addKeyframe(CompositorFloatKeyframe(1, 1), *LinearTimingFunction::shared()); for (int i = 0; i <= 4; ++i) { const double time = i * 0.25; @@ -143,8 +144,8 @@ TEST(WebFloatAnimationCurveTest, EaseInTimingFunction) { std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create(); - curve->addCubicBezierKeyframe(CompositorFloatKeyframe(0, 0), *CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseType::EASE_IN)); - curve->addLinearKeyframe(CompositorFloatKeyframe(1, 1)); + curve->addKeyframe(CompositorFloatKeyframe(0, 0), *CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseType::EASE_IN)); + curve->addKeyframe(CompositorFloatKeyframe(1, 1), *LinearTimingFunction::shared()); std::unique_ptr<cc::TimingFunction> timingFunction( cc::CubicBezierTimingFunction::CreatePreset(CubicBezierTimingFunction::EaseType::EASE_IN)); @@ -158,8 +159,8 @@ TEST(WebFloatAnimationCurveTest, EaseOutTimingFunction) { std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create(); - curve->addCubicBezierKeyframe(CompositorFloatKeyframe(0, 0), *CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseType::EASE_OUT)); - curve->addLinearKeyframe(CompositorFloatKeyframe(1, 1)); + curve->addKeyframe(CompositorFloatKeyframe(0, 0), *CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseType::EASE_OUT)); + curve->addKeyframe(CompositorFloatKeyframe(1, 1), *LinearTimingFunction::shared()); std::unique_ptr<cc::TimingFunction> timingFunction( cc::CubicBezierTimingFunction::CreatePreset(CubicBezierTimingFunction::EaseType::EASE_OUT)); @@ -173,8 +174,8 @@ TEST(WebFloatAnimationCurveTest, EaseInOutTimingFunction) { std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create(); - curve->addCubicBezierKeyframe(CompositorFloatKeyframe(0, 0), *CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseType::EASE_IN_OUT)); - curve->addLinearKeyframe(CompositorFloatKeyframe(1, 1)); + curve->addKeyframe(CompositorFloatKeyframe(0, 0), *CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseType::EASE_IN_OUT)); + curve->addKeyframe(CompositorFloatKeyframe(1, 1), *LinearTimingFunction::shared()); std::unique_ptr<cc::TimingFunction> timingFunction( cc::CubicBezierTimingFunction::CreatePreset(CubicBezierTimingFunction::EaseType::EASE_IN_OUT)); @@ -192,8 +193,9 @@ double y1 = 0.2; double x2 = 0.8; double y2 = 0.7; - curve->addCubicBezierKeyframe(CompositorFloatKeyframe(0, 0), *CubicBezierTimingFunction::create(x1, y1, x2, y2)); - curve->addLinearKeyframe(CompositorFloatKeyframe(1, 1)); + RefPtr<CubicBezierTimingFunction> cubic = CubicBezierTimingFunction::create(x1, y1, x2, y2); + curve->addKeyframe(CompositorFloatKeyframe(0, 0), *cubic); + curve->addKeyframe(CompositorFloatKeyframe(1, 1), *LinearTimingFunction::shared()); std::unique_ptr<cc::TimingFunction> timingFunction( cc::CubicBezierTimingFunction::Create(x1, y1, x2, y2)); @@ -207,8 +209,8 @@ TEST(WebFloatAnimationCurveTest, DefaultTimingFunction) { std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create(); - curve->addCubicBezierKeyframe(CompositorFloatKeyframe(0, 0), *CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseType::EASE)); - curve->addLinearKeyframe(CompositorFloatKeyframe(1, 1)); + curve->addKeyframe(CompositorFloatKeyframe(0, 0), *CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseType::EASE)); + curve->addKeyframe(CompositorFloatKeyframe(1, 1), *LinearTimingFunction::shared()); std::unique_ptr<cc::TimingFunction> timingFunction( cc::CubicBezierTimingFunction::CreatePreset(CubicBezierTimingFunction::EaseType::EASE));
diff --git a/third_party/WebKit/Source/platform/animation/CompositorTransformAnimationCurve.cpp b/third_party/WebKit/Source/platform/animation/CompositorTransformAnimationCurve.cpp index bcdab859..722f4be 100644 --- a/third_party/WebKit/Source/platform/animation/CompositorTransformAnimationCurve.cpp +++ b/third_party/WebKit/Source/platform/animation/CompositorTransformAnimationCurve.cpp
@@ -9,8 +9,6 @@ #include "cc/animation/transform_operations.h" #include "platform/animation/CompositorTransformOperations.h" -using blink::CompositorTransformKeyframe; - namespace blink { CompositorTransformAnimationCurve::CompositorTransformAnimationCurve() @@ -22,14 +20,7 @@ { } -void CompositorTransformAnimationCurve::addLinearKeyframe(const CompositorTransformKeyframe& keyframe) -{ - const cc::TransformOperations& transformOperations = keyframe.value().asTransformOperations(); - m_curve->AddKeyframe(cc::TransformKeyframe::Create( - base::TimeDelta::FromSecondsD(keyframe.time()), transformOperations, nullptr)); -} - -void CompositorTransformAnimationCurve::addCubicBezierKeyframe(const CompositorTransformKeyframe& keyframe, const TimingFunction& timingFunction) +void CompositorTransformAnimationCurve::addKeyframe(const CompositorTransformKeyframe& keyframe, const TimingFunction& timingFunction) { const cc::TransformOperations& transformOperations = keyframe.value().asTransformOperations(); m_curve->AddKeyframe(cc::TransformKeyframe::Create( @@ -37,25 +28,7 @@ timingFunction.cloneToCC())); } -void CompositorTransformAnimationCurve::addStepsKeyframe(const CompositorTransformKeyframe& keyframe, const TimingFunction& timingFunction) -{ - const cc::TransformOperations& transformOperations = keyframe.value().asTransformOperations(); - m_curve->AddKeyframe(cc::TransformKeyframe::Create( - base::TimeDelta::FromSecondsD(keyframe.time()), transformOperations, - timingFunction.cloneToCC())); -} - -void CompositorTransformAnimationCurve::setLinearTimingFunction() -{ - m_curve->SetTimingFunction(nullptr); -} - -void CompositorTransformAnimationCurve::setCubicBezierTimingFunction(const TimingFunction& timingFunction) -{ - m_curve->SetTimingFunction(timingFunction.cloneToCC()); -} - -void CompositorTransformAnimationCurve::setStepsTimingFunction(const TimingFunction& timingFunction) +void CompositorTransformAnimationCurve::setTimingFunction(const TimingFunction& timingFunction) { m_curve->SetTimingFunction(timingFunction.cloneToCC()); }
diff --git a/third_party/WebKit/Source/platform/animation/CompositorTransformAnimationCurve.h b/third_party/WebKit/Source/platform/animation/CompositorTransformAnimationCurve.h index 8853007..ac63cd0 100644 --- a/third_party/WebKit/Source/platform/animation/CompositorTransformAnimationCurve.h +++ b/third_party/WebKit/Source/platform/animation/CompositorTransformAnimationCurve.h
@@ -34,13 +34,8 @@ ~CompositorTransformAnimationCurve() override; - void addLinearKeyframe(const CompositorTransformKeyframe&); - void addCubicBezierKeyframe(const CompositorTransformKeyframe&, const TimingFunction&); - void addStepsKeyframe(const CompositorTransformKeyframe&, const TimingFunction&); - - void setLinearTimingFunction(); - void setCubicBezierTimingFunction(const TimingFunction&); - void setStepsTimingFunction(const TimingFunction&); + void addKeyframe(const CompositorTransformKeyframe&, const TimingFunction&); + void setTimingFunction(const TimingFunction&); // CompositorAnimationCurve implementation. std::unique_ptr<cc::AnimationCurve> cloneToAnimationCurve() const override;
diff --git a/third_party/WebKit/Source/platform/blink_platform.gypi b/third_party/WebKit/Source/platform/blink_platform.gypi index 47b6819..681e772 100644 --- a/third_party/WebKit/Source/platform/blink_platform.gypi +++ b/third_party/WebKit/Source/platform/blink_platform.gypi
@@ -947,6 +947,84 @@ 'plugins/PluginListBuilder.h', 'scheduler/CancellableTaskFactory.cpp', 'scheduler/CancellableTaskFactory.h', + 'scheduler/base/cancelable_closure_holder.cc', + 'scheduler/base/cancelable_closure_holder.h', + 'scheduler/base/enqueue_order.cc', + 'scheduler/base/enqueue_order.h', + 'scheduler/base/lazy_now.cc', + 'scheduler/base/lazy_now.h', + 'scheduler/base/long_task_tracker.cc', + 'scheduler/base/long_task_tracker.h', + 'scheduler/base/pollable_thread_safe_flag.cc', + 'scheduler/base/pollable_thread_safe_flag.h', + 'scheduler/base/queueing_time_estimator.cc', + 'scheduler/base/queueing_time_estimator.h', + 'scheduler/base/real_time_domain.cc', + 'scheduler/base/real_time_domain.h', + 'scheduler/base/task_queue_impl.cc', + 'scheduler/base/task_queue_impl.h', + 'scheduler/base/task_queue_manager.cc', + 'scheduler/base/task_queue_manager.h', + 'scheduler/base/task_queue_manager_delegate.h', + 'scheduler/base/task_queue_selector.cc', + 'scheduler/base/task_queue_selector.h', + 'scheduler/base/task_time_tracker.h', + 'scheduler/base/time_domain.cc', + 'scheduler/base/time_domain.h', + 'scheduler/base/virtual_time_domain.cc', + 'scheduler/base/virtual_time_domain.h', + 'scheduler/base/work_queue.cc', + 'scheduler/base/work_queue.h', + 'scheduler/base/work_queue_sets.cc', + 'scheduler/base/work_queue_sets.h', + 'scheduler/CancellableTaskFactory.h', + 'scheduler/child/compositor_worker_scheduler.cc', + 'scheduler/child/idle_helper.cc', + 'scheduler/child/idle_helper.h', + 'scheduler/child/scheduler_helper.cc', + 'scheduler/child/scheduler_helper.h', + 'scheduler/child/scheduler_tqm_delegate.h', + 'scheduler/child/scheduler_tqm_delegate_impl.cc', + 'scheduler/child/scheduler_tqm_delegate_impl.h', + 'scheduler/child/single_thread_idle_task_runner.cc', + 'scheduler/child/web_scheduler_impl.cc', + 'scheduler/child/web_scheduler_impl.h', + 'scheduler/child/web_task_runner_impl.cc', + 'scheduler/child/web_task_runner_impl.h', + 'scheduler/child/webthread_base.cc', + 'scheduler/child/webthread_impl_for_worker_scheduler.cc', + 'scheduler/child/worker_scheduler.cc', + 'scheduler/child/worker_scheduler_impl.cc', + 'scheduler/child/worker_scheduler_impl.h', + 'scheduler/renderer/auto_advancing_virtual_time_domain.cc', + 'scheduler/renderer/auto_advancing_virtual_time_domain.h', + 'scheduler/renderer/deadline_task_runner.cc', + 'scheduler/renderer/deadline_task_runner.h', + 'scheduler/renderer/idle_time_estimator.cc', + 'scheduler/renderer/idle_time_estimator.h', + 'scheduler/renderer/renderer_scheduler.cc', + 'scheduler/renderer/renderer_scheduler_impl.cc', + 'scheduler/renderer/renderer_scheduler_impl.h', + 'scheduler/renderer/renderer_web_scheduler_impl.cc', + 'scheduler/renderer/renderer_web_scheduler_impl.h', + 'scheduler/renderer/render_widget_scheduling_state.cc', + 'scheduler/renderer/render_widget_signals.cc', + 'scheduler/renderer/render_widget_signals.h', + 'scheduler/renderer/task_cost_estimator.cc', + 'scheduler/renderer/task_cost_estimator.h', + 'scheduler/renderer/throttled_time_domain.cc', + 'scheduler/renderer/throttled_time_domain.h', + 'scheduler/renderer/throttling_helper.cc', + 'scheduler/renderer/throttling_helper.h', + 'scheduler/renderer/user_model.cc', + 'scheduler/renderer/user_model.h', + 'scheduler/renderer/web_frame_scheduler_impl.cc', + 'scheduler/renderer/web_frame_scheduler_impl.h', + 'scheduler/renderer/webthread_impl_for_renderer_scheduler.cc', + 'scheduler/renderer/webthread_impl_for_renderer_scheduler.h', + 'scheduler/renderer/web_view_scheduler_impl.cc', + 'scheduler/renderer/web_view_scheduler_impl.h', + 'scheduler/utility/webthread_impl_for_utility_thread.cc', 'scroll/MainThreadScrollingReason.h', 'scroll/ProgrammaticScrollAnimator.cpp', 'scroll/ProgrammaticScrollAnimator.h', @@ -992,8 +1070,6 @@ 'text/Character.cpp', 'text/Character.h', 'text/CharacterEmoji.cpp', - 'text/CompressibleString.cpp', - 'text/CompressibleString.h', 'text/DateTimeFormat.cpp', 'text/DateTimeFormat.h', 'text/DecodeEscapeSequences.h', @@ -1248,6 +1324,30 @@ 'network/ResourceRequestTest.cpp', 'network/ResourceResponseTest.cpp', 'scheduler/CancellableTaskFactoryTest.cpp', + 'scheduler/base/long_task_tracker_unittest.cc', + 'scheduler/base/task_queue_manager_delegate_for_test.cc', + 'scheduler/base/task_queue_manager_unittest.cc', + 'scheduler/base/task_queue_selector_unittest.cc', + 'scheduler/base/test_count_uses_time_source.cc', + 'scheduler/base/test_time_source.cc', + 'scheduler/base/time_domain_unittest.cc', + 'scheduler/base/work_queue_sets_unittest.cc', + 'scheduler/base/queueing_time_estimator_unittest.cc', + 'scheduler/child/idle_helper_unittest.cc', + 'scheduler/child/scheduler_helper_unittest.cc', + 'scheduler/child/scheduler_tqm_delegate_for_test.cc', + 'scheduler/child/scheduler_tqm_delegate_impl_unittest.cc', + 'scheduler/child/webthread_impl_for_worker_scheduler_unittest.cc', + 'scheduler/child/worker_scheduler_impl_unittest.cc', + 'scheduler/renderer/auto_advancing_virtual_time_domain_unittest.cc', + 'scheduler/renderer/deadline_task_runner_unittest.cc', + 'scheduler/renderer/idle_time_estimator_unittest.cc', + 'scheduler/renderer/renderer_scheduler_impl_unittest.cc', + 'scheduler/renderer/task_cost_estimator_unittest.cc', + 'scheduler/renderer/throttling_helper_unittest.cc', + 'scheduler/renderer/user_model_unittest.cc', + 'scheduler/renderer/webthread_impl_for_renderer_scheduler_unittest.cc', + 'scheduler/renderer/web_view_scheduler_impl_unittest.cc', 'scroll/ScrollableAreaTest.cpp', 'testing/ArenaTestHelpers.h', 'testing/TreeTestHelpers.cpp', @@ -1289,6 +1389,10 @@ 'graphics/test/MockImageDecoder.h', ], 'platform_test_support_files': [ + 'scheduler/test/fake_renderer_scheduler.cc', + 'scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.cc', + 'scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.h', + 'scheduler/test/renderer_scheduler_test_support.cc', 'scroll/ScrollbarTestSuite.h', 'testing/CompositorTest.cpp', 'testing/CompositorTest.h',
diff --git a/third_party/WebKit/Source/platform/fonts/FontDataForRangeSet.h b/third_party/WebKit/Source/platform/fonts/FontDataForRangeSet.h index 9b4950d4..4bb1aae 100644 --- a/third_party/WebKit/Source/platform/fonts/FontDataForRangeSet.h +++ b/third_party/WebKit/Source/platform/fonts/FontDataForRangeSet.h
@@ -58,8 +58,8 @@ virtual ~FontDataForRangeSet() { }; - bool contains(UChar32 testChar) const { return m_rangeSet->contains(testChar); } - bool isEntireRange() const { return m_rangeSet->isEntireRange(); } + bool contains(UChar32 testChar) const { return !m_rangeSet || m_rangeSet->contains(testChar); } + bool isEntireRange() const { return !m_rangeSet || m_rangeSet->isEntireRange(); } UnicodeRangeSet* ranges() const { return m_rangeSet.get(); } bool hasFontData() const { return m_fontData.get(); } const SimpleFontData* fontData() const { return m_fontData.get(); }
diff --git a/third_party/WebKit/Source/platform/fonts/FontFallbackIterator.cpp b/third_party/WebKit/Source/platform/fonts/FontFallbackIterator.cpp index 34879c83..616e2fea 100644 --- a/third_party/WebKit/Source/platform/fonts/FontFallbackIterator.cpp +++ b/third_party/WebKit/Source/platform/fonts/FontFallbackIterator.cpp
@@ -34,16 +34,6 @@ { } -bool FontFallbackIterator::needsHintList() const -{ - if (m_fallbackStage != FontGroupFonts && m_fallbackStage != SegmentedFace) { - return false; - } - - const FontData* fontData = m_fontFallbackList->fontDataAt(m_fontDescription, m_currentFontDataIndex); - return fontData && fontData->isSegmented(); -} - bool FontFallbackIterator::alreadyLoadingRangeForHintChar(UChar32 hintChar) { for (auto it = m_trackedLoadingRangeSets.begin(); it != m_trackedLoadingRangeSets.end(); ++it) { @@ -73,6 +63,26 @@ selector->willUseRange(m_fontDescription, family, rangeSet); } +const PassRefPtr<FontDataForRangeSet> FontFallbackIterator::uniqueOrNext( + PassRefPtr<FontDataForRangeSet> candidate, + const Vector<UChar32>& hintList) { + SkTypeface* candidateTypeface = candidate->fontData()->platformData().typeface(); + if (!candidateTypeface) + return next(hintList); + + uint32_t candidateId = candidateTypeface->uniqueID(); + if (m_uniqueFontDataForRangeSetsReturned.contains(candidateId)) { + return next(hintList); + } + + // We don't want to skip subsetted ranges because HarfBuzzShaper's behavior + // depends on the subsetting. + if (candidate->isEntireRange()) + m_uniqueFontDataForRangeSetsReturned.add(candidateId); + return candidate; +} + + const PassRefPtr<FontDataForRangeSet> FontFallbackIterator::next(const Vector<UChar32>& hintList) { if (m_fallbackStage == OutOfLuck) @@ -84,7 +94,7 @@ m_fallbackStage = SystemFonts; RefPtr<FontDataForRangeSet> fallbackPriorityFontRange = adoptRef(new FontDataForRangeSet(fallbackPriorityFont(hintList[0]))); if (fallbackPriorityFontRange->hasFontData()) - return fallbackPriorityFontRange.release(); + return uniqueOrNext(fallbackPriorityFontRange.release(), hintList); return next(hintList); } @@ -94,7 +104,7 @@ RefPtr<SimpleFontData> systemFont = uniqueSystemFontForHint(hintList[0]); if (systemFont) { // Fallback fonts are not retained in the FontDataCache. - return adoptRef(new FontDataForRangeSet(systemFont)); + return uniqueOrNext(adoptRef(new FontDataForRangeSet(systemFont)), hintList); } // If we don't have options from the system fallback anymore or had @@ -106,6 +116,8 @@ m_fallbackStage = OutOfLuck; RefPtr<SimpleFontData> lastResort = fontCache->getLastResortFallbackFont(m_fontDescription).get(); RELEASE_ASSERT(lastResort); + // Don't skip the LastResort font in uniqueOrNext() since HarfBuzzShaper + // needs to use this one to place missing glyph boxes. return adoptRef(new FontDataForRangeSetFromCache(lastResort)); } @@ -134,7 +146,7 @@ // The fontData object that we have here is tracked in m_fontList of // FontFallbackList and gets released in the font cache when the // FontFallbackList is destroyed. - return adoptRef(new FontDataForRangeSet(nonSegmented)); + return uniqueOrNext(adoptRef(new FontDataForRangeSet(nonSegmented)), hintList); } return next(hintList); } @@ -163,7 +175,7 @@ if (const CustomFontData* customFontData = fontData->customFontData()) customFontData->beginLoadIfNeeded(); if (!fontData->isLoading()) - return currentSegmentedFace; + return uniqueOrNext(currentSegmentedFace, hintList); m_trackedLoadingRangeSets.append(currentSegmentedFace); }
diff --git a/third_party/WebKit/Source/platform/fonts/FontFallbackIterator.h b/third_party/WebKit/Source/platform/fonts/FontFallbackIterator.h index 7f1a065..2563a4e4 100644 --- a/third_party/WebKit/Source/platform/fonts/FontFallbackIterator.h +++ b/third_party/WebKit/Source/platform/fonts/FontFallbackIterator.h
@@ -30,11 +30,6 @@ static PassRefPtr<FontFallbackIterator> create(const FontDescription&, PassRefPtr<FontFallbackList>, FontFallbackPriority); - // Returns whether a list of all remaining characters to be shaped is - // needed. Needed by the FontfallbackIterator in order to check whether a - // font from a segmented range should be loaded. - bool needsHintList() const; - bool hasNext() const { return m_fallbackStage != OutOfLuck; }; // Some system fallback APIs (Windows, Android) require a character, or a @@ -49,6 +44,8 @@ bool alreadyLoadingRangeForHintChar(UChar32 hintChar); void willUseRange(const AtomicString& family, const FontDataForRangeSet&); + const PassRefPtr<FontDataForRangeSet> uniqueOrNext(PassRefPtr<FontDataForRangeSet> candidate, const Vector<UChar32>& hintList); + const PassRefPtr<SimpleFontData> fallbackPriorityFont(UChar32 hint); const PassRefPtr<SimpleFontData> uniqueSystemFontForHint(UChar32 hint); @@ -68,6 +65,12 @@ FallbackStage m_fallbackStage; HashSet<UChar32> m_previouslyAskedForHint; + // FontFallbackIterator is meant for single use by HarfBuzzShaper, + // traversing through the fonts for shaping only once. We must not return + // duplicate FontDataForRangeSet objects from the next() iteration functions + // as returning a duplicate value causes a shaping run that won't return any + // results. + HashSet<uint32_t> m_uniqueFontDataForRangeSetsReturned; Vector<RefPtr<FontDataForRangeSet>> m_trackedLoadingRangeSets; FontFallbackPriority m_fontFallbackPriority; };
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp index 3848a4d2..bca9d48 100644 --- a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp +++ b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp
@@ -496,7 +496,7 @@ return originalFont; } -bool HarfBuzzShaper::collectFallbackHintChars(Vector<UChar32>& hint, bool needsList) +bool HarfBuzzShaper::collectFallbackHintChars(Vector<UChar32>& hint) { if (!m_holesQueue.size()) return false; @@ -514,8 +514,6 @@ while (iterator.consume(hintChar)) { hint.append(hintChar); numCharsAdded++; - if (!needsList) - break; iterator.advance(); } } @@ -599,7 +597,7 @@ // for the shaper and check whether any glyphs were found, or // define a new API on the shaper which will give us coverage // information? - if (!collectFallbackHintChars(fallbackCharsHint, fallbackIterator->needsHintList())) { + if (!collectFallbackHintChars(fallbackCharsHint)) { // Give up shaping since we cannot retrieve a font fallback // font without a hintlist. m_holesQueue.clear();
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.h b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.h index 40f2936..3003f071 100644 --- a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.h +++ b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.h
@@ -200,7 +200,7 @@ const SimpleFontData* currentFont, UScriptCode currentRunScript, bool isLastResort); - bool collectFallbackHintChars(Vector<UChar32>& hint, bool needsList); + bool collectFallbackHintChars(Vector<UChar32>& hint); void insertRunIntoShapeResult(ShapeResult*, std::unique_ptr<ShapeResult::RunInfo> runToInsert, unsigned startGlyph, unsigned numGlyphs, hb_buffer_t*);
diff --git a/third_party/WebKit/Source/platform/fonts/win/FontFallbackWin.cpp b/third_party/WebKit/Source/platform/fonts/win/FontFallbackWin.cpp index 54f6d8f..21dbcbf 100644 --- a/third_party/WebKit/Source/platform/fonts/win/FontFallbackWin.cpp +++ b/third_party/WebKit/Source/platform/fonts/win/FontFallbackWin.cpp
@@ -68,11 +68,15 @@ return matchesRequestedFamily; } +struct FontMapping { + const UChar* familyName; + const UChar* const * candidateFamilyNames; +}; // A simple mapping from UScriptCode to family name. This is a sparse array, // which works well since the range of UScriptCode values is small. -typedef const UChar* ScriptToFontMap[USCRIPT_CODE_LIMIT]; +typedef FontMapping ScriptToFontMap[USCRIPT_CODE_LIMIT]; -void initializeScriptMonospaceFontMap(ScriptToFontMap& scriptFontMap, SkFontMgr* fontManager) +const UChar* findMonospaceFontForScript(UScriptCode script) { struct FontMap { UScriptCode script; @@ -84,28 +88,18 @@ { USCRIPT_ARABIC, L"courier new" }, }; - for (size_t i = 0; i < WTF_ARRAY_LENGTH(fontMap); ++i) - scriptFontMap[fontMap[i].script] = fontMap[i].family; + for (const auto& fontFamily : fontMap) { + if (fontFamily.script == script) + return fontFamily.family; + } + return nullptr; } -void initializeScriptFontMap(ScriptToFontMap& scriptFontMap, SkFontMgr* fontManager) +void initializeScriptFontMap(ScriptToFontMap& scriptFontMap) { - struct FontMap { - UScriptCode script; - const UChar* family; - }; - - static const FontMap fontMap[] = { - { USCRIPT_LATIN, L"Times New Roman" }, - { USCRIPT_GREEK, L"Times New Roman" }, - { USCRIPT_CYRILLIC, L"Times New Roman" }, - // For USCRIPT_COMMON, we map blocks to scripts when - // that makes sense. - }; - struct ScriptToFontFamilies { UScriptCode script; - const UChar** families; + const UChar* const * families; }; // For the following scripts, multiple fonts may be listed. They are tried @@ -118,99 +112,102 @@ // Based on the "Script and Font Support in Windows" MSDN documentation [1] // with overrides and additional fallbacks as needed. // 1: https://msdn.microsoft.com/en-us/goglobal/bb688099.aspx - static const UChar* arabicFonts[] = { L"Tahoma", L"Segoe UI", 0 }; - static const UChar* armenianFonts[] = { L"Segoe UI", L"Sylfaen", 0 }; - static const UChar* bengaliFonts[] = { L"Nirmala UI", L"Vrinda", 0 }; - static const UChar* brahmiFonts[] = { L"Segoe UI Historic", 0 }; - static const UChar* brailleFonts[] = { L"Segoe UI Symbol", 0 }; - static const UChar* bugineseFonts[] = { L"Leelawadee UI", 0 }; - static const UChar* canadianAaboriginalFonts[] = { L"Gadugi", + static const UChar* const arabicFonts[] = { L"Tahoma", L"Segoe UI", 0 }; + static const UChar* const armenianFonts[] = { L"Segoe UI", L"Sylfaen", 0 }; + static const UChar* const bengaliFonts[] = { L"Nirmala UI", L"Vrinda", 0 }; + static const UChar* const brahmiFonts[] = { L"Segoe UI Historic", 0 }; + static const UChar* const brailleFonts[] = { L"Segoe UI Symbol", 0 }; + static const UChar* const bugineseFonts[] = { L"Leelawadee UI", 0 }; + static const UChar* const canadianAaboriginalFonts[] = { L"Gadugi", L"Euphemia", 0 }; - static const UChar* carianFonts[] = { L"Segoe UI Historic", 0 }; - static const UChar* cherokeeFonts[] = { L"Gadugi", L"Plantagenet", 0 }; - static const UChar* copticFonts[] = { L"Segoe UI Symbol", 0 }; - static const UChar* cuneiformFonts[] = { L"Segoe UI Historic", 0 }; - static const UChar* cypriotFonts[] = { L"Segoe UI Historic", 0 }; - static const UChar* deseretFonts[] = { L"Segoe UI Symbol", 0 }; - static const UChar* devanagariFonts[] = { L"Nirmala UI", L"Mangal", 0 }; - static const UChar* egyptianHieroglyphsFonts[] = { L"Segoe UI Historic", + static const UChar* const carianFonts[] = { L"Segoe UI Historic", 0 }; + static const UChar* const cherokeeFonts[] = { L"Gadugi", L"Plantagenet", 0 }; + static const UChar* const copticFonts[] = { L"Segoe UI Symbol", 0 }; + static const UChar* const cuneiformFonts[] = { L"Segoe UI Historic", 0 }; + static const UChar* const cypriotFonts[] = { L"Segoe UI Historic", 0 }; + static const UChar* const cyrillicFonts[] = { L"Times New Roman", 0 }; + static const UChar* const deseretFonts[] = { L"Segoe UI Symbol", 0 }; + static const UChar* const devanagariFonts[] = { L"Nirmala UI", L"Mangal", 0 }; + static const UChar* const egyptianHieroglyphsFonts[] = { L"Segoe UI Historic", 0 }; - static const UChar* ethiopicFonts[] = { L"Nyala", L"Abyssinica SIL", + static const UChar* const ethiopicFonts[] = { L"Nyala", L"Abyssinica SIL", L"Ethiopia Jiret", L"Visual Geez Unicode", L"GF Zemen Unicode", L"Ebrima", 0 }; - static const UChar* georgianFonts[] = { L"Sylfaen", L"Segoe UI", 0 }; - static const UChar* glagoliticFonts[] = { L"Segoe UI Historic", + static const UChar* const georgianFonts[] = { L"Sylfaen", L"Segoe UI", 0 }; + static const UChar* const glagoliticFonts[] = { L"Segoe UI Historic", L"Segoe UI Symbol", 0 }; - static const UChar* gothicFonts[] = { L"Segoe UI Historic", + static const UChar* const gothicFonts[] = { L"Segoe UI Historic", L"Segoe UI Symbol", 0 }; - static const UChar* gujaratiFonts[] = { L"Nirmala UI", L"Shruti", 0 }; - static const UChar* gurmukhiFonts[] = { L"Nirmala UI", L"Raavi", 0 }; - static const UChar* hangulFonts[] = { L"Malgun Gothic", L"Gulim", 0 }; - static const UChar* hebrewFonts[] = { L"David", L"Segoe UI", 0 }; - static const UChar* imperialAramaicFonts[] = { L"Segoe UI Historic", 0 }; - static const UChar* inscriptionalPahlaviFonts[] = { L"Segoe UI Historic", + static const UChar* const greekFonts[] = { L"Times New Roman", 0 }; + static const UChar* const gujaratiFonts[] = { L"Nirmala UI", L"Shruti", 0 }; + static const UChar* const gurmukhiFonts[] = { L"Nirmala UI", L"Raavi", 0 }; + static const UChar* const hangulFonts[] = { L"Malgun Gothic", L"Gulim", 0 }; + static const UChar* const hebrewFonts[] = { L"David", L"Segoe UI", 0 }; + static const UChar* const imperialAramaicFonts[] = { L"Segoe UI Historic", 0 }; + static const UChar* const inscriptionalPahlaviFonts[] = { L"Segoe UI Historic", 0 }; - static const UChar* inscriptionalParthianFonts[] = { L"Segoe UI Historic", + static const UChar* const inscriptionalParthianFonts[] = { L"Segoe UI Historic", 0 }; - static const UChar* javaneseFonts[] = { L"Javanese Text", 0 }; - static const UChar* kannadaFonts[] = { L"Tunga", L"Nirmala UI", 0 }; - static const UChar* katakanaOrHiraganaFonts[] = { L"Meiryo", L"Yu Gothic", + static const UChar* const javaneseFonts[] = { L"Javanese Text", 0 }; + static const UChar* const kannadaFonts[] = { L"Tunga", L"Nirmala UI", 0 }; + static const UChar* const katakanaOrHiraganaFonts[] = { L"Meiryo", L"Yu Gothic", L"MS PGothic", L"Microsoft YaHei", 0 }; - static const UChar* kharoshthiFonts[] = { L"Segoe UI Historic", 0 }; + static const UChar* const kharoshthiFonts[] = { L"Segoe UI Historic", 0 }; // Try Khmer OS before Vista fonts as it goes along better with Latin // and looks better/larger for the same size. - static const UChar* khmerFonts[] = { L"Leelawadee UI", L"Khmer UI", + static const UChar* const khmerFonts[] = { L"Leelawadee UI", L"Khmer UI", L"Khmer OS", L"MoolBoran", L"DaunPenh", 0 }; - static const UChar* laoFonts[] = { L"Leelawadee UI", L"Lao UI", + static const UChar* const laoFonts[] = { L"Leelawadee UI", L"Lao UI", L"DokChampa", L"Saysettha OT", L"Phetsarath OT", L"Code2000", 0 }; - static const UChar* lisuFonts[] = { L"Segoe UI", 0 }; - static const UChar* lycianFonts[] = { L"Segoe UI Historic", 0 }; - static const UChar* lydianFonts[] = { L"Segoe UI Historic", 0 }; - static const UChar* malayalamFonts[] = { L"Nirmala UI", L"Kartika", 0 }; - static const UChar* meroiticCursiveFonts[] = { L"Segoe UI Historic", + static const UChar* const latinFonts[] = { L"Times New Roman", 0 }; + static const UChar* const lisuFonts[] = { L"Segoe UI", 0 }; + static const UChar* const lycianFonts[] = { L"Segoe UI Historic", 0 }; + static const UChar* const lydianFonts[] = { L"Segoe UI Historic", 0 }; + static const UChar* const malayalamFonts[] = { L"Nirmala UI", L"Kartika", 0 }; + static const UChar* const meroiticCursiveFonts[] = { L"Segoe UI Historic", L"Segoe UI Symbol", 0 }; - static const UChar* mongolianFonts[] = { L"Mongolian Baiti", 0 }; - static const UChar* myanmarFonts[] = { L"Myanmar Text", L"Padauk", + static const UChar* const mongolianFonts[] = { L"Mongolian Baiti", 0 }; + static const UChar* const myanmarFonts[] = { L"Myanmar Text", L"Padauk", L"Parabaik", L"Myanmar3", L"Code2000", 0 }; - static const UChar* newTaiLueFonts[] = { L"Microsoft New Tai Lue", 0 }; - static const UChar* nkoFonts[] = { L"Ebrima", 0 }; - static const UChar* oghamFonts[] = { L"Segoe UI Historic", + static const UChar* const newTaiLueFonts[] = { L"Microsoft New Tai Lue", 0 }; + static const UChar* const nkoFonts[] = { L"Ebrima", 0 }; + static const UChar* const oghamFonts[] = { L"Segoe UI Historic", L"Segoe UI Symbol", 0 }; - static const UChar* olChikiFonts[] = { L"Nirmala UI", 0 }; - static const UChar* oldItalicFonts[] = { L"Segoe UI Historic", + static const UChar* const olChikiFonts[] = { L"Nirmala UI", 0 }; + static const UChar* const oldItalicFonts[] = { L"Segoe UI Historic", L"Segoe UI Symbol", 0 }; - static const UChar* oldPersianFonts[] = { L"Segoe UI Historic", 0 }; - static const UChar* oldSouthArabianFonts[] = { L"Segoe UI Historic", 0 }; - static const UChar* oriyaFonts[] = { L"Kalinga", L"ori1Uni", + static const UChar* const oldPersianFonts[] = { L"Segoe UI Historic", 0 }; + static const UChar* const oldSouthArabianFonts[] = { L"Segoe UI Historic", 0 }; + static const UChar* const oriyaFonts[] = { L"Kalinga", L"ori1Uni", L"Lohit Oriya", L"Nirmala UI", 0 }; - static const UChar* orkhonFonts[] = { L"Segoe UI Historic", + static const UChar* const orkhonFonts[] = { L"Segoe UI Historic", L"Segoe UI Symbol", 0 }; - static const UChar* osmanyaFonts[] = { L"Ebrima", 0 }; - static const UChar* phagsPaFonts[] = { L"Microsoft PhagsPa", 0 }; - static const UChar* runicFonts[] = { L"Segoe UI Historic", + static const UChar* const osmanyaFonts[] = { L"Ebrima", 0 }; + static const UChar* const phagsPaFonts[] = { L"Microsoft PhagsPa", 0 }; + static const UChar* const runicFonts[] = { L"Segoe UI Historic", L"Segoe UI Symbol", 0 }; - static const UChar* shavianFonts[] = { L"Segoe UI Historic", 0 }; - static const UChar* simplifiedHanFonts[] = { L"simsun", L"Microsoft YaHei", + static const UChar* const shavianFonts[] = { L"Segoe UI Historic", 0 }; + static const UChar* const simplifiedHanFonts[] = { L"simsun", L"Microsoft YaHei", 0 }; - static const UChar* sinhalaFonts[] = { L"Iskoola Pota", L"AksharUnicode", + static const UChar* const sinhalaFonts[] = { L"Iskoola Pota", L"AksharUnicode", L"Nirmala UI", 0 }; - static const UChar* soraSompengFonts[] = { L"Nirmala UI", 0 }; - static const UChar* symbolsFonts[] = { L"Segoe UI Symbol", 0 }; - static const UChar* syriacFonts[] = { L"Estrangelo Edessa", + static const UChar* const soraSompengFonts[] = { L"Nirmala UI", 0 }; + static const UChar* const symbolsFonts[] = { L"Segoe UI Symbol", 0 }; + static const UChar* const syriacFonts[] = { L"Estrangelo Edessa", L"Estrangelo Nisibin", L"Code2000", 0 }; - static const UChar* taiLeFonts[] = { L"Microsoft Tai Le", 0 }; - static const UChar* tamilFonts[] = { L"Nirmala UI", L"Latha", 0 }; - static const UChar* teluguFonts[] = { L"Nirmala UI", L"Gautami", 0 }; - static const UChar* thaanaFonts[] = { L"MV Boli", 0 }; - static const UChar* thaiFonts[] = { L"Tahoma", L"Leelawadee UI", + static const UChar* const taiLeFonts[] = { L"Microsoft Tai Le", 0 }; + static const UChar* const tamilFonts[] = { L"Nirmala UI", L"Latha", 0 }; + static const UChar* const teluguFonts[] = { L"Nirmala UI", L"Gautami", 0 }; + static const UChar* const thaanaFonts[] = { L"MV Boli", 0 }; + static const UChar* const thaiFonts[] = { L"Tahoma", L"Leelawadee UI", L"Leelawadee", 0 }; - static const UChar* tibetanFonts[] = { L"Microsoft Himalaya", L"Jomolhari", + static const UChar* const tibetanFonts[] = { L"Microsoft Himalaya", L"Jomolhari", L"Tibetan Machine Uni", 0 }; - static const UChar* tifinaghFonts[] = { L"Ebrima", 0 }; - static const UChar* traditionalHanFonts[] = { L"pmingliu", + static const UChar* const tifinaghFonts[] = { L"Ebrima", 0 }; + static const UChar* const traditionalHanFonts[] = { L"pmingliu", L"Microsoft JhengHei", 0 }; - static const UChar* vaiFonts[] = { L"Ebrima", 0 }; - static const UChar* yiFonts[] = { L"Microsoft Yi Baiti", L"Nuosu SIL", + static const UChar* const vaiFonts[] = { L"Ebrima", 0 }; + static const UChar* const yiFonts[] = { L"Microsoft Yi Baiti", L"Nuosu SIL", L"Code2000", 0 }; static const ScriptToFontFamilies scriptToFontFamilies[] = { @@ -226,6 +223,7 @@ { USCRIPT_COPTIC, copticFonts }, { USCRIPT_CUNEIFORM, cuneiformFonts }, { USCRIPT_CYPRIOT, cypriotFonts }, + { USCRIPT_CYRILLIC, cyrillicFonts }, { USCRIPT_DESERET, deseretFonts }, { USCRIPT_DEVANAGARI, devanagariFonts }, { USCRIPT_EGYPTIAN_HIEROGLYPHS, egyptianHieroglyphsFonts }, @@ -233,6 +231,7 @@ { USCRIPT_GEORGIAN, georgianFonts }, { USCRIPT_GLAGOLITIC, glagoliticFonts }, { USCRIPT_GOTHIC, gothicFonts }, + { USCRIPT_GREEK, greekFonts }, { USCRIPT_GUJARATI, gujaratiFonts }, { USCRIPT_GURMUKHI, gurmukhiFonts }, { USCRIPT_HANGUL, hangulFonts }, @@ -248,6 +247,7 @@ { USCRIPT_KHAROSHTHI, kharoshthiFonts }, { USCRIPT_KHMER, khmerFonts }, { USCRIPT_LAO, laoFonts }, + { USCRIPT_LATIN, latinFonts }, { USCRIPT_LISU, lisuFonts }, { USCRIPT_LYCIAN, lycianFonts }, { USCRIPT_LYDIAN, lydianFonts }, @@ -285,30 +285,27 @@ { USCRIPT_YI, yiFonts } }; - for (size_t i = 0; i < WTF_ARRAY_LENGTH(fontMap); ++i) - scriptFontMap[fontMap[i].script] = fontMap[i].family; - - // FIXME: Instead of scanning the hard-coded list, we have to - // use EnumFont* to 'inspect' fonts to pick up fonts covering scripts - // when it's possible (e.g. using OS/2 table). If we do that, this - // had better be pulled out of here. - for (size_t i = 0; i < WTF_ARRAY_LENGTH(scriptToFontFamilies); ++i) { - UScriptCode script = scriptToFontFamilies[i].script; - scriptFontMap[script] = 0; - const UChar** familyPtr = scriptToFontFamilies[i].families; - while (*familyPtr) { - if (isFontPresent(*familyPtr, fontManager)) { - scriptFontMap[script] = *familyPtr; - break; - } - ++familyPtr; - } + for (const auto& fontFamily : scriptToFontFamilies) { + scriptFontMap[fontFamily.script].candidateFamilyNames = fontFamily.families; } // Initialize the locale-dependent mapping from system locale. UScriptCode hanScript = LayoutLocale::getSystem().scriptForHan(); - if (const UChar* localeFamily = scriptFontMap[hanScript]) - scriptFontMap[USCRIPT_HAN] = localeFamily; + DCHECK(hanScript != USCRIPT_HAN); + if (scriptFontMap[hanScript].candidateFamilyNames) { + scriptFontMap[USCRIPT_HAN].candidateFamilyNames = scriptFontMap[hanScript].candidateFamilyNames; + } +} + +void findFirstExistingCandidateFont(FontMapping& scriptFontMapping, SkFontMgr* fontManager) +{ + for (const UChar* const * familyPtr = scriptFontMapping.candidateFamilyNames; *familyPtr; familyPtr++) { + if (isFontPresent(*familyPtr, fontManager)) { + scriptFontMapping.familyName = *familyPtr; + break; + } + } + scriptFontMapping.candidateFamilyNames = nullptr; } // There are a lot of characters in USCRIPT_COMMON that can be covered @@ -361,9 +358,9 @@ const UChar* getFontBasedOnUnicodeBlock(UBlockCode blockCode, SkFontMgr* fontManager) { - static const UChar* emojiFonts[] = {L"Segoe UI Emoji", L"Segoe UI Symbol"}; - static const UChar* mathFonts[] = {L"Cambria Math", L"Segoe UI Symbol", L"Code2000"}; - static const UChar* symbolFont = L"Segoe UI Symbol"; + static const UChar* const emojiFonts[] = {L"Segoe UI Emoji", L"Segoe UI Symbol"}; + static const UChar* const mathFonts[] = {L"Cambria Math", L"Segoe UI Symbol", L"Code2000"}; + static const UChar* const symbolFont = L"Segoe UI Symbol"; static const UChar* emojiFont = 0; static const UChar* mathFont = 0; static bool initialized = false; @@ -436,19 +433,23 @@ SkFontMgr* fontManager) { static ScriptToFontMap scriptFontMap; - static ScriptToFontMap scriptMonospaceFontMap; static bool initialized = false; if (!initialized) { - initializeScriptFontMap(scriptFontMap, fontManager); - initializeScriptMonospaceFontMap(scriptMonospaceFontMap, fontManager); + initializeScriptFontMap(scriptFontMap); initialized = true; } + if (script == USCRIPT_INVALID_CODE) return 0; ASSERT(script < USCRIPT_CODE_LIMIT); - if (generic == FontDescription::MonospaceFamily && scriptMonospaceFontMap[script]) - return scriptMonospaceFontMap[script]; - return scriptFontMap[script]; + if (generic == FontDescription::MonospaceFamily) { + const UChar* monospaceFamily = findMonospaceFontForScript(script); + if (monospaceFamily) + return monospaceFamily; + } + if (scriptFontMap[script].candidateFamilyNames) + findFirstExistingCandidateFont(scriptFontMap[script], fontManager); + return scriptFontMap[script].familyName; } // FIXME:
diff --git a/third_party/WebKit/Source/platform/graphics/CompositorMutableStateTest.cpp b/third_party/WebKit/Source/platform/graphics/CompositorMutableStateTest.cpp index 1843a39..70714be 100644 --- a/third_party/WebKit/Source/platform/graphics/CompositorMutableStateTest.cpp +++ b/third_party/WebKit/Source/platform/graphics/CompositorMutableStateTest.cpp
@@ -33,7 +33,7 @@ class CompositorMutableStateTest : public testing::Test { public: CompositorMutableStateTest() - : m_outputSurface(FakeOutputSurface::Create3d()) + : m_outputSurface(FakeOutputSurface::CreateDelegating3d()) { LayerTreeSettings settings; settings.layer_transforms_should_scale_layer_contents = true;
diff --git a/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.cpp b/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.cpp index df4b8699..99c59dc 100644 --- a/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.cpp +++ b/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.cpp
@@ -98,26 +98,16 @@ prepareLazyDecodedFrames(); - if (index < m_frameData.size()) { - DeferredFrameData* frameData = &m_frameData[index]; - if (m_actualDecoder) - frameData->m_frameBytes = m_actualDecoder->frameBytesAtIndex(index); - else - frameData->m_frameBytes = m_size.area() * sizeof(ImageFrame::PixelData); - // ImageFrameGenerator has the latest known alpha state. There will be a - // performance boost if this frame is opaque. - DCHECK(m_frameGenerator); - return createFrameImageAtIndex(index, !m_frameGenerator->hasAlpha(index)); - } - - if (!m_actualDecoder || m_actualDecoder->failed()) - return nullptr; - - ImageFrame* frame = m_actualDecoder->frameBufferAtIndex(index); - if (!frame || frame->getStatus() == ImageFrame::FrameEmpty) - return nullptr; - - return fromSkSp(SkImage::MakeFromBitmap(frame->bitmap())); + DCHECK(index < m_frameData.size()); + DeferredFrameData* frameData = &m_frameData[index]; + if (m_actualDecoder) + frameData->m_frameBytes = m_actualDecoder->frameBytesAtIndex(index); + else + frameData->m_frameBytes = m_size.area() * sizeof(ImageFrame::PixelData); + // ImageFrameGenerator has the latest known alpha state. There will be a + // performance boost if this frame is opaque. + DCHECK(m_frameGenerator); + return createFrameImageAtIndex(index, !m_frameGenerator->hasAlpha(index)); } PassRefPtr<SharedBuffer> DeferredImageDecoder::data()
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayerTest.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsLayerTest.cpp index fef527b..f17cef0 100644 --- a/third_party/WebKit/Source/platform/graphics/GraphicsLayerTest.cpp +++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayerTest.cpp
@@ -108,7 +108,7 @@ ASSERT_FALSE(m_platformLayer->hasActiveAnimationForTesting()); std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create(); - curve->addCubicBezierKeyframe(CompositorFloatKeyframe(0.0, 0.0), *CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseType::EASE)); + curve->addKeyframe(CompositorFloatKeyframe(0.0, 0.0), *CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseType::EASE)); std::unique_ptr<CompositorAnimation> floatAnimation(CompositorAnimation::create(*curve, CompositorTargetProperty::OPACITY, 0, 0)); int animationId = floatAnimation->id();
diff --git a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurfaceTest.cpp b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurfaceTest.cpp index dd956ebc..f655a6e2 100644 --- a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurfaceTest.cpp +++ b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurfaceTest.cpp
@@ -282,6 +282,12 @@ return 0.0; } + base::SingleThreadTaskRunner* taskRunner() override + { + NOTREACHED(); + return nullptr; + } + Task* m_task; };
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp index da3c470..f26ab817 100644 --- a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp +++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp
@@ -90,7 +90,7 @@ if (!picture) return; gfx::Rect bounds = gfx::SkIRectToRect(picture->cullRect().roundOut()); - list->CreateAndAppendItem<cc::DrawingDisplayItem>(bounds, sk_ref_sp(picture)); + list->CreateAndAppendDrawingItem<cc::DrawingDisplayItem>(bounds, sk_ref_sp(picture)); } } @@ -103,13 +103,13 @@ gfx::Transform translation; translation.Translate(-combinedBounds.x(), -combinedBounds.y()); // TODO(jbroman, wkorman): What visual rectangle is wanted here? - list->CreateAndAppendItem<cc::TransformDisplayItem>(gfx::Rect(), translation); + list->CreateAndAppendPairedBeginItem<cc::TransformDisplayItem>(translation); const DisplayItemList& displayItems = artifact.getDisplayItemList(); for (const auto& displayItem : displayItems.itemsInPaintChunk(chunk)) appendDisplayItemToCcDisplayItemList(displayItem, list.get()); - list->CreateAndAppendItem<cc::EndTransformDisplayItem>(gfx::Rect()); + list->CreateAndAppendPairedEndItem<cc::EndTransformDisplayItem>(); list->Finalize(); return list; @@ -591,6 +591,8 @@ // queried by RenderSurfaceImpl. layer->Set3dSortingContextId(host->property_trees()->transform_tree.Node(transformId)->sorting_context_id); + layer->SetShouldCheckBackfaceVisibility(paintChunk.properties.backfaceHidden); + if (m_extraDataForTestingEnabled) m_extraDataForTesting->contentLayers.append(layer); }
diff --git a/third_party/WebKit/Source/platform/graphics/paint/ClipDisplayItem.cpp b/third_party/WebKit/Source/platform/graphics/paint/ClipDisplayItem.cpp index 75a305b..80a8ebc 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/ClipDisplayItem.cpp +++ b/third_party/WebKit/Source/platform/graphics/paint/ClipDisplayItem.cpp
@@ -32,7 +32,7 @@ for (size_t i = 0; i < m_roundedRectClips.size(); ++i) webRoundedRects[i] = m_roundedRectClips[i]; - list->appendClipItem(visualRect, m_clipRect, webRoundedRects); + list->appendClipItem(m_clipRect, webRoundedRects); } void EndClipDisplayItem::replay(GraphicsContext& context) const @@ -42,7 +42,7 @@ void EndClipDisplayItem::appendToWebDisplayItemList(const IntRect& visualRect, WebDisplayItemList* list) const { - list->appendEndClipItem(visualRect); + list->appendEndClipItem(); } #ifndef NDEBUG
diff --git a/third_party/WebKit/Source/platform/graphics/paint/ClipPathDisplayItem.cpp b/third_party/WebKit/Source/platform/graphics/paint/ClipPathDisplayItem.cpp index 2cbbff1..7aa2b368 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/ClipPathDisplayItem.cpp +++ b/third_party/WebKit/Source/platform/graphics/paint/ClipPathDisplayItem.cpp
@@ -20,7 +20,7 @@ void BeginClipPathDisplayItem::appendToWebDisplayItemList(const IntRect& visualRect, WebDisplayItemList* list) const { - list->appendClipPathItem(visualRect, m_clipPath, SkRegion::kIntersect_Op, true); + list->appendClipPathItem(m_clipPath, SkRegion::kIntersect_Op, true); } void BeginClipPathDisplayItem::analyzeForGpuRasterization(SkPictureGpuAnalyzer& analyzer) const @@ -36,7 +36,7 @@ void EndClipPathDisplayItem::appendToWebDisplayItemList(const IntRect& visualRect, WebDisplayItemList* list) const { - list->appendEndClipPathItem(visualRect); + list->appendEndClipPathItem(); } #ifndef NDEBUG
diff --git a/third_party/WebKit/Source/platform/graphics/paint/CompositingDisplayItem.cpp b/third_party/WebKit/Source/platform/graphics/paint/CompositingDisplayItem.cpp index cd12538..7b9df256 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/CompositingDisplayItem.cpp +++ b/third_party/WebKit/Source/platform/graphics/paint/CompositingDisplayItem.cpp
@@ -19,7 +19,7 @@ void BeginCompositingDisplayItem::appendToWebDisplayItemList(const IntRect& visualRect, WebDisplayItemList* list) const { SkRect bounds = m_bounds; - list->appendCompositingItem(visualRect, m_opacity, m_xferMode, + list->appendCompositingItem(m_opacity, m_xferMode, m_hasBounds ? &bounds : nullptr, GraphicsContext::WebCoreColorFilterToSkiaColorFilter(m_colorFilter).get()); } @@ -41,7 +41,7 @@ void EndCompositingDisplayItem::appendToWebDisplayItemList(const IntRect& visualRect, WebDisplayItemList* list) const { - list->appendEndCompositingItem(visualRect); + list->appendEndCompositingItem(); } } // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h b/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h index be857e6c..cf38fc4 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h +++ b/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h
@@ -240,6 +240,8 @@ void setSkippedCache() { m_skippedCache = true; } bool skippedCache() const { return m_skippedCache; } + // TODO(wkorman): Only DrawingDisplayItem needs the visual rect argument. + // Consider refactoring class hierarchy to make this more explicit. virtual void appendToWebDisplayItemList(const IntRect&, WebDisplayItemList*) const { } // See comments of enum Type for usage of the following macros.
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DisplayItemList.cpp b/third_party/WebKit/Source/platform/graphics/paint/DisplayItemList.cpp index c3f23f1..c7ecf68 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/DisplayItemList.cpp +++ b/third_party/WebKit/Source/platform/graphics/paint/DisplayItemList.cpp
@@ -34,36 +34,7 @@ void DisplayItemList::appendVisualRect(const IntRect& visualRect) { - size_t itemIndex = m_visualRects.size(); - const DisplayItem& item = (*this)[itemIndex]; - - // For paired display items such as transforms, since we are not guaranteed containment, the - // visual rect must comprise the union of the visual rects for all items within its block. - - if (item.isBegin()) { - m_visualRects.append(visualRect); - m_beginItemIndices.append(itemIndex); - - } else if (item.isEnd()) { - size_t lastBeginIndex = m_beginItemIndices.last(); - m_beginItemIndices.removeLast(); - - // Ending bounds match the starting bounds. - m_visualRects.append(m_visualRects[lastBeginIndex]); - - // The block that ended needs to be included in the bounds of the enclosing block. - growCurrentBeginItemVisualRect(m_visualRects[lastBeginIndex]); - - } else { - m_visualRects.append(visualRect); - growCurrentBeginItemVisualRect(visualRect); - } -} - -void DisplayItemList::growCurrentBeginItemVisualRect(const IntRect& visualRect) -{ - if (!m_beginItemIndices.isEmpty()) - m_visualRects[m_beginItemIndices.last()].unite(visualRect); + m_visualRects.append(visualRect); } DisplayItemList::Range<DisplayItemList::iterator>
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DisplayItemList.h b/third_party/WebKit/Source/platform/graphics/paint/DisplayItemList.h index 6ebb963..5f2183a 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/DisplayItemList.h +++ b/third_party/WebKit/Source/platform/graphics/paint/DisplayItemList.h
@@ -32,14 +32,12 @@ DisplayItemList(DisplayItemList&& source) : ContiguousContainer(std::move(source)) , m_visualRects(std::move(source.m_visualRects)) - , m_beginItemIndices(std::move(source.m_beginItemIndices)) {} DisplayItemList& operator=(DisplayItemList&& source) { ContiguousContainer::operator=(std::move(source)); m_visualRects = std::move(source.m_visualRects); - m_beginItemIndices = std::move(source.m_beginItemIndices); return *this; } @@ -70,12 +68,7 @@ Range<const_iterator> itemsInPaintChunk(const PaintChunk&) const; private: - // If we're currently within a paired display item block, unions the - // given visual rect with the begin display item's visual rect. - void growCurrentBeginItemVisualRect(const IntRect& visualRect); - Vector<IntRect> m_visualRects; - Vector<size_t> m_beginItemIndices; }; } // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DisplayItemListTest.cpp b/third_party/WebKit/Source/platform/graphics/paint/DisplayItemListTest.cpp index 31cfb4db..eceb235 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/DisplayItemListTest.cpp +++ b/third_party/WebKit/Source/platform/graphics/paint/DisplayItemListTest.cpp
@@ -8,10 +8,8 @@ #include "SkTypes.h" #include "platform/graphics/paint/DrawingDisplayItem.h" #include "platform/graphics/paint/SubsequenceDisplayItem.h" -#include "platform/graphics/paint/TransformDisplayItem.h" #include "platform/graphics/skia/SkiaUtils.h" #include "platform/testing/FakeDisplayItemClient.h" -#include "platform/transforms/AffineTransform.h" #include "testing/gtest/include/gtest/gtest.h" namespace blink { @@ -48,8 +46,6 @@ TEST_F(DisplayItemListTest, AppendVisualRect_Simple) { - // One drawing: D. - IntRect drawingBounds(5, 6, 7, 8); m_list.allocateAndConstruct<DrawingDisplayItem>( m_client, DisplayItem::Type::DocumentBackground, createRectPicture(drawingBounds), true); @@ -59,79 +55,13 @@ EXPECT_RECT_EQ(drawingBounds, m_list.visualRect(0)); } -TEST_F(DisplayItemListTest, AppendVisualRect_EmptyBlock) -{ - // One block: B1, E1. - - IntRect subsequenceBounds(5, 6, 7, 8); - m_list.allocateAndConstruct<BeginSubsequenceDisplayItem>(m_client); - m_list.appendVisualRect(subsequenceBounds); - - m_list.allocateAndConstruct<EndSubsequenceDisplayItem>(m_client); - m_list.appendVisualRect(subsequenceBounds); - - EXPECT_EQ(static_cast<size_t>(2), m_list.size()); - EXPECT_RECT_EQ(subsequenceBounds, m_list.visualRect(0)); - EXPECT_RECT_EQ(subsequenceBounds, m_list.visualRect(1)); -} - -TEST_F(DisplayItemListTest, AppendVisualRect_EmptyBlockContainingEmptyBlock) -{ - // Two nested blocks: B1, B2, E2, E1. - - IntRect subsequenceBounds(5, 6, 7, 8); - m_list.allocateAndConstruct<BeginSubsequenceDisplayItem>(m_client); - m_list.appendVisualRect(subsequenceBounds); - - IntRect transformBounds(5, 6, 1, 1); - AffineTransform transform; - m_list.allocateAndConstruct<BeginTransformDisplayItem>(m_client, transform); - m_list.appendVisualRect(transformBounds); - - m_list.allocateAndConstruct<EndTransformDisplayItem>(m_client); - m_list.appendVisualRect(transformBounds); - - m_list.allocateAndConstruct<EndSubsequenceDisplayItem>(m_client); - m_list.appendVisualRect(subsequenceBounds); - - EXPECT_EQ(static_cast<size_t>(4), m_list.size()); - EXPECT_RECT_EQ(subsequenceBounds, m_list.visualRect(0)); - EXPECT_RECT_EQ(transformBounds, m_list.visualRect(1)); - EXPECT_RECT_EQ(transformBounds, m_list.visualRect(2)); - EXPECT_RECT_EQ(subsequenceBounds, m_list.visualRect(3)); -} - -TEST_F(DisplayItemListTest, AppendVisualRect_EmptyBlockContainingEscapedEmptyBlock) -{ - // Two nested blocks with the inner block escaping: - // B1, B2 (escapes), E2, E1. - - IntRect subsequenceBounds(5, 6, 7, 8); - m_list.allocateAndConstruct<BeginSubsequenceDisplayItem>(m_client); - m_list.appendVisualRect(subsequenceBounds); - - IntRect transformBounds(1, 2, 3, 4); - AffineTransform transform; - m_list.allocateAndConstruct<BeginTransformDisplayItem>(m_client, transform); - m_list.appendVisualRect(transformBounds); - - m_list.allocateAndConstruct<EndTransformDisplayItem>(m_client); - m_list.appendVisualRect(transformBounds); - - m_list.allocateAndConstruct<EndSubsequenceDisplayItem>(m_client); - m_list.appendVisualRect(subsequenceBounds); - - EXPECT_EQ(static_cast<size_t>(4), m_list.size()); - IntRect mergedSubsequenceBounds(1, 2, 11, 12); - EXPECT_RECT_EQ(mergedSubsequenceBounds, m_list.visualRect(0)); - EXPECT_RECT_EQ(transformBounds, m_list.visualRect(1)); - EXPECT_RECT_EQ(transformBounds, m_list.visualRect(2)); - EXPECT_RECT_EQ(mergedSubsequenceBounds, m_list.visualRect(3)); -} - TEST_F(DisplayItemListTest, AppendVisualRect_BlockContainingDrawing) { - // One block with one drawing: B1, Da, E1. + // TODO(wkorman): Note the visual rects for the paired begin/end are now + // irrelevant as they're overwritten in cc::DisplayItemList when rebuilt to + // represent the union of all drawing display item visual rects between the + // pair. We should consider revising Blink's display item list in some form + // so as to only store visual rects for drawing display items. IntRect subsequenceBounds(5, 6, 7, 8); m_list.allocateAndConstruct<BeginSubsequenceDisplayItem>(m_client); @@ -150,216 +80,5 @@ EXPECT_RECT_EQ(drawingBounds, m_list.visualRect(1)); EXPECT_RECT_EQ(subsequenceBounds, m_list.visualRect(2)); } - -TEST_F(DisplayItemListTest, AppendVisualRect_BlockContainingEscapedDrawing) -{ - // One block with one drawing: B1, Da (escapes), E1. - - IntRect subsequenceBounds(5, 6, 7, 8); - m_list.allocateAndConstruct<BeginSubsequenceDisplayItem>(m_client); - m_list.appendVisualRect(subsequenceBounds); - - IntRect drawingBounds(1, 2, 3, 4); - m_list.allocateAndConstruct<DrawingDisplayItem>( - m_client, DisplayItem::Type::DocumentBackground, createRectPicture(drawingBounds), true); - m_list.appendVisualRect(drawingBounds); - - m_list.allocateAndConstruct<EndSubsequenceDisplayItem>(m_client); - m_list.appendVisualRect(subsequenceBounds); - - EXPECT_EQ(static_cast<size_t>(3), m_list.size()); - IntRect mergedSubsequenceBounds(1, 2, 11, 12); - EXPECT_RECT_EQ(mergedSubsequenceBounds, m_list.visualRect(0)); - EXPECT_RECT_EQ(drawingBounds, m_list.visualRect(1)); - EXPECT_RECT_EQ(mergedSubsequenceBounds, m_list.visualRect(2)); -} - -TEST_F(DisplayItemListTest, AppendVisualRect_DrawingFollowedByBlockContainingEscapedDrawing) -{ - // One drawing followed by one block with one drawing: Da, B1, Db (escapes), E1. - - IntRect drawingABounds(1, 2, 3, 4); - m_list.allocateAndConstruct<DrawingDisplayItem>( - m_client, DisplayItem::Type::DocumentBackground, createRectPicture(drawingABounds), true); - m_list.appendVisualRect(drawingABounds); - - IntRect subsequenceBounds(5, 6, 7, 8); - m_list.allocateAndConstruct<BeginSubsequenceDisplayItem>(m_client); - m_list.appendVisualRect(subsequenceBounds); - - IntRect drawingBBounds(13, 14, 1, 1); - m_list.allocateAndConstruct<DrawingDisplayItem>( - m_client, DisplayItem::Type::DocumentBackground, createRectPicture(drawingBBounds), true); - m_list.appendVisualRect(drawingBBounds); - - m_list.allocateAndConstruct<EndSubsequenceDisplayItem>(m_client); - m_list.appendVisualRect(subsequenceBounds); - - EXPECT_EQ(static_cast<size_t>(4), m_list.size()); - EXPECT_RECT_EQ(drawingABounds, m_list.visualRect(0)); - IntRect mergedSubsequenceBounds(5, 6, 9, 9); - EXPECT_RECT_EQ(mergedSubsequenceBounds, m_list.visualRect(1)); - EXPECT_RECT_EQ(drawingBBounds, m_list.visualRect(2)); - EXPECT_RECT_EQ(mergedSubsequenceBounds, m_list.visualRect(3)); -} - -TEST_F(DisplayItemListTest, AppendVisualRect_TwoBlocksTwoDrawings) -{ - // Multiple nested blocks with drawings amidst: B1, Da, B2, Db, E2, E1. - - IntRect subsequenceBounds(5, 6, 7, 8); - m_list.allocateAndConstruct<BeginSubsequenceDisplayItem>(m_client); - m_list.appendVisualRect(subsequenceBounds); - - IntRect drawingABounds(5, 6, 1, 1); - m_list.allocateAndConstruct<DrawingDisplayItem>( - m_client, DisplayItem::Type::DocumentBackground, createRectPicture(drawingABounds), true); - m_list.appendVisualRect(drawingABounds); - - IntRect transformBounds(7, 8, 2, 2); - AffineTransform transform; - m_list.allocateAndConstruct<BeginTransformDisplayItem>(m_client, transform); - m_list.appendVisualRect(transformBounds); - - IntRect drawingBBounds(7, 8, 1, 1); - m_list.allocateAndConstruct<DrawingDisplayItem>( - m_client, DisplayItem::Type::DocumentBackground, createRectPicture(drawingBBounds), true); - m_list.appendVisualRect(drawingBBounds); - - m_list.allocateAndConstruct<EndTransformDisplayItem>(m_client); - m_list.appendVisualRect(transformBounds); - - m_list.allocateAndConstruct<EndSubsequenceDisplayItem>(m_client); - m_list.appendVisualRect(subsequenceBounds); - - EXPECT_EQ(static_cast<size_t>(6), m_list.size()); - EXPECT_RECT_EQ(subsequenceBounds, m_list.visualRect(0)); - EXPECT_RECT_EQ(drawingABounds, m_list.visualRect(1)); - EXPECT_RECT_EQ(transformBounds, m_list.visualRect(2)); - EXPECT_RECT_EQ(drawingBBounds, m_list.visualRect(3)); - EXPECT_RECT_EQ(transformBounds, m_list.visualRect(4)); - EXPECT_RECT_EQ(subsequenceBounds, m_list.visualRect(5)); -} - -TEST_F(DisplayItemListTest, AppendVisualRect_TwoBlocksTwoDrawingsInnerDrawingEscaped) -{ - // Multiple nested blocks with drawings amidst: B1, Da, B2, Db (escapes), E2, E1. - - IntRect subsequenceBounds(5, 6, 7, 8); - m_list.allocateAndConstruct<BeginSubsequenceDisplayItem>(m_client); - m_list.appendVisualRect(subsequenceBounds); - - IntRect drawingABounds(5, 6, 1, 1); - m_list.allocateAndConstruct<DrawingDisplayItem>( - m_client, DisplayItem::Type::DocumentBackground, createRectPicture(drawingABounds), true); - m_list.appendVisualRect(drawingABounds); - - IntRect transformBounds(7, 8, 2, 2); - AffineTransform transform; - m_list.allocateAndConstruct<BeginTransformDisplayItem>(m_client, transform); - m_list.appendVisualRect(transformBounds); - - IntRect drawingBBounds(1, 2, 3, 4); - m_list.allocateAndConstruct<DrawingDisplayItem>( - m_client, DisplayItem::Type::DocumentBackground, createRectPicture(drawingBBounds), true); - m_list.appendVisualRect(drawingBBounds); - - m_list.allocateAndConstruct<EndTransformDisplayItem>(m_client); - m_list.appendVisualRect(transformBounds); - - m_list.allocateAndConstruct<EndSubsequenceDisplayItem>(m_client); - m_list.appendVisualRect(subsequenceBounds); - - EXPECT_EQ(static_cast<size_t>(6), m_list.size()); - IntRect mergedSubsequenceBounds(1, 2, 11, 12); - EXPECT_RECT_EQ(mergedSubsequenceBounds, m_list.visualRect(0)); - EXPECT_RECT_EQ(drawingABounds, m_list.visualRect(1)); - IntRect mergedTransformBounds(1, 2, 8, 8); - EXPECT_RECT_EQ(mergedTransformBounds, m_list.visualRect(2)); - EXPECT_RECT_EQ(drawingBBounds, m_list.visualRect(3)); - EXPECT_RECT_EQ(mergedTransformBounds, m_list.visualRect(4)); - EXPECT_RECT_EQ(mergedSubsequenceBounds, m_list.visualRect(5)); -} - -TEST_F(DisplayItemListTest, AppendVisualRect_TwoBlocksTwoDrawingsOuterDrawingEscaped) -{ - // Multiple nested blocks with drawings amidst: B1, Da (escapes), B2, Db, E2, E1. - - IntRect subsequenceBounds(5, 6, 7, 8); - m_list.allocateAndConstruct<BeginSubsequenceDisplayItem>(m_client); - m_list.appendVisualRect(subsequenceBounds); - - IntRect drawingABounds(1, 2, 3, 4); - m_list.allocateAndConstruct<DrawingDisplayItem>( - m_client, DisplayItem::Type::DocumentBackground, createRectPicture(drawingABounds), true); - m_list.appendVisualRect(drawingABounds); - - IntRect transformBounds(7, 8, 2, 2); - AffineTransform transform; - m_list.allocateAndConstruct<BeginTransformDisplayItem>(m_client, transform); - m_list.appendVisualRect(transformBounds); - - IntRect drawingBBounds(7, 8, 1, 1); - m_list.allocateAndConstruct<DrawingDisplayItem>( - m_client, DisplayItem::Type::DocumentBackground, createRectPicture(drawingBBounds), true); - m_list.appendVisualRect(drawingBBounds); - - m_list.allocateAndConstruct<EndTransformDisplayItem>(m_client); - m_list.appendVisualRect(transformBounds); - - m_list.allocateAndConstruct<EndSubsequenceDisplayItem>(m_client); - m_list.appendVisualRect(subsequenceBounds); - - EXPECT_EQ(static_cast<size_t>(6), m_list.size()); - IntRect mergedSubsequenceBounds(1, 2, 11, 12); - EXPECT_RECT_EQ(mergedSubsequenceBounds, m_list.visualRect(0)); - EXPECT_RECT_EQ(drawingABounds, m_list.visualRect(1)); - EXPECT_RECT_EQ(transformBounds, m_list.visualRect(2)); - EXPECT_RECT_EQ(drawingBBounds, m_list.visualRect(3)); - EXPECT_RECT_EQ(transformBounds, m_list.visualRect(4)); - EXPECT_RECT_EQ(mergedSubsequenceBounds, m_list.visualRect(5)); -} - -TEST_F(DisplayItemListTest, AppendVisualRect_TwoBlocksTwoDrawingsBothDrawingsEscaped) -{ - // Multiple nested blocks with drawings amidst: - // B1, Da (escapes to the right), B2, Db (escapes to the left), E2, E1. - - IntRect subsequenceBounds(5, 6, 7, 8); - m_list.allocateAndConstruct<BeginSubsequenceDisplayItem>(m_client); - m_list.appendVisualRect(subsequenceBounds); - - IntRect drawingABounds(13, 14, 1, 1); - m_list.allocateAndConstruct<DrawingDisplayItem>( - m_client, DisplayItem::Type::DocumentBackground, createRectPicture(drawingABounds), true); - m_list.appendVisualRect(drawingABounds); - - IntRect transformBounds(7, 8, 2, 2); - AffineTransform transform; - m_list.allocateAndConstruct<BeginTransformDisplayItem>(m_client, transform); - m_list.appendVisualRect(transformBounds); - - IntRect drawingBBounds(1, 2, 3, 4); - m_list.allocateAndConstruct<DrawingDisplayItem>( - m_client, DisplayItem::Type::DocumentBackground, createRectPicture(drawingBBounds), true); - m_list.appendVisualRect(drawingBBounds); - - m_list.allocateAndConstruct<EndTransformDisplayItem>(m_client); - m_list.appendVisualRect(transformBounds); - - m_list.allocateAndConstruct<EndSubsequenceDisplayItem>(m_client); - m_list.appendVisualRect(subsequenceBounds); - - EXPECT_EQ(static_cast<size_t>(6), m_list.size()); - IntRect mergedSubsequenceBounds(1, 2, 13, 13); - EXPECT_RECT_EQ(mergedSubsequenceBounds, m_list.visualRect(0)); - EXPECT_RECT_EQ(drawingABounds, m_list.visualRect(1)); - IntRect mergedTransformBounds(1, 2, 8, 8); - EXPECT_RECT_EQ(mergedTransformBounds, m_list.visualRect(2)); - EXPECT_RECT_EQ(drawingBBounds, m_list.visualRect(3)); - EXPECT_RECT_EQ(mergedTransformBounds, m_list.visualRect(4)); - EXPECT_RECT_EQ(mergedSubsequenceBounds, m_list.visualRect(5)); -} - } // namespace } // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/paint/FilterDisplayItem.cpp b/third_party/WebKit/Source/platform/graphics/paint/FilterDisplayItem.cpp index 5ab5dcf..f2c549a5 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/FilterDisplayItem.cpp +++ b/third_party/WebKit/Source/platform/graphics/paint/FilterDisplayItem.cpp
@@ -20,7 +20,7 @@ void BeginFilterDisplayItem::appendToWebDisplayItemList(const IntRect& visualRect, WebDisplayItemList* list) const { - list->appendFilterItem(visualRect, m_webFilterOperations->asFilterOperations(), m_bounds); + list->appendFilterItem(m_webFilterOperations->asFilterOperations(), m_bounds); } bool BeginFilterDisplayItem::drawsContent() const @@ -47,7 +47,7 @@ void EndFilterDisplayItem::appendToWebDisplayItemList(const IntRect& visualRect, WebDisplayItemList* list) const { - list->appendEndFilterItem(visualRect); + list->appendEndFilterItem(); } } // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/paint/FloatClipDisplayItem.cpp b/third_party/WebKit/Source/platform/graphics/paint/FloatClipDisplayItem.cpp index b2f3552..82e2fff 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/FloatClipDisplayItem.cpp +++ b/third_party/WebKit/Source/platform/graphics/paint/FloatClipDisplayItem.cpp
@@ -18,7 +18,7 @@ void FloatClipDisplayItem::appendToWebDisplayItemList(const IntRect& visualRect, WebDisplayItemList* list) const { - list->appendFloatClipItem(visualRect, m_clipRect); + list->appendFloatClipItem(m_clipRect); } void EndFloatClipDisplayItem::replay(GraphicsContext& context) const @@ -28,7 +28,7 @@ void EndFloatClipDisplayItem::appendToWebDisplayItemList(const IntRect& visualRect, WebDisplayItemList* list) const { - list->appendEndFloatClipItem(visualRect); + list->appendEndFloatClipItem(); } #ifndef NDEBUG
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp index 58d2f40c..cde9a3c9 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp +++ b/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp
@@ -439,6 +439,7 @@ if (gpuAnalyzer.suitableForGpuRasterization()) item.analyzeForGpuRasterization(gpuAnalyzer); + // TODO(wkorman): Only compute and append visual rect for drawings. m_newDisplayItemList.appendVisualRect(visualRectForDisplayItem(item, offsetFromLayoutObject)); if (item.isCacheable()) { @@ -512,6 +513,7 @@ DCHECK(m_newDisplayItemList.isEmpty()); DrawingDisplayItem& displayItem = m_currentPaintArtifact.getDisplayItemList().allocateAndConstruct<DrawingDisplayItem>(displayItemClient, DisplayItem::DebugDrawing, picture); displayItem.setSkippedCache(); + // TODO(wkorman): Only compute and append visual rect for drawings. m_currentPaintArtifact.getDisplayItemList().appendVisualRect(visualRectForDisplayItem(displayItem, offsetFromLayoutObject)); }
diff --git a/third_party/WebKit/Source/platform/graphics/paint/ScrollDisplayItem.cpp b/third_party/WebKit/Source/platform/graphics/paint/ScrollDisplayItem.cpp index d8f33504..e310fb8 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/ScrollDisplayItem.cpp +++ b/third_party/WebKit/Source/platform/graphics/paint/ScrollDisplayItem.cpp
@@ -19,7 +19,7 @@ void BeginScrollDisplayItem::appendToWebDisplayItemList(const IntRect& visualRect, WebDisplayItemList* list) const { WebDisplayItemList::ScrollContainerId scrollContainerId = &client(); - list->appendScrollItem(visualRect, m_currentOffset, scrollContainerId); + list->appendScrollItem(m_currentOffset, scrollContainerId); } #ifndef NDEBUG @@ -37,7 +37,7 @@ void EndScrollDisplayItem::appendToWebDisplayItemList(const IntRect& visualRect, WebDisplayItemList* list) const { - list->appendEndScrollItem(visualRect); + list->appendEndScrollItem(); } } // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/paint/Transform3DDisplayItem.cpp b/third_party/WebKit/Source/platform/graphics/paint/Transform3DDisplayItem.cpp index a21519a..3fa5233 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/Transform3DDisplayItem.cpp +++ b/third_party/WebKit/Source/platform/graphics/paint/Transform3DDisplayItem.cpp
@@ -23,7 +23,7 @@ // TODO(jbroman): The compositor will need the transform origin separately. TransformationMatrix transform(m_transform); transform.applyTransformOrigin(m_transformOrigin); - list->appendTransformItem(visualRect, TransformationMatrix::toSkMatrix44(transform)); + list->appendTransformItem(TransformationMatrix::toSkMatrix44(transform)); } #ifndef NDEBUG @@ -51,7 +51,7 @@ void EndTransform3DDisplayItem::appendToWebDisplayItemList(const IntRect& visualRect, WebDisplayItemList* list) const { - list->appendEndTransformItem(visualRect); + list->appendEndTransformItem(); } } // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/paint/TransformDisplayItem.cpp b/third_party/WebKit/Source/platform/graphics/paint/TransformDisplayItem.cpp index 0f5d153..7a2d3eb 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/TransformDisplayItem.cpp +++ b/third_party/WebKit/Source/platform/graphics/paint/TransformDisplayItem.cpp
@@ -18,7 +18,7 @@ void BeginTransformDisplayItem::appendToWebDisplayItemList(const IntRect& visualRect, WebDisplayItemList* list) const { - list->appendTransformItem(visualRect, affineTransformToSkMatrix(m_transform)); + list->appendTransformItem(affineTransformToSkMatrix(m_transform)); } #ifndef NDEBUG @@ -37,7 +37,7 @@ void EndTransformDisplayItem::appendToWebDisplayItemList(const IntRect& visualRect, WebDisplayItemList* list) const { - list->appendEndTransformItem(visualRect); + list->appendEndTransformItem(); } } // namespace blink
diff --git a/third_party/WebKit/Source/platform/heap/PersistentNode.h b/third_party/WebKit/Source/platform/heap/PersistentNode.h index c9bebe3..abff969 100644 --- a/third_party/WebKit/Source/platform/heap/PersistentNode.h +++ b/third_party/WebKit/Source/platform/heap/PersistentNode.h
@@ -226,6 +226,7 @@ void prepareForThreadStateTermination(ThreadState*); + NO_LAZY_SWEEP_SANITIZE_ADDRESS static bool shouldTracePersistentNode(Visitor*, PersistentNode*); private:
diff --git a/third_party/WebKit/Source/platform/inspector_protocol/generate-inspector-protocol-version b/third_party/WebKit/Source/platform/inspector_protocol/generate-inspector-protocol-version index d15f765..0c01e16 100755 --- a/third_party/WebKit/Source/platform/inspector_protocol/generate-inspector-protocol-version +++ b/third_party/WebKit/Source/platform/inspector_protocol/generate-inspector-protocol-version
@@ -60,7 +60,7 @@ def list_to_map(items, key): result = {} for item in items: - if not "hidden" in item: + if not "experimental" in item and not "hidden" in item: result[item[key]] = item return result @@ -287,7 +287,7 @@ { "name": "requestWillBeSent", "parameters": [ - { "name": "frameId", "type": "string", "hidden": True }, + { "name": "frameId", "type": "string", "experimental": True }, { "name": "request", "$ref": "Request" }, { "name": "becameOptional", "type": "string" }, { "name": "removedRequired", "type": "string" },
diff --git a/third_party/WebKit/Source/platform/mhtml/MHTMLArchive.cpp b/third_party/WebKit/Source/platform/mhtml/MHTMLArchive.cpp index b735d6e..26fe8ab 100644 --- a/third_party/WebKit/Source/platform/mhtml/MHTMLArchive.cpp +++ b/third_party/WebKit/Source/platform/mhtml/MHTMLArchive.cpp
@@ -69,8 +69,9 @@ MHTMLArchive* MHTMLArchive::create(const KURL& url, PassRefPtr<SharedBuffer> data) { - // For security reasons we only load MHTML pages from local URLs. - if (!SchemeRegistry::shouldTreatURLSchemeAsLocal(url.protocol())) + // MHTML pages can only be loaded from local URLs and http/https URLs. + // The latter is now allowed due to full sandboxing enforcement on MHTML pages. + if (!SchemeRegistry::shouldTreatURLSchemeAsLocal(url.protocol()) && !url.protocolIsInHTTPFamily()) return nullptr; MHTMLParser parser(data);
diff --git a/third_party/WebKit/Source/platform/scheduler/.clang-format b/third_party/WebKit/Source/platform/scheduler/.clang-format new file mode 100644 index 0000000..6fdf1dc --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/.clang-format
@@ -0,0 +1,8 @@ +# Defines the Chromium style for automatic reformatting. +# http://clang.llvm.org/docs/ClangFormatStyleOptions.html +BasedOnStyle: Chromium +# This defaults to 'Auto'. Explicitly set it for a while, so that +# 'vector<vector<int> >' in existing files gets formatted to +# 'vector<vector<int>>'. ('Auto' means that clang-format will only use +# 'int>>' if the file already contains at least one such instance.) +Standard: Cpp11
diff --git a/third_party/WebKit/Source/platform/scheduler/DEPS b/third_party/WebKit/Source/platform/scheduler/DEPS new file mode 100644 index 0000000..db5c0b70 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/DEPS
@@ -0,0 +1,30 @@ +include_rules = [ + "+base/atomicops.h", + "+base/atomic_sequence_num.h", + "+base/bind_helpers.h", + "+base/callback.h", + "+base/cancelable_callback.h", + "+base/command_line.h", + "+base/compiler_specific.h", + "+base/containers/scoped_ptr_hash_map.h", + "+base/debug/stack_trace.h", + "+base/debug/task_annotator.h", + "+base/feature_list.h", + "+base/logging.h", + "+base/message_loop/message_loop.h", + "+base/metrics/field_trial.h", + "+base/metrics/histogram_macros.h", + "+base/pending_task.h", + "+base/run_loop.h", + "+base/single_thread_task_runner.h", + "+base/synchronization/lock.h", + "+base/threading/platform_thread.h", + "+base/threading/thread_checker.h", + "+base/threading/thread.h", +] + +specific_include_rules = { + ".*test\.cc": [ + "+testing", + ], +}
diff --git a/components/scheduler/OWNERS b/third_party/WebKit/Source/platform/scheduler/OWNERS similarity index 100% rename from components/scheduler/OWNERS rename to third_party/WebKit/Source/platform/scheduler/OWNERS
diff --git a/third_party/WebKit/Source/platform/scheduler/README.md b/third_party/WebKit/Source/platform/scheduler/README.md new file mode 100644 index 0000000..0ac9ed5 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/README.md
@@ -0,0 +1,13 @@ +# Blink Scheduler + +This directory contains the Blink Scheduler, which coordinates task execution +in renderer processes. The main subdirectories are: + +- `base/` -- basic scheduling primitives such as `TaskQueue` and + `TaskQueueManager`. +- `child/` -- contains the `ChildScheduler` which is the base class for all + thread schedulers, as well as a `WorkerScheduler` for worker threads. +- `utility/` -- a small scheduler for utility processes. +- `renderer/` -- `RendererScheduler` for the renderer process. + +The scheduler exposes an API at `public/platform/scheduler`.
diff --git a/third_party/WebKit/Source/platform/scheduler/base/DEPS b/third_party/WebKit/Source/platform/scheduler/base/DEPS new file mode 100644 index 0000000..5333f29 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/DEPS
@@ -0,0 +1,5 @@ +specific_include_rules = { + "(test_time_source|.*test)\.cc": [ + "+cc/test", + ], +}
diff --git a/third_party/WebKit/Source/platform/scheduler/base/cancelable_closure_holder.cc b/third_party/WebKit/Source/platform/scheduler/base/cancelable_closure_holder.cc new file mode 100644 index 0000000..12c0506e --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/cancelable_closure_holder.cc
@@ -0,0 +1,30 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "platform/scheduler/base/cancelable_closure_holder.h" + +namespace blink { +namespace scheduler { + +CancelableClosureHolder::CancelableClosureHolder() {} + +CancelableClosureHolder::~CancelableClosureHolder() {} + +void CancelableClosureHolder::Reset(const base::Closure& callback) { + callback_ = callback; + cancelable_callback_.Reset(callback_); +} + +void CancelableClosureHolder::Cancel() { + DCHECK(!callback_.is_null()); + cancelable_callback_.Reset(callback_); +} + +const base::Closure& CancelableClosureHolder::callback() const { + DCHECK(!callback_.is_null()); + return cancelable_callback_.callback(); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/base/cancelable_closure_holder.h b/third_party/WebKit/Source/platform/scheduler/base/cancelable_closure_holder.h new file mode 100644 index 0000000..53ec676 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/cancelable_closure_holder.h
@@ -0,0 +1,42 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_CANCELABLE_CLOSURE_HOLDER_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_CANCELABLE_CLOSURE_HOLDER_H_ + +#include "base/cancelable_callback.h" +#include "base/macros.h" + +namespace blink { +namespace scheduler { + +// A CancelableClosureHolder is a CancelableCallback which resets its wrapped +// callback with a cached closure whenever it is canceled. +class CancelableClosureHolder { + public: + CancelableClosureHolder(); + ~CancelableClosureHolder(); + + // Resets the closure to be wrapped by the cancelable callback. Cancels any + // outstanding callbacks. + void Reset(const base::Closure& callback); + + // Cancels any outstanding closures returned by callback(). + void Cancel(); + + // Returns a callback that will be disabled by calling Cancel(). Callback + // must have been set using Reset() before calling this function. + const base::Closure& callback() const; + + private: + base::Closure callback_; + base::CancelableClosure cancelable_callback_; + + DISALLOW_COPY_AND_ASSIGN(CancelableClosureHolder); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_CANCELABLE_CLOSURE_HOLDER_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/base/enqueue_order.cc b/third_party/WebKit/Source/platform/scheduler/base/enqueue_order.cc new file mode 100644 index 0000000..487f39b --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/enqueue_order.cc
@@ -0,0 +1,22 @@ +// 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 "platform/scheduler/base/enqueue_order.h" + +namespace blink { +namespace scheduler { +namespace internal { + +EnqueueOrderGenerator::EnqueueOrderGenerator() : enqueue_order_(0) {} + +EnqueueOrderGenerator::~EnqueueOrderGenerator() {} + +EnqueueOrder EnqueueOrderGenerator::GenerateNext() { + base::AutoLock lock(lock_); + return enqueue_order_++; +} + +} // namespace internal +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/base/enqueue_order.h b/third_party/WebKit/Source/platform/scheduler/base/enqueue_order.h new file mode 100644 index 0000000..6318555 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/enqueue_order.h
@@ -0,0 +1,34 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_ENQUEUE_ORDER_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_ENQUEUE_ORDER_H_ + +#include <stdint.h> + +#include "base/synchronization/lock.h" + +namespace blink { +namespace scheduler { +namespace internal { + +using EnqueueOrder = uint64_t; + +class EnqueueOrderGenerator { + public: + EnqueueOrderGenerator(); + ~EnqueueOrderGenerator(); + + EnqueueOrder GenerateNext(); + + private: + base::Lock lock_; + EnqueueOrder enqueue_order_; +}; + +} // namespace internal +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_ENQUEUE_ORDER_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/base/lazy_now.cc b/third_party/WebKit/Source/platform/scheduler/base/lazy_now.cc new file mode 100644 index 0000000..b554a95e --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/lazy_now.cc
@@ -0,0 +1,19 @@ +// 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 "platform/scheduler/base/lazy_now.h" + +#include "base/time/tick_clock.h" +#include "platform/scheduler/base/task_queue_manager.h" + +namespace blink { +namespace scheduler { +base::TimeTicks LazyNow::Now() { + if (now_.is_null()) + now_ = tick_clock_->NowTicks(); + return now_; +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/base/lazy_now.h b/third_party/WebKit/Source/platform/scheduler/base/lazy_now.h new file mode 100644 index 0000000..1b63f0f --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/lazy_now.h
@@ -0,0 +1,38 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_LAZY_NOW_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_LAZY_NOW_H_ + +#include "base/time/time.h" +#include "public/platform/WebCommon.h" + +namespace base { +class TickClock; +} + +namespace blink { +namespace scheduler { + +// Now() is somewhat expensive so it makes sense not to call Now() unless we +// really need to. +class BLINK_PLATFORM_EXPORT LazyNow { + public: + explicit LazyNow(base::TimeTicks now) : tick_clock_(nullptr), now_(now) { + DCHECK(!now.is_null()); + } + + explicit LazyNow(base::TickClock* tick_clock) : tick_clock_(tick_clock) {} + + base::TimeTicks Now(); + + private: + base::TickClock* tick_clock_; // NOT OWNED + base::TimeTicks now_; +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_LAZY_NOW_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/base/long_task_tracker.cc b/third_party/WebKit/Source/platform/scheduler/base/long_task_tracker.cc new file mode 100644 index 0000000..a7a65ac --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/long_task_tracker.cc
@@ -0,0 +1,30 @@ +// 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 "platform/scheduler/base/long_task_tracker.h" + +namespace blink { +namespace scheduler { + +namespace { +int kLongTaskThresholdMillis = 50; +} + +LongTaskTracker::LongTaskTracker() {} + +LongTaskTracker::~LongTaskTracker() {} + +void LongTaskTracker::RecordLongTask(base::TimeTicks startTime, + base::TimeDelta duration) { + if (duration.InMilliseconds() > kLongTaskThresholdMillis) { + long_task_times_.push_back(std::make_pair(startTime, duration)); + } +} + +LongTaskTracker::LongTaskTiming LongTaskTracker::GetLongTaskTiming() { + return std::move(long_task_times_); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/base/long_task_tracker.h b/third_party/WebKit/Source/platform/scheduler/base/long_task_tracker.h new file mode 100644 index 0000000..680d530b --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/long_task_tracker.h
@@ -0,0 +1,41 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_LONG_TASK_TRACKER_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_LONG_TASK_TRACKER_H_ + +#include <vector> + +#include "base/macros.h" +#include "base/time/time.h" +#include "public/platform/WebCommon.h" + +namespace blink { +namespace scheduler { + +// Records and reports long task times, above the threshold. +// The threshold is set to 50ms in the implementation. +class BLINK_PLATFORM_EXPORT LongTaskTracker { + public: + using LongTaskTiming = + std::vector<std::pair<base::TimeTicks, base::TimeDelta>>; + + LongTaskTracker(); + ~LongTaskTracker(); + + LongTaskTiming GetLongTaskTiming(); + void RecordLongTask(base::TimeTicks startTime, base::TimeDelta duration); + + private: + friend class LongTaskTrackerTest; + + LongTaskTiming long_task_times_; + + DISALLOW_COPY_AND_ASSIGN(LongTaskTracker); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_LONG_TASK_TRACKER_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/base/long_task_tracker_unittest.cc b/third_party/WebKit/Source/platform/scheduler/base/long_task_tracker_unittest.cc new file mode 100644 index 0000000..322d0287 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/long_task_tracker_unittest.cc
@@ -0,0 +1,53 @@ +// 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 "platform/scheduler/base/long_task_tracker.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace blink { +namespace scheduler { + +class LongTaskTrackerTest : public ::testing::Test { + protected: + LongTaskTracker long_task_tracker_; + + size_t NumLongTasks() { return long_task_tracker_.long_task_times_.size(); } +}; + +TEST_F(LongTaskTrackerTest, RecordAndReport) { + EXPECT_EQ(0U, NumLongTasks()); + + // Add long tasks above 50ms threshold + long_task_tracker_.RecordLongTask( + base::TimeTicks() + base::TimeDelta::FromMilliseconds(4500), + base::TimeDelta::FromMilliseconds(51)); + EXPECT_EQ(1U, NumLongTasks()); + + long_task_tracker_.RecordLongTask( + base::TimeTicks() + base::TimeDelta::FromMilliseconds(5500), + base::TimeDelta::FromMilliseconds(75)); + EXPECT_EQ(2U, NumLongTasks()); + + // Add task below 50ms threshold + long_task_tracker_.RecordLongTask( + base::TimeTicks() + base::TimeDelta::FromMilliseconds(6500), + base::TimeDelta::FromMilliseconds(49)); + EXPECT_EQ(2U, NumLongTasks()); + + LongTaskTracker::LongTaskTiming long_task_times = + long_task_tracker_.GetLongTaskTiming(); + // GetLongTaskTiming clears the internal vector + EXPECT_EQ(0U, NumLongTasks()); + // Validate recorded contents + EXPECT_EQ(2U, long_task_times.size()); + EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromMilliseconds(4500), + long_task_times[0].first); + EXPECT_EQ(51, long_task_times[0].second.InMilliseconds()); + EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromMilliseconds(5500), + long_task_times[1].first); + EXPECT_EQ(75, long_task_times[1].second.InMilliseconds()); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/base/pollable_thread_safe_flag.cc b/third_party/WebKit/Source/platform/scheduler/base/pollable_thread_safe_flag.cc new file mode 100644 index 0000000..a24241de --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/pollable_thread_safe_flag.cc
@@ -0,0 +1,19 @@ +// 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 "platform/scheduler/base/pollable_thread_safe_flag.h" + +PollableThreadSafeFlag::PollableThreadSafeFlag(base::Lock* write_lock_) + : flag_(false), write_lock_(write_lock_) {} + +PollableThreadSafeFlag::~PollableThreadSafeFlag() {} + +void PollableThreadSafeFlag::SetWhileLocked(bool value) { + write_lock_->AssertAcquired(); + base::subtle::Release_Store(&flag_, value); +} + +bool PollableThreadSafeFlag::IsSet() const { + return base::subtle::Acquire_Load(&flag_) != false; +}
diff --git a/third_party/WebKit/Source/platform/scheduler/base/pollable_thread_safe_flag.h b/third_party/WebKit/Source/platform/scheduler/base/pollable_thread_safe_flag.h new file mode 100644 index 0000000..040fdd4 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/pollable_thread_safe_flag.h
@@ -0,0 +1,36 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_POLLABLE_THREAD_SAFE_FLAG_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_POLLABLE_THREAD_SAFE_FLAG_H_ + +#include "base/atomicops.h" +#include "base/macros.h" +#include "base/synchronization/lock.h" + +// A PollableThreadSafeFlag can be polled without requiring a lock, but can only +// be updated if a lock is held. This enables lock-free checking as to whether a +// condition has changed, while protecting operations which update the condition +// with a lock. You must ensure that the flag is only updated within the same +// lock-protected critical section as any other variables on which the condition +// depends. +class PollableThreadSafeFlag { + public: + explicit PollableThreadSafeFlag(base::Lock* write_lock); + ~PollableThreadSafeFlag(); + + // Set the flag. May only be called if |write_lock| is held. + void SetWhileLocked(bool value); + + // Returns true iff the flag is set to true. + bool IsSet() const; + + private: + base::subtle::Atomic32 flag_; + base::Lock* write_lock_; // Not owned. + + DISALLOW_COPY_AND_ASSIGN(PollableThreadSafeFlag); +}; + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_POLLABLE_THREAD_SAFE_FLAG_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator.cc b/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator.cc new file mode 100644 index 0000000..a8efe8d --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator.cc
@@ -0,0 +1,90 @@ +// 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 "platform/scheduler/base/queueing_time_estimator.h" + +#include "base/time/default_tick_clock.h" + +#include <algorithm> + +namespace blink { +namespace scheduler { + +namespace { + +// This method computes the expected queueing time of a randomly distributed +// task R within a window containing a single task T. Let T' be the time range +// for which T overlaps the window. We first compute the probability that R will +// start within T'. We then compute the expected queueing duration if R does +// start within this range. Since the start time of R is uniformly distributed +// within the window, this is equal to the average of the queueing times if R +// started at the beginning or end of T'. The expected queueing time of T is the +// probability that R will start within T', multiplied by the expected queueing +// duration if R does fall in this range. +base::TimeDelta ExpectedQueueingTimeFromTask(base::TimeTicks task_start, + base::TimeTicks task_end, + base::TimeTicks window_start, + base::TimeTicks window_end) { + DCHECK(task_start <= task_end); + DCHECK(task_start <= window_end); + DCHECK(window_start < window_end); + DCHECK(task_end >= window_start); + base::TimeTicks task_in_window_start_time = + std::max(task_start, window_start); + base::TimeTicks task_in_window_end_time = std::min(task_end, window_end); + DCHECK(task_in_window_end_time <= task_in_window_end_time); + + double probability_of_this_task = + static_cast<double>((task_in_window_end_time - task_in_window_start_time) + .InMicroseconds()) / + (window_end - window_start).InMicroseconds(); + + base::TimeDelta expected_queueing_duration_within_task = + ((task_end - task_in_window_start_time) + + (task_end - task_in_window_end_time)) / + 2; + + return base::TimeDelta::FromMillisecondsD( + probability_of_this_task * + expected_queueing_duration_within_task.InMillisecondsF()); +} + +} // namespace + +QueueingTimeEstimator::QueueingTimeEstimator( + QueueingTimeEstimator::Client* client, + base::TimeDelta window_duration) + : client_(client), + window_duration_(window_duration), + window_start_time_() {} + +void QueueingTimeEstimator::OnToplevelTaskCompleted( + base::TimeTicks task_start_time, + base::TimeTicks task_end_time) { + if (window_start_time_.is_null()) + window_start_time_ = task_start_time; + + while (TimePastWindowEnd(task_end_time)) { + if (!TimePastWindowEnd(task_start_time)) { + // Include the current task in this window. + current_expected_queueing_time_ += ExpectedQueueingTimeFromTask( + task_start_time, task_end_time, window_start_time_, + window_start_time_ + window_duration_); + } + client_->OnQueueingTimeForWindowEstimated(current_expected_queueing_time_); + window_start_time_ += window_duration_; + current_expected_queueing_time_ = base::TimeDelta(); + } + + current_expected_queueing_time_ += ExpectedQueueingTimeFromTask( + task_start_time, task_end_time, window_start_time_, + window_start_time_ + window_duration_); +} + +bool QueueingTimeEstimator::TimePastWindowEnd(base::TimeTicks time) { + return time > window_start_time_ + window_duration_; +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator.h b/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator.h new file mode 100644 index 0000000..21db255 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator.h
@@ -0,0 +1,53 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_QUEUEING_TIME_ESTIMATOR_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_QUEUEING_TIME_ESTIMATOR_H_ + +#include "base/macros.h" +#include "base/time/time.h" +#include "public/platform/WebCommon.h" + +namespace base { +class TickClock; +} + +namespace blink { +namespace scheduler { + +// Records the expected queueing time for a high priority task occurring +// randomly during each interval of length |window_duration|. +class BLINK_PLATFORM_EXPORT QueueingTimeEstimator { + public: + class BLINK_PLATFORM_EXPORT Client { + public: + virtual void OnQueueingTimeForWindowEstimated( + base::TimeDelta queueing_time) = 0; + Client() {} + virtual ~Client() {} + + private: + DISALLOW_COPY_AND_ASSIGN(Client); + }; + + QueueingTimeEstimator(Client* client, base::TimeDelta window_duration); + + void OnToplevelTaskCompleted(base::TimeTicks task_start_time, + base::TimeTicks task_end_time); + + private: + bool TimePastWindowEnd(base::TimeTicks task_end_time); + Client* client_; // NOT OWNED. + + base::TimeDelta current_expected_queueing_time_; + base::TimeDelta window_duration_; + base::TimeTicks window_start_time_; + + DISALLOW_COPY_AND_ASSIGN(QueueingTimeEstimator); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_QUEUEING_TIME_ESTIMATOR_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator_unittest.cc b/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator_unittest.cc new file mode 100644 index 0000000..54772ba --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/queueing_time_estimator_unittest.cc
@@ -0,0 +1,95 @@ +// 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 "platform/scheduler/base/queueing_time_estimator.h" +#include "platform/scheduler/base/test_time_source.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace blink { +namespace scheduler { + +using QueueingTimeEstimatorTest = testing::Test; + +class TestQueueingTimeEstimatorClient : public QueueingTimeEstimator::Client { + public: + void OnQueueingTimeForWindowEstimated( + base::TimeDelta queueing_time) override { + expected_queueing_times_.push_back(queueing_time); + } + const std::vector<base::TimeDelta>& expected_queueing_times() { + return expected_queueing_times_; + } + + private: + std::vector<base::TimeDelta> expected_queueing_times_; +}; + +class QueueingTimeEstimatorForTest : public QueueingTimeEstimator { + public: + QueueingTimeEstimatorForTest(TestQueueingTimeEstimatorClient* client, + base::TimeDelta window_duration) + : QueueingTimeEstimator(client, window_duration) {} +}; + +// Three tasks of one second each, all within a 5 second window. Expected +// queueing time is the probability of falling into one of these tasks (3/5), +// multiplied by the expected queueing time within a task (0.5 seconds). Thus we +// expect a queueing time of 0.3 seconds. +TEST_F(QueueingTimeEstimatorTest, AllTasksWithinWindow) { + base::TimeTicks time; + TestQueueingTimeEstimatorClient client; + QueueingTimeEstimatorForTest estimator(&client, + base::TimeDelta::FromSeconds(5)); + for (int i = 0; i < 3; ++i) { + estimator.OnToplevelTaskCompleted( + time, time + base::TimeDelta::FromMilliseconds(1000)); + time += base::TimeDelta::FromMilliseconds(1500); + } + + // Flush the data by adding a task in the next window. + time += base::TimeDelta::FromMilliseconds(5000); + estimator.OnToplevelTaskCompleted( + time, time + base::TimeDelta::FromMilliseconds(500)); + + EXPECT_THAT(client.expected_queueing_times(), + testing::ElementsAre(base::TimeDelta::FromMilliseconds(300))); +} + +// One 20 second long task, starting 3 seconds into the first window. +// Window 1: Probability of being within task = 2/5. Expected delay within task: +// avg(20, 18). Total expected queueing time = 7.6s. +// Window 2: Probability of being within task = 1. Expected delay within task: +// avg(18, 13). Total expected queueing time = 15.5s. +// Window 5: Probability of being within task = 3/5. Expected delay within task: +// avg(3, 0). Total expected queueing time = 0.9s. +TEST_F(QueueingTimeEstimatorTest, MultiWindowTask) { + TestQueueingTimeEstimatorClient client; + QueueingTimeEstimatorForTest estimator(&client, + base::TimeDelta::FromSeconds(5)); + base::TimeTicks time; + time += base::TimeDelta::FromMilliseconds(5000); + estimator.OnToplevelTaskCompleted(time, time); + + time += base::TimeDelta::FromMilliseconds(3000); + + estimator.OnToplevelTaskCompleted( + time, time + base::TimeDelta::FromMilliseconds(20000)); + + // Flush the data by adding a task in the next window. + time += base::TimeDelta::FromMilliseconds(25000); + + estimator.OnToplevelTaskCompleted( + time, time + base::TimeDelta::FromMilliseconds(500)); + + EXPECT_THAT(client.expected_queueing_times(), + testing::ElementsAre(base::TimeDelta::FromMilliseconds(7600), + base::TimeDelta::FromMilliseconds(15500), + base::TimeDelta::FromMilliseconds(10500), + base::TimeDelta::FromMilliseconds(5500), + base::TimeDelta::FromMilliseconds(900))); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/base/real_time_domain.cc b/third_party/WebKit/Source/platform/scheduler/base/real_time_domain.cc new file mode 100644 index 0000000..80f18b99 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/real_time_domain.cc
@@ -0,0 +1,75 @@ +// 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 "platform/scheduler/base/real_time_domain.h" + +#include "base/bind.h" +#include "platform/scheduler/base/task_queue_impl.h" +#include "platform/scheduler/base/task_queue_manager.h" +#include "platform/scheduler/base/task_queue_manager_delegate.h" + +namespace blink { +namespace scheduler { + +RealTimeDomain::RealTimeDomain(const char* tracing_category) + : TimeDomain(nullptr), + tracing_category_(tracing_category), + task_queue_manager_(nullptr) {} + +RealTimeDomain::RealTimeDomain(TimeDomain::Observer* observer, + const char* tracing_category) + : TimeDomain(observer), + tracing_category_(tracing_category), + task_queue_manager_(nullptr) {} + +RealTimeDomain::~RealTimeDomain() {} + +void RealTimeDomain::OnRegisterWithTaskQueueManager( + TaskQueueManager* task_queue_manager) { + task_queue_manager_ = task_queue_manager; + DCHECK(task_queue_manager_); +} + +LazyNow RealTimeDomain::CreateLazyNow() const { + return task_queue_manager_->CreateLazyNow(); +} + +base::TimeTicks RealTimeDomain::Now() const { + return task_queue_manager_->delegate()->NowTicks(); +} + +void RealTimeDomain::RequestWakeup(base::TimeTicks now, base::TimeDelta delay) { + // NOTE this is only called if the scheduled runtime is sooner than any + // previously scheduled runtime, or there is no (outstanding) previously + // scheduled runtime. + task_queue_manager_->MaybeScheduleDelayedWork(FROM_HERE, now, delay); +} + +bool RealTimeDomain::MaybeAdvanceTime() { + base::TimeTicks next_run_time; + if (!NextScheduledRunTime(&next_run_time)) + return false; + + base::TimeTicks now = Now(); + if (now >= next_run_time) + return true; // Causes DoWork to post a continuation. + + base::TimeDelta delay = next_run_time - now; + TRACE_EVENT1(tracing_category_, "RealTimeDomain::MaybeAdvanceTime", + "delay_ms", delay.InMillisecondsF()); + + // The next task is sometime in the future, make sure we schedule a DoWork to + // run it. + task_queue_manager_->MaybeScheduleDelayedWork(FROM_HERE, now, delay); + return false; +} + +void RealTimeDomain::AsValueIntoInternal( + base::trace_event::TracedValue* state) const {} + +const char* RealTimeDomain::GetName() const { + return "RealTimeDomain"; +} +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/base/real_time_domain.h b/third_party/WebKit/Source/platform/scheduler/base/real_time_domain.h new file mode 100644 index 0000000..94d8a59 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/real_time_domain.h
@@ -0,0 +1,46 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_REAL_TIME_DOMAIN_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_REAL_TIME_DOMAIN_H_ + +#include <set> + +#include "base/macros.h" +#include "platform/scheduler/base/time_domain.h" +#include "public/platform/WebCommon.h" + +namespace blink { +namespace scheduler { + +class BLINK_PLATFORM_EXPORT RealTimeDomain : public TimeDomain { + public: + explicit RealTimeDomain(const char* tracing_category); + RealTimeDomain(TimeDomain::Observer* observer, const char* tracing_category); + ~RealTimeDomain() override; + + // TimeDomain implementation: + LazyNow CreateLazyNow() const override; + base::TimeTicks Now() const override; + bool MaybeAdvanceTime() override; + const char* GetName() const override; + + protected: + void OnRegisterWithTaskQueueManager( + TaskQueueManager* task_queue_manager) override; + void RequestWakeup(base::TimeTicks now, base::TimeDelta delay) override; + void AsValueIntoInternal( + base::trace_event::TracedValue* state) const override; + + private: + const char* tracing_category_; // NOT OWNED + TaskQueueManager* task_queue_manager_; // NOT OWNED + + DISALLOW_COPY_AND_ASSIGN(RealTimeDomain); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_REAL_TIME_DOMAIN_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc new file mode 100644 index 0000000..02f5cef6 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc
@@ -0,0 +1,717 @@ +// 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 "platform/scheduler/base/task_queue_impl.h" + +#include "base/trace_event/blame_context.h" +#include "platform/scheduler/base/task_queue_manager.h" +#include "platform/scheduler/base/task_queue_manager_delegate.h" +#include "platform/scheduler/base/time_domain.h" +#include "platform/scheduler/base/work_queue.h" + +namespace blink { +namespace scheduler { +namespace internal { + +TaskQueueImpl::TaskQueueImpl( + TaskQueueManager* task_queue_manager, + TimeDomain* time_domain, + const Spec& spec, + const char* disabled_by_default_tracing_category, + const char* disabled_by_default_verbose_tracing_category) + : thread_id_(base::PlatformThread::CurrentId()), + any_thread_(task_queue_manager, spec.pump_policy, time_domain), + name_(spec.name), + disabled_by_default_tracing_category_( + disabled_by_default_tracing_category), + disabled_by_default_verbose_tracing_category_( + disabled_by_default_verbose_tracing_category), + main_thread_only_(task_queue_manager, + spec.pump_policy, + this, + time_domain), + wakeup_policy_(spec.wakeup_policy), + should_monitor_quiescence_(spec.should_monitor_quiescence), + should_notify_observers_(spec.should_notify_observers), + should_report_when_execution_blocked_( + spec.should_report_when_execution_blocked) { + DCHECK(time_domain); + time_domain->RegisterQueue(this); +} + +TaskQueueImpl::~TaskQueueImpl() { +#if DCHECK_IS_ON() + base::AutoLock lock(any_thread_lock_); + // NOTE this check shouldn't fire because |TaskQueueManager::queues_| + // contains a strong reference to this TaskQueueImpl and the TaskQueueManager + // destructor calls UnregisterTaskQueue on all task queues. + DCHECK(any_thread().task_queue_manager == nullptr) + << "UnregisterTaskQueue must be called first!"; + +#endif +} + +TaskQueueImpl::Task::Task() + : PendingTask(tracked_objects::Location(), + base::Closure(), + base::TimeTicks(), + true), +#ifndef NDEBUG + enqueue_order_set_(false), +#endif + enqueue_order_(0) { + sequence_num = 0; +} + +TaskQueueImpl::Task::Task(const tracked_objects::Location& posted_from, + const base::Closure& task, + base::TimeTicks desired_run_time, + EnqueueOrder sequence_number, + bool nestable) + : PendingTask(posted_from, task, desired_run_time, nestable), +#ifndef NDEBUG + enqueue_order_set_(false), +#endif + enqueue_order_(0) { + sequence_num = sequence_number; +} + +TaskQueueImpl::Task::Task(const tracked_objects::Location& posted_from, + const base::Closure& task, + base::TimeTicks desired_run_time, + EnqueueOrder sequence_number, + bool nestable, + EnqueueOrder enqueue_order) + : PendingTask(posted_from, task, desired_run_time, nestable), +#ifndef NDEBUG + enqueue_order_set_(true), +#endif + enqueue_order_(enqueue_order) { + sequence_num = sequence_number; +} + +TaskQueueImpl::AnyThread::AnyThread(TaskQueueManager* task_queue_manager, + PumpPolicy pump_policy, + TimeDomain* time_domain) + : task_queue_manager(task_queue_manager), + pump_policy(pump_policy), + time_domain(time_domain) {} + +TaskQueueImpl::AnyThread::~AnyThread() {} + +TaskQueueImpl::MainThreadOnly::MainThreadOnly( + TaskQueueManager* task_queue_manager, + PumpPolicy pump_policy, + TaskQueueImpl* task_queue, + TimeDomain* time_domain) + : task_queue_manager(task_queue_manager), + pump_policy(pump_policy), + time_domain(time_domain), + delayed_work_queue(new WorkQueue(task_queue, "delayed")), + immediate_work_queue(new WorkQueue(task_queue, "immediate")), + set_index(0), + is_enabled(true), + blame_context(nullptr) {} + +TaskQueueImpl::MainThreadOnly::~MainThreadOnly() {} + +void TaskQueueImpl::UnregisterTaskQueue() { + base::AutoLock lock(any_thread_lock_); + if (main_thread_only().time_domain) + main_thread_only().time_domain->UnregisterQueue(this); + if (!any_thread().task_queue_manager) + return; + any_thread().time_domain = nullptr; + main_thread_only().time_domain = nullptr; + any_thread().task_queue_manager->UnregisterTaskQueue(this); + + any_thread().task_queue_manager = nullptr; + main_thread_only().task_queue_manager = nullptr; + main_thread_only().delayed_incoming_queue = std::priority_queue<Task>(); + any_thread().immediate_incoming_queue = std::queue<Task>(); + main_thread_only().immediate_work_queue.reset(); + main_thread_only().delayed_work_queue.reset(); +} + +bool TaskQueueImpl::RunsTasksOnCurrentThread() const { + base::AutoLock lock(any_thread_lock_); + return base::PlatformThread::CurrentId() == thread_id_; +} + +bool TaskQueueImpl::PostDelayedTask(const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) { + if (delay.is_zero()) + return PostImmediateTaskImpl(from_here, task, TaskType::NORMAL); + + return PostDelayedTaskImpl(from_here, task, delay, TaskType::NORMAL); +} + +bool TaskQueueImpl::PostNonNestableDelayedTask( + const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) { + if (delay.is_zero()) + return PostImmediateTaskImpl(from_here, task, TaskType::NON_NESTABLE); + + return PostDelayedTaskImpl(from_here, task, delay, TaskType::NON_NESTABLE); +} + +bool TaskQueueImpl::PostImmediateTaskImpl( + const tracked_objects::Location& from_here, + const base::Closure& task, + TaskType task_type) { + base::AutoLock lock(any_thread_lock_); + if (!any_thread().task_queue_manager) + return false; + + EnqueueOrder sequence_number = + any_thread().task_queue_manager->GetNextSequenceNumber(); + + PushOntoImmediateIncomingQueueLocked( + Task(from_here, task, base::TimeTicks(), sequence_number, + task_type != TaskType::NON_NESTABLE, sequence_number)); + return true; +} + +bool TaskQueueImpl::PostDelayedTaskImpl( + const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay, + TaskType task_type) { + DCHECK_GT(delay, base::TimeDelta()); + if (base::PlatformThread::CurrentId() == thread_id_) { + // Lock-free fast path for delayed tasks posted from the main thread. + if (!main_thread_only().task_queue_manager) + return false; + + EnqueueOrder sequence_number = + main_thread_only().task_queue_manager->GetNextSequenceNumber(); + + base::TimeTicks time_domain_now = main_thread_only().time_domain->Now(); + base::TimeTicks time_domain_delayed_run_time = time_domain_now + delay; + PushOntoDelayedIncomingQueueFromMainThread( + Task(from_here, task, time_domain_delayed_run_time, sequence_number, + task_type != TaskType::NON_NESTABLE), + time_domain_now); + } else { + // NOTE posting a delayed task from a different thread is not expected to + // be common. This pathway is less optimal than perhaps it could be + // because it causes two main thread tasks to be run. Should this + // assumption prove to be false in future, we may need to revisit this. + base::AutoLock lock(any_thread_lock_); + if (!any_thread().task_queue_manager) + return false; + + EnqueueOrder sequence_number = + any_thread().task_queue_manager->GetNextSequenceNumber(); + + base::TimeTicks time_domain_now = any_thread().time_domain->Now(); + base::TimeTicks time_domain_delayed_run_time = time_domain_now + delay; + PushOntoDelayedIncomingQueueLocked( + Task(from_here, task, time_domain_delayed_run_time, sequence_number, + task_type != TaskType::NON_NESTABLE)); + } + return true; +} + +void TaskQueueImpl::PushOntoDelayedIncomingQueueFromMainThread( + Task pending_task, + base::TimeTicks now) { + main_thread_only().task_queue_manager->DidQueueTask(pending_task); + + // Schedule a later call to MoveReadyDelayedTasksToDelayedWorkQueue. + base::TimeTicks delayed_run_time = pending_task.delayed_run_time; + main_thread_only().delayed_incoming_queue.push(std::move(pending_task)); + main_thread_only().time_domain->ScheduleDelayedWork(this, delayed_run_time, + now); + TraceQueueSize(false); +} + +void TaskQueueImpl::PushOntoDelayedIncomingQueueLocked(Task pending_task) { + any_thread().task_queue_manager->DidQueueTask(pending_task); + + int thread_hop_task_sequence_number = + any_thread().task_queue_manager->GetNextSequenceNumber(); + PushOntoImmediateIncomingQueueLocked( + Task(FROM_HERE, base::Bind(&TaskQueueImpl::ScheduleDelayedWorkTask, this, + base::Passed(&pending_task)), + base::TimeTicks(), thread_hop_task_sequence_number, false, + thread_hop_task_sequence_number)); +} + +void TaskQueueImpl::PushOntoImmediateIncomingQueueLocked(Task pending_task) { + if (any_thread().immediate_incoming_queue.empty()) + any_thread().time_domain->RegisterAsUpdatableTaskQueue(this); + if (any_thread().pump_policy == PumpPolicy::AUTO && + any_thread().immediate_incoming_queue.empty()) { + any_thread().task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE); + } + any_thread().task_queue_manager->DidQueueTask(pending_task); + any_thread().immediate_incoming_queue.push(std::move(pending_task)); + TraceQueueSize(true); +} + +void TaskQueueImpl::ScheduleDelayedWorkTask(Task pending_task) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + base::TimeTicks delayed_run_time = pending_task.delayed_run_time; + main_thread_only().delayed_incoming_queue.push(std::move(pending_task)); + main_thread_only().time_domain->ScheduleDelayedWork( + this, delayed_run_time, main_thread_only().time_domain->Now()); +} + +void TaskQueueImpl::SetQueueEnabled(bool enabled) { + if (main_thread_only().is_enabled == enabled) + return; + main_thread_only().is_enabled = enabled; + if (!main_thread_only().task_queue_manager) + return; + if (enabled) { + main_thread_only().task_queue_manager->selector_.EnableQueue(this); + } else { + main_thread_only().task_queue_manager->selector_.DisableQueue(this); + } +} + +bool TaskQueueImpl::IsQueueEnabled() const { + return main_thread_only().is_enabled; +} + +bool TaskQueueImpl::IsEmpty() const { + if (!main_thread_only().delayed_work_queue->Empty() || + !main_thread_only().immediate_work_queue->Empty()) { + return false; + } + + base::AutoLock lock(any_thread_lock_); + return any_thread().immediate_incoming_queue.empty() && + main_thread_only().delayed_incoming_queue.empty(); +} + +bool TaskQueueImpl::HasPendingImmediateWork() const { + if (!main_thread_only().delayed_work_queue->Empty() || + !main_thread_only().immediate_work_queue->Empty()) { + return true; + } + + return NeedsPumping(); +} + +bool TaskQueueImpl::NeedsPumping() const { + if (!main_thread_only().immediate_work_queue->Empty()) + return false; + + base::AutoLock lock(any_thread_lock_); + if (!any_thread().immediate_incoming_queue.empty()) + return true; + + // If there's no immediate Incoming work then we only need pumping if there + // is a delayed task that should be running now. + if (main_thread_only().delayed_incoming_queue.empty()) + return false; + + return main_thread_only().delayed_incoming_queue.top().delayed_run_time <= + main_thread_only().time_domain->CreateLazyNow().Now(); +} + +bool TaskQueueImpl::TaskIsOlderThanQueuedImmediateTasksLocked( + const Task* task) { + // A null task is passed when UpdateQueue is called before any task is run. + // In this case we don't want to pump an after_wakeup queue, so return true + // here. + if (!task) + return true; + + // Return false if task is newer than the oldest immediate task. + if (!any_thread().immediate_incoming_queue.empty() && + task->enqueue_order() > + any_thread().immediate_incoming_queue.front().enqueue_order()) { + return false; + } + return true; +} + +bool TaskQueueImpl::TaskIsOlderThanQueuedDelayedTasks(const Task* task) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + // A null task is passed when UpdateQueue is called before any task is run. + // In this case we don't want to pump an after_wakeup queue, so return true + // here. + if (!task) + return true; + + EnqueueOrder enqueue_order; + if (!main_thread_only().delayed_work_queue->GetFrontTaskEnqueueOrder( + &enqueue_order)) { + return true; + } + + return task->enqueue_order() < enqueue_order; +} + +bool TaskQueueImpl::ShouldAutoPumpImmediateQueueLocked( + bool should_trigger_wakeup, + const Task* previous_task) { + if (main_thread_only().pump_policy == PumpPolicy::MANUAL) + return false; + if (main_thread_only().pump_policy == PumpPolicy::AFTER_WAKEUP && + (!should_trigger_wakeup || + TaskIsOlderThanQueuedImmediateTasksLocked(previous_task))) + return false; + return true; +} + +bool TaskQueueImpl::ShouldAutoPumpDelayedQueue(bool should_trigger_wakeup, + const Task* previous_task) { + if (main_thread_only().pump_policy == PumpPolicy::MANUAL) + return false; + if (main_thread_only().pump_policy == PumpPolicy::AFTER_WAKEUP && + (!should_trigger_wakeup || + TaskIsOlderThanQueuedDelayedTasks(previous_task))) + return false; + return true; +} + +void TaskQueueImpl::MoveReadyDelayedTasksToDelayedWorkQueue(LazyNow* lazy_now) { + // Enqueue all delayed tasks that should be running now. + while (!main_thread_only().delayed_incoming_queue.empty() && + main_thread_only().delayed_incoming_queue.top().delayed_run_time <= + lazy_now->Now()) { + // Note: the const_cast is needed because there is no direct way to move + // elements out of a priority queue. The queue must not be modified between + // the top() and the pop(). + main_thread_only().delayed_work_queue->PushAndSetEnqueueOrder( + std::move( + const_cast<Task&>(main_thread_only().delayed_incoming_queue.top())), + main_thread_only().task_queue_manager->GetNextSequenceNumber()); + main_thread_only().delayed_incoming_queue.pop(); + } +} + +void TaskQueueImpl::UpdateDelayedWorkQueue(LazyNow* lazy_now, + bool should_trigger_wakeup, + const Task* previous_task) { + if (!main_thread_only().task_queue_manager) + return; + if (!ShouldAutoPumpDelayedQueue(should_trigger_wakeup, previous_task)) + return; + MoveReadyDelayedTasksToDelayedWorkQueue(lazy_now); + TraceQueueSize(false); +} + +void TaskQueueImpl::UpdateImmediateWorkQueue(bool should_trigger_wakeup, + const Task* previous_task) { + DCHECK(main_thread_only().immediate_work_queue->Empty()); + base::AutoLock lock(any_thread_lock_); + if (!main_thread_only().task_queue_manager) + return; + if (!ShouldAutoPumpImmediateQueueLocked(should_trigger_wakeup, previous_task)) + return; + + main_thread_only().immediate_work_queue->SwapLocked( + any_thread().immediate_incoming_queue); + + // |any_thread().immediate_incoming_queue| is now empty so + // TimeDomain::UpdateQueues no longer needs to consider this queue for + // reloading. + main_thread_only().time_domain->UnregisterAsUpdatableTaskQueue(this); +} + +void TaskQueueImpl::TraceQueueSize(bool is_locked) const { + bool is_tracing; + TRACE_EVENT_CATEGORY_GROUP_ENABLED(disabled_by_default_tracing_category_, + &is_tracing); + if (!is_tracing) + return; + + // It's only safe to access the work queues from the main thread. + // TODO(alexclarke): We should find another way of tracing this + if (base::PlatformThread::CurrentId() != thread_id_) + return; + + if (!is_locked) + any_thread_lock_.Acquire(); + else + any_thread_lock_.AssertAcquired(); + TRACE_COUNTER1(disabled_by_default_tracing_category_, GetName(), + any_thread().immediate_incoming_queue.size() + + main_thread_only().immediate_work_queue->Size() + + main_thread_only().delayed_work_queue->Size() + + main_thread_only().delayed_incoming_queue.size()); + if (!is_locked) + any_thread_lock_.Release(); +} + +void TaskQueueImpl::SetPumpPolicy(PumpPolicy pump_policy) { + base::AutoLock lock(any_thread_lock_); + if (pump_policy == PumpPolicy::AUTO && + any_thread().pump_policy != PumpPolicy::AUTO) { + LazyNow lazy_now(main_thread_only().time_domain->CreateLazyNow()); + PumpQueueLocked(&lazy_now, true); + } + any_thread().pump_policy = pump_policy; + main_thread_only().pump_policy = pump_policy; +} + +TaskQueue::PumpPolicy TaskQueueImpl::GetPumpPolicy() const { + return main_thread_only().pump_policy; +} + +void TaskQueueImpl::PumpQueueLocked(LazyNow* lazy_now, bool may_post_dowork) { + TRACE_EVENT1(disabled_by_default_tracing_category_, + "TaskQueueImpl::PumpQueueLocked", "queue", name_); + TaskQueueManager* task_queue_manager = any_thread().task_queue_manager; + if (!task_queue_manager) + return; + + MoveReadyDelayedTasksToDelayedWorkQueue(lazy_now); + + while (!any_thread().immediate_incoming_queue.empty()) { + main_thread_only().immediate_work_queue->Push( + std::move(any_thread().immediate_incoming_queue.front())); + any_thread().immediate_incoming_queue.pop(); + } + + // |immediate_incoming_queue| is now empty so TimeDomain::UpdateQueues no + // longer needs to consider this queue for reloading. + main_thread_only().time_domain->UnregisterAsUpdatableTaskQueue(this); + + if (main_thread_only().immediate_work_queue->Empty() && + main_thread_only().delayed_work_queue->Empty()) { + return; + } + + if (may_post_dowork) + task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE); +} + +void TaskQueueImpl::PumpQueue(LazyNow* lazy_now, bool may_post_dowork) { + base::AutoLock lock(any_thread_lock_); + PumpQueueLocked(lazy_now, may_post_dowork); +} + +const char* TaskQueueImpl::GetName() const { + return name_; +} + +void TaskQueueImpl::SetQueuePriority(QueuePriority priority) { + if (!main_thread_only().task_queue_manager || priority == GetQueuePriority()) + return; + main_thread_only().task_queue_manager->selector_.SetQueuePriority(this, + priority); +} + +TaskQueueImpl::QueuePriority TaskQueueImpl::GetQueuePriority() const { + size_t set_index = immediate_work_queue()->work_queue_set_index(); + DCHECK_EQ(set_index, delayed_work_queue()->work_queue_set_index()); + return static_cast<TaskQueue::QueuePriority>(set_index); +} + +// static +const char* TaskQueueImpl::PumpPolicyToString( + TaskQueue::PumpPolicy pump_policy) { + switch (pump_policy) { + case TaskQueue::PumpPolicy::AUTO: + return "auto"; + case TaskQueue::PumpPolicy::AFTER_WAKEUP: + return "after_wakeup"; + case TaskQueue::PumpPolicy::MANUAL: + return "manual"; + default: + NOTREACHED(); + return nullptr; + } +} + +// static +const char* TaskQueueImpl::WakeupPolicyToString( + TaskQueue::WakeupPolicy wakeup_policy) { + switch (wakeup_policy) { + case TaskQueue::WakeupPolicy::CAN_WAKE_OTHER_QUEUES: + return "can_wake_other_queues"; + case TaskQueue::WakeupPolicy::DONT_WAKE_OTHER_QUEUES: + return "dont_wake_other_queues"; + default: + NOTREACHED(); + return nullptr; + } +} + +// static +const char* TaskQueueImpl::PriorityToString(QueuePriority priority) { + switch (priority) { + case CONTROL_PRIORITY: + return "control"; + case HIGH_PRIORITY: + return "high"; + case NORMAL_PRIORITY: + return "normal"; + case BEST_EFFORT_PRIORITY: + return "best_effort"; + default: + NOTREACHED(); + return nullptr; + } +} + +void TaskQueueImpl::AsValueInto(base::trace_event::TracedValue* state) const { + base::AutoLock lock(any_thread_lock_); + state->BeginDictionary(); + state->SetString("name", GetName()); + state->SetBoolean("enabled", main_thread_only().is_enabled); + state->SetString("time_domain_name", + main_thread_only().time_domain->GetName()); + state->SetString("pump_policy", PumpPolicyToString(any_thread().pump_policy)); + state->SetString("wakeup_policy", WakeupPolicyToString(wakeup_policy_)); + bool verbose_tracing_enabled = false; + TRACE_EVENT_CATEGORY_GROUP_ENABLED( + disabled_by_default_verbose_tracing_category_, &verbose_tracing_enabled); + state->SetInteger("immediate_incoming_queue_size", + any_thread().immediate_incoming_queue.size()); + state->SetInteger("delayed_incoming_queue_size", + main_thread_only().delayed_incoming_queue.size()); + state->SetInteger("immediate_work_queue_size", + main_thread_only().immediate_work_queue->Size()); + state->SetInteger("delayed_work_queue_size", + main_thread_only().delayed_work_queue->Size()); + if (!main_thread_only().delayed_incoming_queue.empty()) { + base::TimeDelta delay_to_next_task = + (main_thread_only().delayed_incoming_queue.top().delayed_run_time - + main_thread_only().time_domain->CreateLazyNow().Now()); + state->SetDouble("delay_to_next_task_ms", + delay_to_next_task.InMillisecondsF()); + } + if (verbose_tracing_enabled) { + state->BeginArray("immediate_incoming_queue"); + QueueAsValueInto(any_thread().immediate_incoming_queue, state); + state->EndArray(); + state->BeginArray("delayed_work_queue"); + main_thread_only().delayed_work_queue->AsValueInto(state); + state->EndArray(); + state->BeginArray("immediate_work_queue"); + main_thread_only().immediate_work_queue->AsValueInto(state); + state->EndArray(); + state->BeginArray("delayed_incoming_queue"); + QueueAsValueInto(main_thread_only().delayed_incoming_queue, state); + state->EndArray(); + } + state->SetString("priority", PriorityToString(GetQueuePriority())); + state->EndDictionary(); +} + +void TaskQueueImpl::AddTaskObserver( + base::MessageLoop::TaskObserver* task_observer) { + main_thread_only().task_observers.AddObserver(task_observer); +} + +void TaskQueueImpl::RemoveTaskObserver( + base::MessageLoop::TaskObserver* task_observer) { + main_thread_only().task_observers.RemoveObserver(task_observer); +} + +void TaskQueueImpl::NotifyWillProcessTask( + const base::PendingTask& pending_task) { + DCHECK(should_notify_observers_); + if (main_thread_only().blame_context) + main_thread_only().blame_context->Enter(); + FOR_EACH_OBSERVER(base::MessageLoop::TaskObserver, + main_thread_only().task_observers, + WillProcessTask(pending_task)); +} + +void TaskQueueImpl::NotifyDidProcessTask( + const base::PendingTask& pending_task) { + DCHECK(should_notify_observers_); + FOR_EACH_OBSERVER(base::MessageLoop::TaskObserver, + main_thread_only().task_observers, + DidProcessTask(pending_task)); + if (main_thread_only().blame_context) + main_thread_only().blame_context->Leave(); +} + +void TaskQueueImpl::SetTimeDomain(TimeDomain* time_domain) { + base::AutoLock lock(any_thread_lock_); + DCHECK(time_domain); + // NOTE this is similar to checking |any_thread().task_queue_manager| but the + // TaskQueueSelectorTests constructs TaskQueueImpl directly with a null + // task_queue_manager. Instead we check |any_thread().time_domain| which is + // another way of asserting that UnregisterTaskQueue has not been called. + DCHECK(any_thread().time_domain); + if (!any_thread().time_domain) + return; + DCHECK(main_thread_checker_.CalledOnValidThread()); + if (time_domain == main_thread_only().time_domain) + return; + + main_thread_only().time_domain->MigrateQueue(this, time_domain); + main_thread_only().time_domain = time_domain; + any_thread().time_domain = time_domain; +} + +TimeDomain* TaskQueueImpl::GetTimeDomain() const { + if (base::PlatformThread::CurrentId() == thread_id_) + return main_thread_only().time_domain; + + base::AutoLock lock(any_thread_lock_); + return any_thread().time_domain; +} + +void TaskQueueImpl::SetBlameContext( + base::trace_event::BlameContext* blame_context) { + main_thread_only().blame_context = blame_context; +} + +// static +void TaskQueueImpl::QueueAsValueInto(const std::queue<Task>& queue, + base::trace_event::TracedValue* state) { + // Remove const to search |queue| in the destructive manner. Restore the + // content from |visited| later. + std::queue<Task>* mutable_queue = const_cast<std::queue<Task>*>(&queue); + std::queue<Task> visited; + while (!mutable_queue->empty()) { + TaskAsValueInto(mutable_queue->front(), state); + visited.push(std::move(mutable_queue->front())); + mutable_queue->pop(); + } + *mutable_queue = std::move(visited); +} + +// static +void TaskQueueImpl::QueueAsValueInto(const std::priority_queue<Task>& queue, + base::trace_event::TracedValue* state) { + // Remove const to search |queue| in the destructive manner. Restore the + // content from |visited| later. + std::priority_queue<Task>* mutable_queue = + const_cast<std::priority_queue<Task>*>(&queue); + std::priority_queue<Task> visited; + while (!mutable_queue->empty()) { + TaskAsValueInto(mutable_queue->top(), state); + visited.push(std::move(const_cast<Task&>(mutable_queue->top()))); + mutable_queue->pop(); + } + *mutable_queue = std::move(visited); +} + +// static +void TaskQueueImpl::TaskAsValueInto(const Task& task, + base::trace_event::TracedValue* state) { + state->BeginDictionary(); + state->SetString("posted_from", task.posted_from.ToString()); +#ifndef NDEBUG + if (task.enqueue_order_set()) + state->SetInteger("enqueue_order", task.enqueue_order()); +#else + state->SetInteger("enqueue_order", task.enqueue_order()); +#endif + state->SetInteger("sequence_num", task.sequence_num); + state->SetBoolean("nestable", task.nestable); + state->SetBoolean("is_high_res", task.is_high_res); + state->SetDouble( + "delayed_run_time", + (task.delayed_run_time - base::TimeTicks()).InMicroseconds() / 1000.0L); + state->EndDictionary(); +} + +} // namespace internal +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.h b/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.h new file mode 100644 index 0000000..dee99194 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.h
@@ -0,0 +1,308 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_IMPL_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_IMPL_H_ + +#include <stddef.h> + +#include <memory> +#include <set> + +#include "base/macros.h" +#include "base/pending_task.h" +#include "base/threading/thread_checker.h" +#include "base/trace_event/trace_event.h" +#include "base/trace_event/trace_event_argument.h" +#include "platform/scheduler/base/enqueue_order.h" +#include "public/platform/scheduler/base/task_queue.h" + +namespace blink { +namespace scheduler { +class LazyNow; +class TimeDomain; +class TaskQueueManager; + +namespace internal { +class WorkQueue; +class WorkQueueSets; + +class BLINK_PLATFORM_EXPORT TaskQueueImpl final : public TaskQueue { + public: + TaskQueueImpl(TaskQueueManager* task_queue_manager, + TimeDomain* time_domain, + const Spec& spec, + const char* disabled_by_default_tracing_category, + const char* disabled_by_default_verbose_tracing_category); + + class BLINK_PLATFORM_EXPORT Task : public base::PendingTask { + public: + Task(); + Task(const tracked_objects::Location& posted_from, + const base::Closure& task, + base::TimeTicks desired_run_time, + EnqueueOrder sequence_number, + bool nestable); + + Task(const tracked_objects::Location& posted_from, + const base::Closure& task, + base::TimeTicks desired_run_time, + EnqueueOrder sequence_number, + bool nestable, + EnqueueOrder enqueue_order); + + EnqueueOrder enqueue_order() const { +#ifndef NDEBUG + DCHECK(enqueue_order_set_); +#endif + return enqueue_order_; + } + + void set_enqueue_order(EnqueueOrder enqueue_order) { +#ifndef NDEBUG + DCHECK(!enqueue_order_set_); + enqueue_order_set_ = true; +#endif + enqueue_order_ = enqueue_order; + } + +#ifndef NDEBUG + bool enqueue_order_set() const { return enqueue_order_set_; } +#endif + + private: +#ifndef NDEBUG + bool enqueue_order_set_; +#endif + // Similar to sequence number, but the |enqueue_order| is set by + // EnqueueTasksLocked and is not initially defined for delayed tasks until + // they are enqueued on the |immediate_incoming_queue_|. + EnqueueOrder enqueue_order_; + }; + + // TaskQueue implementation. + void UnregisterTaskQueue() override; + bool RunsTasksOnCurrentThread() const override; + bool PostDelayedTask(const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) override; + bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) override; + + void SetQueueEnabled(bool enabled) override; + bool IsQueueEnabled() const override; + bool IsEmpty() const override; + bool HasPendingImmediateWork() const override; + bool NeedsPumping() const override; + void SetQueuePriority(QueuePriority priority) override; + QueuePriority GetQueuePriority() const override; + void PumpQueue(LazyNow* lazy_now, bool may_post_dowork) override; + void SetPumpPolicy(PumpPolicy pump_policy) override; + PumpPolicy GetPumpPolicy() const override; + void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer) override; + void RemoveTaskObserver( + base::MessageLoop::TaskObserver* task_observer) override; + void SetTimeDomain(TimeDomain* time_domain) override; + TimeDomain* GetTimeDomain() const override; + void SetBlameContext(base::trace_event::BlameContext* blame_context) override; + + void UpdateImmediateWorkQueue(bool should_trigger_wakeup, + const Task* previous_task); + void UpdateDelayedWorkQueue(LazyNow* lazy_now, + bool should_trigger_wakeup, + const Task* previous_task); + + WakeupPolicy wakeup_policy() const { + DCHECK(main_thread_checker_.CalledOnValidThread()); + return wakeup_policy_; + } + + const char* GetName() const override; + + void AsValueInto(base::trace_event::TracedValue* state) const; + + bool GetQuiescenceMonitored() const { return should_monitor_quiescence_; } + bool GetShouldNotifyObservers() const { return should_notify_observers_; } + + void NotifyWillProcessTask(const base::PendingTask& pending_task); + void NotifyDidProcessTask(const base::PendingTask& pending_task); + + // Can be called on any thread. + static const char* PumpPolicyToString(TaskQueue::PumpPolicy pump_policy); + + // Can be called on any thread. + static const char* WakeupPolicyToString( + TaskQueue::WakeupPolicy wakeup_policy); + + // Can be called on any thread. + static const char* PriorityToString(TaskQueue::QueuePriority priority); + + WorkQueue* delayed_work_queue() { + return main_thread_only().delayed_work_queue.get(); + } + + const WorkQueue* delayed_work_queue() const { + return main_thread_only().delayed_work_queue.get(); + } + + WorkQueue* immediate_work_queue() { + return main_thread_only().immediate_work_queue.get(); + } + + const WorkQueue* immediate_work_queue() const { + return main_thread_only().immediate_work_queue.get(); + } + + bool should_report_when_execution_blocked() const { + return should_report_when_execution_blocked_; + } + + private: + friend class WorkQueue; + + enum class TaskType { + NORMAL, + NON_NESTABLE, + }; + + struct AnyThread { + AnyThread(TaskQueueManager* task_queue_manager, + PumpPolicy pump_policy, + TimeDomain* time_domain); + ~AnyThread(); + + // TaskQueueManager, PumpPolicy and TimeDomain are maintained in two copies: + // inside AnyThread and inside MainThreadOnly. They can be changed only from + // main thread, so it should be locked before accessing from other threads. + TaskQueueManager* task_queue_manager; + PumpPolicy pump_policy; + TimeDomain* time_domain; + + std::queue<Task> immediate_incoming_queue; + }; + + struct MainThreadOnly { + MainThreadOnly(TaskQueueManager* task_queue_manager, + PumpPolicy pump_policy, + TaskQueueImpl* task_queue, + TimeDomain* time_domain); + ~MainThreadOnly(); + + // Another copy of TaskQueueManager, PumpPolicy and TimeDomain for lock-free + // access from the main thread. See description inside struct AnyThread for + // details. + TaskQueueManager* task_queue_manager; + PumpPolicy pump_policy; + TimeDomain* time_domain; + + std::unique_ptr<WorkQueue> delayed_work_queue; + std::unique_ptr<WorkQueue> immediate_work_queue; + std::priority_queue<Task> delayed_incoming_queue; + base::ObserverList<base::MessageLoop::TaskObserver> task_observers; + size_t set_index; + bool is_enabled; + base::trace_event::BlameContext* blame_context; // Not owned. + }; + + ~TaskQueueImpl() override; + + bool PostImmediateTaskImpl(const tracked_objects::Location& from_here, + const base::Closure& task, + TaskType task_type); + bool PostDelayedTaskImpl(const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay, + TaskType task_type); + + // Push the task onto the |delayed_incoming_queue|. Lock-free main thread + // only fast path. + void PushOntoDelayedIncomingQueueFromMainThread(Task pending_task, + base::TimeTicks now); + + // Push the task onto the |delayed_incoming_queue|. Slow path from other + // threads. + void PushOntoDelayedIncomingQueueLocked(Task pending_task); + + void ScheduleDelayedWorkTask(Task pending_task); + + // Enqueues any delayed tasks which should be run now on the + // |delayed_work_queue|. Must be called from the main thread. + void MoveReadyDelayedTasksToDelayedWorkQueue(LazyNow* lazy_now); + + void MoveReadyImmediateTasksToImmediateWorkQueueLocked(); + + // Note this does nothing if its not called from the main thread. + void PumpQueueLocked(LazyNow* lazy_now, bool may_post_dowork); + + // Returns true if |task| is older than the oldest incoming immediate task. + // NOTE |any_thread_lock_| must be locked. + bool TaskIsOlderThanQueuedImmediateTasksLocked(const Task* task); + + // Returns true if |task| is older than the oldest delayed task. Must be + // called from the main thread. + bool TaskIsOlderThanQueuedDelayedTasks(const Task* task); + + // NOTE |any_thread_lock_| must be locked. + bool ShouldAutoPumpImmediateQueueLocked(bool should_trigger_wakeup, + const Task* previous_task); + + // Must be called from the main thread. + bool ShouldAutoPumpDelayedQueue(bool should_trigger_wakeup, + const Task* previous_task); + + // Push the task onto the |immediate_incoming_queue| and for auto pumped + // queues it calls MaybePostDoWorkOnMainRunner if the Incoming queue was + // empty. + void PushOntoImmediateIncomingQueueLocked(Task pending_task); + + void TraceQueueSize(bool is_locked) const; + static void QueueAsValueInto(const std::queue<Task>& queue, + base::trace_event::TracedValue* state); + static void QueueAsValueInto(const std::priority_queue<Task>& queue, + base::trace_event::TracedValue* state); + static void TaskAsValueInto(const Task& task, + base::trace_event::TracedValue* state); + + const base::PlatformThreadId thread_id_; + + mutable base::Lock any_thread_lock_; + AnyThread any_thread_; + struct AnyThread& any_thread() { + any_thread_lock_.AssertAcquired(); + return any_thread_; + } + const struct AnyThread& any_thread() const { + any_thread_lock_.AssertAcquired(); + return any_thread_; + } + + const char* name_; + const char* disabled_by_default_tracing_category_; + const char* disabled_by_default_verbose_tracing_category_; + + base::ThreadChecker main_thread_checker_; + MainThreadOnly main_thread_only_; + MainThreadOnly& main_thread_only() { + DCHECK(main_thread_checker_.CalledOnValidThread()); + return main_thread_only_; + } + const MainThreadOnly& main_thread_only() const { + DCHECK(main_thread_checker_.CalledOnValidThread()); + return main_thread_only_; + } + + const WakeupPolicy wakeup_policy_; + const bool should_monitor_quiescence_; + const bool should_notify_observers_; + const bool should_report_when_execution_blocked_; + + DISALLOW_COPY_AND_ASSIGN(TaskQueueImpl); +}; + +} // namespace internal +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_IMPL_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc new file mode 100644 index 0000000..31adb72 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc
@@ -0,0 +1,443 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "platform/scheduler/base/task_queue_manager.h" + +#include <queue> +#include <set> + +#include "base/bind.h" +#include "base/metrics/histogram_macros.h" +#include "base/trace_event/trace_event.h" +#include "platform/scheduler/base/real_time_domain.h" +#include "platform/scheduler/base/task_queue_impl.h" +#include "platform/scheduler/base/task_queue_manager_delegate.h" +#include "platform/scheduler/base/task_queue_selector.h" +#include "platform/scheduler/base/task_time_tracker.h" +#include "platform/scheduler/base/work_queue.h" +#include "platform/scheduler/base/work_queue_sets.h" + +namespace blink { +namespace scheduler { + +namespace { +const size_t kRecordRecordTaskDelayHistogramsEveryNTasks = 10; + +void RecordDelayedTaskLateness(base::TimeDelta lateness) { + UMA_HISTOGRAM_TIMES("RendererScheduler.TaskQueueManager.DelayedTaskLateness", + lateness); +} + +void RecordImmediateTaskQueueingDuration(tracked_objects::Duration duration) { + UMA_HISTOGRAM_TIMES( + "RendererScheduler.TaskQueueManager.ImmediateTaskQueueingDuration", + base::TimeDelta::FromMilliseconds(duration.InMilliseconds())); +} +} + +TaskQueueManager::TaskQueueManager( + scoped_refptr<TaskQueueManagerDelegate> delegate, + const char* tracing_category, + const char* disabled_by_default_tracing_category, + const char* disabled_by_default_verbose_tracing_category) + : real_time_domain_(new RealTimeDomain(tracing_category)), + delegate_(delegate), + task_was_run_on_quiescence_monitored_queue_(false), + work_batch_size_(1), + task_count_(0), + task_time_tracker_(nullptr), + tracing_category_(tracing_category), + disabled_by_default_tracing_category_( + disabled_by_default_tracing_category), + disabled_by_default_verbose_tracing_category_( + disabled_by_default_verbose_tracing_category), + currently_executing_task_queue_(nullptr), + observer_(nullptr), + deletion_sentinel_(new DeletionSentinel()), + weak_factory_(this) { + DCHECK(delegate->RunsTasksOnCurrentThread()); + TRACE_EVENT_OBJECT_CREATED_WITH_ID(disabled_by_default_tracing_category, + "TaskQueueManager", this); + selector_.SetTaskQueueSelectorObserver(this); + + from_main_thread_immediate_do_work_closure_ = + base::Bind(&TaskQueueManager::DoWork, weak_factory_.GetWeakPtr(), + base::TimeTicks(), true); + from_other_thread_immediate_do_work_closure_ = + base::Bind(&TaskQueueManager::DoWork, weak_factory_.GetWeakPtr(), + base::TimeTicks(), false); + + // TODO(alexclarke): Change this to be a parameter that's passed in. + RegisterTimeDomain(real_time_domain_.get()); +} + +TaskQueueManager::~TaskQueueManager() { + TRACE_EVENT_OBJECT_DELETED_WITH_ID(disabled_by_default_tracing_category_, + "TaskQueueManager", this); + + while (!queues_.empty()) + (*queues_.begin())->UnregisterTaskQueue(); + + selector_.SetTaskQueueSelectorObserver(nullptr); +} + +void TaskQueueManager::RegisterTimeDomain(TimeDomain* time_domain) { + time_domains_.insert(time_domain); + time_domain->OnRegisterWithTaskQueueManager(this); +} + +void TaskQueueManager::UnregisterTimeDomain(TimeDomain* time_domain) { + time_domains_.erase(time_domain); +} + +scoped_refptr<internal::TaskQueueImpl> TaskQueueManager::NewTaskQueue( + const TaskQueue::Spec& spec) { + TRACE_EVENT1(tracing_category_, "TaskQueueManager::NewTaskQueue", + "queue_name", spec.name); + DCHECK(main_thread_checker_.CalledOnValidThread()); + TimeDomain* time_domain = + spec.time_domain ? spec.time_domain : real_time_domain_.get(); + DCHECK(time_domains_.find(time_domain) != time_domains_.end()); + scoped_refptr<internal::TaskQueueImpl> queue( + make_scoped_refptr(new internal::TaskQueueImpl( + this, time_domain, spec, disabled_by_default_tracing_category_, + disabled_by_default_verbose_tracing_category_))); + queues_.insert(queue); + selector_.AddQueue(queue.get()); + return queue; +} + +void TaskQueueManager::SetObserver(Observer* observer) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + observer_ = observer; +} + +void TaskQueueManager::UnregisterTaskQueue( + scoped_refptr<internal::TaskQueueImpl> task_queue) { + TRACE_EVENT1(tracing_category_, "TaskQueueManager::UnregisterTaskQueue", + "queue_name", task_queue->GetName()); + DCHECK(main_thread_checker_.CalledOnValidThread()); + if (observer_) + observer_->OnUnregisterTaskQueue(task_queue); + + // Add |task_queue| to |queues_to_delete_| so we can prevent it from being + // freed while any of our structures hold hold a raw pointer to it. + queues_to_delete_.insert(task_queue); + queues_.erase(task_queue); + selector_.RemoveQueue(task_queue.get()); +} + +void TaskQueueManager::UpdateWorkQueues( + bool should_trigger_wakeup, + const internal::TaskQueueImpl::Task* previous_task, + LazyNow lazy_now) { + TRACE_EVENT0(disabled_by_default_tracing_category_, + "TaskQueueManager::UpdateWorkQueues"); + + for (TimeDomain* time_domain : time_domains_) { + LazyNow lazy_now_in_domain = time_domain == real_time_domain_.get() + ? lazy_now + : time_domain->CreateLazyNow(); + time_domain->UpdateWorkQueues(should_trigger_wakeup, previous_task, + lazy_now_in_domain); + } +} + +void TaskQueueManager::MaybeScheduleImmediateWork( + const tracked_objects::Location& from_here) { + bool on_main_thread = delegate_->BelongsToCurrentThread(); + // De-duplicate DoWork posts. + if (on_main_thread) { + if (!main_thread_pending_wakeups_.insert(base::TimeTicks()).second) { + return; + } + delegate_->PostTask(from_here, from_main_thread_immediate_do_work_closure_); + } else { + { + base::AutoLock lock(other_thread_lock_); + if (!other_thread_pending_wakeups_.insert(base::TimeTicks()).second) + return; + } + delegate_->PostTask(from_here, + from_other_thread_immediate_do_work_closure_); + } +} + +void TaskQueueManager::MaybeScheduleDelayedWork( + const tracked_objects::Location& from_here, + base::TimeTicks now, + base::TimeDelta delay) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + DCHECK_GE(delay, base::TimeDelta()); + base::TimeTicks run_time = now + delay; + // De-duplicate DoWork posts. + if (!main_thread_pending_wakeups_.insert(run_time).second) + return; + delegate_->PostDelayedTask( + from_here, base::Bind(&TaskQueueManager::DoWork, + weak_factory_.GetWeakPtr(), run_time, true), + delay); +} + +void TaskQueueManager::DoWork(base::TimeTicks run_time, bool from_main_thread) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + TRACE_EVENT1(tracing_category_, "TaskQueueManager::DoWork", + "from_main_thread", from_main_thread); + if (from_main_thread) { + main_thread_pending_wakeups_.erase(run_time); + } else { + base::AutoLock lock(other_thread_lock_); + other_thread_pending_wakeups_.erase(run_time); + } + + if (!delegate_->IsNested()) + queues_to_delete_.clear(); + + LazyNow lazy_now(real_time_domain()->CreateLazyNow()); + base::TimeTicks task_start_time; + + if (!delegate_->IsNested() && task_time_tracker_) + task_start_time = lazy_now.Now(); + + // Pass false and nullptr to UpdateWorkQueues here to prevent waking up a + // pump-after-wakeup queue. + UpdateWorkQueues(false, nullptr, lazy_now); + + internal::TaskQueueImpl::Task previous_task; + + for (int i = 0; i < work_batch_size_; i++) { + internal::WorkQueue* work_queue; + if (!SelectWorkQueueToService(&work_queue)) { + break; + } + + bool should_trigger_wakeup = work_queue->task_queue()->wakeup_policy() == + TaskQueue::WakeupPolicy::CAN_WAKE_OTHER_QUEUES; + + switch (ProcessTaskFromWorkQueue(work_queue, &previous_task)) { + case ProcessTaskResult::DEFERRED: + // If a task was deferred, try again with another task. Note that this + // means deferred tasks (i.e. non-nestable tasks) will never trigger + // queue wake-ups. + continue; + case ProcessTaskResult::EXECUTED: + break; + case ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED: + return; // The TaskQueueManager got deleted, we must bail out. + } + + lazy_now = real_time_domain()->CreateLazyNow(); + if (!delegate_->IsNested() && task_time_tracker_) { + // Only report top level task durations. + base::TimeTicks task_end_time = lazy_now.Now(); + task_time_tracker_->ReportTaskTime(task_start_time, task_end_time); + task_start_time = task_end_time; + } + + work_queue = nullptr; // The queue may have been unregistered. + + UpdateWorkQueues(should_trigger_wakeup, &previous_task, lazy_now); + + // Only run a single task per batch in nested run loops so that we can + // properly exit the nested loop when someone calls RunLoop::Quit(). + if (delegate_->IsNested()) + break; + } + + // TODO(alexclarke): Consider refactoring the above loop to terminate only + // when there's no more work left to be done, rather than posting a + // continuation task. + if (!selector_.EnabledWorkQueuesEmpty() || TryAdvanceTimeDomains()) + MaybeScheduleImmediateWork(FROM_HERE); +} + +bool TaskQueueManager::TryAdvanceTimeDomains() { + bool can_advance = false; + for (TimeDomain* time_domain : time_domains_) { + can_advance |= time_domain->MaybeAdvanceTime(); + } + return can_advance; +} + +bool TaskQueueManager::SelectWorkQueueToService( + internal::WorkQueue** out_work_queue) { + bool should_run = selector_.SelectWorkQueueToService(out_work_queue); + TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( + disabled_by_default_tracing_category_, "TaskQueueManager", this, + AsValueWithSelectorResult(should_run, *out_work_queue)); + return should_run; +} + +void TaskQueueManager::DidQueueTask( + const internal::TaskQueueImpl::Task& pending_task) { + task_annotator_.DidQueueTask("TaskQueueManager::PostTask", pending_task); +} + +TaskQueueManager::ProcessTaskResult TaskQueueManager::ProcessTaskFromWorkQueue( + internal::WorkQueue* work_queue, + internal::TaskQueueImpl::Task* out_previous_task) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + scoped_refptr<DeletionSentinel> protect(deletion_sentinel_); + internal::TaskQueueImpl* queue = work_queue->task_queue(); + + if (queue->GetQuiescenceMonitored()) + task_was_run_on_quiescence_monitored_queue_ = true; + + internal::TaskQueueImpl::Task pending_task = + work_queue->TakeTaskFromWorkQueue(); + if (!pending_task.nestable && delegate_->IsNested()) { + // Defer non-nestable work to the main task runner. NOTE these tasks can be + // arbitrarily delayed so the additional delay should not be a problem. + // TODO(skyostil): Figure out a way to not forget which task queue the + // task is associated with. See http://crbug.com/522843. + delegate_->PostNonNestableTask(pending_task.posted_from, pending_task.task); + return ProcessTaskResult::DEFERRED; + } + + MaybeRecordTaskDelayHistograms(pending_task, queue); + + TRACE_TASK_EXECUTION("TaskQueueManager::ProcessTaskFromWorkQueue", + pending_task); + if (queue->GetShouldNotifyObservers()) { + FOR_EACH_OBSERVER(base::MessageLoop::TaskObserver, task_observers_, + WillProcessTask(pending_task)); + queue->NotifyWillProcessTask(pending_task); + } + TRACE_EVENT1(tracing_category_, "TaskQueueManager::RunTask", "queue", + queue->GetName()); + // NOTE when TaskQueues get unregistered a reference ends up getting retained + // by |queues_to_delete_| which is cleared at the top of |DoWork|. This means + // we are OK to use raw pointers here. + internal::TaskQueueImpl* prev_executing_task_queue = + currently_executing_task_queue_; + currently_executing_task_queue_ = queue; + task_annotator_.RunTask("TaskQueueManager::PostTask", pending_task); + + // Detect if the TaskQueueManager just got deleted. If this happens we must + // not access any member variables after this point. + if (protect->HasOneRef()) + return ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED; + + currently_executing_task_queue_ = prev_executing_task_queue; + + if (queue->GetShouldNotifyObservers()) { + FOR_EACH_OBSERVER(base::MessageLoop::TaskObserver, task_observers_, + DidProcessTask(pending_task)); + queue->NotifyDidProcessTask(pending_task); + } + + pending_task.task.Reset(); + *out_previous_task = std::move(pending_task); + return ProcessTaskResult::EXECUTED; +} + +void TaskQueueManager::MaybeRecordTaskDelayHistograms( + const internal::TaskQueueImpl::Task& pending_task, + const internal::TaskQueueImpl* queue) { + if ((task_count_++ % kRecordRecordTaskDelayHistogramsEveryNTasks) != 0) + return; + + // Record delayed task lateness and immediate task queueing durations, but + // only for auto-pumped queues. Manually pumped and after wakeup queues can + // have arbitarially large delayes, which would cloud any analysis. + if (queue->GetPumpPolicy() == TaskQueue::PumpPolicy::AUTO) { + if (!pending_task.delayed_run_time.is_null()) { + RecordDelayedTaskLateness(delegate_->NowTicks() - + pending_task.delayed_run_time); + } else if (!pending_task.time_posted.is_null()) { + RecordImmediateTaskQueueingDuration(tracked_objects::TrackedTime::Now() - + pending_task.time_posted); + } + } +} + +bool TaskQueueManager::RunsTasksOnCurrentThread() const { + return delegate_->RunsTasksOnCurrentThread(); +} + +void TaskQueueManager::SetWorkBatchSize(int work_batch_size) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + DCHECK_GE(work_batch_size, 1); + work_batch_size_ = work_batch_size; +} + +void TaskQueueManager::AddTaskObserver( + base::MessageLoop::TaskObserver* task_observer) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + task_observers_.AddObserver(task_observer); +} + +void TaskQueueManager::RemoveTaskObserver( + base::MessageLoop::TaskObserver* task_observer) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + task_observers_.RemoveObserver(task_observer); +} + +bool TaskQueueManager::GetAndClearSystemIsQuiescentBit() { + bool task_was_run = task_was_run_on_quiescence_monitored_queue_; + task_was_run_on_quiescence_monitored_queue_ = false; + return !task_was_run; +} + +const scoped_refptr<TaskQueueManagerDelegate>& TaskQueueManager::delegate() + const { + return delegate_; +} + +internal::EnqueueOrder TaskQueueManager::GetNextSequenceNumber() { + return enqueue_order_generator_.GenerateNext(); +} + +LazyNow TaskQueueManager::CreateLazyNow() const { + return LazyNow(delegate_.get()); +} + +std::unique_ptr<base::trace_event::ConvertableToTraceFormat> +TaskQueueManager::AsValueWithSelectorResult( + bool should_run, + internal::WorkQueue* selected_work_queue) const { + DCHECK(main_thread_checker_.CalledOnValidThread()); + std::unique_ptr<base::trace_event::TracedValue> state( + new base::trace_event::TracedValue()); + state->BeginArray("queues"); + for (auto& queue : queues_) + queue->AsValueInto(state.get()); + state->EndArray(); + state->BeginDictionary("selector"); + selector_.AsValueInto(state.get()); + state->EndDictionary(); + if (should_run) { + state->SetString("selected_queue", + selected_work_queue->task_queue()->GetName()); + state->SetString("work_queue_name", selected_work_queue->name()); + } + + state->BeginArray("time_domains"); + for (auto* time_domain : time_domains_) + time_domain->AsValueInto(state.get()); + state->EndArray(); + return std::move(state); +} + +void TaskQueueManager::OnTaskQueueEnabled(internal::TaskQueueImpl* queue) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + // Only schedule DoWork if there's something to do. + if (!queue->immediate_work_queue()->Empty() || + !queue->delayed_work_queue()->Empty()) { + MaybeScheduleImmediateWork(FROM_HERE); + } +} + +void TaskQueueManager::OnTriedToSelectBlockedWorkQueue( + internal::WorkQueue* work_queue) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + DCHECK(!work_queue->Empty()); + if (observer_) { + observer_->OnTriedToExecuteBlockedTask(*work_queue->task_queue(), + *work_queue->GetFrontTask()); + } +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.h b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.h new file mode 100644 index 0000000..7e84e40 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.h
@@ -0,0 +1,269 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_MANAGER_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_MANAGER_H_ + +#include <map> + +#include "base/atomic_sequence_num.h" +#include "base/debug/task_annotator.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "base/message_loop/message_loop.h" +#include "base/pending_task.h" +#include "base/synchronization/lock.h" +#include "base/threading/thread_checker.h" +#include "platform/scheduler/base/enqueue_order.h" +#include "platform/scheduler/base/task_queue_impl.h" +#include "platform/scheduler/base/task_queue_selector.h" + +namespace base { +class TickClock; + +namespace trace_event { +class ConvertableToTraceFormat; +class TracedValue; +} // namespace trace_event +} // namespace base + +namespace blink { +namespace scheduler { +namespace internal { +class TaskQueueImpl; +} // namespace internal + +class LazyNow; +class RealTimeDomain; +class TimeDomain; +class TaskQueueManagerDelegate; +class TaskTimeTracker; + +// The task queue manager provides N task queues and a selector interface for +// choosing which task queue to service next. Each task queue consists of two +// sub queues: +// +// 1. Incoming task queue. Tasks that are posted get immediately appended here. +// When a task is appended into an empty incoming queue, the task manager +// work function (DoWork) is scheduled to run on the main task runner. +// +// 2. Work queue. If a work queue is empty when DoWork() is entered, tasks from +// the incoming task queue (if any) are moved here. The work queues are +// registered with the selector as input to the scheduling decision. +// +class BLINK_PLATFORM_EXPORT TaskQueueManager + : public internal::TaskQueueSelector::Observer { + public: + // Create a task queue manager where |delegate| identifies the thread + // on which where the tasks are eventually run. Category strings must have + // application lifetime (statics or literals). They may not include " chars. + TaskQueueManager(scoped_refptr<TaskQueueManagerDelegate> delegate, + const char* tracing_category, + const char* disabled_by_default_tracing_category, + const char* disabled_by_default_verbose_tracing_category); + ~TaskQueueManager() override; + + // Requests that a task to process work is posted on the main task runner. + // These tasks are de-duplicated in two buckets: main-thread and all other + // threads. This distinction is done to reduce the overehead from locks, we + // assume the main-thread path will be hot. + void MaybeScheduleImmediateWork(const tracked_objects::Location& from_here); + + // Requests that a delayed task to process work is posted on the main task + // runner. These delayed tasks are de-duplicated. Must be called on the thread + // this class was created on. + void MaybeScheduleDelayedWork(const tracked_objects::Location& from_here, + base::TimeTicks now, + base::TimeDelta delay); + + // Set the number of tasks executed in a single invocation of the task queue + // manager. Increasing the batch size can reduce the overhead of yielding + // back to the main message loop -- at the cost of potentially delaying other + // tasks posted to the main loop. The batch size is 1 by default. + void SetWorkBatchSize(int work_batch_size); + + // When given a non-null TaskTimeTracker, the TaskQueueManager calls its + // ReportTaskTime method for every top level task. The task_time_tracker must + // outlive this object, or be removed via SetTaskTimeTracker(nullptr). + void SetTaskTimeTracker(TaskTimeTracker* task_time_tracker) { + task_time_tracker_ = task_time_tracker; + } + + // These functions can only be called on the same thread that the task queue + // manager executes its tasks on. + void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer); + void RemoveTaskObserver(base::MessageLoop::TaskObserver* task_observer); + + // Returns true if any task from a monitored task queue was was run since the + // last call to GetAndClearSystemIsQuiescentBit. + bool GetAndClearSystemIsQuiescentBit(); + + // Creates a task queue with the given |spec|. Must be called on the thread + // this class was created on. + scoped_refptr<internal::TaskQueueImpl> NewTaskQueue( + const TaskQueue::Spec& spec); + + class BLINK_PLATFORM_EXPORT Observer { + public: + virtual ~Observer() {} + + // Called when |queue| is unregistered. + virtual void OnUnregisterTaskQueue( + const scoped_refptr<TaskQueue>& queue) = 0; + + // Called when the manager tried to execute a task from a disabled + // queue. See TaskQueue::Spec::SetShouldReportWhenExecutionBlocked. + virtual void OnTriedToExecuteBlockedTask(const TaskQueue& queue, + const base::PendingTask& task) = 0; + }; + + // Called once to set the Observer. This function is called on the main + // thread. If |observer| is null, then no callbacks will occur. + // Note |observer| is expected to outlive the SchedulerHelper. + void SetObserver(Observer* observer); + + // Returns the delegate used by the TaskQueueManager. + const scoped_refptr<TaskQueueManagerDelegate>& delegate() const; + + // Time domains must be registered for the task queues to get updated. + void RegisterTimeDomain(TimeDomain* time_domain); + void UnregisterTimeDomain(TimeDomain* time_domain); + + RealTimeDomain* real_time_domain() const { return real_time_domain_.get(); } + + LazyNow CreateLazyNow() const; + + // Returns the currently executing TaskQueue if any. Must be called on the + // thread this class was created on. + TaskQueue* currently_executing_task_queue() const { + DCHECK(main_thread_checker_.CalledOnValidThread()); + return currently_executing_task_queue_; + } + + private: + friend class LazyNow; + friend class internal::TaskQueueImpl; + friend class TaskQueueManagerTest; + + class DeletionSentinel : public base::RefCounted<DeletionSentinel> { + private: + friend class base::RefCounted<DeletionSentinel>; + ~DeletionSentinel() {} + }; + + // Unregisters a TaskQueue previously created by |NewTaskQueue()|. + // NOTE we have to flush the queue from |newly_updatable_| which means as a + // side effect MoveNewlyUpdatableQueuesIntoUpdatableQueueSet is called by this + // function. + void UnregisterTaskQueue(scoped_refptr<internal::TaskQueueImpl> task_queue); + + // TaskQueueSelector::Observer implementation: + void OnTaskQueueEnabled(internal::TaskQueueImpl* queue) override; + void OnTriedToSelectBlockedWorkQueue( + internal::WorkQueue* work_queue) override; + + // Called by the task queue to register a new pending task. + void DidQueueTask(const internal::TaskQueueImpl::Task& pending_task); + + // Use the selector to choose a pending task and run it. + void DoWork(base::TimeTicks run_time, bool from_main_thread); + + // Delayed Tasks with run_times <= Now() are enqueued onto the work queue. + // Reloads any empty work queues which have automatic pumping enabled and + // which are eligible to be auto pumped based on the |previous_task| which was + // run and |should_trigger_wakeup|. Call with an empty |previous_task| if no + // task was just run. + void UpdateWorkQueues(bool should_trigger_wakeup, + const internal::TaskQueueImpl::Task* previous_task, + LazyNow lazy_now); + + // Chooses the next work queue to service. Returns true if |out_queue| + // indicates the queue from which the next task should be run, false to + // avoid running any tasks. + bool SelectWorkQueueToService(internal::WorkQueue** out_work_queue); + + // Runs a single nestable task from the |queue|. On exit, |out_task| will + // contain the task which was executed. Non-nestable task are reposted on the + // run loop. The queue must not be empty. + enum class ProcessTaskResult { + DEFERRED, + EXECUTED, + TASK_QUEUE_MANAGER_DELETED + }; + ProcessTaskResult ProcessTaskFromWorkQueue( + internal::WorkQueue* work_queue, + internal::TaskQueueImpl::Task* out_previous_task); + + bool RunsTasksOnCurrentThread() const; + bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay); + + internal::EnqueueOrder GetNextSequenceNumber(); + + // Calls MaybeAdvanceTime on all time domains and returns true if one of them + // was able to advance. + bool TryAdvanceTimeDomains(); + + void MaybeRecordTaskDelayHistograms( + const internal::TaskQueueImpl::Task& pending_task, + const internal::TaskQueueImpl* queue); + + std::unique_ptr<base::trace_event::ConvertableToTraceFormat> + AsValueWithSelectorResult(bool should_run, + internal::WorkQueue* selected_work_queue) const; + + std::set<TimeDomain*> time_domains_; + std::unique_ptr<RealTimeDomain> real_time_domain_; + + std::set<scoped_refptr<internal::TaskQueueImpl>> queues_; + + // We have to be careful when deleting a queue because some of the code uses + // raw pointers and doesn't expect the rug to be pulled out from underneath. + std::set<scoped_refptr<internal::TaskQueueImpl>> queues_to_delete_; + + internal::EnqueueOrderGenerator enqueue_order_generator_; + base::debug::TaskAnnotator task_annotator_; + + base::ThreadChecker main_thread_checker_; + scoped_refptr<TaskQueueManagerDelegate> delegate_; + internal::TaskQueueSelector selector_; + + base::Closure from_main_thread_immediate_do_work_closure_; + base::Closure from_other_thread_immediate_do_work_closure_; + + bool task_was_run_on_quiescence_monitored_queue_; + + // To reduce locking overhead we track pending calls to DoWork separately for + // the main thread and other threads. + std::set<base::TimeTicks> main_thread_pending_wakeups_; + + // Protects |other_thread_pending_wakeups_|. + mutable base::Lock other_thread_lock_; + std::set<base::TimeTicks> other_thread_pending_wakeups_; + + int work_batch_size_; + size_t task_count_; + + base::ObserverList<base::MessageLoop::TaskObserver> task_observers_; + + TaskTimeTracker* task_time_tracker_; // NOT OWNED + + const char* tracing_category_; + const char* disabled_by_default_tracing_category_; + const char* disabled_by_default_verbose_tracing_category_; + + internal::TaskQueueImpl* currently_executing_task_queue_; // NOT OWNED + + Observer* observer_; // NOT OWNED + scoped_refptr<DeletionSentinel> deletion_sentinel_; + base::WeakPtrFactory<TaskQueueManager> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(TaskQueueManager); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_MANAGER_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_delegate.h b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_delegate.h new file mode 100644 index 0000000..38c4632 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_delegate.h
@@ -0,0 +1,36 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_MANAGER_DELEGATE_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_MANAGER_DELEGATE_H_ + +#include "base/callback.h" +#include "base/macros.h" +#include "base/message_loop/message_loop.h" +#include "base/time/tick_clock.h" +#include "public/platform/WebCommon.h" + +namespace blink { +namespace scheduler { + +class BLINK_PLATFORM_EXPORT TaskQueueManagerDelegate + : public base::SingleThreadTaskRunner, + public base::TickClock { + public: + TaskQueueManagerDelegate() {} + + // Returns true if the task runner is nested (i.e., running a run loop within + // a nested task). + virtual bool IsNested() const = 0; + + protected: + ~TaskQueueManagerDelegate() override {} + + DISALLOW_COPY_AND_ASSIGN(TaskQueueManagerDelegate); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_MANAGER_DELEGATE_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_delegate_for_test.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_delegate_for_test.cc new file mode 100644 index 0000000..cf1a5b2d --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_delegate_for_test.cc
@@ -0,0 +1,58 @@ +// 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 "platform/scheduler/base/task_queue_manager_delegate_for_test.h" + +#include <utility> + +#include "base/bind.h" +#include "base/bind_helpers.h" + +namespace blink { +namespace scheduler { + +// static +scoped_refptr<TaskQueueManagerDelegateForTest> +TaskQueueManagerDelegateForTest::Create( + scoped_refptr<base::SingleThreadTaskRunner> task_runner, + std::unique_ptr<base::TickClock> time_source) { + return make_scoped_refptr( + new TaskQueueManagerDelegateForTest(task_runner, std::move(time_source))); +} + +TaskQueueManagerDelegateForTest::TaskQueueManagerDelegateForTest( + scoped_refptr<base::SingleThreadTaskRunner> task_runner, + std::unique_ptr<base::TickClock> time_source) + : task_runner_(task_runner), time_source_(std::move(time_source)) {} + +TaskQueueManagerDelegateForTest::~TaskQueueManagerDelegateForTest() {} + +bool TaskQueueManagerDelegateForTest::PostDelayedTask( + const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) { + return task_runner_->PostDelayedTask(from_here, task, delay); +} + +bool TaskQueueManagerDelegateForTest::PostNonNestableDelayedTask( + const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) { + return task_runner_->PostNonNestableDelayedTask(from_here, task, delay); +} + +bool TaskQueueManagerDelegateForTest::RunsTasksOnCurrentThread() const { + return task_runner_->RunsTasksOnCurrentThread(); +} + +bool TaskQueueManagerDelegateForTest::IsNested() const { + return false; +} + +base::TimeTicks TaskQueueManagerDelegateForTest::NowTicks() { + return time_source_->NowTicks(); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_delegate_for_test.h b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_delegate_for_test.h new file mode 100644 index 0000000..4708735 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_delegate_for_test.h
@@ -0,0 +1,50 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_MANAGER_DELEGATE_FOR_TEST_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_MANAGER_DELEGATE_FOR_TEST_H_ + +#include <memory> + +#include "base/macros.h" +#include "base/time/tick_clock.h" +#include "platform/scheduler/base/task_queue_manager_delegate.h" + +namespace blink { +namespace scheduler { + +class TaskQueueManagerDelegateForTest : public TaskQueueManagerDelegate { + public: + static scoped_refptr<TaskQueueManagerDelegateForTest> Create( + scoped_refptr<base::SingleThreadTaskRunner> task_runner, + std::unique_ptr<base::TickClock> time_source); + + // NestableSingleThreadTaskRunner implementation + bool PostDelayedTask(const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) override; + bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) override; + bool RunsTasksOnCurrentThread() const override; + bool IsNested() const override; + base::TimeTicks NowTicks() override; + + protected: + ~TaskQueueManagerDelegateForTest() override; + TaskQueueManagerDelegateForTest( + scoped_refptr<base::SingleThreadTaskRunner> task_runner, + std::unique_ptr<base::TickClock> time_source); + + private: + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + std::unique_ptr<base::TickClock> time_source_; + + DISALLOW_COPY_AND_ASSIGN(TaskQueueManagerDelegateForTest); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_MANAGER_DELEGATE_FOR_TEST_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_perftest.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_perftest.cc new file mode 100644 index 0000000..5a37ad85 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_perftest.cc
@@ -0,0 +1,173 @@ +// 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 "platform/scheduler/base/task_queue_manager.h" + +#include <stddef.h> + +#include "base/bind.h" +#include "base/memory/ptr_util.h" +#include "base/run_loop.h" +#include "base/threading/thread.h" +#include "base/time/default_tick_clock.h" +#include "platform/scheduler/base/task_queue_impl.h" +#include "platform/scheduler/base/task_queue_manager_delegate_for_test.h" +#include "platform/scheduler/base/task_queue_selector.h" +#include "platform/scheduler/base/test_task_time_tracker.h" +#include "platform/scheduler/base/work_queue_sets.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/perf/perf_test.h" + +namespace blink { +namespace scheduler { + +class TaskQueueManagerPerfTest : public testing::Test { + public: + TaskQueueManagerPerfTest() + : num_queues_(0), + max_tasks_in_flight_(0), + num_tasks_in_flight_(0), + num_tasks_to_post_(0), + num_tasks_to_run_(0) {} + + void SetUp() override { + if (base::ThreadTicks::IsSupported()) + base::ThreadTicks::WaitUntilInitialized(); + } + + void Initialize(size_t num_queues) { + num_queues_ = num_queues; + message_loop_.reset(new base::MessageLoop()); + run_loop_.reset(new base::RunLoop()); + manager_ = base::WrapUnique(new TaskQueueManager( + TaskQueueManagerDelegateForTest::Create( + message_loop_->task_runner(), + base::WrapUnique(new base::DefaultTickClock())), + "fake.category", "fake.category", "fake.category.debug")); + manager_->SetTaskTimeTracker(&test_task_time_tracker_); + for (size_t i = 0; i < num_queues; i++) + queues_.push_back(manager_->NewTaskQueue(TaskQueue::Spec("test"))); + } + + void TestDelayedTask() { + if (--num_tasks_to_run_ == 0) { + run_loop_->QuitWhenIdle(); + } + + num_tasks_in_flight_--; + // NOTE there are only up to max_tasks_in_flight_ pending delayed tasks at + // any one time. Thanks to the lower_num_tasks_to_post going to zero if + // there are a lot of tasks in flight, the total number of task in flight at + // any one time is very variable. + unsigned int lower_num_tasks_to_post = + num_tasks_in_flight_ < (max_tasks_in_flight_ / 2) ? 1 : 0; + unsigned int max_tasks_to_post = + num_tasks_to_post_ % 2 ? lower_num_tasks_to_post : 10; + for (unsigned int i = 0; + i < max_tasks_to_post && num_tasks_in_flight_ < max_tasks_in_flight_ && + num_tasks_to_post_ > 0; + i++) { + // Choose a queue weighted towards queue 0. + unsigned int queue = num_tasks_to_post_ % (num_queues_ + 1); + if (queue == num_queues_) { + queue = 0; + } + // Simulate a mix of short and longer delays. + unsigned int delay = + num_tasks_to_post_ % 2 ? 1 : (10 + num_tasks_to_post_ % 10); + queues_[queue]->PostDelayedTask( + FROM_HERE, base::Bind(&TaskQueueManagerPerfTest::TestDelayedTask, + base::Unretained(this)), + base::TimeDelta::FromMicroseconds(delay)); + num_tasks_in_flight_++; + num_tasks_to_post_--; + } + } + + void ResetAndCallTestDelayedTask(unsigned int num_tasks_to_run) { + num_tasks_in_flight_ = 1; + num_tasks_to_post_ = num_tasks_to_run; + num_tasks_to_run_ = num_tasks_to_run; + TestDelayedTask(); + } + + void Benchmark(const std::string& trace, const base::Closure& test_task) { + base::ThreadTicks start = base::ThreadTicks::Now(); + base::ThreadTicks now; + unsigned long long num_iterations = 0; + do { + test_task.Run(); + run_loop_->Run(); + now = base::ThreadTicks::Now(); + num_iterations++; + } while (now - start < base::TimeDelta::FromSeconds(5)); + perf_test::PrintResult( + "task", "", trace, + (now - start).InMicroseconds() / static_cast<double>(num_iterations), + "us/run", true); + } + + size_t num_queues_; + unsigned int max_tasks_in_flight_; + unsigned int num_tasks_in_flight_; + unsigned int num_tasks_to_post_; + unsigned int num_tasks_to_run_; + std::unique_ptr<TaskQueueManager> manager_; + std::unique_ptr<base::MessageLoop> message_loop_; + std::unique_ptr<base::RunLoop> run_loop_; + std::vector<scoped_refptr<base::SingleThreadTaskRunner>> queues_; + // TODO(alexclarke): parameterize so we can measure with and without a + // TaskTimeTracker. + TestTaskTimeTracker test_task_time_tracker_; +}; + +TEST_F(TaskQueueManagerPerfTest, RunTenThousandDelayedTasks_OneQueue) { + if (!base::ThreadTicks::IsSupported()) + return; + Initialize(1u); + + max_tasks_in_flight_ = 200; + Benchmark("run 10000 delayed tasks with one queue", + base::Bind(&TaskQueueManagerPerfTest::ResetAndCallTestDelayedTask, + base::Unretained(this), 10000)); +} + +TEST_F(TaskQueueManagerPerfTest, RunTenThousandDelayedTasks_FourQueues) { + if (!base::ThreadTicks::IsSupported()) + return; + Initialize(4u); + + max_tasks_in_flight_ = 200; + Benchmark("run 10000 delayed tasks with four queues", + base::Bind(&TaskQueueManagerPerfTest::ResetAndCallTestDelayedTask, + base::Unretained(this), 10000)); +} + +TEST_F(TaskQueueManagerPerfTest, RunTenThousandDelayedTasks_EightQueues) { + if (!base::ThreadTicks::IsSupported()) + return; + Initialize(8u); + + max_tasks_in_flight_ = 200; + Benchmark("run 10000 delayed tasks with eight queues", + base::Bind(&TaskQueueManagerPerfTest::ResetAndCallTestDelayedTask, + base::Unretained(this), 10000)); +} + +TEST_F(TaskQueueManagerPerfTest, RunTenThousandDelayedTasks_ThirtyTwoQueues) { + if (!base::ThreadTicks::IsSupported()) + return; + Initialize(32u); + + max_tasks_in_flight_ = 200; + Benchmark("run 10000 delayed tasks with eight queues", + base::Bind(&TaskQueueManagerPerfTest::ResetAndCallTestDelayedTask, + base::Unretained(this), 10000)); +} + +// TODO(alexclarke): Add additional tests with different mixes of non-delayed vs +// delayed tasks. + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc new file mode 100644 index 0000000..5e3ecf57 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc
@@ -0,0 +1,2008 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "platform/scheduler/base/task_queue_manager.h" + +#include <stddef.h> + +#include <utility> + +#include "base/location.h" +#include "base/memory/ptr_util.h" +#include "base/memory/ref_counted_memory.h" +#include "base/run_loop.h" +#include "base/single_thread_task_runner.h" +#include "base/test/simple_test_tick_clock.h" +#include "base/test/trace_event_analyzer.h" +#include "base/threading/thread.h" +#include "base/trace_event/blame_context.h" +#include "base/trace_event/trace_buffer.h" +#include "cc/test/ordered_simple_task_runner.h" +#include "platform/scheduler/base/real_time_domain.h" +#include "platform/scheduler/base/task_queue_impl.h" +#include "platform/scheduler/base/task_queue_manager_delegate_for_test.h" +#include "platform/scheduler/base/task_queue_selector.h" +#include "platform/scheduler/base/test_count_uses_time_source.h" +#include "platform/scheduler/base/test_task_time_tracker.h" +#include "platform/scheduler/base/test_time_source.h" +#include "platform/scheduler/base/virtual_time_domain.h" +#include "platform/scheduler/base/work_queue.h" +#include "platform/scheduler/base/work_queue_sets.h" +#include "testing/gmock/include/gmock/gmock.h" + +using testing::ElementsAre; +using testing::ElementsAreArray; +using testing::_; +using blink::scheduler::internal::EnqueueOrder; + +namespace blink { +namespace scheduler { + +class MessageLoopTaskRunner : public TaskQueueManagerDelegateForTest { + public: + static scoped_refptr<MessageLoopTaskRunner> Create( + std::unique_ptr<base::TickClock> tick_clock) { + return make_scoped_refptr(new MessageLoopTaskRunner(std::move(tick_clock))); + } + + // NestableTaskRunner implementation. + bool IsNested() const override { + return base::MessageLoop::current()->IsNested(); + } + + private: + explicit MessageLoopTaskRunner(std::unique_ptr<base::TickClock> tick_clock) + : TaskQueueManagerDelegateForTest( + base::MessageLoop::current()->task_runner(), + std::move(tick_clock)) {} + ~MessageLoopTaskRunner() override {} +}; + +class TaskQueueManagerTest : public testing::Test { + public: + TaskQueueManagerTest() {} + void DeleteTaskQueueManager() { manager_.reset(); } + + protected: + void InitializeWithClock(size_t num_queues, + std::unique_ptr<base::TickClock> test_time_source) { + test_task_runner_ = make_scoped_refptr( + new cc::OrderedSimpleTaskRunner(now_src_.get(), false)); + main_task_runner_ = TaskQueueManagerDelegateForTest::Create( + test_task_runner_.get(), + base::WrapUnique(new TestTimeSource(now_src_.get()))); + + manager_ = base::WrapUnique( + new TaskQueueManager(main_task_runner_, "test.scheduler", + "test.scheduler", "test.scheduler.debug")); + manager_->SetTaskTimeTracker(&test_task_time_tracker_); + + for (size_t i = 0; i < num_queues; i++) + runners_.push_back(manager_->NewTaskQueue(TaskQueue::Spec("test_queue"))); + } + + void Initialize(size_t num_queues) { + now_src_.reset(new base::SimpleTestTickClock()); + now_src_->Advance(base::TimeDelta::FromMicroseconds(1000)); + InitializeWithClock(num_queues, + base::WrapUnique(new TestTimeSource(now_src_.get()))); + } + + void InitializeWithRealMessageLoop(size_t num_queues) { + now_src_.reset(new base::SimpleTestTickClock()); + message_loop_.reset(new base::MessageLoop()); + // A null clock triggers some assertions. + now_src_->Advance(base::TimeDelta::FromMicroseconds(1000)); + manager_ = base::WrapUnique(new TaskQueueManager( + MessageLoopTaskRunner::Create( + base::WrapUnique(new TestTimeSource(now_src_.get()))), + "test.scheduler", "test.scheduler", "test.scheduler.debug")); + manager_->SetTaskTimeTracker(&test_task_time_tracker_); + + for (size_t i = 0; i < num_queues; i++) + runners_.push_back(manager_->NewTaskQueue(TaskQueue::Spec("test_queue"))); + } + + std::unique_ptr<base::MessageLoop> message_loop_; + std::unique_ptr<base::SimpleTestTickClock> now_src_; + scoped_refptr<TaskQueueManagerDelegateForTest> main_task_runner_; + scoped_refptr<cc::OrderedSimpleTaskRunner> test_task_runner_; + std::unique_ptr<TaskQueueManager> manager_; + std::vector<scoped_refptr<internal::TaskQueueImpl>> runners_; + TestTaskTimeTracker test_task_time_tracker_; +}; + +void PostFromNestedRunloop(base::MessageLoop* message_loop, + base::SingleThreadTaskRunner* runner, + std::vector<std::pair<base::Closure, bool>>* tasks) { + base::MessageLoop::ScopedNestableTaskAllower allow(message_loop); + for (std::pair<base::Closure, bool>& pair : *tasks) { + if (pair.second) { + runner->PostTask(FROM_HERE, pair.first); + } else { + runner->PostNonNestableTask(FROM_HERE, pair.first); + } + } + base::RunLoop().RunUntilIdle(); +} + +void NopTask() {} + +TEST_F(TaskQueueManagerTest, + NowCalledMinimumNumberOfTimesToComputeTaskDurations) { + message_loop_.reset(new base::MessageLoop()); + // This memory is managed by the TaskQueueManager, but we need to hold a + // pointer to this object to read out how many times Now was called. + TestCountUsesTimeSource* test_count_uses_time_source = + new TestCountUsesTimeSource(); + + manager_ = base::WrapUnique(new TaskQueueManager( + MessageLoopTaskRunner::Create( + base::WrapUnique(test_count_uses_time_source)), + "test.scheduler", "test.scheduler", "test.scheduler.debug")); + manager_->SetWorkBatchSize(6); + manager_->SetTaskTimeTracker(&test_task_time_tracker_); + + for (size_t i = 0; i < 3; i++) + runners_.push_back(manager_->NewTaskQueue(TaskQueue::Spec("test_queue"))); + + runners_[0]->PostTask(FROM_HERE, base::Bind(&NopTask)); + runners_[0]->PostTask(FROM_HERE, base::Bind(&NopTask)); + runners_[1]->PostTask(FROM_HERE, base::Bind(&NopTask)); + runners_[1]->PostTask(FROM_HERE, base::Bind(&NopTask)); + runners_[2]->PostTask(FROM_HERE, base::Bind(&NopTask)); + runners_[2]->PostTask(FROM_HERE, base::Bind(&NopTask)); + + base::RunLoop().RunUntilIdle(); + // We need to call Now for the beginning of the first task, and then the end + // of every task after. We reuse the end time of one task for the start time + // of the next task. In this case, there were 6 tasks, so we expect 7 calls to + // Now. + EXPECT_EQ(7, test_count_uses_time_source->now_calls_count()); +} + +TEST_F(TaskQueueManagerTest, NowNotCalledForNestedTasks) { + message_loop_.reset(new base::MessageLoop()); + // This memory is managed by the TaskQueueManager, but we need to hold a + // pointer to this object to read out how many times Now was called. + TestCountUsesTimeSource* test_count_uses_time_source = + new TestCountUsesTimeSource(); + + manager_ = base::WrapUnique(new TaskQueueManager( + MessageLoopTaskRunner::Create( + base::WrapUnique(test_count_uses_time_source)), + "test.scheduler", "test.scheduler", "test.scheduler.debug")); + manager_->SetTaskTimeTracker(&test_task_time_tracker_); + + runners_.push_back(manager_->NewTaskQueue(TaskQueue::Spec("test_queue"))); + + std::vector<std::pair<base::Closure, bool>> tasks_to_post_from_nested_loop; + for (int i = 0; i <= 6; ++i) { + tasks_to_post_from_nested_loop.push_back( + std::make_pair(base::Bind(&NopTask), true)); + } + + runners_[0]->PostTask( + FROM_HERE, base::Bind(&PostFromNestedRunloop, message_loop_.get(), + base::RetainedRef(runners_[0]), + base::Unretained(&tasks_to_post_from_nested_loop))); + + base::RunLoop().RunUntilIdle(); + // We need to call Now twice, to measure the start and end of the outermost + // task. We shouldn't call it for any of the nested tasks. + EXPECT_EQ(2, test_count_uses_time_source->now_calls_count()); +} + +void NullTask() {} + +void TestTask(EnqueueOrder value, std::vector<EnqueueOrder>* out_result) { + out_result->push_back(value); +} + +TEST_F(TaskQueueManagerTest, SingleQueuePosting) { + Initialize(1u); + + std::vector<EnqueueOrder> run_order; + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order)); + + test_task_runner_->RunUntilIdle(); + EXPECT_THAT(run_order, ElementsAre(1, 2, 3)); +} + +TEST_F(TaskQueueManagerTest, MultiQueuePosting) { + Initialize(3u); + + std::vector<EnqueueOrder> run_order; + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); + runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order)); + runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 4, &run_order)); + runners_[2]->PostTask(FROM_HERE, base::Bind(&TestTask, 5, &run_order)); + runners_[2]->PostTask(FROM_HERE, base::Bind(&TestTask, 6, &run_order)); + + test_task_runner_->RunUntilIdle(); + EXPECT_THAT(run_order, ElementsAre(1, 2, 3, 4, 5, 6)); +} + +TEST_F(TaskQueueManagerTest, NonNestableTaskPosting) { + InitializeWithRealMessageLoop(1u); + + std::vector<EnqueueOrder> run_order; + runners_[0]->PostNonNestableTask(FROM_HERE, + base::Bind(&TestTask, 1, &run_order)); + + base::RunLoop().RunUntilIdle(); + EXPECT_THAT(run_order, ElementsAre(1)); +} + +TEST_F(TaskQueueManagerTest, NonNestableTaskExecutesInExpectedOrder) { + InitializeWithRealMessageLoop(1u); + + std::vector<EnqueueOrder> run_order; + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order)); + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 4, &run_order)); + runners_[0]->PostNonNestableTask(FROM_HERE, + base::Bind(&TestTask, 5, &run_order)); + + base::RunLoop().RunUntilIdle(); + EXPECT_THAT(run_order, ElementsAre(1, 2, 3, 4, 5)); +} + +TEST_F(TaskQueueManagerTest, NonNestableTaskDoesntExecuteInNestedLoop) { + InitializeWithRealMessageLoop(1u); + + std::vector<EnqueueOrder> run_order; + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); + + std::vector<std::pair<base::Closure, bool>> tasks_to_post_from_nested_loop; + tasks_to_post_from_nested_loop.push_back( + std::make_pair(base::Bind(&TestTask, 3, &run_order), false)); + tasks_to_post_from_nested_loop.push_back( + std::make_pair(base::Bind(&TestTask, 4, &run_order), true)); + tasks_to_post_from_nested_loop.push_back( + std::make_pair(base::Bind(&TestTask, 5, &run_order), true)); + + runners_[0]->PostTask( + FROM_HERE, base::Bind(&PostFromNestedRunloop, message_loop_.get(), + base::RetainedRef(runners_[0]), + base::Unretained(&tasks_to_post_from_nested_loop))); + + base::RunLoop().RunUntilIdle(); + // Note we expect task 3 to run last because it's non-nestable. + EXPECT_THAT(run_order, ElementsAre(1, 2, 4, 5, 3)); +} + +TEST_F(TaskQueueManagerTest, QueuePolling) { + Initialize(1u); + + std::vector<EnqueueOrder> run_order; + EXPECT_FALSE(runners_[0]->HasPendingImmediateWork()); + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); + EXPECT_TRUE(runners_[0]->HasPendingImmediateWork()); + + test_task_runner_->RunUntilIdle(); + EXPECT_FALSE(runners_[0]->HasPendingImmediateWork()); +} + +TEST_F(TaskQueueManagerTest, DelayedTaskPosting) { + Initialize(1u); + + std::vector<EnqueueOrder> run_order; + base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10)); + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order), + delay); + EXPECT_EQ(delay, test_task_runner_->DelayToNextTaskTime()); + EXPECT_FALSE(runners_[0]->HasPendingImmediateWork()); + EXPECT_TRUE(run_order.empty()); + + // The task doesn't run before the delay has completed. + test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(9)); + EXPECT_TRUE(run_order.empty()); + + // After the delay has completed, the task runs normally. + test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(1)); + EXPECT_THAT(run_order, ElementsAre(1)); + EXPECT_FALSE(runners_[0]->HasPendingImmediateWork()); +} + +bool MessageLoopTaskCounter(size_t* count) { + *count = *count + 1; + return true; +} + +TEST_F(TaskQueueManagerTest, DelayedTaskExecutedInOneMessageLoopTask) { + Initialize(1u); + + base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10)); + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), delay); + + size_t task_count = 0; + test_task_runner_->RunTasksWhile( + base::Bind(&MessageLoopTaskCounter, &task_count)); + EXPECT_EQ(1u, task_count); +} + +TEST_F(TaskQueueManagerTest, DelayedTaskPosting_MultipleTasks_DecendingOrder) { + Initialize(1u); + + std::vector<EnqueueOrder> run_order; + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order), + base::TimeDelta::FromMilliseconds(10)); + + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order), + base::TimeDelta::FromMilliseconds(8)); + + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order), + base::TimeDelta::FromMilliseconds(5)); + + EXPECT_EQ(base::TimeDelta::FromMilliseconds(5), + test_task_runner_->DelayToNextTaskTime()); + + test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(5)); + EXPECT_THAT(run_order, ElementsAre(3)); + EXPECT_EQ(base::TimeDelta::FromMilliseconds(3), + test_task_runner_->DelayToNextTaskTime()); + + test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(3)); + EXPECT_THAT(run_order, ElementsAre(3, 2)); + EXPECT_EQ(base::TimeDelta::FromMilliseconds(2), + test_task_runner_->DelayToNextTaskTime()); + + test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(2)); + EXPECT_THAT(run_order, ElementsAre(3, 2, 1)); +} + +TEST_F(TaskQueueManagerTest, DelayedTaskPosting_MultipleTasks_AscendingOrder) { + Initialize(1u); + + std::vector<EnqueueOrder> run_order; + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order), + base::TimeDelta::FromMilliseconds(1)); + + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order), + base::TimeDelta::FromMilliseconds(5)); + + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order), + base::TimeDelta::FromMilliseconds(10)); + + EXPECT_EQ(base::TimeDelta::FromMilliseconds(1), + test_task_runner_->DelayToNextTaskTime()); + + test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(1)); + EXPECT_THAT(run_order, ElementsAre(1)); + EXPECT_EQ(base::TimeDelta::FromMilliseconds(4), + test_task_runner_->DelayToNextTaskTime()); + + test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(4)); + EXPECT_THAT(run_order, ElementsAre(1, 2)); + EXPECT_EQ(base::TimeDelta::FromMilliseconds(5), + test_task_runner_->DelayToNextTaskTime()); + + test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(5)); + EXPECT_THAT(run_order, ElementsAre(1, 2, 3)); +} + +TEST_F(TaskQueueManagerTest, PostDelayedTask_SharesUnderlyingDelayedTasks) { + Initialize(1u); + + std::vector<EnqueueOrder> run_order; + base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10)); + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order), + delay); + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order), + delay); + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order), + delay); + + EXPECT_EQ(1u, test_task_runner_->NumPendingTasks()); +} + +class TestObject { + public: + ~TestObject() { destructor_count_++; } + + void Run() { FAIL() << "TestObject::Run should not be called"; } + + static int destructor_count_; +}; + +int TestObject::destructor_count_ = 0; + +TEST_F(TaskQueueManagerTest, PendingDelayedTasksRemovedOnShutdown) { + Initialize(1u); + + TestObject::destructor_count_ = 0; + + base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10)); + runners_[0]->PostDelayedTask( + FROM_HERE, base::Bind(&TestObject::Run, base::Owned(new TestObject())), + delay); + runners_[0]->PostTask( + FROM_HERE, base::Bind(&TestObject::Run, base::Owned(new TestObject()))); + + manager_.reset(); + + EXPECT_EQ(2, TestObject::destructor_count_); +} + +TEST_F(TaskQueueManagerTest, ManualPumping) { + Initialize(1u); + runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL); + + std::vector<EnqueueOrder> run_order; + // Posting a task when pumping is disabled doesn't result in work getting + // posted. + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); + EXPECT_FALSE(test_task_runner_->HasPendingTasks()); + + // However polling still works. + EXPECT_TRUE(runners_[0]->HasPendingImmediateWork()); + + // After pumping the task runs normally. + LazyNow lazy_now(now_src_.get()); + runners_[0]->PumpQueue(&lazy_now, true); + EXPECT_TRUE(test_task_runner_->HasPendingTasks()); + test_task_runner_->RunUntilIdle(); + EXPECT_THAT(run_order, ElementsAre(1)); +} + +TEST_F(TaskQueueManagerTest, ManualPumpingToggle) { + Initialize(1u); + runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL); + + std::vector<EnqueueOrder> run_order; + // Posting a task when pumping is disabled doesn't result in work getting + // posted. + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); + EXPECT_FALSE(test_task_runner_->HasPendingTasks()); + + // When pumping is enabled the task runs normally. + runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::AUTO); + EXPECT_TRUE(test_task_runner_->HasPendingTasks()); + test_task_runner_->RunUntilIdle(); + EXPECT_THAT(run_order, ElementsAre(1)); +} + +TEST_F(TaskQueueManagerTest, DenyRunning_BeforePosting) { + Initialize(1u); + + std::vector<EnqueueOrder> run_order; + runners_[0]->SetQueueEnabled(false); + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); + + test_task_runner_->RunUntilIdle(); + EXPECT_TRUE(run_order.empty()); + + runners_[0]->SetQueueEnabled(true); + test_task_runner_->RunUntilIdle(); + EXPECT_THAT(run_order, ElementsAre(1)); +} + +TEST_F(TaskQueueManagerTest, DenyRunning_AfterPosting) { + Initialize(1u); + + std::vector<EnqueueOrder> run_order; + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); + runners_[0]->SetQueueEnabled(false); + + test_task_runner_->RunUntilIdle(); + EXPECT_TRUE(run_order.empty()); + + runners_[0]->SetQueueEnabled(true); + test_task_runner_->RunUntilIdle(); + EXPECT_THAT(run_order, ElementsAre(1)); +} + +TEST_F(TaskQueueManagerTest, DenyRunning_ManuallyPumpedTransitionsToAuto) { + Initialize(1u); + + std::vector<EnqueueOrder> run_order; + runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL); + runners_[0]->SetQueueEnabled(false); + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); + + test_task_runner_->RunUntilIdle(); + EXPECT_TRUE(run_order.empty()); + + runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::AUTO); + runners_[0]->SetQueueEnabled(true); + test_task_runner_->RunUntilIdle(); + EXPECT_THAT(run_order, ElementsAre(1)); +} + +TEST_F(TaskQueueManagerTest, ManualPumpingWithDelayedTask) { + Initialize(1u); + runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL); + + std::vector<EnqueueOrder> run_order; + // Posting a delayed task when pumping will apply the delay, but won't cause + // work to executed afterwards. + base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10)); + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order), + delay); + + // After pumping but before the delay period has expired, task does not run. + LazyNow lazy_now1(now_src_.get()); + runners_[0]->PumpQueue(&lazy_now1, true); + test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(5)); + EXPECT_TRUE(run_order.empty()); + + // Once the delay has expired, pumping causes the task to run. + now_src_->Advance(base::TimeDelta::FromMilliseconds(5)); + LazyNow lazy_now2(now_src_.get()); + runners_[0]->PumpQueue(&lazy_now2, true); + EXPECT_TRUE(test_task_runner_->HasPendingTasks()); + test_task_runner_->RunPendingTasks(); + EXPECT_THAT(run_order, ElementsAre(1)); +} + +TEST_F(TaskQueueManagerTest, ManualPumpingWithMultipleDelayedTasks) { + Initialize(1u); + runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL); + + std::vector<EnqueueOrder> run_order; + // Posting a delayed task when pumping will apply the delay, but won't cause + // work to executed afterwards. + base::TimeDelta delay1(base::TimeDelta::FromMilliseconds(1)); + base::TimeDelta delay2(base::TimeDelta::FromMilliseconds(10)); + base::TimeDelta delay3(base::TimeDelta::FromMilliseconds(20)); + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order), + delay1); + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order), + delay2); + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order), + delay3); + + now_src_->Advance(base::TimeDelta::FromMilliseconds(15)); + test_task_runner_->RunUntilIdle(); + EXPECT_TRUE(run_order.empty()); + + // Once the delay has expired, pumping causes the task to run. + LazyNow lazy_now(now_src_.get()); + runners_[0]->PumpQueue(&lazy_now, true); + test_task_runner_->RunUntilIdle(); + EXPECT_THAT(run_order, ElementsAre(1, 2)); +} + +TEST_F(TaskQueueManagerTest, DelayedTasksDontAutoRunWithManualPumping) { + Initialize(1u); + runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL); + + std::vector<EnqueueOrder> run_order; + base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10)); + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order), + delay); + + test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(10)); + EXPECT_TRUE(run_order.empty()); +} + +TEST_F(TaskQueueManagerTest, ManualPumpingWithNonEmptyWorkQueue) { + Initialize(1u); + runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL); + + std::vector<EnqueueOrder> run_order; + // Posting two tasks and pumping twice should result in two tasks in the work + // queue. + LazyNow lazy_now(now_src_.get()); + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); + runners_[0]->PumpQueue(&lazy_now, true); + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); + runners_[0]->PumpQueue(&lazy_now, true); + + EXPECT_EQ(2u, runners_[0]->immediate_work_queue()->Size()); +} + +void ReentrantTestTask(scoped_refptr<base::SingleThreadTaskRunner> runner, + int countdown, + std::vector<EnqueueOrder>* out_result) { + out_result->push_back(countdown); + if (--countdown) { + runner->PostTask(FROM_HERE, + Bind(&ReentrantTestTask, runner, countdown, out_result)); + } +} + +TEST_F(TaskQueueManagerTest, ReentrantPosting) { + Initialize(1u); + + std::vector<EnqueueOrder> run_order; + runners_[0]->PostTask(FROM_HERE, + Bind(&ReentrantTestTask, runners_[0], 3, &run_order)); + + test_task_runner_->RunUntilIdle(); + EXPECT_THAT(run_order, ElementsAre(3, 2, 1)); +} + +TEST_F(TaskQueueManagerTest, NoTasksAfterShutdown) { + Initialize(1u); + + std::vector<EnqueueOrder> run_order; + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); + manager_.reset(); + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); + + test_task_runner_->RunUntilIdle(); + EXPECT_TRUE(run_order.empty()); +} + +void PostTaskToRunner(scoped_refptr<base::SingleThreadTaskRunner> runner, + std::vector<EnqueueOrder>* run_order) { + runner->PostTask(FROM_HERE, base::Bind(&TestTask, 1, run_order)); +} + +TEST_F(TaskQueueManagerTest, PostFromThread) { + InitializeWithRealMessageLoop(1u); + + std::vector<EnqueueOrder> run_order; + base::Thread thread("TestThread"); + thread.Start(); + thread.task_runner()->PostTask( + FROM_HERE, base::Bind(&PostTaskToRunner, runners_[0], &run_order)); + thread.Stop(); + + base::RunLoop().RunUntilIdle(); + EXPECT_THAT(run_order, ElementsAre(1)); +} + +void RePostingTestTask(scoped_refptr<base::SingleThreadTaskRunner> runner, + int* run_count) { + (*run_count)++; + runner->PostTask(FROM_HERE, Bind(&RePostingTestTask, + base::Unretained(runner.get()), run_count)); +} + +TEST_F(TaskQueueManagerTest, DoWorkCantPostItselfMultipleTimes) { + Initialize(1u); + + int run_count = 0; + runners_[0]->PostTask( + FROM_HERE, base::Bind(&RePostingTestTask, runners_[0], &run_count)); + + test_task_runner_->RunPendingTasks(); + // NOTE without the executing_task_ check in MaybeScheduleDoWork there + // will be two tasks here. + EXPECT_EQ(1u, test_task_runner_->NumPendingTasks()); + EXPECT_EQ(1, run_count); +} + +TEST_F(TaskQueueManagerTest, PostFromNestedRunloop) { + InitializeWithRealMessageLoop(1u); + + std::vector<EnqueueOrder> run_order; + std::vector<std::pair<base::Closure, bool>> tasks_to_post_from_nested_loop; + tasks_to_post_from_nested_loop.push_back( + std::make_pair(base::Bind(&TestTask, 1, &run_order), true)); + + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 0, &run_order)); + runners_[0]->PostTask( + FROM_HERE, base::Bind(&PostFromNestedRunloop, message_loop_.get(), + base::RetainedRef(runners_[0]), + base::Unretained(&tasks_to_post_from_nested_loop))); + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); + + base::RunLoop().RunUntilIdle(); + + EXPECT_THAT(run_order, ElementsAre(0, 2, 1)); +} + +TEST_F(TaskQueueManagerTest, WorkBatching) { + Initialize(1u); + + manager_->SetWorkBatchSize(2); + + std::vector<EnqueueOrder> run_order; + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order)); + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 4, &run_order)); + + // Running one task in the host message loop should cause two posted tasks to + // get executed. + EXPECT_EQ(test_task_runner_->NumPendingTasks(), 1u); + test_task_runner_->RunPendingTasks(); + EXPECT_THAT(run_order, ElementsAre(1, 2)); + + // The second task runs the remaining two posted tasks. + EXPECT_EQ(test_task_runner_->NumPendingTasks(), 1u); + test_task_runner_->RunPendingTasks(); + EXPECT_THAT(run_order, ElementsAre(1, 2, 3, 4)); +} + +TEST_F(TaskQueueManagerTest, AutoPumpAfterWakeup) { + Initialize(2u); + runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP); + + std::vector<EnqueueOrder> run_order; + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); + test_task_runner_->RunUntilIdle(); + EXPECT_TRUE(run_order.empty()); // Shouldn't run - no other task to wake TQM. + + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); + test_task_runner_->RunUntilIdle(); + EXPECT_TRUE(run_order.empty()); // Still shouldn't wake TQM. + + runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order)); + test_task_runner_->RunUntilIdle(); + // Executing a task on an auto pumped queue should wake the TQM. + EXPECT_THAT(run_order, ElementsAre(3, 1, 2)); +} + +TEST_F(TaskQueueManagerTest, AutoPumpAfterWakeupWhenAlreadyAwake) { + Initialize(2u); + runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP); + + std::vector<EnqueueOrder> run_order; + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); + runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); + test_task_runner_->RunUntilIdle(); + EXPECT_THAT(run_order, ElementsAre(2, 1)); // TQM was already awake. +} + +TEST_F(TaskQueueManagerTest, + AutoPumpAfterWakeupTriggeredByManuallyPumpedQueue) { + Initialize(2u); + runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP); + runners_[1]->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL); + + std::vector<EnqueueOrder> run_order; + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); + test_task_runner_->RunUntilIdle(); + EXPECT_TRUE(run_order.empty()); // Shouldn't run - no other task to wake TQM. + + runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); + test_task_runner_->RunUntilIdle(); + // This still shouldn't wake TQM as manual queue was not pumped. + EXPECT_TRUE(run_order.empty()); + + LazyNow lazy_now(now_src_.get()); + runners_[1]->PumpQueue(&lazy_now, true); + test_task_runner_->RunUntilIdle(); + // Executing a task on an auto pumped queue should wake the TQM. + EXPECT_THAT(run_order, ElementsAre(2, 1)); +} + +void TestPostingTask(scoped_refptr<base::SingleThreadTaskRunner> task_runner, + base::Closure task) { + task_runner->PostTask(FROM_HERE, task); +} + +TEST_F(TaskQueueManagerTest, AutoPumpAfterWakeupFromTask) { + Initialize(2u); + runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP); + + std::vector<EnqueueOrder> run_order; + // Check that a task which posts a task to an auto pump after wakeup queue + // doesn't cause the queue to wake up. + base::Closure after_wakeup_task = base::Bind(&TestTask, 1, &run_order); + runners_[1]->PostTask( + FROM_HERE, base::Bind(&TestPostingTask, runners_[0], after_wakeup_task)); + test_task_runner_->RunUntilIdle(); + EXPECT_TRUE(run_order.empty()); + + // Wake up the queue. + runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); + test_task_runner_->RunUntilIdle(); + EXPECT_THAT(run_order, ElementsAre(2, 1)); +} + +TEST_F(TaskQueueManagerTest, AutoPumpAfterWakeupFromMultipleTasks) { + Initialize(2u); + runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP); + + std::vector<EnqueueOrder> run_order; + // Check that a task which posts a task to an auto pump after wakeup queue + // doesn't cause the queue to wake up. + base::Closure after_wakeup_task_1 = base::Bind(&TestTask, 1, &run_order); + base::Closure after_wakeup_task_2 = base::Bind(&TestTask, 2, &run_order); + runners_[1]->PostTask(FROM_HERE, base::Bind(&TestPostingTask, runners_[0], + after_wakeup_task_1)); + runners_[1]->PostTask(FROM_HERE, base::Bind(&TestPostingTask, runners_[0], + after_wakeup_task_2)); + test_task_runner_->RunUntilIdle(); + EXPECT_TRUE(run_order.empty()); + + // Wake up the queue. + runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order)); + test_task_runner_->RunUntilIdle(); + EXPECT_THAT(run_order, ElementsAre(3, 1, 2)); +} + +TEST_F(TaskQueueManagerTest, AutoPumpAfterWakeupBecomesQuiescent) { + Initialize(2u); + runners_[0]->SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP); + + int run_count = 0; + // Check that if multiple tasks reposts themselves onto a pump-after-wakeup + // queue they don't wake each other and will eventually stop when no other + // tasks execute. + runners_[0]->PostTask( + FROM_HERE, base::Bind(&RePostingTestTask, runners_[0], &run_count)); + runners_[0]->PostTask( + FROM_HERE, base::Bind(&RePostingTestTask, runners_[0], &run_count)); + runners_[1]->PostTask(FROM_HERE, base::Bind(&NopTask)); + test_task_runner_->RunUntilIdle(); + // The reposting tasks posted to the after wakeup queue shouldn't have woken + // each other up. + EXPECT_EQ(2, run_count); +} + +TEST_F(TaskQueueManagerTest, AutoPumpAfterWakeupWithDontWakeQueue) { + Initialize(1u); + + scoped_refptr<internal::TaskQueueImpl> queue0 = manager_->NewTaskQueue( + TaskQueue::Spec("test_queue 0") + .SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP)); + scoped_refptr<internal::TaskQueueImpl> queue1 = manager_->NewTaskQueue( + TaskQueue::Spec("test_queue 0") + .SetWakeupPolicy(TaskQueue::WakeupPolicy::DONT_WAKE_OTHER_QUEUES)); + scoped_refptr<internal::TaskQueueImpl> queue2 = runners_[0]; + + std::vector<EnqueueOrder> run_order; + queue0->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); + queue1->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); + test_task_runner_->RunUntilIdle(); + // Executing a DONT_WAKE_OTHER_QUEUES queue shouldn't wake the autopump after + // wakeup queue. + EXPECT_THAT(run_order, ElementsAre(2)); + + queue2->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order)); + test_task_runner_->RunUntilIdle(); + // Executing a CAN_WAKE_OTHER_QUEUES queue should wake the autopump after + // wakeup queue. + EXPECT_THAT(run_order, ElementsAre(2, 3, 1)); +} + +class MockTaskObserver : public base::MessageLoop::TaskObserver { + public: + MOCK_METHOD1(DidProcessTask, void(const base::PendingTask& task)); + MOCK_METHOD1(WillProcessTask, void(const base::PendingTask& task)); +}; + +TEST_F(TaskQueueManagerTest, TaskObserverAdding) { + InitializeWithRealMessageLoop(1u); + MockTaskObserver observer; + + manager_->SetWorkBatchSize(2); + manager_->AddTaskObserver(&observer); + + std::vector<EnqueueOrder> run_order; + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); + + EXPECT_CALL(observer, WillProcessTask(_)).Times(2); + EXPECT_CALL(observer, DidProcessTask(_)).Times(2); + base::RunLoop().RunUntilIdle(); +} + +TEST_F(TaskQueueManagerTest, TaskObserverRemoving) { + InitializeWithRealMessageLoop(1u); + MockTaskObserver observer; + manager_->SetWorkBatchSize(2); + manager_->AddTaskObserver(&observer); + manager_->RemoveTaskObserver(&observer); + + std::vector<EnqueueOrder> run_order; + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); + + EXPECT_CALL(observer, WillProcessTask(_)).Times(0); + EXPECT_CALL(observer, DidProcessTask(_)).Times(0); + + base::RunLoop().RunUntilIdle(); +} + +void RemoveObserverTask(TaskQueueManager* manager, + base::MessageLoop::TaskObserver* observer) { + manager->RemoveTaskObserver(observer); +} + +TEST_F(TaskQueueManagerTest, TaskObserverRemovingInsideTask) { + InitializeWithRealMessageLoop(1u); + MockTaskObserver observer; + manager_->SetWorkBatchSize(3); + manager_->AddTaskObserver(&observer); + + runners_[0]->PostTask( + FROM_HERE, base::Bind(&RemoveObserverTask, manager_.get(), &observer)); + + EXPECT_CALL(observer, WillProcessTask(_)).Times(1); + EXPECT_CALL(observer, DidProcessTask(_)).Times(0); + base::RunLoop().RunUntilIdle(); +} + +TEST_F(TaskQueueManagerTest, QueueTaskObserverAdding) { + InitializeWithRealMessageLoop(2u); + MockTaskObserver observer; + + manager_->SetWorkBatchSize(2); + runners_[0]->AddTaskObserver(&observer); + + std::vector<EnqueueOrder> run_order; + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); + runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); + + EXPECT_CALL(observer, WillProcessTask(_)).Times(1); + EXPECT_CALL(observer, DidProcessTask(_)).Times(1); + base::RunLoop().RunUntilIdle(); +} + +TEST_F(TaskQueueManagerTest, QueueTaskObserverRemoving) { + InitializeWithRealMessageLoop(1u); + MockTaskObserver observer; + manager_->SetWorkBatchSize(2); + runners_[0]->AddTaskObserver(&observer); + runners_[0]->RemoveTaskObserver(&observer); + + std::vector<EnqueueOrder> run_order; + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); + + EXPECT_CALL(observer, WillProcessTask(_)).Times(0); + EXPECT_CALL(observer, DidProcessTask(_)).Times(0); + + base::RunLoop().RunUntilIdle(); +} + +void RemoveQueueObserverTask(scoped_refptr<TaskQueue> queue, + base::MessageLoop::TaskObserver* observer) { + queue->RemoveTaskObserver(observer); +} + +TEST_F(TaskQueueManagerTest, QueueTaskObserverRemovingInsideTask) { + InitializeWithRealMessageLoop(1u); + MockTaskObserver observer; + runners_[0]->AddTaskObserver(&observer); + + runners_[0]->PostTask( + FROM_HERE, base::Bind(&RemoveQueueObserverTask, runners_[0], &observer)); + + EXPECT_CALL(observer, WillProcessTask(_)).Times(1); + EXPECT_CALL(observer, DidProcessTask(_)).Times(0); + base::RunLoop().RunUntilIdle(); +} + +TEST_F(TaskQueueManagerTest, ThreadCheckAfterTermination) { + Initialize(1u); + EXPECT_TRUE(runners_[0]->RunsTasksOnCurrentThread()); + manager_.reset(); + EXPECT_TRUE(runners_[0]->RunsTasksOnCurrentThread()); +} + +TEST_F(TaskQueueManagerTest, TimeDomain_NextScheduledRunTime) { + Initialize(2u); + now_src_->Advance(base::TimeDelta::FromMicroseconds(10000)); + + // With no delayed tasks. + base::TimeTicks run_time; + EXPECT_FALSE(manager_->real_time_domain()->NextScheduledRunTime(&run_time)); + + // With a non-delayed task. + runners_[0]->PostTask(FROM_HERE, base::Bind(&NopTask)); + EXPECT_FALSE(manager_->real_time_domain()->NextScheduledRunTime(&run_time)); + + // With a delayed task. + base::TimeDelta expected_delay = base::TimeDelta::FromMilliseconds(50); + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), expected_delay); + EXPECT_TRUE(manager_->real_time_domain()->NextScheduledRunTime(&run_time)); + EXPECT_EQ(now_src_->NowTicks() + expected_delay, run_time); + + // With another delayed task in the same queue with a longer delay. + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), + base::TimeDelta::FromMilliseconds(100)); + EXPECT_TRUE(manager_->real_time_domain()->NextScheduledRunTime(&run_time)); + EXPECT_EQ(now_src_->NowTicks() + expected_delay, run_time); + + // With another delayed task in the same queue with a shorter delay. + expected_delay = base::TimeDelta::FromMilliseconds(20); + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), expected_delay); + EXPECT_TRUE(manager_->real_time_domain()->NextScheduledRunTime(&run_time)); + EXPECT_EQ(now_src_->NowTicks() + expected_delay, run_time); + + // With another delayed task in a different queue with a shorter delay. + expected_delay = base::TimeDelta::FromMilliseconds(10); + runners_[1]->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), expected_delay); + EXPECT_TRUE(manager_->real_time_domain()->NextScheduledRunTime(&run_time)); + EXPECT_EQ(now_src_->NowTicks() + expected_delay, run_time); + + // Test it updates as time progresses + now_src_->Advance(expected_delay); + EXPECT_TRUE(manager_->real_time_domain()->NextScheduledRunTime(&run_time)); + EXPECT_EQ(now_src_->NowTicks(), run_time); +} + +TEST_F(TaskQueueManagerTest, TimeDomain_NextScheduledRunTime_MultipleQueues) { + Initialize(3u); + + base::TimeDelta delay1 = base::TimeDelta::FromMilliseconds(50); + base::TimeDelta delay2 = base::TimeDelta::FromMilliseconds(5); + base::TimeDelta delay3 = base::TimeDelta::FromMilliseconds(10); + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), delay1); + runners_[1]->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), delay2); + runners_[2]->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), delay3); + runners_[0]->PostTask(FROM_HERE, base::Bind(&NopTask)); + + base::TimeTicks run_time; + EXPECT_TRUE(manager_->real_time_domain()->NextScheduledRunTime(&run_time)); + EXPECT_EQ(now_src_->NowTicks() + delay2, run_time); +} + +TEST_F(TaskQueueManagerTest, DeleteTaskQueueManagerInsideATask) { + Initialize(1u); + + runners_[0]->PostTask( + FROM_HERE, base::Bind(&TaskQueueManagerTest::DeleteTaskQueueManager, + base::Unretained(this))); + + // This should not crash, assuming DoWork detects the TaskQueueManager has + // been deleted. + test_task_runner_->RunUntilIdle(); +} + +TEST_F(TaskQueueManagerTest, GetAndClearSystemIsQuiescentBit) { + Initialize(3u); + + scoped_refptr<internal::TaskQueueImpl> queue0 = manager_->NewTaskQueue( + TaskQueue::Spec("test_queue 0").SetShouldMonitorQuiescence(true)); + scoped_refptr<internal::TaskQueueImpl> queue1 = manager_->NewTaskQueue( + TaskQueue::Spec("test_queue 1").SetShouldMonitorQuiescence(true)); + scoped_refptr<internal::TaskQueueImpl> queue2 = manager_->NewTaskQueue( + TaskQueue::Spec("test_queue 2").SetShouldMonitorQuiescence(false)); + + EXPECT_TRUE(manager_->GetAndClearSystemIsQuiescentBit()); + + queue0->PostTask(FROM_HERE, base::Bind(&NopTask)); + test_task_runner_->RunUntilIdle(); + EXPECT_FALSE(manager_->GetAndClearSystemIsQuiescentBit()); + EXPECT_TRUE(manager_->GetAndClearSystemIsQuiescentBit()); + + queue1->PostTask(FROM_HERE, base::Bind(&NopTask)); + test_task_runner_->RunUntilIdle(); + EXPECT_FALSE(manager_->GetAndClearSystemIsQuiescentBit()); + EXPECT_TRUE(manager_->GetAndClearSystemIsQuiescentBit()); + + queue2->PostTask(FROM_HERE, base::Bind(&NopTask)); + test_task_runner_->RunUntilIdle(); + EXPECT_TRUE(manager_->GetAndClearSystemIsQuiescentBit()); + + queue0->PostTask(FROM_HERE, base::Bind(&NopTask)); + queue1->PostTask(FROM_HERE, base::Bind(&NopTask)); + test_task_runner_->RunUntilIdle(); + EXPECT_FALSE(manager_->GetAndClearSystemIsQuiescentBit()); + EXPECT_TRUE(manager_->GetAndClearSystemIsQuiescentBit()); +} + +TEST_F(TaskQueueManagerTest, HasPendingImmediateWork) { + Initialize(2u); + internal::TaskQueueImpl* queue0 = runners_[0].get(); + internal::TaskQueueImpl* queue1 = runners_[1].get(); + queue0->SetPumpPolicy(TaskQueue::PumpPolicy::AUTO); + queue1->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL); + + EXPECT_FALSE(queue0->HasPendingImmediateWork()); + EXPECT_FALSE(queue1->HasPendingImmediateWork()); + + queue0->PostTask(FROM_HERE, base::Bind(NullTask)); + queue1->PostTask(FROM_HERE, base::Bind(NullTask)); + EXPECT_TRUE(queue0->HasPendingImmediateWork()); + EXPECT_TRUE(queue1->HasPendingImmediateWork()); + + test_task_runner_->RunUntilIdle(); + EXPECT_FALSE(queue0->HasPendingImmediateWork()); + EXPECT_TRUE(queue1->HasPendingImmediateWork()); + + LazyNow lazy_now(now_src_.get()); + queue1->PumpQueue(&lazy_now, true); + EXPECT_FALSE(queue0->HasPendingImmediateWork()); + EXPECT_TRUE(queue1->HasPendingImmediateWork()); + + test_task_runner_->RunUntilIdle(); + EXPECT_FALSE(queue0->HasPendingImmediateWork()); + EXPECT_FALSE(queue1->HasPendingImmediateWork()); +} + +TEST_F(TaskQueueManagerTest, HasPendingImmediateWorkAndNeedsPumping) { + Initialize(2u); + internal::TaskQueueImpl* queue0 = runners_[0].get(); + internal::TaskQueueImpl* queue1 = runners_[1].get(); + queue0->SetPumpPolicy(TaskQueue::PumpPolicy::AUTO); + queue1->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL); + + EXPECT_FALSE(queue0->HasPendingImmediateWork()); + EXPECT_FALSE(queue0->NeedsPumping()); + EXPECT_FALSE(queue1->HasPendingImmediateWork()); + EXPECT_FALSE(queue1->NeedsPumping()); + + queue0->PostTask(FROM_HERE, base::Bind(NullTask)); + queue0->PostTask(FROM_HERE, base::Bind(NullTask)); + queue1->PostTask(FROM_HERE, base::Bind(NullTask)); + EXPECT_TRUE(queue0->HasPendingImmediateWork()); + EXPECT_TRUE(queue0->NeedsPumping()); + EXPECT_TRUE(queue1->HasPendingImmediateWork()); + EXPECT_TRUE(queue1->NeedsPumping()); + + test_task_runner_->SetRunTaskLimit(1); + test_task_runner_->RunPendingTasks(); + EXPECT_TRUE(queue0->HasPendingImmediateWork()); + EXPECT_FALSE(queue0->NeedsPumping()); + EXPECT_TRUE(queue1->HasPendingImmediateWork()); + EXPECT_TRUE(queue1->NeedsPumping()); + + test_task_runner_->ClearRunTaskLimit(); + test_task_runner_->RunUntilIdle(); + EXPECT_FALSE(queue0->HasPendingImmediateWork()); + EXPECT_FALSE(queue0->NeedsPumping()); + EXPECT_TRUE(queue1->HasPendingImmediateWork()); + EXPECT_TRUE(queue1->NeedsPumping()); + + LazyNow lazy_now(now_src_.get()); + queue1->PumpQueue(&lazy_now, true); + EXPECT_FALSE(queue0->HasPendingImmediateWork()); + EXPECT_FALSE(queue0->NeedsPumping()); + EXPECT_TRUE(queue1->HasPendingImmediateWork()); + EXPECT_FALSE(queue1->NeedsPumping()); + + test_task_runner_->RunUntilIdle(); + EXPECT_FALSE(queue0->HasPendingImmediateWork()); + EXPECT_FALSE(queue0->NeedsPumping()); + EXPECT_FALSE(queue1->HasPendingImmediateWork()); + EXPECT_FALSE(queue1->NeedsPumping()); +} + +void ExpensiveTestTask(int value, + base::SimpleTestTickClock* clock, + std::vector<EnqueueOrder>* out_result) { + out_result->push_back(value); + clock->Advance(base::TimeDelta::FromMilliseconds(1)); +} + +TEST_F(TaskQueueManagerTest, ImmediateAndDelayedTaskInterleaving) { + Initialize(1u); + + std::vector<EnqueueOrder> run_order; + base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10); + for (int i = 10; i < 19; i++) { + runners_[0]->PostDelayedTask( + FROM_HERE, + base::Bind(&ExpensiveTestTask, i, now_src_.get(), &run_order), delay); + } + + test_task_runner_->RunForPeriod(delay); + + for (int i = 0; i < 9; i++) { + runners_[0]->PostTask(FROM_HERE, base::Bind(&ExpensiveTestTask, i, + now_src_.get(), &run_order)); + } + + test_task_runner_->SetAutoAdvanceNowToPendingTasks(true); + test_task_runner_->RunUntilIdle(); + + // Delayed tasks are not allowed to starve out immediate work which is why + // some of the immediate tasks run out of order. + int expected_run_order[] = {10, 11, 12, 13, 0, 14, 15, 16, 1, + 17, 18, 2, 3, 4, 5, 6, 7, 8}; + EXPECT_THAT(run_order, ElementsAreArray(expected_run_order)); +} + +TEST_F(TaskQueueManagerTest, + DelayedTaskDoesNotSkipAHeadOfNonDelayedTask_SameQueue) { + Initialize(1u); + + std::vector<EnqueueOrder> run_order; + base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10); + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order)); + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order), + delay); + + now_src_->Advance(delay * 2); + test_task_runner_->RunUntilIdle(); + + EXPECT_THAT(run_order, ElementsAre(2, 3, 1)); +} + +TEST_F(TaskQueueManagerTest, + DelayedTaskDoesNotSkipAHeadOfNonDelayedTask_DifferentQueues) { + Initialize(2u); + + std::vector<EnqueueOrder> run_order; + base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10); + runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); + runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order)); + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order), + delay); + + now_src_->Advance(delay * 2); + test_task_runner_->RunUntilIdle(); + + EXPECT_THAT(run_order, ElementsAre(2, 3, 1)); +} + +TEST_F(TaskQueueManagerTest, DelayedTaskDoesNotSkipAHeadOfShorterDelayedTask) { + Initialize(2u); + + std::vector<EnqueueOrder> run_order; + base::TimeDelta delay1 = base::TimeDelta::FromMilliseconds(10); + base::TimeDelta delay2 = base::TimeDelta::FromMilliseconds(5); + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order), + delay1); + runners_[1]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order), + delay2); + + now_src_->Advance(delay1 * 2); + test_task_runner_->RunUntilIdle(); + + EXPECT_THAT(run_order, ElementsAre(2, 1)); +} + +void CheckIsNested(bool* is_nested) { + *is_nested = base::MessageLoop::current()->IsNested(); +} + +void PostAndQuitFromNestedRunloop(base::RunLoop* run_loop, + base::SingleThreadTaskRunner* runner, + bool* was_nested) { + base::MessageLoop::ScopedNestableTaskAllower allow( + base::MessageLoop::current()); + runner->PostTask(FROM_HERE, run_loop->QuitClosure()); + runner->PostTask(FROM_HERE, base::Bind(&CheckIsNested, was_nested)); + run_loop->Run(); +} + +TEST_F(TaskQueueManagerTest, QuitWhileNested) { + // This test makes sure we don't continue running a work batch after a nested + // run loop has been exited in the middle of the batch. + InitializeWithRealMessageLoop(1u); + manager_->SetWorkBatchSize(2); + + bool was_nested = true; + base::RunLoop run_loop; + runners_[0]->PostTask(FROM_HERE, base::Bind(&PostAndQuitFromNestedRunloop, + base::Unretained(&run_loop), + base::RetainedRef(runners_[0]), + base::Unretained(&was_nested))); + + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(was_nested); +} + +class SequenceNumberCapturingTaskObserver + : public base::MessageLoop::TaskObserver { + public: + // MessageLoop::TaskObserver overrides. + void WillProcessTask(const base::PendingTask& pending_task) override {} + void DidProcessTask(const base::PendingTask& pending_task) override { + sequence_numbers_.push_back(pending_task.sequence_num); + } + + const std::vector<EnqueueOrder>& sequence_numbers() const { + return sequence_numbers_; + } + + private: + std::vector<EnqueueOrder> sequence_numbers_; +}; + +TEST_F(TaskQueueManagerTest, SequenceNumSetWhenTaskIsPosted) { + Initialize(1u); + + SequenceNumberCapturingTaskObserver observer; + manager_->AddTaskObserver(&observer); + + // Register four tasks that will run in reverse order. + std::vector<EnqueueOrder> run_order; + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order), + base::TimeDelta::FromMilliseconds(30)); + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order), + base::TimeDelta::FromMilliseconds(20)); + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order), + base::TimeDelta::FromMilliseconds(10)); + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 4, &run_order)); + + test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(40)); + ASSERT_THAT(run_order, ElementsAre(4, 3, 2, 1)); + + // The sequence numbers are a zero-based monotonically incrememting counter + // which should be set when the task is posted rather than when it's enqueued + // onto the Incoming queue. + EXPECT_THAT(observer.sequence_numbers(), ElementsAre(3, 2, 1, 0)); + + manager_->RemoveTaskObserver(&observer); +} + +TEST_F(TaskQueueManagerTest, NewTaskQueues) { + Initialize(1u); + + scoped_refptr<internal::TaskQueueImpl> queue1 = + manager_->NewTaskQueue(TaskQueue::Spec("foo")); + scoped_refptr<internal::TaskQueueImpl> queue2 = + manager_->NewTaskQueue(TaskQueue::Spec("bar")); + scoped_refptr<internal::TaskQueueImpl> queue3 = + manager_->NewTaskQueue(TaskQueue::Spec("baz")); + + ASSERT_NE(queue1, queue2); + ASSERT_NE(queue1, queue3); + ASSERT_NE(queue2, queue3); + + std::vector<EnqueueOrder> run_order; + queue1->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); + queue2->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); + queue3->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order)); + test_task_runner_->RunUntilIdle(); + + EXPECT_THAT(run_order, ElementsAre(1, 2, 3)); +} + +TEST_F(TaskQueueManagerTest, UnregisterTaskQueue) { + Initialize(1u); + + scoped_refptr<internal::TaskQueueImpl> queue1 = + manager_->NewTaskQueue(TaskQueue::Spec("foo")); + scoped_refptr<internal::TaskQueueImpl> queue2 = + manager_->NewTaskQueue(TaskQueue::Spec("bar")); + scoped_refptr<internal::TaskQueueImpl> queue3 = + manager_->NewTaskQueue(TaskQueue::Spec("baz")); + + ASSERT_NE(queue1, queue2); + ASSERT_NE(queue1, queue3); + ASSERT_NE(queue2, queue3); + + std::vector<EnqueueOrder> run_order; + queue1->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); + queue2->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); + queue3->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order)); + + queue2->UnregisterTaskQueue(); + test_task_runner_->RunUntilIdle(); + + EXPECT_THAT(run_order, ElementsAre(1, 3)); +} + +TEST_F(TaskQueueManagerTest, UnregisterTaskQueue_WithDelayedTasks) { + Initialize(2u); + + // Register three delayed tasks + std::vector<EnqueueOrder> run_order; + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order), + base::TimeDelta::FromMilliseconds(10)); + runners_[1]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order), + base::TimeDelta::FromMilliseconds(20)); + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order), + base::TimeDelta::FromMilliseconds(30)); + + runners_[1]->UnregisterTaskQueue(); + test_task_runner_->RunUntilIdle(); + + test_task_runner_->RunForPeriod(base::TimeDelta::FromMilliseconds(40)); + ASSERT_THAT(run_order, ElementsAre(1, 3)); +} + +namespace { +void UnregisterQueue(scoped_refptr<internal::TaskQueueImpl> queue) { + queue->UnregisterTaskQueue(); +} +} + +TEST_F(TaskQueueManagerTest, UnregisterTaskQueue_InTasks) { + Initialize(3u); + + std::vector<EnqueueOrder> run_order; + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); + runners_[0]->PostTask(FROM_HERE, base::Bind(&UnregisterQueue, runners_[1])); + runners_[0]->PostTask(FROM_HERE, base::Bind(&UnregisterQueue, runners_[2])); + runners_[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order)); + runners_[2]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order)); + + test_task_runner_->RunUntilIdle(); + ASSERT_THAT(run_order, ElementsAre(1)); +} + +void PostTestTasksFromNestedMessageLoop( + base::MessageLoop* message_loop, + scoped_refptr<base::SingleThreadTaskRunner> main_runner, + scoped_refptr<base::SingleThreadTaskRunner> wake_up_runner, + std::vector<EnqueueOrder>* run_order) { + base::MessageLoop::ScopedNestableTaskAllower allow(message_loop); + main_runner->PostNonNestableTask(FROM_HERE, + base::Bind(&TestTask, 1, run_order)); + // The following should never get executed. + wake_up_runner->PostTask(FROM_HERE, base::Bind(&TestTask, 2, run_order)); + base::RunLoop().RunUntilIdle(); +} + +TEST_F(TaskQueueManagerTest, DeferredNonNestableTaskDoesNotTriggerWakeUp) { + // This test checks that running (i.e., deferring) a non-nestable task in a + // nested run loop does not trigger the pumping of an on-wakeup queue. + InitializeWithRealMessageLoop(2u); + runners_[1]->SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP); + + std::vector<EnqueueOrder> run_order; + runners_[0]->PostTask( + FROM_HERE, + base::Bind(&PostTestTasksFromNestedMessageLoop, message_loop_.get(), + runners_[0], runners_[1], base::Unretained(&run_order))); + + base::RunLoop().RunUntilIdle(); + ASSERT_THAT(run_order, ElementsAre(1)); +} + +namespace { + +class MockObserver : public TaskQueueManager::Observer { + public: + MOCK_METHOD1(OnUnregisterTaskQueue, + void(const scoped_refptr<TaskQueue>& queue)); + MOCK_METHOD2(OnTriedToExecuteBlockedTask, + void(const TaskQueue& queue, const base::PendingTask& task)); +}; + +} // namespace + +TEST_F(TaskQueueManagerTest, OnUnregisterTaskQueue) { + Initialize(0u); + + MockObserver observer; + manager_->SetObserver(&observer); + + scoped_refptr<internal::TaskQueueImpl> task_queue = + manager_->NewTaskQueue(TaskQueue::Spec("test_queue")); + + EXPECT_CALL(observer, OnUnregisterTaskQueue(_)).Times(1); + task_queue->UnregisterTaskQueue(); + + manager_->SetObserver(nullptr); +} + +TEST_F(TaskQueueManagerTest, OnTriedToExecuteBlockedTask) { + Initialize(0u); + + MockObserver observer; + manager_->SetObserver(&observer); + + scoped_refptr<internal::TaskQueueImpl> task_queue = manager_->NewTaskQueue( + TaskQueue::Spec("test_queue").SetShouldReportWhenExecutionBlocked(true)); + task_queue->SetQueueEnabled(false); + task_queue->PostTask(FROM_HERE, base::Bind(&NopTask)); + + EXPECT_CALL(observer, OnTriedToExecuteBlockedTask(_, _)).Times(1); + test_task_runner_->RunPendingTasks(); + + manager_->SetObserver(nullptr); +} + +TEST_F(TaskQueueManagerTest, ExecutedNonBlockedTask) { + Initialize(0u); + + MockObserver observer; + manager_->SetObserver(&observer); + + scoped_refptr<internal::TaskQueueImpl> task_queue = manager_->NewTaskQueue( + TaskQueue::Spec("test_queue").SetShouldReportWhenExecutionBlocked(true)); + task_queue->PostTask(FROM_HERE, base::Bind(&NopTask)); + + EXPECT_CALL(observer, OnTriedToExecuteBlockedTask(_, _)).Times(0); + test_task_runner_->RunPendingTasks(); + + manager_->SetObserver(nullptr); +} + +void HasOneRefTask(std::vector<bool>* log, internal::TaskQueueImpl* tq) { + log->push_back(tq->HasOneRef()); +} + +TEST_F(TaskQueueManagerTest, UnregisterTaskQueueInNestedLoop) { + InitializeWithRealMessageLoop(1u); + + // We retain a reference to the task queue even when the manager has deleted + // its reference. + scoped_refptr<internal::TaskQueueImpl> task_queue = + manager_->NewTaskQueue(TaskQueue::Spec("test_queue")); + + std::vector<bool> log; + std::vector<std::pair<base::Closure, bool>> tasks_to_post_from_nested_loop; + + // Inside a nested run loop, call task_queue->UnregisterTaskQueue, bookended + // by calls to HasOneRefTask to make sure the manager doesn't release its + // reference until the nested run loop exits. + // NB: This first HasOneRefTask is a sanity check. + tasks_to_post_from_nested_loop.push_back( + std::make_pair(base::Bind(&HasOneRefTask, base::Unretained(&log), + base::Unretained(task_queue.get())), + true)); + tasks_to_post_from_nested_loop.push_back( + std::make_pair(base::Bind(&internal::TaskQueueImpl::UnregisterTaskQueue, + base::Unretained(task_queue.get())), + true)); + tasks_to_post_from_nested_loop.push_back( + std::make_pair(base::Bind(&HasOneRefTask, base::Unretained(&log), + base::Unretained(task_queue.get())), + true)); + runners_[0]->PostTask( + FROM_HERE, base::Bind(&PostFromNestedRunloop, message_loop_.get(), + base::RetainedRef(runners_[0]), + base::Unretained(&tasks_to_post_from_nested_loop))); + base::RunLoop().RunUntilIdle(); + + // Add a final call to HasOneRefTask. This gives the manager a chance to + // release its reference, and checks that it has. + runners_[0]->PostTask(FROM_HERE, + base::Bind(&HasOneRefTask, base::Unretained(&log), + base::Unretained(task_queue.get()))); + base::RunLoop().RunUntilIdle(); + + EXPECT_THAT(log, ElementsAre(false, false, true)); +} + +TEST_F(TaskQueueManagerTest, TimeDomainsAreIndependant) { + Initialize(2u); + + base::TimeTicks start_time = manager_->delegate()->NowTicks(); + std::unique_ptr<VirtualTimeDomain> domain_a( + new VirtualTimeDomain(nullptr, start_time)); + std::unique_ptr<VirtualTimeDomain> domain_b( + new VirtualTimeDomain(nullptr, start_time)); + manager_->RegisterTimeDomain(domain_a.get()); + manager_->RegisterTimeDomain(domain_b.get()); + runners_[0]->SetTimeDomain(domain_a.get()); + runners_[1]->SetTimeDomain(domain_b.get()); + + std::vector<EnqueueOrder> run_order; + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order), + base::TimeDelta::FromMilliseconds(10)); + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order), + base::TimeDelta::FromMilliseconds(20)); + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order), + base::TimeDelta::FromMilliseconds(30)); + + runners_[1]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 4, &run_order), + base::TimeDelta::FromMilliseconds(10)); + runners_[1]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 5, &run_order), + base::TimeDelta::FromMilliseconds(20)); + runners_[1]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 6, &run_order), + base::TimeDelta::FromMilliseconds(30)); + + domain_b->AdvanceTo(start_time + base::TimeDelta::FromMilliseconds(50)); + manager_->MaybeScheduleImmediateWork(FROM_HERE); + + test_task_runner_->RunUntilIdle(); + EXPECT_THAT(run_order, ElementsAre(4, 5, 6)); + + domain_a->AdvanceTo(start_time + base::TimeDelta::FromMilliseconds(50)); + manager_->MaybeScheduleImmediateWork(FROM_HERE); + + test_task_runner_->RunUntilIdle(); + EXPECT_THAT(run_order, ElementsAre(4, 5, 6, 1, 2, 3)); + + runners_[0]->UnregisterTaskQueue(); + runners_[1]->UnregisterTaskQueue(); + + manager_->UnregisterTimeDomain(domain_a.get()); + manager_->UnregisterTimeDomain(domain_b.get()); +} + +TEST_F(TaskQueueManagerTest, TimeDomainMigration) { + Initialize(1u); + + base::TimeTicks start_time = manager_->delegate()->NowTicks(); + std::unique_ptr<VirtualTimeDomain> domain_a( + new VirtualTimeDomain(nullptr, start_time)); + manager_->RegisterTimeDomain(domain_a.get()); + runners_[0]->SetTimeDomain(domain_a.get()); + + std::vector<EnqueueOrder> run_order; + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order), + base::TimeDelta::FromMilliseconds(10)); + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order), + base::TimeDelta::FromMilliseconds(20)); + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order), + base::TimeDelta::FromMilliseconds(30)); + runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 4, &run_order), + base::TimeDelta::FromMilliseconds(40)); + + domain_a->AdvanceTo(start_time + base::TimeDelta::FromMilliseconds(20)); + manager_->MaybeScheduleImmediateWork(FROM_HERE); + test_task_runner_->RunUntilIdle(); + EXPECT_THAT(run_order, ElementsAre(1, 2)); + + std::unique_ptr<VirtualTimeDomain> domain_b( + new VirtualTimeDomain(nullptr, start_time)); + manager_->RegisterTimeDomain(domain_b.get()); + runners_[0]->SetTimeDomain(domain_b.get()); + + domain_b->AdvanceTo(start_time + base::TimeDelta::FromMilliseconds(50)); + manager_->MaybeScheduleImmediateWork(FROM_HERE); + + test_task_runner_->RunUntilIdle(); + EXPECT_THAT(run_order, ElementsAre(1, 2, 3, 4)); + + runners_[0]->UnregisterTaskQueue(); + + manager_->UnregisterTimeDomain(domain_a.get()); + manager_->UnregisterTimeDomain(domain_b.get()); +} + +TEST_F(TaskQueueManagerTest, TimeDomainMigrationWithIncomingImmediateTasks) { + Initialize(1u); + + base::TimeTicks start_time = manager_->delegate()->NowTicks(); + std::unique_ptr<VirtualTimeDomain> domain_a( + new VirtualTimeDomain(nullptr, start_time)); + std::unique_ptr<VirtualTimeDomain> domain_b( + new VirtualTimeDomain(nullptr, start_time)); + manager_->RegisterTimeDomain(domain_a.get()); + manager_->RegisterTimeDomain(domain_b.get()); + + runners_[0]->SetTimeDomain(domain_a.get()); + std::vector<EnqueueOrder> run_order; + runners_[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order)); + runners_[0]->SetTimeDomain(domain_b.get()); + + test_task_runner_->RunUntilIdle(); + EXPECT_THAT(run_order, ElementsAre(1)); + + runners_[0]->UnregisterTaskQueue(); + + manager_->UnregisterTimeDomain(domain_a.get()); + manager_->UnregisterTimeDomain(domain_b.get()); +} + +namespace { +void ChromiumRunloopInspectionTask( + scoped_refptr<cc::OrderedSimpleTaskRunner> test_task_runner) { + EXPECT_EQ(1u, test_task_runner->NumPendingTasks()); +} +} // namespace + +TEST_F(TaskQueueManagerTest, NumberOfPendingTasksOnChromiumRunLoop) { + Initialize(1u); + + // NOTE because tasks posted to the chromiumrun loop are not cancellable, we + // will end up with a lot more tasks posted if the delayed tasks were posted + // in the reverse order. + // TODO(alexclarke): Consider talking to the message pump directly. + test_task_runner_->SetAutoAdvanceNowToPendingTasks(true); + for (int i = 1; i < 100; i++) { + runners_[0]->PostDelayedTask( + FROM_HERE, + base::Bind(&ChromiumRunloopInspectionTask, test_task_runner_), + base::TimeDelta::FromMilliseconds(i)); + } + test_task_runner_->RunUntilIdle(); +} + +namespace { + +class QuadraticTask { + public: + QuadraticTask(scoped_refptr<internal::TaskQueueImpl> task_queue, + base::TimeDelta delay, + base::SimpleTestTickClock* now_src) + : count_(0), task_queue_(task_queue), delay_(delay), now_src_(now_src) {} + + void SetShouldExit(base::Callback<bool()> should_exit) { + should_exit_ = should_exit; + } + + void Run() { + if (should_exit_.Run()) + return; + count_++; + task_queue_->PostDelayedTask( + FROM_HERE, base::Bind(&QuadraticTask::Run, base::Unretained(this)), + delay_); + task_queue_->PostDelayedTask( + FROM_HERE, base::Bind(&QuadraticTask::Run, base::Unretained(this)), + delay_); + now_src_->Advance(base::TimeDelta::FromMilliseconds(5)); + } + + int count() const { return count_; } + + private: + int count_; + scoped_refptr<internal::TaskQueueImpl> task_queue_; + base::TimeDelta delay_; + base::Callback<bool()> should_exit_; + base::SimpleTestTickClock* now_src_; +}; + +class LinearTask { + public: + LinearTask(scoped_refptr<internal::TaskQueueImpl> task_queue, + base::TimeDelta delay, + base::SimpleTestTickClock* now_src) + : count_(0), task_queue_(task_queue), delay_(delay), now_src_(now_src) {} + + void SetShouldExit(base::Callback<bool()> should_exit) { + should_exit_ = should_exit; + } + + void Run() { + if (should_exit_.Run()) + return; + count_++; + task_queue_->PostDelayedTask( + FROM_HERE, base::Bind(&LinearTask::Run, base::Unretained(this)), + delay_); + now_src_->Advance(base::TimeDelta::FromMilliseconds(5)); + } + + int count() const { return count_; } + + private: + int count_; + scoped_refptr<internal::TaskQueueImpl> task_queue_; + base::TimeDelta delay_; + base::Callback<bool()> should_exit_; + base::SimpleTestTickClock* now_src_; +}; + +bool ShouldExit(QuadraticTask* quadratic_task, LinearTask* linear_task) { + return quadratic_task->count() == 1000 || linear_task->count() == 1000; +} + +} // namespace + +TEST_F(TaskQueueManagerTest, + DelayedTasksDontBadlyStarveNonDelayedWork_SameQueue) { + Initialize(1u); + + QuadraticTask quadratic_delayed_task( + runners_[0], base::TimeDelta::FromMilliseconds(10), now_src_.get()); + LinearTask linear_immediate_task(runners_[0], base::TimeDelta(), + now_src_.get()); + base::Callback<bool()> should_exit = + base::Bind(ShouldExit, &quadratic_delayed_task, &linear_immediate_task); + quadratic_delayed_task.SetShouldExit(should_exit); + linear_immediate_task.SetShouldExit(should_exit); + + quadratic_delayed_task.Run(); + linear_immediate_task.Run(); + + test_task_runner_->SetAutoAdvanceNowToPendingTasks(true); + test_task_runner_->RunUntilIdle(); + + double ratio = static_cast<double>(linear_immediate_task.count()) / + static_cast<double>(quadratic_delayed_task.count()); + + EXPECT_GT(ratio, 0.333); + EXPECT_LT(ratio, 1.1); +} + +TEST_F(TaskQueueManagerTest, ImmediateWorkCanStarveDelayedTasks_SameQueue) { + Initialize(1u); + + QuadraticTask quadratic_immediate_task(runners_[0], base::TimeDelta(), + now_src_.get()); + LinearTask linear_delayed_task( + runners_[0], base::TimeDelta::FromMilliseconds(10), now_src_.get()); + base::Callback<bool()> should_exit = + base::Bind(&ShouldExit, &quadratic_immediate_task, &linear_delayed_task); + + quadratic_immediate_task.SetShouldExit(should_exit); + linear_delayed_task.SetShouldExit(should_exit); + + quadratic_immediate_task.Run(); + linear_delayed_task.Run(); + + test_task_runner_->SetAutoAdvanceNowToPendingTasks(true); + test_task_runner_->RunUntilIdle(); + + double ratio = static_cast<double>(linear_delayed_task.count()) / + static_cast<double>(quadratic_immediate_task.count()); + + // This is by design, we want to enforce a strict ordering in task execution + // where by delayed tasks can not skip ahead of non-delayed work. + EXPECT_GT(ratio, 0.0); + EXPECT_LT(ratio, 0.1); +} + +TEST_F(TaskQueueManagerTest, + DelayedTasksDontBadlyStarveNonDelayedWork_DifferentQueue) { + Initialize(2u); + + QuadraticTask quadratic_delayed_task( + runners_[0], base::TimeDelta::FromMilliseconds(10), now_src_.get()); + LinearTask linear_immediate_task(runners_[1], base::TimeDelta(), + now_src_.get()); + base::Callback<bool()> should_exit = + base::Bind(ShouldExit, &quadratic_delayed_task, &linear_immediate_task); + quadratic_delayed_task.SetShouldExit(should_exit); + linear_immediate_task.SetShouldExit(should_exit); + + quadratic_delayed_task.Run(); + linear_immediate_task.Run(); + + test_task_runner_->SetAutoAdvanceNowToPendingTasks(true); + test_task_runner_->RunUntilIdle(); + + double ratio = static_cast<double>(linear_immediate_task.count()) / + static_cast<double>(quadratic_delayed_task.count()); + + EXPECT_GT(ratio, 0.333); + EXPECT_LT(ratio, 1.1); +} + +TEST_F(TaskQueueManagerTest, + ImmediateWorkCanStarveDelayedTasks_DifferentQueue) { + Initialize(2u); + + QuadraticTask quadratic_immediate_task(runners_[0], base::TimeDelta(), + now_src_.get()); + LinearTask linear_delayed_task( + runners_[1], base::TimeDelta::FromMilliseconds(10), now_src_.get()); + base::Callback<bool()> should_exit = + base::Bind(&ShouldExit, &quadratic_immediate_task, &linear_delayed_task); + + quadratic_immediate_task.SetShouldExit(should_exit); + linear_delayed_task.SetShouldExit(should_exit); + + quadratic_immediate_task.Run(); + linear_delayed_task.Run(); + + test_task_runner_->SetAutoAdvanceNowToPendingTasks(true); + test_task_runner_->RunUntilIdle(); + + double ratio = static_cast<double>(linear_delayed_task.count()) / + static_cast<double>(quadratic_immediate_task.count()); + + // This is by design, we want to enforce a strict ordering in task execution + // where by delayed tasks can not skip ahead of non-delayed work. + EXPECT_GT(ratio, 0.0); + EXPECT_LT(ratio, 0.1); +} + +TEST_F(TaskQueueManagerTest, CurrentlyExecutingTaskQueue_NoTaskRunning) { + Initialize(1u); + + EXPECT_EQ(nullptr, manager_->currently_executing_task_queue()); +} + +namespace { +void CurrentlyExecutingTaskQueueTestTask( + TaskQueueManager* task_queue_manager, + std::vector<TaskQueue*>* task_sources) { + task_sources->push_back(task_queue_manager->currently_executing_task_queue()); +} +} + +TEST_F(TaskQueueManagerTest, CurrentlyExecutingTaskQueue_TaskRunning) { + Initialize(2u); + + internal::TaskQueueImpl* queue0 = runners_[0].get(); + internal::TaskQueueImpl* queue1 = runners_[1].get(); + + std::vector<TaskQueue*> task_sources; + queue0->PostTask(FROM_HERE, base::Bind(&CurrentlyExecutingTaskQueueTestTask, + manager_.get(), &task_sources)); + queue1->PostTask(FROM_HERE, base::Bind(&CurrentlyExecutingTaskQueueTestTask, + manager_.get(), &task_sources)); + test_task_runner_->RunUntilIdle(); + + EXPECT_THAT(task_sources, ElementsAre(queue0, queue1)); + EXPECT_EQ(nullptr, manager_->currently_executing_task_queue()); +} + +namespace { +void RunloopCurrentlyExecutingTaskQueueTestTask( + base::MessageLoop* message_loop, + TaskQueueManager* task_queue_manager, + std::vector<TaskQueue*>* task_sources, + std::vector<std::pair<base::Closure, TaskQueue*>>* tasks) { + base::MessageLoop::ScopedNestableTaskAllower allow(message_loop); + task_sources->push_back(task_queue_manager->currently_executing_task_queue()); + + for (std::pair<base::Closure, TaskQueue*>& pair : *tasks) { + pair.second->PostTask(FROM_HERE, pair.first); + } + + base::RunLoop().RunUntilIdle(); + task_sources->push_back(task_queue_manager->currently_executing_task_queue()); +} +} + +TEST_F(TaskQueueManagerTest, CurrentlyExecutingTaskQueue_NestedLoop) { + InitializeWithRealMessageLoop(3u); + + TaskQueue* queue0 = runners_[0].get(); + TaskQueue* queue1 = runners_[1].get(); + TaskQueue* queue2 = runners_[2].get(); + + std::vector<TaskQueue*> task_sources; + std::vector<std::pair<base::Closure, TaskQueue*>> + tasks_to_post_from_nested_loop; + tasks_to_post_from_nested_loop.push_back( + std::make_pair(base::Bind(&CurrentlyExecutingTaskQueueTestTask, + manager_.get(), &task_sources), + queue1)); + tasks_to_post_from_nested_loop.push_back( + std::make_pair(base::Bind(&CurrentlyExecutingTaskQueueTestTask, + manager_.get(), &task_sources), + queue2)); + + queue0->PostTask( + FROM_HERE, base::Bind(&RunloopCurrentlyExecutingTaskQueueTestTask, + message_loop_.get(), manager_.get(), &task_sources, + &tasks_to_post_from_nested_loop)); + + base::RunLoop().RunUntilIdle(); + EXPECT_THAT(task_sources, ElementsAre(queue0, queue1, queue2, queue0)); + EXPECT_EQ(nullptr, manager_->currently_executing_task_queue()); +} + +void OnTraceDataCollected(base::Closure quit_closure, + base::trace_event::TraceResultBuffer* buffer, + const scoped_refptr<base::RefCountedString>& json, + bool has_more_events) { + buffer->AddFragment(json->data()); + if (!has_more_events) + quit_closure.Run(); +} + +class TaskQueueManagerTestWithTracing : public TaskQueueManagerTest { + public: + void StartTracing(); + void StopTracing(); + std::unique_ptr<trace_analyzer::TraceAnalyzer> CreateTraceAnalyzer(); +}; + +void TaskQueueManagerTestWithTracing::StartTracing() { + base::trace_event::TraceLog::GetInstance()->SetEnabled( + base::trace_event::TraceConfig("*"), + base::trace_event::TraceLog::RECORDING_MODE); +} + +void TaskQueueManagerTestWithTracing::StopTracing() { + base::trace_event::TraceLog::GetInstance()->SetDisabled(); +} + +std::unique_ptr<trace_analyzer::TraceAnalyzer> +TaskQueueManagerTestWithTracing::CreateTraceAnalyzer() { + base::trace_event::TraceResultBuffer buffer; + base::trace_event::TraceResultBuffer::SimpleOutput trace_output; + buffer.SetOutputCallback(trace_output.GetCallback()); + base::RunLoop run_loop; + buffer.Start(); + base::trace_event::TraceLog::GetInstance()->Flush( + Bind(&OnTraceDataCollected, run_loop.QuitClosure(), + base::Unretained(&buffer))); + run_loop.Run(); + buffer.Finish(); + + return base::WrapUnique( + trace_analyzer::TraceAnalyzer::Create(trace_output.json_output)); +} + +TEST_F(TaskQueueManagerTestWithTracing, BlameContextAttribution) { + using trace_analyzer::Query; + + InitializeWithRealMessageLoop(1u); + TaskQueue* queue = runners_[0].get(); + + StartTracing(); + { + base::trace_event::BlameContext blame_context("cat", "name", "type", + "scope", 0, nullptr); + blame_context.Initialize(); + queue->SetBlameContext(&blame_context); + queue->PostTask(FROM_HERE, base::Bind(&NopTask)); + base::RunLoop().RunUntilIdle(); + } + StopTracing(); + std::unique_ptr<trace_analyzer::TraceAnalyzer> analyzer = + CreateTraceAnalyzer(); + + trace_analyzer::TraceEventVector events; + Query q = Query::EventPhaseIs(TRACE_EVENT_PHASE_ENTER_CONTEXT) || + Query::EventPhaseIs(TRACE_EVENT_PHASE_LEAVE_CONTEXT); + analyzer->FindEvents(q, &events); + + EXPECT_EQ(2u, events.size()); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_selector.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_selector.cc new file mode 100644 index 0000000..d7c5c29 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_selector.cc
@@ -0,0 +1,381 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "platform/scheduler/base/task_queue_selector.h" + +#include "base/logging.h" +#include "base/trace_event/trace_event_argument.h" +#include "platform/scheduler/base/task_queue_impl.h" +#include "platform/scheduler/base/work_queue.h" + +namespace blink { +namespace scheduler { +namespace internal { + +TaskQueueSelector::TaskQueueSelector() + : enabled_selector_(this, "enabled"), + blocked_selector_(this, "blocked"), + immediate_starvation_count_(0), + high_priority_starvation_count_(0), + num_blocked_queues_to_report_(0), + task_queue_selector_observer_(nullptr) {} + +TaskQueueSelector::~TaskQueueSelector() {} + +void TaskQueueSelector::AddQueue(internal::TaskQueueImpl* queue) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + DCHECK(queue->IsQueueEnabled()); + enabled_selector_.AddQueue(queue, TaskQueue::NORMAL_PRIORITY); +} + +void TaskQueueSelector::RemoveQueue(internal::TaskQueueImpl* queue) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + if (queue->IsQueueEnabled()) { + enabled_selector_.RemoveQueue(queue); +// The #if DCHECK_IS_ON() shouldn't be necessary but this doesn't compile on +// chromeos bots without it :( +#if DCHECK_IS_ON() + DCHECK(!blocked_selector_.CheckContainsQueueForTest(queue)); +#endif + } else if (queue->should_report_when_execution_blocked()) { + DCHECK_GT(num_blocked_queues_to_report_, 0u); + num_blocked_queues_to_report_--; + blocked_selector_.RemoveQueue(queue); +#if DCHECK_IS_ON() + DCHECK(!enabled_selector_.CheckContainsQueueForTest(queue)); +#endif + } +} + +void TaskQueueSelector::EnableQueue(internal::TaskQueueImpl* queue) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + DCHECK(queue->IsQueueEnabled()); + if (queue->should_report_when_execution_blocked()) { + DCHECK_GT(num_blocked_queues_to_report_, 0u); + num_blocked_queues_to_report_--; + blocked_selector_.RemoveQueue(queue); + } + enabled_selector_.AddQueue(queue, queue->GetQueuePriority()); + if (task_queue_selector_observer_) + task_queue_selector_observer_->OnTaskQueueEnabled(queue); +} + +void TaskQueueSelector::DisableQueue(internal::TaskQueueImpl* queue) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + DCHECK(!queue->IsQueueEnabled()); + enabled_selector_.RemoveQueue(queue); + if (queue->should_report_when_execution_blocked()) { + blocked_selector_.AddQueue(queue, queue->GetQueuePriority()); + num_blocked_queues_to_report_++; + } +} + +void TaskQueueSelector::SetQueuePriority(internal::TaskQueueImpl* queue, + TaskQueue::QueuePriority priority) { + DCHECK_LT(priority, TaskQueue::QUEUE_PRIORITY_COUNT); + DCHECK(main_thread_checker_.CalledOnValidThread()); + if (queue->IsQueueEnabled()) { + enabled_selector_.ChangeSetIndex(queue, priority); + } else if (queue->should_report_when_execution_blocked()) { + blocked_selector_.ChangeSetIndex(queue, priority); + } else { + // Normally blocked_selector_.ChangeSetIndex would assign the queue's + // priority, however if |queue->should_report_when_execution_blocked()| is + // false then the disabled queue is not in any set so we need to do it here. + queue->delayed_work_queue()->AssignSetIndex(priority); + queue->immediate_work_queue()->AssignSetIndex(priority); + } + DCHECK_EQ(priority, queue->GetQueuePriority()); +} + +TaskQueue::QueuePriority TaskQueueSelector::NextPriority( + TaskQueue::QueuePriority priority) { + DCHECK(priority < TaskQueue::QUEUE_PRIORITY_COUNT); + return static_cast<TaskQueue::QueuePriority>(static_cast<int>(priority) + 1); +} + +TaskQueueSelector::PrioritizingSelector::PrioritizingSelector( + TaskQueueSelector* task_queue_selector, + const char* name) + : task_queue_selector_(task_queue_selector), + delayed_work_queue_sets_(TaskQueue::QUEUE_PRIORITY_COUNT, name), + immediate_work_queue_sets_(TaskQueue::QUEUE_PRIORITY_COUNT, name) {} + +void TaskQueueSelector::PrioritizingSelector::AddQueue( + internal::TaskQueueImpl* queue, + TaskQueue::QueuePriority priority) { +#if DCHECK_IS_ON() + DCHECK(!CheckContainsQueueForTest(queue)); +#endif + delayed_work_queue_sets_.AddQueue(queue->delayed_work_queue(), priority); + immediate_work_queue_sets_.AddQueue(queue->immediate_work_queue(), priority); +#if DCHECK_IS_ON() + DCHECK(CheckContainsQueueForTest(queue)); +#endif +} + +void TaskQueueSelector::PrioritizingSelector::ChangeSetIndex( + internal::TaskQueueImpl* queue, + TaskQueue::QueuePriority priority) { +#if DCHECK_IS_ON() + DCHECK(CheckContainsQueueForTest(queue)); +#endif + delayed_work_queue_sets_.ChangeSetIndex(queue->delayed_work_queue(), + priority); + immediate_work_queue_sets_.ChangeSetIndex(queue->immediate_work_queue(), + priority); +#if DCHECK_IS_ON() + DCHECK(CheckContainsQueueForTest(queue)); +#endif +} + +void TaskQueueSelector::PrioritizingSelector::RemoveQueue( + internal::TaskQueueImpl* queue) { +#if DCHECK_IS_ON() + DCHECK(CheckContainsQueueForTest(queue)); +#endif + delayed_work_queue_sets_.RemoveQueue(queue->delayed_work_queue()); + immediate_work_queue_sets_.RemoveQueue(queue->immediate_work_queue()); + +#if DCHECK_IS_ON() + DCHECK(!CheckContainsQueueForTest(queue)); +#endif +} + +bool TaskQueueSelector::PrioritizingSelector:: + ChooseOldestImmediateTaskWithPriority(TaskQueue::QueuePriority priority, + WorkQueue** out_work_queue) const { + return immediate_work_queue_sets_.GetOldestQueueInSet(priority, + out_work_queue); +} + +bool TaskQueueSelector::PrioritizingSelector:: + ChooseOldestDelayedTaskWithPriority(TaskQueue::QueuePriority priority, + WorkQueue** out_work_queue) const { + return delayed_work_queue_sets_.GetOldestQueueInSet(priority, out_work_queue); +} + +bool TaskQueueSelector::PrioritizingSelector:: + ChooseOldestImmediateOrDelayedTaskWithPriority( + TaskQueue::QueuePriority priority, + bool* out_chose_delayed_over_immediate, + WorkQueue** out_work_queue) const { + WorkQueue* immediate_queue; + DCHECK_EQ(*out_chose_delayed_over_immediate, false); + if (immediate_work_queue_sets_.GetOldestQueueInSet(priority, + &immediate_queue)) { + WorkQueue* delayed_queue; + if (delayed_work_queue_sets_.GetOldestQueueInSet(priority, + &delayed_queue)) { + if (immediate_queue->ShouldRunBefore(delayed_queue)) { + *out_work_queue = immediate_queue; + } else { + *out_chose_delayed_over_immediate = true; + *out_work_queue = delayed_queue; + } + } else { + *out_work_queue = immediate_queue; + } + return true; + } + return delayed_work_queue_sets_.GetOldestQueueInSet(priority, out_work_queue); +} + +bool TaskQueueSelector::PrioritizingSelector::ChooseOldestWithPriority( + TaskQueue::QueuePriority priority, + bool* out_chose_delayed_over_immediate, + WorkQueue** out_work_queue) const { + // Select an immediate work queue if we are starving immediate tasks. + if (task_queue_selector_->immediate_starvation_count_ >= + kMaxDelayedStarvationTasks) { + if (ChooseOldestImmediateTaskWithPriority(priority, out_work_queue)) { + return true; + } + if (ChooseOldestDelayedTaskWithPriority(priority, out_work_queue)) { + return true; + } + return false; + } + return ChooseOldestImmediateOrDelayedTaskWithPriority( + priority, out_chose_delayed_over_immediate, out_work_queue); +} + +bool TaskQueueSelector::PrioritizingSelector::SelectWorkQueueToService( + TaskQueue::QueuePriority max_priority, + WorkQueue** out_work_queue, + bool* out_chose_delayed_over_immediate) { + DCHECK(task_queue_selector_->main_thread_checker_.CalledOnValidThread()); + DCHECK_EQ(*out_chose_delayed_over_immediate, false); + + // Always service the control queue if it has any work. + if (max_priority > TaskQueue::CONTROL_PRIORITY && + ChooseOldestWithPriority(TaskQueue::CONTROL_PRIORITY, + out_chose_delayed_over_immediate, + out_work_queue)) { + return true; + } + + // Select from the normal priority queue if we are starving it. + if (max_priority > TaskQueue::NORMAL_PRIORITY && + task_queue_selector_->high_priority_starvation_count_ >= + kMaxHighPriorityStarvationTasks && + ChooseOldestWithPriority(TaskQueue::NORMAL_PRIORITY, + out_chose_delayed_over_immediate, + out_work_queue)) { + return true; + } + // Otherwise choose in priority order. + for (TaskQueue::QueuePriority priority = TaskQueue::HIGH_PRIORITY; + priority < max_priority; priority = NextPriority(priority)) { + if (ChooseOldestWithPriority(priority, out_chose_delayed_over_immediate, + out_work_queue)) { + return true; + } + } + return false; +} + +#if DCHECK_IS_ON() || !defined(NDEBUG) +bool TaskQueueSelector::PrioritizingSelector::CheckContainsQueueForTest( + const internal::TaskQueueImpl* queue) const { + bool contains_delayed_work_queue = + delayed_work_queue_sets_.ContainsWorkQueueForTest( + queue->delayed_work_queue()); + + bool contains_immediate_work_queue = + immediate_work_queue_sets_.ContainsWorkQueueForTest( + queue->immediate_work_queue()); + + DCHECK_EQ(contains_delayed_work_queue, contains_immediate_work_queue); + return contains_delayed_work_queue; +} +#endif + +bool TaskQueueSelector::SelectWorkQueueToService(WorkQueue** out_work_queue) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + bool chose_delayed_over_immediate = false; + bool found_queue = enabled_selector_.SelectWorkQueueToService( + TaskQueue::QUEUE_PRIORITY_COUNT, out_work_queue, + &chose_delayed_over_immediate); + if (!found_queue) { + TrySelectingBlockedQueue(); + return false; + } + + TrySelectingBlockedQueueOverEnabledQueue(**out_work_queue); + DidSelectQueueWithPriority( + (*out_work_queue)->task_queue()->GetQueuePriority(), + chose_delayed_over_immediate); + return true; +} + +void TaskQueueSelector::TrySelectingBlockedQueue() { + DCHECK(main_thread_checker_.CalledOnValidThread()); + if (!num_blocked_queues_to_report_ || !task_queue_selector_observer_) + return; + WorkQueue* chosen_blocked_queue; + bool chose_delayed_over_immediate = false; + // There was nothing unblocked to run, see if we could have run a blocked + // task. + if (blocked_selector_.SelectWorkQueueToService( + TaskQueue::QUEUE_PRIORITY_COUNT, &chosen_blocked_queue, + &chose_delayed_over_immediate)) { + task_queue_selector_observer_->OnTriedToSelectBlockedWorkQueue( + chosen_blocked_queue); + } +} + +void TaskQueueSelector::TrySelectingBlockedQueueOverEnabledQueue( + const WorkQueue& chosen_enabled_queue) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + if (!num_blocked_queues_to_report_ || !task_queue_selector_observer_) + return; + + TaskQueue::QueuePriority max_priority = + NextPriority(chosen_enabled_queue.task_queue()->GetQueuePriority()); + + WorkQueue* chosen_blocked_queue; + bool chose_delayed_over_immediate = false; + bool found_queue = blocked_selector_.SelectWorkQueueToService( + max_priority, &chosen_blocked_queue, &chose_delayed_over_immediate); + if (!found_queue) + return; + + // Check if the chosen blocked queue has a lower numerical priority than the + // chosen enabled queue. If so we would have chosen the blocked queue (since + // zero is the highest priority). + if (chosen_blocked_queue->task_queue()->GetQueuePriority() < + chosen_enabled_queue.task_queue()->GetQueuePriority()) { + task_queue_selector_observer_->OnTriedToSelectBlockedWorkQueue( + chosen_blocked_queue); + return; + } + DCHECK_EQ(chosen_blocked_queue->task_queue()->GetQueuePriority(), + chosen_enabled_queue.task_queue()->GetQueuePriority()); + // Otherwise there was an enabled and a blocked task with the same priority. + // The one with the older enqueue order wins. + if (chosen_blocked_queue->ShouldRunBefore(&chosen_enabled_queue)) { + task_queue_selector_observer_->OnTriedToSelectBlockedWorkQueue( + chosen_blocked_queue); + } +} + +void TaskQueueSelector::DidSelectQueueWithPriority( + TaskQueue::QueuePriority priority, + bool chose_delayed_over_immediate) { + switch (priority) { + case TaskQueue::CONTROL_PRIORITY: + break; + case TaskQueue::HIGH_PRIORITY: + high_priority_starvation_count_++; + break; + case TaskQueue::NORMAL_PRIORITY: + case TaskQueue::BEST_EFFORT_PRIORITY: + high_priority_starvation_count_ = 0; + break; + default: + NOTREACHED(); + } + if (chose_delayed_over_immediate) { + immediate_starvation_count_++; + } else { + immediate_starvation_count_ = 0; + } +} + +void TaskQueueSelector::AsValueInto( + base::trace_event::TracedValue* state) const { + DCHECK(main_thread_checker_.CalledOnValidThread()); + state->SetInteger("high_priority_starvation_count", + high_priority_starvation_count_); + state->SetInteger("immediate_starvation_count", immediate_starvation_count_); + state->SetInteger("num_blocked_queues_to_report", + num_blocked_queues_to_report_); +} + +void TaskQueueSelector::SetTaskQueueSelectorObserver(Observer* observer) { + task_queue_selector_observer_ = observer; +} + +bool TaskQueueSelector::EnabledWorkQueuesEmpty() const { + DCHECK(main_thread_checker_.CalledOnValidThread()); + for (TaskQueue::QueuePriority priority = TaskQueue::CONTROL_PRIORITY; + priority < TaskQueue::QUEUE_PRIORITY_COUNT; + priority = NextPriority(priority)) { + if (!enabled_selector_.delayed_work_queue_sets()->IsSetEmpty(priority) || + !enabled_selector_.immediate_work_queue_sets()->IsSetEmpty(priority)) { + return false; + } + } + return true; +} + +void TaskQueueSelector::SetImmediateStarvationCountForTest( + size_t immediate_starvation_count) { + immediate_starvation_count_ = immediate_starvation_count; +} + +} // namespace internal +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_selector.h b/third_party/WebKit/Source/platform/scheduler/base/task_queue_selector.h new file mode 100644 index 0000000..2ebf18f --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_selector.h
@@ -0,0 +1,207 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_SELECTOR_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_SELECTOR_H_ + +#include <stddef.h> + +#include <set> + +#include "base/compiler_specific.h" +#include "base/macros.h" +#include "base/pending_task.h" +#include "base/threading/thread_checker.h" +#include "platform/scheduler/base/work_queue_sets.h" + +namespace blink { +namespace scheduler { +namespace internal { + +// TaskQueueSelector is used by the SchedulerHelper to enable prioritization +// of particular task queues. +class BLINK_PLATFORM_EXPORT TaskQueueSelector { + public: + TaskQueueSelector(); + ~TaskQueueSelector(); + + // Called to register a queue that can be selected. This function is called + // on the main thread. + void AddQueue(internal::TaskQueueImpl* queue); + + // The specified work will no longer be considered for selection. This + // function is called on the main thread. + void RemoveQueue(internal::TaskQueueImpl* queue); + + // Make |queue| eligible for selection. This function is called on the main + // thread. Must only be called if |queue| is disabled. + void EnableQueue(internal::TaskQueueImpl* queue); + + // Disable selection from |queue|. If task blocking is enabled for the queue, + // Observer::OnTriedToSelectBlockedWorkQueue will be emitted if the + // SelectWorkQueueToService tries to select this disabled queue for execution. + // Must only be called if |queue| is enabled. + void DisableQueue(internal::TaskQueueImpl* queue); + + // Called get or set the priority of |queue|. + void SetQueuePriority(internal::TaskQueueImpl* queue, + TaskQueue::QueuePriority priority); + + // Called to choose the work queue from which the next task should be taken + // and run. Return true if |out_work_queue| indicates the queue to service or + // false to avoid running any task. + // + // This function is called on the main thread. + bool SelectWorkQueueToService(WorkQueue** out_work_queue); + + // Serialize the selector state for tracing. + void AsValueInto(base::trace_event::TracedValue* state) const; + + class BLINK_PLATFORM_EXPORT Observer { + public: + virtual ~Observer() {} + + // Called when |queue| transitions from disabled to enabled. + virtual void OnTaskQueueEnabled(internal::TaskQueueImpl* queue) = 0; + + // Called when the selector tried to select a task from a disabled work + // queue. See TaskQueue::Spec::SetShouldReportWhenExecutionBlocked. A single + // call to SelectWorkQueueToService will only result in up to one + // blocking notification even if multiple disabled queues could have been + // selected. + virtual void OnTriedToSelectBlockedWorkQueue( + internal::WorkQueue* work_queue) = 0; + }; + + // Called once to set the Observer. This function is called + // on the main thread. If |observer| is null, then no callbacks will occur. + void SetTaskQueueSelectorObserver(Observer* observer); + + // Returns true if all the enabled work queues are empty. Returns false + // otherwise. + bool EnabledWorkQueuesEmpty() const; + + protected: + class BLINK_PLATFORM_EXPORT PrioritizingSelector { + public: + PrioritizingSelector(TaskQueueSelector* task_queue_selector, + const char* name); + + void ChangeSetIndex(internal::TaskQueueImpl* queue, + TaskQueue::QueuePriority priority); + void AddQueue(internal::TaskQueueImpl* queue, + TaskQueue::QueuePriority priority); + void RemoveQueue(internal::TaskQueueImpl* queue); + + bool SelectWorkQueueToService(TaskQueue::QueuePriority max_priority, + WorkQueue** out_work_queue, + bool* out_chose_delayed_over_immediate); + + WorkQueueSets* delayed_work_queue_sets() { + return &delayed_work_queue_sets_; + } + WorkQueueSets* immediate_work_queue_sets() { + return &immediate_work_queue_sets_; + } + + const WorkQueueSets* delayed_work_queue_sets() const { + return &delayed_work_queue_sets_; + } + const WorkQueueSets* immediate_work_queue_sets() const { + return &immediate_work_queue_sets_; + } + + bool ChooseOldestWithPriority(TaskQueue::QueuePriority priority, + bool* out_chose_delayed_over_immediate, + WorkQueue** out_work_queue) const; + +#if DCHECK_IS_ON() || !defined(NDEBUG) + bool CheckContainsQueueForTest(const internal::TaskQueueImpl* queue) const; +#endif + + private: + bool ChooseOldestImmediateTaskWithPriority( + TaskQueue::QueuePriority priority, + WorkQueue** out_work_queue) const; + + bool ChooseOldestDelayedTaskWithPriority(TaskQueue::QueuePriority priority, + WorkQueue** out_work_queue) const; + + // Return true if |out_queue| contains the queue with the oldest pending + // task from the set of queues of |priority|, or false if all queues of that + // priority are empty. In addition |out_chose_delayed_over_immediate| is set + // to true iff we chose a delayed work queue in favour of an immediate work + // queue. + bool ChooseOldestImmediateOrDelayedTaskWithPriority( + TaskQueue::QueuePriority priority, + bool* out_chose_delayed_over_immediate, + WorkQueue** out_work_queue) const; + + const TaskQueueSelector* task_queue_selector_; + WorkQueueSets delayed_work_queue_sets_; + WorkQueueSets immediate_work_queue_sets_; + + DISALLOW_COPY_AND_ASSIGN(PrioritizingSelector); + }; + + // Return true if |out_queue| contains the queue with the oldest pending task + // from the set of queues of |priority|, or false if all queues of that + // priority are empty. In addition |out_chose_delayed_over_immediate| is set + // to true iff we chose a delayed work queue in favour of an immediate work + // queue. This method will force select an immediate task if those are being + // starved by delayed tasks. + void SetImmediateStarvationCountForTest(size_t immediate_starvation_count); + + PrioritizingSelector* enabled_selector_for_test() { + return &enabled_selector_; + } + + private: + // Returns the priority which is next after |priority|. + static TaskQueue::QueuePriority NextPriority( + TaskQueue::QueuePriority priority); + + bool SelectWorkQueueToServiceInternal(WorkQueue** out_work_queue); + + // Called whenever the selector chooses a task queue for execution with the + // priority |priority|. + void DidSelectQueueWithPriority(TaskQueue::QueuePriority priority, + bool chose_delayed_over_immediate); + + // No enabled queue could be selected, check if we could have chosen a + // disabled (blocked) work queue instead. + void TrySelectingBlockedQueue(); + + // Check if we could have chosen a disabled (blocked) work queue instead. + // |chosen_enabled_queue| is the enabled queue that got chosen. + void TrySelectingBlockedQueueOverEnabledQueue( + const WorkQueue& chosen_enabled_queue); + + // Number of high priority tasks which can be run before a normal priority + // task should be selected to prevent starvation. + // TODO(rmcilroy): Check if this is a good value. + static const size_t kMaxHighPriorityStarvationTasks = 5; + + // Maximum number of delayed tasks tasks which can be run while there's a + // waiting non-delayed task. + static const size_t kMaxDelayedStarvationTasks = 3; + + private: + base::ThreadChecker main_thread_checker_; + + PrioritizingSelector enabled_selector_; + PrioritizingSelector blocked_selector_; + size_t immediate_starvation_count_; + size_t high_priority_starvation_count_; + size_t num_blocked_queues_to_report_; + + Observer* task_queue_selector_observer_; // NOT OWNED + DISALLOW_COPY_AND_ASSIGN(TaskQueueSelector); +}; + +} // namespace internal +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_SELECTOR_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_selector_unittest.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_selector_unittest.cc new file mode 100644 index 0000000..fb47901 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_selector_unittest.cc
@@ -0,0 +1,493 @@ +// 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 "platform/scheduler/base/task_queue_selector.h" + +#include <stddef.h> + +#include <memory> + +#include "base/bind.h" +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "base/pending_task.h" +#include "platform/scheduler/base/task_queue_impl.h" +#include "platform/scheduler/base/virtual_time_domain.h" +#include "platform/scheduler/base/work_queue.h" +#include "platform/scheduler/base/work_queue_sets.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::_; + +namespace blink { +namespace scheduler { +namespace internal { + +class MockObserver : public TaskQueueSelector::Observer { + public: + MockObserver() {} + virtual ~MockObserver() {} + + MOCK_METHOD1(OnTaskQueueEnabled, void(internal::TaskQueueImpl*)); + MOCK_METHOD1(OnTriedToSelectBlockedWorkQueue, void(internal::WorkQueue*)); + + private: + DISALLOW_COPY_AND_ASSIGN(MockObserver); +}; + +class TaskQueueSelectorForTest : public TaskQueueSelector { + public: + using TaskQueueSelector::SetImmediateStarvationCountForTest; + using TaskQueueSelector::PrioritizingSelector; + using TaskQueueSelector::enabled_selector_for_test; +}; + +class TaskQueueSelectorTest : public testing::Test { + public: + TaskQueueSelectorTest() + : test_closure_(base::Bind(&TaskQueueSelectorTest::TestFunction)) {} + ~TaskQueueSelectorTest() override {} + + TaskQueueSelectorForTest::PrioritizingSelector* enabled_selector() { + return selector_.enabled_selector_for_test(); + } + + WorkQueueSets* delayed_work_queue_sets() { + return enabled_selector()->delayed_work_queue_sets(); + } + WorkQueueSets* immediate_work_queue_sets() { + return enabled_selector()->immediate_work_queue_sets(); + } + + void PushTasks(const size_t queue_indices[], size_t num_tasks) { + std::set<size_t> changed_queue_set; + for (size_t i = 0; i < num_tasks; i++) { + changed_queue_set.insert(queue_indices[i]); + task_queues_[queue_indices[i]]->immediate_work_queue()->Push( + TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(), 0, + true, i)); + } + } + + void PushTasksWithEnqueueOrder(const size_t queue_indices[], + const size_t enqueue_orders[], + size_t num_tasks) { + std::set<size_t> changed_queue_set; + for (size_t i = 0; i < num_tasks; i++) { + changed_queue_set.insert(queue_indices[i]); + task_queues_[queue_indices[i]]->immediate_work_queue()->Push( + TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(), 0, + true, enqueue_orders[i])); + } + } + + std::vector<size_t> PopTasks() { + std::vector<size_t> order; + WorkQueue* chosen_work_queue; + while (selector_.SelectWorkQueueToService(&chosen_work_queue)) { + size_t chosen_queue_index = + queue_to_index_map_.find(chosen_work_queue->task_queue())->second; + order.push_back(chosen_queue_index); + chosen_work_queue->PopTaskForTest(); + immediate_work_queue_sets()->OnPopQueue(chosen_work_queue); + } + return order; + } + + static void TestFunction() {} + + void EnableQueue(TaskQueueImpl* queue) { + queue->SetQueueEnabled(true); + selector_.EnableQueue(queue); + } + + void DisableQueue(TaskQueueImpl* queue) { + queue->SetQueueEnabled(false); + selector_.DisableQueue(queue); + } + + protected: + void SetUp() final { + virtual_time_domain_ = base::WrapUnique<VirtualTimeDomain>( + new VirtualTimeDomain(nullptr, base::TimeTicks())); + for (size_t i = 0; i < kTaskQueueCount; i++) { + scoped_refptr<TaskQueueImpl> task_queue = make_scoped_refptr( + new TaskQueueImpl(nullptr, virtual_time_domain_.get(), + TaskQueue::Spec("test queue"), "test", "test")); + selector_.AddQueue(task_queue.get()); + task_queues_.push_back(task_queue); + } + for (size_t i = 0; i < kTaskQueueCount; i++) { + EXPECT_EQ(TaskQueue::NORMAL_PRIORITY, task_queues_[i]->GetQueuePriority()) + << i; + queue_to_index_map_.insert(std::make_pair(task_queues_[i].get(), i)); + } + } + + void TearDown() final { + for (scoped_refptr<TaskQueueImpl>& task_queue : task_queues_) { + task_queue->UnregisterTaskQueue(); + // Note since this test doesn't have a TaskQueueManager we need to + // manually remove |task_queue| from the |selector_|. Normally + // UnregisterTaskQueue would do that. + selector_.RemoveQueue(task_queue.get()); + } + } + + scoped_refptr<TaskQueueImpl> NewTaskQueueWithBlockReporting() { + return make_scoped_refptr(new TaskQueueImpl( + nullptr, virtual_time_domain_.get(), + TaskQueue::Spec("test queue").SetShouldReportWhenExecutionBlocked(true), + "test", "test")); + } + + const size_t kTaskQueueCount = 5; + base::Closure test_closure_; + TaskQueueSelectorForTest selector_; + std::unique_ptr<VirtualTimeDomain> virtual_time_domain_; + std::vector<scoped_refptr<TaskQueueImpl>> task_queues_; + std::map<TaskQueueImpl*, size_t> queue_to_index_map_; +}; + +TEST_F(TaskQueueSelectorTest, TestDefaultPriority) { + size_t queue_order[] = {4, 3, 2, 1, 0}; + PushTasks(queue_order, 5); + EXPECT_THAT(PopTasks(), testing::ElementsAre(4, 3, 2, 1, 0)); +} + +TEST_F(TaskQueueSelectorTest, TestHighPriority) { + size_t queue_order[] = {0, 1, 2, 3, 4}; + PushTasks(queue_order, 5); + selector_.SetQueuePriority(task_queues_[2].get(), TaskQueue::HIGH_PRIORITY); + EXPECT_THAT(PopTasks(), testing::ElementsAre(2, 0, 1, 3, 4)); +} + +TEST_F(TaskQueueSelectorTest, TestBestEffortPriority) { + size_t queue_order[] = {0, 1, 2, 3, 4}; + PushTasks(queue_order, 5); + selector_.SetQueuePriority(task_queues_[0].get(), + TaskQueue::BEST_EFFORT_PRIORITY); + selector_.SetQueuePriority(task_queues_[2].get(), TaskQueue::HIGH_PRIORITY); + EXPECT_THAT(PopTasks(), testing::ElementsAre(2, 1, 3, 4, 0)); +} + +TEST_F(TaskQueueSelectorTest, TestControlPriority) { + size_t queue_order[] = {0, 1, 2, 3, 4}; + PushTasks(queue_order, 5); + selector_.SetQueuePriority(task_queues_[4].get(), + TaskQueue::CONTROL_PRIORITY); + EXPECT_EQ(TaskQueue::CONTROL_PRIORITY, task_queues_[4]->GetQueuePriority()); + selector_.SetQueuePriority(task_queues_[2].get(), TaskQueue::HIGH_PRIORITY); + EXPECT_EQ(TaskQueue::HIGH_PRIORITY, task_queues_[2]->GetQueuePriority()); + EXPECT_THAT(PopTasks(), testing::ElementsAre(4, 2, 0, 1, 3)); +} + +TEST_F(TaskQueueSelectorTest, TestObserverWithEnabledQueue) { + DisableQueue(task_queues_[1].get()); + MockObserver mock_observer; + selector_.SetTaskQueueSelectorObserver(&mock_observer); + EXPECT_CALL(mock_observer, OnTaskQueueEnabled(_)).Times(1); + EnableQueue(task_queues_[1].get()); +} + +TEST_F(TaskQueueSelectorTest, + TestObserverWithSetQueuePriorityAndQueueAlreadyEnabled) { + selector_.SetQueuePriority(task_queues_[1].get(), TaskQueue::HIGH_PRIORITY); + MockObserver mock_observer; + selector_.SetTaskQueueSelectorObserver(&mock_observer); + EXPECT_CALL(mock_observer, OnTaskQueueEnabled(_)).Times(0); + selector_.SetQueuePriority(task_queues_[1].get(), TaskQueue::NORMAL_PRIORITY); +} + +TEST_F(TaskQueueSelectorTest, TestDisableEnable) { + MockObserver mock_observer; + selector_.SetTaskQueueSelectorObserver(&mock_observer); + + size_t queue_order[] = {0, 1, 2, 3, 4}; + PushTasks(queue_order, 5); + DisableQueue(task_queues_[2].get()); + DisableQueue(task_queues_[4].get()); + // Disabling a queue should not affect its priority. + EXPECT_EQ(TaskQueue::NORMAL_PRIORITY, task_queues_[2]->GetQueuePriority()); + EXPECT_EQ(TaskQueue::NORMAL_PRIORITY, task_queues_[4]->GetQueuePriority()); + EXPECT_THAT(PopTasks(), testing::ElementsAre(0, 1, 3)); + + EXPECT_CALL(mock_observer, OnTaskQueueEnabled(_)).Times(2); + EnableQueue(task_queues_[2].get()); + selector_.SetQueuePriority(task_queues_[2].get(), + TaskQueue::BEST_EFFORT_PRIORITY); + EXPECT_THAT(PopTasks(), testing::ElementsAre(2)); + EnableQueue(task_queues_[4].get()); + EXPECT_THAT(PopTasks(), testing::ElementsAre(4)); +} + +TEST_F(TaskQueueSelectorTest, TestDisableChangePriorityThenEnable) { + EXPECT_TRUE(task_queues_[2]->delayed_work_queue()->Empty()); + EXPECT_TRUE(task_queues_[2]->immediate_work_queue()->Empty()); + + DisableQueue(task_queues_[2].get()); + selector_.SetQueuePriority(task_queues_[2].get(), TaskQueue::HIGH_PRIORITY); + + size_t queue_order[] = {0, 1, 2, 3, 4}; + PushTasks(queue_order, 5); + + EXPECT_TRUE(task_queues_[2]->delayed_work_queue()->Empty()); + EXPECT_FALSE(task_queues_[2]->immediate_work_queue()->Empty()); + EnableQueue(task_queues_[2].get()); + + EXPECT_EQ(TaskQueue::HIGH_PRIORITY, task_queues_[2]->GetQueuePriority()); + EXPECT_THAT(PopTasks(), testing::ElementsAre(2, 0, 1, 3, 4)); +} + +TEST_F(TaskQueueSelectorTest, TestEmptyQueues) { + WorkQueue* chosen_work_queue = nullptr; + EXPECT_FALSE(selector_.SelectWorkQueueToService(&chosen_work_queue)); + + // Test only disabled queues. + size_t queue_order[] = {0}; + PushTasks(queue_order, 1); + task_queues_[0]->SetQueueEnabled(false); + selector_.DisableQueue(task_queues_[0].get()); + EXPECT_FALSE(selector_.SelectWorkQueueToService(&chosen_work_queue)); +} + +TEST_F(TaskQueueSelectorTest, TestAge) { + size_t enqueue_order[] = {10, 1, 2, 9, 4}; + size_t queue_order[] = {0, 1, 2, 3, 4}; + PushTasksWithEnqueueOrder(queue_order, enqueue_order, 5); + EXPECT_THAT(PopTasks(), testing::ElementsAre(1, 2, 4, 3, 0)); +} + +TEST_F(TaskQueueSelectorTest, TestControlStarvesOthers) { + size_t queue_order[] = {0, 1, 2, 3}; + PushTasks(queue_order, 4); + selector_.SetQueuePriority(task_queues_[3].get(), + TaskQueue::CONTROL_PRIORITY); + selector_.SetQueuePriority(task_queues_[2].get(), TaskQueue::HIGH_PRIORITY); + selector_.SetQueuePriority(task_queues_[1].get(), + TaskQueue::BEST_EFFORT_PRIORITY); + for (int i = 0; i < 100; i++) { + WorkQueue* chosen_work_queue = nullptr; + EXPECT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue)); + EXPECT_EQ(task_queues_[3].get(), chosen_work_queue->task_queue()); + // Don't remove task from queue to simulate all queues still being full. + } +} + +TEST_F(TaskQueueSelectorTest, TestHighPriorityDoesNotStarveNormal) { + size_t queue_order[] = {0, 1, 2}; + PushTasks(queue_order, 3); + selector_.SetQueuePriority(task_queues_[2].get(), TaskQueue::HIGH_PRIORITY); + selector_.SetQueuePriority(task_queues_[1].get(), + TaskQueue::BEST_EFFORT_PRIORITY); + size_t counts[] = {0, 0, 0}; + for (int i = 0; i < 100; i++) { + WorkQueue* chosen_work_queue = nullptr; + EXPECT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue)); + size_t chosen_queue_index = + queue_to_index_map_.find(chosen_work_queue->task_queue())->second; + counts[chosen_queue_index]++; + // Don't remove task from queue to simulate all queues still being full. + } + EXPECT_GT(counts[0], 0ul); // Check high doesn't starve normal. + EXPECT_GT(counts[2], counts[0]); // Check high gets more chance to run. + EXPECT_EQ(0ul, counts[1]); // Check best effort is starved. +} + +TEST_F(TaskQueueSelectorTest, TestBestEffortGetsStarved) { + size_t queue_order[] = {0, 1}; + PushTasks(queue_order, 2); + selector_.SetQueuePriority(task_queues_[0].get(), + TaskQueue::BEST_EFFORT_PRIORITY); + EXPECT_EQ(TaskQueue::NORMAL_PRIORITY, task_queues_[1]->GetQueuePriority()); + WorkQueue* chosen_work_queue = nullptr; + for (int i = 0; i < 100; i++) { + EXPECT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue)); + EXPECT_EQ(task_queues_[1].get(), chosen_work_queue->task_queue()); + // Don't remove task from queue to simulate all queues still being full. + } + selector_.SetQueuePriority(task_queues_[1].get(), TaskQueue::HIGH_PRIORITY); + for (int i = 0; i < 100; i++) { + EXPECT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue)); + EXPECT_EQ(task_queues_[1].get(), chosen_work_queue->task_queue()); + // Don't remove task from queue to simulate all queues still being full. + } + selector_.SetQueuePriority(task_queues_[1].get(), + TaskQueue::CONTROL_PRIORITY); + for (int i = 0; i < 100; i++) { + EXPECT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue)); + EXPECT_EQ(task_queues_[1].get(), chosen_work_queue->task_queue()); + // Don't remove task from queue to simulate all queues still being full. + } +} + +TEST_F(TaskQueueSelectorTest, EnabledWorkQueuesEmpty) { + EXPECT_TRUE(selector_.EnabledWorkQueuesEmpty()); + size_t queue_order[] = {0, 1}; + PushTasks(queue_order, 2); + + EXPECT_FALSE(selector_.EnabledWorkQueuesEmpty()); + PopTasks(); + EXPECT_TRUE(selector_.EnabledWorkQueuesEmpty()); +} + +TEST_F(TaskQueueSelectorTest, EnabledWorkQueuesEmpty_ControlPriority) { + size_t queue_order[] = {0}; + PushTasks(queue_order, 1); + + selector_.SetQueuePriority(task_queues_[0].get(), + TaskQueue::CONTROL_PRIORITY); + + EXPECT_FALSE(selector_.EnabledWorkQueuesEmpty()); +} + +TEST_F(TaskQueueSelectorTest, ChooseOldestWithPriority_Empty) { + WorkQueue* chosen_work_queue = nullptr; + bool chose_delayed_over_immediate = false; + EXPECT_FALSE(enabled_selector()->ChooseOldestWithPriority( + TaskQueue::NORMAL_PRIORITY, &chose_delayed_over_immediate, + &chosen_work_queue)); + EXPECT_FALSE(chose_delayed_over_immediate); +} + +TEST_F(TaskQueueSelectorTest, ChooseOldestWithPriority_OnlyDelayed) { + task_queues_[0]->delayed_work_queue()->Push(TaskQueueImpl::Task( + FROM_HERE, test_closure_, base::TimeTicks(), 0, true, 0)); + + WorkQueue* chosen_work_queue = nullptr; + bool chose_delayed_over_immediate = false; + EXPECT_TRUE(enabled_selector()->ChooseOldestWithPriority( + TaskQueue::NORMAL_PRIORITY, &chose_delayed_over_immediate, + &chosen_work_queue)); + EXPECT_EQ(chosen_work_queue, task_queues_[0]->delayed_work_queue()); + EXPECT_FALSE(chose_delayed_over_immediate); +} + +TEST_F(TaskQueueSelectorTest, ChooseOldestWithPriority_OnlyImmediate) { + task_queues_[0]->immediate_work_queue()->Push(TaskQueueImpl::Task( + FROM_HERE, test_closure_, base::TimeTicks(), 0, true, 0)); + + WorkQueue* chosen_work_queue = nullptr; + bool chose_delayed_over_immediate = false; + EXPECT_TRUE(enabled_selector()->ChooseOldestWithPriority( + TaskQueue::NORMAL_PRIORITY, &chose_delayed_over_immediate, + &chosen_work_queue)); + EXPECT_EQ(chosen_work_queue, task_queues_[0]->immediate_work_queue()); + EXPECT_FALSE(chose_delayed_over_immediate); +} + +TEST_F(TaskQueueSelectorTest, TestObserverWithOneBlockedQueue) { + TaskQueueSelectorForTest selector; + MockObserver mock_observer; + selector.SetTaskQueueSelectorObserver(&mock_observer); + + scoped_refptr<TaskQueueImpl> task_queue(NewTaskQueueWithBlockReporting()); + selector.AddQueue(task_queue.get()); + task_queue->SetQueueEnabled(false); + selector.DisableQueue(task_queue.get()); + + task_queue->immediate_work_queue()->PushAndSetEnqueueOrder( + TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(), 0, true), + 0); + + WorkQueue* chosen_work_queue; + EXPECT_CALL(mock_observer, OnTriedToSelectBlockedWorkQueue(_)).Times(1); + EXPECT_FALSE(selector.SelectWorkQueueToService(&chosen_work_queue)); + + task_queue->UnregisterTaskQueue(); + selector.RemoveQueue(task_queue.get()); +} + +TEST_F(TaskQueueSelectorTest, TestObserverWithTwoBlockedQueues) { + TaskQueueSelectorForTest selector; + MockObserver mock_observer; + selector.SetTaskQueueSelectorObserver(&mock_observer); + + scoped_refptr<TaskQueueImpl> task_queue(NewTaskQueueWithBlockReporting()); + scoped_refptr<TaskQueueImpl> task_queue2(NewTaskQueueWithBlockReporting()); + selector.AddQueue(task_queue.get()); + selector.AddQueue(task_queue2.get()); + task_queue->SetQueueEnabled(false); + task_queue2->SetQueueEnabled(false); + selector.DisableQueue(task_queue.get()); + selector.DisableQueue(task_queue2.get()); + selector.SetQueuePriority(task_queue2.get(), TaskQueue::CONTROL_PRIORITY); + + task_queue->immediate_work_queue()->PushAndSetEnqueueOrder( + TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(), 0, true), + 0); + task_queue2->immediate_work_queue()->PushAndSetEnqueueOrder( + TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(), 0, true), + 0); + + // Should still only see one call to OnTriedToSelectBlockedWorkQueue. + WorkQueue* chosen_work_queue; + EXPECT_CALL(mock_observer, OnTriedToSelectBlockedWorkQueue(_)).Times(1); + EXPECT_FALSE(selector.SelectWorkQueueToService(&chosen_work_queue)); + testing::Mock::VerifyAndClearExpectations(&mock_observer); + + // Removing the second queue and selecting again should result in another + // notification. + task_queue->UnregisterTaskQueue(); + selector.RemoveQueue(task_queue.get()); + EXPECT_CALL(mock_observer, OnTriedToSelectBlockedWorkQueue(_)).Times(1); + EXPECT_FALSE(selector.SelectWorkQueueToService(&chosen_work_queue)); + + task_queue2->UnregisterTaskQueue(); + selector.RemoveQueue(task_queue2.get()); +} + +struct ChooseOldestWithPriorityTestParam { + int delayed_task_enqueue_order; + int immediate_task_enqueue_order; + int immediate_starvation_count; + const char* expected_work_queue_name; + bool expected_did_starve_immediate_queue; +}; + +static const ChooseOldestWithPriorityTestParam + kChooseOldestWithPriorityTestCases[] = { + {1, 2, 0, "delayed", true}, {1, 2, 1, "delayed", true}, + {1, 2, 2, "delayed", true}, {1, 2, 3, "immediate", false}, + {1, 2, 4, "immediate", false}, {2, 1, 4, "immediate", false}, + {2, 1, 4, "immediate", false}, +}; + +class ChooseOldestWithPriorityTest + : public TaskQueueSelectorTest, + public testing::WithParamInterface<ChooseOldestWithPriorityTestParam> {}; + +TEST_P(ChooseOldestWithPriorityTest, RoundRobinTest) { + task_queues_[0]->immediate_work_queue()->Push( + TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(), + GetParam().immediate_task_enqueue_order, true, + GetParam().immediate_task_enqueue_order)); + + task_queues_[0]->delayed_work_queue()->Push( + TaskQueueImpl::Task(FROM_HERE, test_closure_, base::TimeTicks(), + GetParam().delayed_task_enqueue_order, true, + GetParam().delayed_task_enqueue_order)); + + selector_.SetImmediateStarvationCountForTest( + GetParam().immediate_starvation_count); + + WorkQueue* chosen_work_queue = nullptr; + bool chose_delayed_over_immediate = false; + EXPECT_TRUE(enabled_selector()->ChooseOldestWithPriority( + TaskQueue::NORMAL_PRIORITY, &chose_delayed_over_immediate, + &chosen_work_queue)); + EXPECT_EQ(chosen_work_queue->task_queue(), task_queues_[0].get()); + EXPECT_STREQ(chosen_work_queue->name(), GetParam().expected_work_queue_name); + EXPECT_EQ(chose_delayed_over_immediate, + GetParam().expected_did_starve_immediate_queue); +} + +INSTANTIATE_TEST_CASE_P(ChooseOldestWithPriorityTest, + ChooseOldestWithPriorityTest, + testing::ValuesIn(kChooseOldestWithPriorityTestCases)); + +} // namespace internal +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_time_tracker.h b/third_party/WebKit/Source/platform/scheduler/base/task_time_tracker.h new file mode 100644 index 0000000..561241f7 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/task_time_tracker.h
@@ -0,0 +1,29 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TASK_TIME_TRACKER_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TASK_TIME_TRACKER_H_ + +#include "base/time/time.h" +#include "public/platform/WebCommon.h" + +namespace blink { +namespace scheduler { + +class BLINK_PLATFORM_EXPORT TaskTimeTracker { + public: + TaskTimeTracker() {} + virtual ~TaskTimeTracker() {} + + virtual void ReportTaskTime(base::TimeTicks startTime, + base::TimeTicks endTime) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(TaskTimeTracker); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TASK_TIME_TRACKER_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/base/test_count_uses_time_source.cc b/third_party/WebKit/Source/platform/scheduler/base/test_count_uses_time_source.cc new file mode 100644 index 0000000..28f82a8 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/test_count_uses_time_source.cc
@@ -0,0 +1,22 @@ +// 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 "platform/scheduler/base/test_count_uses_time_source.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace blink { +namespace scheduler { + +TestCountUsesTimeSource::TestCountUsesTimeSource() : now_calls_count_(0) {} + +TestCountUsesTimeSource::~TestCountUsesTimeSource() {} + +base::TimeTicks TestCountUsesTimeSource::NowTicks() { + now_calls_count_++; + // Don't return 0, as it triggers some assertions. + return base::TimeTicks() + base::TimeDelta::FromSeconds(1); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/base/test_count_uses_time_source.h b/third_party/WebKit/Source/platform/scheduler/base/test_count_uses_time_source.h new file mode 100644 index 0000000..cdefe0e --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/test_count_uses_time_source.h
@@ -0,0 +1,31 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TEST_COUNT_USES_TIME_SOURCE_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TEST_COUNT_USES_TIME_SOURCE_H_ + +#include "base/macros.h" +#include "base/time/tick_clock.h" + +namespace blink { +namespace scheduler { + +class TestCountUsesTimeSource : public base::TickClock { + public: + explicit TestCountUsesTimeSource(); + ~TestCountUsesTimeSource() override; + + base::TimeTicks NowTicks() override; + int now_calls_count() { return now_calls_count_; } + + private: + DISALLOW_COPY_AND_ASSIGN(TestCountUsesTimeSource); + + int now_calls_count_; +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TEST_COUNT_USES_TIME_SOURCE_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/base/test_task_time_tracker.h b/third_party/WebKit/Source/platform/scheduler/base/test_task_time_tracker.h new file mode 100644 index 0000000..1558923 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/test_task_time_tracker.h
@@ -0,0 +1,23 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TEST_TASK_TIME_TRACKER_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TEST_TASK_TIME_TRACKER_H_ + +#include "base/time/time.h" +#include "platform/scheduler/base/task_time_tracker.h" + +namespace blink { +namespace scheduler { + +class TestTaskTimeTracker : public TaskTimeTracker { + public: + void ReportTaskTime(base::TimeTicks startTime, + base::TimeTicks endTime) override {} +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TEST_TASK_TIME_TRACKER_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/base/test_time_source.cc b/third_party/WebKit/Source/platform/scheduler/base/test_time_source.cc new file mode 100644 index 0000000..ea193a4 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/test_time_source.cc
@@ -0,0 +1,22 @@ +// 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 "platform/scheduler/base/test_time_source.h" + +namespace blink { +namespace scheduler { + +TestTimeSource::TestTimeSource(base::SimpleTestTickClock* time_source) + : time_source_(time_source) { + DCHECK(time_source_); +} + +TestTimeSource::~TestTimeSource() {} + +base::TimeTicks TestTimeSource::NowTicks() { + return time_source_->NowTicks(); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/base/test_time_source.h b/third_party/WebKit/Source/platform/scheduler/base/test_time_source.h new file mode 100644 index 0000000..2148cfc --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/test_time_source.h
@@ -0,0 +1,33 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TEST_TIME_SOURCE_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TEST_TIME_SOURCE_H_ + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/test/simple_test_tick_clock.h" +#include "base/time/tick_clock.h" + +namespace blink { +namespace scheduler { + +class TestTimeSource : public base::TickClock { + public: + explicit TestTimeSource(base::SimpleTestTickClock* time_source); + ~TestTimeSource() override; + + base::TimeTicks NowTicks() override; + + private: + // Not owned. + base::SimpleTestTickClock* time_source_; + + DISALLOW_COPY_AND_ASSIGN(TestTimeSource); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TEST_TIME_SOURCE_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/base/time_domain.cc b/third_party/WebKit/Source/platform/scheduler/base/time_domain.cc new file mode 100644 index 0000000..539fca26 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/time_domain.cc
@@ -0,0 +1,222 @@ +// 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 "platform/scheduler/base/time_domain.h" + +#include <set> + +#include "platform/scheduler/base/task_queue_impl.h" +#include "platform/scheduler/base/task_queue_manager_delegate.h" +#include "platform/scheduler/base/work_queue.h" + +namespace blink { +namespace scheduler { + +TimeDomain::TimeDomain(Observer* observer) : observer_(observer) {} + +TimeDomain::~TimeDomain() { + DCHECK(main_thread_checker_.CalledOnValidThread()); +} + +void TimeDomain::RegisterQueue(internal::TaskQueueImpl* queue) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + DCHECK_EQ(queue->GetTimeDomain(), this); +} + +void TimeDomain::UnregisterQueue(internal::TaskQueueImpl* queue) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + DCHECK_EQ(queue->GetTimeDomain(), this); + UnregisterAsUpdatableTaskQueue(queue); + + // We need to remove |task_queue| from delayed_wakeup_multimap_ which is a + // little awkward since it's keyed by time. O(n) running time. + for (DelayedWakeupMultimap::iterator iter = delayed_wakeup_multimap_.begin(); + iter != delayed_wakeup_multimap_.end();) { + if (iter->second == queue) { + // O(1) amortized. + iter = delayed_wakeup_multimap_.erase(iter); + } else { + iter++; + } + } +} + +void TimeDomain::MigrateQueue(internal::TaskQueueImpl* queue, + TimeDomain* destination_time_domain) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + DCHECK_EQ(queue->GetTimeDomain(), this); + DCHECK(destination_time_domain); + + // Make sure we remember to update |queue| if it's got incoming immediate + // work. + if (UnregisterAsUpdatableTaskQueue(queue)) + destination_time_domain->updatable_queue_set_.insert(queue); + + base::TimeTicks destination_now = destination_time_domain->Now(); + // We need to remove |task_queue| from delayed_wakeup_multimap_ which is a + // little awkward since it's keyed by time. O(n) running time. + for (DelayedWakeupMultimap::iterator iter = delayed_wakeup_multimap_.begin(); + iter != delayed_wakeup_multimap_.end();) { + if (iter->second == queue) { + destination_time_domain->ScheduleDelayedWork(queue, iter->first, + destination_now); + // O(1) amortized. + iter = delayed_wakeup_multimap_.erase(iter); + } else { + iter++; + } + } +} + +void TimeDomain::ScheduleDelayedWork(internal::TaskQueueImpl* queue, + base::TimeTicks delayed_run_time, + base::TimeTicks now) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + if (delayed_wakeup_multimap_.empty() || + delayed_run_time < delayed_wakeup_multimap_.begin()->first) { + base::TimeDelta delay = std::max(base::TimeDelta(), delayed_run_time - now); + RequestWakeup(now, delay); + } + + delayed_wakeup_multimap_.insert(std::make_pair(delayed_run_time, queue)); + if (observer_) + observer_->OnTimeDomainHasDelayedWork(); +} + +void TimeDomain::RegisterAsUpdatableTaskQueue(internal::TaskQueueImpl* queue) { + { + base::AutoLock lock(newly_updatable_lock_); + newly_updatable_.push_back(queue); + } + if (observer_) + observer_->OnTimeDomainHasImmediateWork(); +} + +bool TimeDomain::UnregisterAsUpdatableTaskQueue( + internal::TaskQueueImpl* queue) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + + bool was_updatable = updatable_queue_set_.erase(queue) != 0; + + base::AutoLock lock(newly_updatable_lock_); + // Remove all copies of |queue| from |newly_updatable_|. + for (size_t i = 0; i < newly_updatable_.size();) { + if (newly_updatable_[i] == queue) { + // Move last element into slot #i and then compact. + newly_updatable_[i] = newly_updatable_.back(); + newly_updatable_.pop_back(); + was_updatable = true; + } else { + i++; + } + } + return was_updatable; +} + +void TimeDomain::UpdateWorkQueues( + bool should_trigger_wakeup, + const internal::TaskQueueImpl::Task* previous_task, + LazyNow lazy_now) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + + // Move any ready delayed tasks into the Incoming queues. + WakeupReadyDelayedQueues(&lazy_now, should_trigger_wakeup, previous_task); + + MoveNewlyUpdatableQueuesIntoUpdatableQueueSet(); + + auto iter = updatable_queue_set_.begin(); + while (iter != updatable_queue_set_.end()) { + internal::TaskQueueImpl* queue = *iter++; + // NOTE Update work queue may erase itself from |updatable_queue_set_|. + // This is fine, erasing an element won't invalidate any interator, as long + // as the iterator isn't the element being delated. + if (queue->immediate_work_queue()->Empty()) + queue->UpdateImmediateWorkQueue(should_trigger_wakeup, previous_task); + } +} + +void TimeDomain::MoveNewlyUpdatableQueuesIntoUpdatableQueueSet() { + DCHECK(main_thread_checker_.CalledOnValidThread()); + base::AutoLock lock(newly_updatable_lock_); + while (!newly_updatable_.empty()) { + updatable_queue_set_.insert(newly_updatable_.back()); + newly_updatable_.pop_back(); + } +} + +void TimeDomain::WakeupReadyDelayedQueues( + LazyNow* lazy_now, + bool should_trigger_wakeup, + const internal::TaskQueueImpl::Task* previous_task) { + DCHECK(main_thread_checker_.CalledOnValidThread()); + // Wake up any queues with pending delayed work. Note std::multipmap stores + // the elements sorted by key, so the begin() iterator points to the earliest + // queue to wakeup. + std::set<internal::TaskQueueImpl*> dedup_set; + while (!delayed_wakeup_multimap_.empty()) { + DelayedWakeupMultimap::iterator next_wakeup = + delayed_wakeup_multimap_.begin(); + if (next_wakeup->first > lazy_now->Now()) + break; + // A queue could have any number of delayed tasks pending so it's worthwhile + // deduping calls to UpdateDelayedWorkQueue since it takes a lock. + // NOTE the order in which these are called matters since the order + // in which EnqueueTaskLocks is called is respected when choosing which + // queue to execute a task from. + if (dedup_set.insert(next_wakeup->second).second) { + next_wakeup->second->UpdateDelayedWorkQueue( + lazy_now, should_trigger_wakeup, previous_task); + } + delayed_wakeup_multimap_.erase(next_wakeup); + } +} + +void TimeDomain::ClearExpiredWakeups() { + DCHECK(main_thread_checker_.CalledOnValidThread()); + LazyNow lazy_now(CreateLazyNow()); + while (!delayed_wakeup_multimap_.empty()) { + DelayedWakeupMultimap::iterator next_wakeup = + delayed_wakeup_multimap_.begin(); + if (next_wakeup->first > lazy_now.Now()) + break; + delayed_wakeup_multimap_.erase(next_wakeup); + } +} + +bool TimeDomain::NextScheduledRunTime(base::TimeTicks* out_time) const { + DCHECK(main_thread_checker_.CalledOnValidThread()); + if (delayed_wakeup_multimap_.empty()) + return false; + + *out_time = delayed_wakeup_multimap_.begin()->first; + return true; +} + +bool TimeDomain::NextScheduledTaskQueue(TaskQueue** out_task_queue) const { + DCHECK(main_thread_checker_.CalledOnValidThread()); + if (delayed_wakeup_multimap_.empty()) + return false; + + *out_task_queue = delayed_wakeup_multimap_.begin()->second; + return true; +} + +void TimeDomain::AsValueInto(base::trace_event::TracedValue* state) const { + state->BeginDictionary(); + state->SetString("name", GetName()); + state->BeginArray("updatable_queue_set"); + for (auto* queue : updatable_queue_set_) + state->AppendString(queue->GetName()); + state->EndArray(); + state->SetInteger("registered_delay_count", delayed_wakeup_multimap_.size()); + if (!delayed_wakeup_multimap_.empty()) { + base::TimeDelta delay = delayed_wakeup_multimap_.begin()->first - Now(); + state->SetDouble("next_delay_ms", delay.InMillisecondsF()); + } + AsValueIntoInternal(state); + state->EndDictionary(); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/base/time_domain.h b/third_party/WebKit/Source/platform/scheduler/base/time_domain.h new file mode 100644 index 0000000..12ba4c9 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/time_domain.h
@@ -0,0 +1,158 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TIME_DOMAIN_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TIME_DOMAIN_H_ + +#include <map> + +#include "base/callback.h" +#include "base/logging.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" +#include "base/time/time.h" +#include "platform/scheduler/base/lazy_now.h" +#include "platform/scheduler/base/task_queue_impl.h" + +namespace blink { +namespace scheduler { +namespace internal { +class TaskQueueImpl; +} // internal +class TaskQueueManager; +class TaskQueueManagerDelegate; + +class BLINK_PLATFORM_EXPORT TimeDomain { + public: + class BLINK_PLATFORM_EXPORT Observer { + public: + virtual ~Observer() {} + + // Called when an empty TaskQueue registered with this TimeDomain has a task + // enqueued. + virtual void OnTimeDomainHasImmediateWork() = 0; + + // Called when a TaskQueue registered with this TimeDomain has a delayed + // task enqueued. + virtual void OnTimeDomainHasDelayedWork() = 0; + }; + + explicit TimeDomain(Observer* observer); + virtual ~TimeDomain(); + + // Returns a LazyNow that evaluate this TimeDomain's Now. Can be called from + // any thread. + // TODO(alexclarke): Make this main thread only. + virtual LazyNow CreateLazyNow() const = 0; + + // Evaluate this TimeDomain's Now. Can be called from any thread. + virtual base::TimeTicks Now() const = 0; + + // Some TimeDomains support virtual time, this method tells us to advance time + // if possible and return true if time was advanced. + virtual bool MaybeAdvanceTime() = 0; + + // Returns the name of this time domain for tracing. + virtual const char* GetName() const = 0; + + // If there is a scheduled delayed task, |out_time| is set to the scheduled + // runtime for the next one and it returns true. Returns false otherwise. + bool NextScheduledRunTime(base::TimeTicks* out_time) const; + + protected: + friend class internal::TaskQueueImpl; + friend class TaskQueueManager; + + void AsValueInto(base::trace_event::TracedValue* state) const; + + // Migrates |queue| from this time domain to |destination_time_domain|. + void MigrateQueue(internal::TaskQueueImpl* queue, + TimeDomain* destination_time_domain); + + // If there is a scheduled delayed task, |out_task_queue| is set to the queue + // the next task was posted to and it returns true. Returns false otherwise. + bool NextScheduledTaskQueue(TaskQueue** out_task_queue) const; + + // Adds |queue| to the set of task queues that UpdateWorkQueues calls + // UpdateWorkQueue on. + void RegisterAsUpdatableTaskQueue(internal::TaskQueueImpl* queue); + + // Schedules a call to TaskQueueImpl::MoveReadyDelayedTasksToDelayedWorkQueue + // when this TimeDomain reaches |delayed_run_time|. + void ScheduleDelayedWork(internal::TaskQueueImpl* queue, + base::TimeTicks delayed_run_time, + base::TimeTicks now); + + // Registers the |queue|. + void RegisterQueue(internal::TaskQueueImpl* queue); + + // Removes |queue| from the set of task queues that UpdateWorkQueues calls + // UpdateWorkQueue on. Returns true if |queue| was updatable. + bool UnregisterAsUpdatableTaskQueue(internal::TaskQueueImpl* queue); + + // Removes |queue| from all internal data structures. + void UnregisterQueue(internal::TaskQueueImpl* queue); + + // Updates active queues associated with this TimeDomain. + void UpdateWorkQueues(bool should_trigger_wakeup, + const internal::TaskQueueImpl::Task* previous_task, + LazyNow lazy_now); + + // Called by the TaskQueueManager when the TimeDomain is registered. + virtual void OnRegisterWithTaskQueueManager( + TaskQueueManager* task_queue_manager) = 0; + + // The implementaion will secedule task processing to run with |delay| with + // respect to the TimeDomain's time source. Always called on the main thread. + // NOTE this is only called by ScheduleDelayedWork if the scheduled runtime + // is sooner than any previously sheduled work or if there is no other + // scheduled work. + virtual void RequestWakeup(base::TimeTicks now, base::TimeDelta delay) = 0; + + // For implementation specific tracing. + virtual void AsValueIntoInternal( + base::trace_event::TracedValue* state) const = 0; + + // Call TaskQueueImpl::UpdateDelayedWorkQueue for each queue where the delay + // has elapsed. + void WakeupReadyDelayedQueues( + LazyNow* lazy_now, + bool should_trigger_wakeup, + const internal::TaskQueueImpl::Task* previous_task); + + protected: + // Clears expired entries from |delayed_wakeup_multimap_|. Caution needs to be + // taken to ensure TaskQueueImpl::UpdateDelayedWorkQueue or + // TaskQueueImpl::Pump is called on the affected queues. + void ClearExpiredWakeups(); + + private: + void MoveNewlyUpdatableQueuesIntoUpdatableQueueSet(); + + typedef std::multimap<base::TimeTicks, internal::TaskQueueImpl*> + DelayedWakeupMultimap; + + DelayedWakeupMultimap delayed_wakeup_multimap_; + + // This lock guards only |newly_updatable_|. It's not expected to be heavily + // contended. + base::Lock newly_updatable_lock_; + std::vector<internal::TaskQueueImpl*> newly_updatable_; + + // Set of task queues with avaliable work on the incoming queue. This should + // only be accessed from the main thread. + std::set<internal::TaskQueueImpl*> updatable_queue_set_; + + Observer* observer_; // NOT OWNED. + + base::ThreadChecker main_thread_checker_; + + DISALLOW_COPY_AND_ASSIGN(TimeDomain); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TIME_DOMAIN_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/base/time_domain_unittest.cc b/third_party/WebKit/Source/platform/scheduler/base/time_domain_unittest.cc new file mode 100644 index 0000000..3648fca5 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/time_domain_unittest.cc
@@ -0,0 +1,233 @@ +// 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 "platform/scheduler/base/time_domain.h" + +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "base/test/simple_test_tick_clock.h" +#include "cc/test/ordered_simple_task_runner.h" +#include "platform/scheduler/base/task_queue_impl.h" +#include "platform/scheduler/base/task_queue_manager.h" +#include "platform/scheduler/base/task_queue_manager_delegate_for_test.h" +#include "platform/scheduler/base/test_time_source.h" +#include "platform/scheduler/base/work_queue.h" +#include "testing/gmock/include/gmock/gmock.h" + +using testing::_; +using testing::AnyNumber; +using testing::Mock; + +namespace blink { +namespace scheduler { + +class MockTimeDomain : public TimeDomain { + public: + explicit MockTimeDomain(TimeDomain::Observer* observer) + : TimeDomain(observer), + now_(base::TimeTicks() + base::TimeDelta::FromSeconds(1)) {} + + ~MockTimeDomain() override {} + + using TimeDomain::ClearExpiredWakeups; + using TimeDomain::NextScheduledRunTime; + using TimeDomain::NextScheduledTaskQueue; + using TimeDomain::ScheduleDelayedWork; + using TimeDomain::UnregisterQueue; + using TimeDomain::UpdateWorkQueues; + using TimeDomain::RegisterAsUpdatableTaskQueue; + + // TimeSource implementation: + LazyNow CreateLazyNow() const override { return LazyNow(now_); } + base::TimeTicks Now() const override { return now_; } + + void AsValueIntoInternal( + base::trace_event::TracedValue* state) const override {} + + bool MaybeAdvanceTime() override { return false; } + const char* GetName() const override { return "Test"; } + void OnRegisterWithTaskQueueManager( + TaskQueueManager* task_queue_manager) override {} + + MOCK_METHOD2(RequestWakeup, void(base::TimeTicks now, base::TimeDelta delay)); + + void SetNow(base::TimeTicks now) { now_ = now; } + + private: + base::TimeTicks now_; + + DISALLOW_COPY_AND_ASSIGN(MockTimeDomain); +}; + +class TimeDomainTest : public testing::Test { + public: + void SetUp() final { + time_domain_ = base::WrapUnique(CreateMockTimeDomain()); + task_queue_ = make_scoped_refptr(new internal::TaskQueueImpl( + nullptr, time_domain_.get(), TaskQueue::Spec("test_queue"), + "test.category", "test.category")); + } + + void TearDown() final { + if (task_queue_) + task_queue_->UnregisterTaskQueue(); + } + + virtual MockTimeDomain* CreateMockTimeDomain() { + return new MockTimeDomain(nullptr); + } + + std::unique_ptr<MockTimeDomain> time_domain_; + scoped_refptr<internal::TaskQueueImpl> task_queue_; +}; + +TEST_F(TimeDomainTest, ScheduleDelayedWork) { + base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10); + base::TimeTicks delayed_runtime = time_domain_->Now() + delay; + EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, delay)); + base::TimeTicks now = time_domain_->Now(); + time_domain_->ScheduleDelayedWork(task_queue_.get(), now + delay, now); + + base::TimeTicks next_scheduled_runtime; + EXPECT_TRUE(time_domain_->NextScheduledRunTime(&next_scheduled_runtime)); + EXPECT_EQ(delayed_runtime, next_scheduled_runtime); + + TaskQueue* next_task_queue; + EXPECT_TRUE(time_domain_->NextScheduledTaskQueue(&next_task_queue)); + EXPECT_EQ(task_queue_.get(), next_task_queue); +} + +TEST_F(TimeDomainTest, RequestWakeup_OnlyCalledForEarlierTasks) { + base::TimeDelta delay1 = base::TimeDelta::FromMilliseconds(10); + base::TimeDelta delay2 = base::TimeDelta::FromMilliseconds(20); + base::TimeDelta delay3 = base::TimeDelta::FromMilliseconds(30); + base::TimeDelta delay4 = base::TimeDelta::FromMilliseconds(1); + + // RequestWakeup should always be called if there are no other wakeups. + EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, delay1)); + base::TimeTicks now = time_domain_->Now(); + time_domain_->ScheduleDelayedWork(task_queue_.get(), now + delay1, now); + + Mock::VerifyAndClearExpectations(time_domain_.get()); + + // RequestWakeup should not be called when scheduling later tasks. + EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, _)).Times(0); + time_domain_->ScheduleDelayedWork(task_queue_.get(), now + delay2, now); + time_domain_->ScheduleDelayedWork(task_queue_.get(), now + delay3, now); + + // RequestWakeup should be called when scheduling earlier tasks. + Mock::VerifyAndClearExpectations(time_domain_.get()); + EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, delay4)); + time_domain_->ScheduleDelayedWork(task_queue_.get(), now + delay4, now); +} + +TEST_F(TimeDomainTest, UnregisterQueue) { + scoped_refptr<internal::TaskQueueImpl> task_queue2_ = + make_scoped_refptr(new internal::TaskQueueImpl( + nullptr, time_domain_.get(), TaskQueue::Spec("test_queue2"), + "test.category", "test.category")); + + EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, _)).Times(1); + base::TimeTicks now = time_domain_->Now(); + time_domain_->ScheduleDelayedWork( + task_queue_.get(), now + base::TimeDelta::FromMilliseconds(10), now); + time_domain_->ScheduleDelayedWork( + task_queue2_.get(), now + base::TimeDelta::FromMilliseconds(100), now); + + TaskQueue* next_task_queue; + EXPECT_TRUE(time_domain_->NextScheduledTaskQueue(&next_task_queue)); + EXPECT_EQ(task_queue_.get(), next_task_queue); + + time_domain_->UnregisterQueue(task_queue_.get()); + task_queue_ = scoped_refptr<internal::TaskQueueImpl>(); + EXPECT_TRUE(time_domain_->NextScheduledTaskQueue(&next_task_queue)); + EXPECT_EQ(task_queue2_.get(), next_task_queue); + + time_domain_->UnregisterQueue(task_queue2_.get()); + EXPECT_FALSE(time_domain_->NextScheduledTaskQueue(&next_task_queue)); +} + +TEST_F(TimeDomainTest, UpdateWorkQueues) { + base::TimeDelta delay = base::TimeDelta::FromMilliseconds(50); + EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, delay)); + base::TimeTicks now = time_domain_->Now(); + base::TimeTicks delayed_runtime = now + delay; + time_domain_->ScheduleDelayedWork(task_queue_.get(), delayed_runtime, now); + + base::TimeTicks next_run_time; + ASSERT_TRUE(time_domain_->NextScheduledRunTime(&next_run_time)); + EXPECT_EQ(delayed_runtime, next_run_time); + + LazyNow lazy_now = time_domain_->CreateLazyNow(); + time_domain_->UpdateWorkQueues(false, nullptr, lazy_now); + ASSERT_TRUE(time_domain_->NextScheduledRunTime(&next_run_time)); + EXPECT_EQ(delayed_runtime, next_run_time); + + time_domain_->SetNow(delayed_runtime); + lazy_now = time_domain_->CreateLazyNow(); + time_domain_->UpdateWorkQueues(false, nullptr, lazy_now); + ASSERT_FALSE(time_domain_->NextScheduledRunTime(&next_run_time)); +} + +TEST_F(TimeDomainTest, ClearExpiredWakeups) { + base::TimeTicks now = time_domain_->Now(); + base::TimeDelta delay1 = base::TimeDelta::FromMilliseconds(10); + base::TimeDelta delay2 = base::TimeDelta::FromMilliseconds(20); + base::TimeTicks run_time1 = now + delay1; + base::TimeTicks run_time2 = now + delay2; + + EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, _)).Times(AnyNumber()); + time_domain_->ScheduleDelayedWork(task_queue_.get(), run_time1, now); + time_domain_->ScheduleDelayedWork(task_queue_.get(), run_time2, now); + + base::TimeTicks next_run_time; + ASSERT_TRUE(time_domain_->NextScheduledRunTime(&next_run_time)); + EXPECT_EQ(run_time1, next_run_time); + + time_domain_->SetNow(run_time1); + time_domain_->ClearExpiredWakeups(); + + ASSERT_TRUE(time_domain_->NextScheduledRunTime(&next_run_time)); + EXPECT_EQ(run_time2, next_run_time); + + time_domain_->SetNow(run_time2); + time_domain_->ClearExpiredWakeups(); + ASSERT_FALSE(time_domain_->NextScheduledRunTime(&next_run_time)); +} + +namespace { +class MockObserver : public TimeDomain::Observer { + public: + ~MockObserver() override {} + + MOCK_METHOD0(OnTimeDomainHasImmediateWork, void()); + MOCK_METHOD0(OnTimeDomainHasDelayedWork, void()); +}; +} // namespace + +class TimeDomainWithObserverTest : public TimeDomainTest { + public: + MockTimeDomain* CreateMockTimeDomain() override { + observer_.reset(new MockObserver()); + return new MockTimeDomain(observer_.get()); + } + + std::unique_ptr<MockObserver> observer_; +}; + +TEST_F(TimeDomainWithObserverTest, OnTimeDomainHasImmediateWork) { + EXPECT_CALL(*observer_, OnTimeDomainHasImmediateWork()); + time_domain_->RegisterAsUpdatableTaskQueue(task_queue_.get()); +} + +TEST_F(TimeDomainWithObserverTest, OnTimeDomainHasDelayedWork) { + EXPECT_CALL(*observer_, OnTimeDomainHasDelayedWork()); + EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, _)); + base::TimeTicks now = time_domain_->Now(); + time_domain_->ScheduleDelayedWork( + task_queue_.get(), now + base::TimeDelta::FromMilliseconds(10), now); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/base/virtual_time_domain.cc b/third_party/WebKit/Source/platform/scheduler/base/virtual_time_domain.cc new file mode 100644 index 0000000..a22796c5d --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/virtual_time_domain.cc
@@ -0,0 +1,66 @@ +// 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 "platform/scheduler/base/virtual_time_domain.h" + +#include "base/bind.h" +#include "platform/scheduler/base/task_queue_impl.h" +#include "platform/scheduler/base/task_queue_manager.h" +#include "platform/scheduler/base/task_queue_manager_delegate.h" + +namespace blink { +namespace scheduler { + +VirtualTimeDomain::VirtualTimeDomain(TimeDomain::Observer* observer, + base::TimeTicks initial_time) + : TimeDomain(observer), now_(initial_time), task_queue_manager_(nullptr) {} + +VirtualTimeDomain::~VirtualTimeDomain() {} + +void VirtualTimeDomain::OnRegisterWithTaskQueueManager( + TaskQueueManager* task_queue_manager) { + task_queue_manager_ = task_queue_manager; + DCHECK(task_queue_manager_); +} + +LazyNow VirtualTimeDomain::CreateLazyNow() const { + base::AutoLock lock(lock_); + return LazyNow(now_); +} + +base::TimeTicks VirtualTimeDomain::Now() const { + base::AutoLock lock(lock_); + return now_; +} + +void VirtualTimeDomain::RequestWakeup(base::TimeTicks now, + base::TimeDelta delay) { + // We don't need to do anything here because the caller of AdvanceTo is + // responsible for calling TaskQueueManager::MaybeScheduleImmediateWork if + // needed. +} + +bool VirtualTimeDomain::MaybeAdvanceTime() { + return false; +} + +void VirtualTimeDomain::AsValueIntoInternal( + base::trace_event::TracedValue* state) const {} + +void VirtualTimeDomain::AdvanceTo(base::TimeTicks now) { + base::AutoLock lock(lock_); + DCHECK_GE(now, now_); + now_ = now; +} + +void VirtualTimeDomain::RequestDoWork() { + task_queue_manager_->MaybeScheduleImmediateWork(FROM_HERE); +} + +const char* VirtualTimeDomain::GetName() const { + return "VirtualTimeDomain"; +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/base/virtual_time_domain.h b/third_party/WebKit/Source/platform/scheduler/base/virtual_time_domain.h new file mode 100644 index 0000000..d924186 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/virtual_time_domain.h
@@ -0,0 +1,56 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_VIRTUAL_TIME_DOMAIN_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_VIRTUAL_TIME_DOMAIN_H_ + +#include "base/callback.h" +#include "base/macros.h" +#include "platform/scheduler/base/time_domain.h" + +namespace blink { +namespace scheduler { + +class BLINK_PLATFORM_EXPORT VirtualTimeDomain : public TimeDomain { + public: + VirtualTimeDomain(TimeDomain::Observer* observer, + base::TimeTicks initial_time); + ~VirtualTimeDomain() override; + + // TimeDomain implementation: + LazyNow CreateLazyNow() const override; + base::TimeTicks Now() const override; + bool MaybeAdvanceTime() override; + const char* GetName() const override; + + // Advances this time domain to |now|. NOTE |now| is supposed to be + // monotonically increasing. NOTE it's the responsibility of the caller to + // call TaskQueueManager::MaybeScheduleImmediateWork if needed. + void AdvanceTo(base::TimeTicks now); + + using TimeDomain::ClearExpiredWakeups; + + protected: + void OnRegisterWithTaskQueueManager( + TaskQueueManager* task_queue_manager) override; + void RequestWakeup(base::TimeTicks now, base::TimeDelta delay) override; + void AsValueIntoInternal( + base::trace_event::TracedValue* state) const override; + + void RequestDoWork(); + + private: + mutable base::Lock lock_; // Protects |now_|. + base::TimeTicks now_; + + TaskQueueManager* task_queue_manager_; // NOT OWNED + base::Closure do_work_closure_; + + DISALLOW_COPY_AND_ASSIGN(VirtualTimeDomain); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_VIRTUAL_TIME_DOMAIN_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/base/work_queue.cc b/third_party/WebKit/Source/platform/scheduler/base/work_queue.cc new file mode 100644 index 0000000..1864f581 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/work_queue.cc
@@ -0,0 +1,113 @@ +// 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 "platform/scheduler/base/work_queue.h" + +#include "platform/scheduler/base/work_queue_sets.h" + +namespace blink { +namespace scheduler { +namespace internal { + +WorkQueue::WorkQueue(TaskQueueImpl* task_queue, const char* name) + : work_queue_sets_(nullptr), + task_queue_(task_queue), + work_queue_set_index_(0), + name_(name) {} + +void WorkQueue::AsValueInto(base::trace_event::TracedValue* state) const { + // Remove const to search |work_queue_| in the destructive manner. Restore the + // content from |visited| later. + std::queue<TaskQueueImpl::Task>* mutable_queue = + const_cast<std::queue<TaskQueueImpl::Task>*>(&work_queue_); + std::queue<TaskQueueImpl::Task> visited; + while (!mutable_queue->empty()) { + TaskQueueImpl::TaskAsValueInto(mutable_queue->front(), state); + visited.push(std::move(mutable_queue->front())); + mutable_queue->pop(); + } + *mutable_queue = std::move(visited); +} + +WorkQueue::~WorkQueue() { + DCHECK(!work_queue_sets_) << task_queue_->GetName() << " : " + << work_queue_sets_->name() << " : " << name_; +} + +const TaskQueueImpl::Task* WorkQueue::GetFrontTask() const { + if (work_queue_.empty()) + return nullptr; + return &work_queue_.front(); +} + +bool WorkQueue::GetFrontTaskEnqueueOrder(EnqueueOrder* enqueue_order) const { + if (work_queue_.empty()) + return false; + *enqueue_order = work_queue_.front().enqueue_order(); + return true; +} + +void WorkQueue::Push(TaskQueueImpl::Task task) { + bool was_empty = work_queue_.empty(); + work_queue_.push(std::move(task)); + if (was_empty && work_queue_sets_) + work_queue_sets_->OnPushQueue(this); +} + +void WorkQueue::PushAndSetEnqueueOrder(TaskQueueImpl::Task task, + EnqueueOrder enqueue_order) { + bool was_empty = work_queue_.empty(); + work_queue_.push(std::move(task)); + work_queue_.back().set_enqueue_order(enqueue_order); + + if (was_empty && work_queue_sets_) + work_queue_sets_->OnPushQueue(this); +} + +void WorkQueue::PopTaskForTest() { + work_queue_.pop(); +} + +void WorkQueue::SwapLocked(std::queue<TaskQueueImpl::Task>& incoming_queue) { + std::swap(work_queue_, incoming_queue); + + if (!work_queue_.empty() && work_queue_sets_) + work_queue_sets_->OnPushQueue(this); + task_queue_->TraceQueueSize(true); +} + +TaskQueueImpl::Task WorkQueue::TakeTaskFromWorkQueue() { + DCHECK(work_queue_sets_); + DCHECK(!work_queue_.empty()); + TaskQueueImpl::Task pending_task = std::move(work_queue_.front()); + work_queue_.pop(); + work_queue_sets_->OnPopQueue(this); + task_queue_->TraceQueueSize(false); + return pending_task; +} + +void WorkQueue::AssignToWorkQueueSets(WorkQueueSets* work_queue_sets) { + work_queue_sets_ = work_queue_sets; +} + +void WorkQueue::AssignSetIndex(size_t work_queue_set_index) { + work_queue_set_index_ = work_queue_set_index; +} + +bool WorkQueue::ShouldRunBefore(const WorkQueue* other_queue) const { + DCHECK(!work_queue_.empty()); + DCHECK(!other_queue->work_queue_.empty()); + EnqueueOrder enqueue_order = 0; + EnqueueOrder other_enqueue_order = 0; + bool have_task = GetFrontTaskEnqueueOrder(&enqueue_order); + bool have_other_task = + other_queue->GetFrontTaskEnqueueOrder(&other_enqueue_order); + DCHECK(have_task); + DCHECK(have_other_task); + return enqueue_order < other_enqueue_order; +} + +} // namespace internal +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/base/work_queue.h b/third_party/WebKit/Source/platform/scheduler/base/work_queue.h new file mode 100644 index 0000000..977c27fd --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/work_queue.h
@@ -0,0 +1,99 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_WORK_QUEUE_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_WORK_QUEUE_H_ + +#include <stddef.h> + +#include <set> + +#include "base/trace_event/trace_event.h" +#include "base/trace_event/trace_event_argument.h" +#include "platform/scheduler/base/enqueue_order.h" +#include "platform/scheduler/base/task_queue_impl.h" + +namespace blink { +namespace scheduler { +namespace internal { +class WorkQueueSets; + +class BLINK_PLATFORM_EXPORT WorkQueue { + public: + WorkQueue(TaskQueueImpl* task_queue, const char* name); + ~WorkQueue(); + + // Associates this work queue with the given work queue sets. This must be + // called before any tasks can be inserted into this work queue. + void AssignToWorkQueueSets(WorkQueueSets* work_queue_sets); + + // Assigns the current set index. + void AssignSetIndex(size_t work_queue_set_index); + + void AsValueInto(base::trace_event::TracedValue* state) const; + + // Clears the |work_queue_|. + void Clear(); + + // returns true if the |work_queue_| is empty. + bool Empty() const { return work_queue_.empty(); } + + // If the |work_queue_| isn't empty, |enqueue_order| gets set to the enqueue + // order of the front task and the function returns true. Otherwise the + // function returns false. + bool GetFrontTaskEnqueueOrder(EnqueueOrder* enqueue_order) const; + + // Returns the first task in this queue or null if the queue is empty. + const TaskQueueImpl::Task* GetFrontTask() const; + + // Pushes the task onto the |work_queue_| and informs the WorkQueueSets if + // the head changed. + void Push(TaskQueueImpl::Task task); + + // Pushes the task onto the |work_queue_|, sets the |enqueue_order| and + // informs the WorkQueueSets if the head changed. + void PushAndSetEnqueueOrder(TaskQueueImpl::Task task, + EnqueueOrder enqueue_order); + + // Swap the |work_queue_| with |incoming_queue| and informs the + // WorkQueueSets if the head changed. Assumes |task_queue_->any_thread_lock_| + // is locked. + void SwapLocked(std::queue<TaskQueueImpl::Task>& incoming_queue); + + size_t Size() const { return work_queue_.size(); } + + // Pulls a task off the |work_queue_| and informs the WorkQueueSets. + TaskQueueImpl::Task TakeTaskFromWorkQueue(); + + const char* name() const { return name_; } + + TaskQueueImpl* task_queue() const { return task_queue_; } + + WorkQueueSets* work_queue_sets() const { return work_queue_sets_; } + + size_t work_queue_set_index() const { return work_queue_set_index_; } + + // Test support function. This should not be used in production code. + void PopTaskForTest(); + + // Returns true if the front task in this queue has an older enqueue order + // than the front task of |other_queue|. Both queue are assumed to be + // non-empty. + bool ShouldRunBefore(const WorkQueue* other_queue) const; + + private: + std::queue<TaskQueueImpl::Task> work_queue_; + WorkQueueSets* work_queue_sets_; // NOT OWNED. + TaskQueueImpl* task_queue_; // NOT OWNED. + size_t work_queue_set_index_; + const char* name_; + + DISALLOW_COPY_AND_ASSIGN(WorkQueue); +}; + +} // namespace internal +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_WORK_QUEUE_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/base/work_queue_sets.cc b/third_party/WebKit/Source/platform/scheduler/base/work_queue_sets.cc new file mode 100644 index 0000000..47ffb0e --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/work_queue_sets.cc
@@ -0,0 +1,148 @@ +// 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 "platform/scheduler/base/work_queue_sets.h" + +#include "base/logging.h" +#include "platform/scheduler/base/work_queue.h" + +namespace blink { +namespace scheduler { +namespace internal { + +WorkQueueSets::WorkQueueSets(size_t num_sets, const char* name) + : enqueue_order_to_work_queue_maps_(num_sets), name_(name) {} + +WorkQueueSets::~WorkQueueSets() {} + +void WorkQueueSets::AddQueue(WorkQueue* work_queue, size_t set_index) { + DCHECK(!work_queue->work_queue_sets()); + DCHECK_LT(set_index, enqueue_order_to_work_queue_maps_.size()); + EnqueueOrder enqueue_order; + bool has_enqueue_order = work_queue->GetFrontTaskEnqueueOrder(&enqueue_order); + work_queue->AssignToWorkQueueSets(this); + work_queue->AssignSetIndex(set_index); + if (!has_enqueue_order) + return; + enqueue_order_to_work_queue_maps_[set_index].insert( + std::make_pair(enqueue_order, work_queue)); +} + +void WorkQueueSets::RemoveQueue(WorkQueue* work_queue) { + DCHECK_EQ(this, work_queue->work_queue_sets()); + EnqueueOrder enqueue_order; + bool has_enqueue_order = work_queue->GetFrontTaskEnqueueOrder(&enqueue_order); + work_queue->AssignToWorkQueueSets(nullptr); + if (!has_enqueue_order) + return; + size_t set_index = work_queue->work_queue_set_index(); + DCHECK_LT(set_index, enqueue_order_to_work_queue_maps_.size()); + DCHECK_EQ( + work_queue, + enqueue_order_to_work_queue_maps_[set_index].find(enqueue_order)->second); + enqueue_order_to_work_queue_maps_[set_index].erase(enqueue_order); +} + +void WorkQueueSets::ChangeSetIndex(WorkQueue* work_queue, size_t set_index) { + DCHECK_EQ(this, work_queue->work_queue_sets()); + DCHECK_LT(set_index, enqueue_order_to_work_queue_maps_.size()); + EnqueueOrder enqueue_order; + bool has_enqueue_order = work_queue->GetFrontTaskEnqueueOrder(&enqueue_order); + size_t old_set = work_queue->work_queue_set_index(); + DCHECK_LT(old_set, enqueue_order_to_work_queue_maps_.size()); + DCHECK_NE(old_set, set_index); + work_queue->AssignSetIndex(set_index); + if (!has_enqueue_order) + return; + enqueue_order_to_work_queue_maps_[old_set].erase(enqueue_order); + enqueue_order_to_work_queue_maps_[set_index].insert( + std::make_pair(enqueue_order, work_queue)); +} + +void WorkQueueSets::OnPushQueue(WorkQueue* work_queue) { + // NOTE if this funciton changes, we need to keep |WorkQueueSets::AddQueue| in + // sync. + DCHECK_EQ(this, work_queue->work_queue_sets()); + EnqueueOrder enqueue_order; + bool has_enqueue_order = work_queue->GetFrontTaskEnqueueOrder(&enqueue_order); + DCHECK(has_enqueue_order); + size_t set_index = work_queue->work_queue_set_index(); + DCHECK_LT(set_index, enqueue_order_to_work_queue_maps_.size()) + << " set_index = " << set_index; + enqueue_order_to_work_queue_maps_[set_index].insert( + std::make_pair(enqueue_order, work_queue)); +} + +void WorkQueueSets::OnPopQueue(WorkQueue* work_queue) { + size_t set_index = work_queue->work_queue_set_index(); + DCHECK_EQ(this, work_queue->work_queue_sets()); + DCHECK_LT(set_index, enqueue_order_to_work_queue_maps_.size()); + DCHECK(!enqueue_order_to_work_queue_maps_[set_index].empty()) + << " set_index = " << set_index; + DCHECK_EQ(enqueue_order_to_work_queue_maps_[set_index].begin()->second, + work_queue) + << " set_index = " << set_index; + // O(1) amortised. + enqueue_order_to_work_queue_maps_[set_index].erase( + enqueue_order_to_work_queue_maps_[set_index].begin()); + EnqueueOrder enqueue_order; + bool has_enqueue_order = work_queue->GetFrontTaskEnqueueOrder(&enqueue_order); + if (!has_enqueue_order) + return; + enqueue_order_to_work_queue_maps_[set_index].insert( + std::make_pair(enqueue_order, work_queue)); +} + +bool WorkQueueSets::GetOldestQueueInSet(size_t set_index, + WorkQueue** out_work_queue) const { + DCHECK_LT(set_index, enqueue_order_to_work_queue_maps_.size()); + if (enqueue_order_to_work_queue_maps_[set_index].empty()) + return false; + *out_work_queue = + enqueue_order_to_work_queue_maps_[set_index].begin()->second; +#ifndef NDEBUG + EnqueueOrder enqueue_order; + DCHECK((*out_work_queue)->GetFrontTaskEnqueueOrder(&enqueue_order)); + DCHECK_EQ(enqueue_order, + enqueue_order_to_work_queue_maps_[set_index].begin()->first); +#endif + return true; +} + +bool WorkQueueSets::IsSetEmpty(size_t set_index) const { + DCHECK_LT(set_index, enqueue_order_to_work_queue_maps_.size()) + << " set_index = " << set_index; + return enqueue_order_to_work_queue_maps_[set_index].empty(); +} + +#if DCHECK_IS_ON() || !defined(NDEBUG) +bool WorkQueueSets::ContainsWorkQueueForTest( + const WorkQueue* work_queue) const { + EnqueueOrder enqueue_order; + bool has_enqueue_order = work_queue->GetFrontTaskEnqueueOrder(&enqueue_order); + + for (const EnqueueOrderToWorkQueueMap& map : + enqueue_order_to_work_queue_maps_) { + for (const EnqueueOrderToWorkQueueMap::value_type& key_value_pair : map) { + if (key_value_pair.second == work_queue) { + DCHECK(has_enqueue_order); + DCHECK_EQ(key_value_pair.first, enqueue_order); + DCHECK_EQ(this, work_queue->work_queue_sets()); + return true; + } + } + } + + if (work_queue->work_queue_sets() == this) { + DCHECK(!has_enqueue_order); + return true; + } + + return false; +} +#endif + +} // namespace internal +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/base/work_queue_sets.h b/third_party/WebKit/Source/platform/scheduler/base/work_queue_sets.h new file mode 100644 index 0000000..1dd0fcfe --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/work_queue_sets.h
@@ -0,0 +1,70 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_WORK_QUEUE_SETS_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_WORK_QUEUE_SETS_H_ + +#include <stddef.h> + +#include <map> +#include <vector> + +#include "base/logging.h" +#include "base/macros.h" +#include "base/trace_event/trace_event_argument.h" +#include "platform/scheduler/base/task_queue_impl.h" +#include "public/platform/WebCommon.h" + +namespace blink { +namespace scheduler { +namespace internal { +class TaskQueueImpl; + +class BLINK_PLATFORM_EXPORT WorkQueueSets { + public: + WorkQueueSets(size_t num_sets, const char* name); + ~WorkQueueSets(); + + // O(log num queues) + void AddQueue(WorkQueue* queue, size_t set_index); + + // O(log num queues) + void RemoveQueue(WorkQueue* work_queue); + + // O(log num queues) + void ChangeSetIndex(WorkQueue* queue, size_t set_index); + + // O(log num queues) + void OnPushQueue(WorkQueue* work_queue); + + // If empty it's O(1) amortized, otherwise it's O(log num queues) + void OnPopQueue(WorkQueue* work_queue); + + // O(1) + bool GetOldestQueueInSet(size_t set_index, WorkQueue** out_work_queue) const; + + // O(1) + bool IsSetEmpty(size_t set_index) const; + +#if DCHECK_IS_ON() || !defined(NDEBUG) + // Note this iterates over everything in |enqueue_order_to_work_queue_maps_|. + // It's intended for use with DCHECKS and for testing + bool ContainsWorkQueueForTest(const WorkQueue* queue) const; +#endif + + const char* name() const { return name_; } + + private: + typedef std::map<EnqueueOrder, WorkQueue*> EnqueueOrderToWorkQueueMap; + std::vector<EnqueueOrderToWorkQueueMap> enqueue_order_to_work_queue_maps_; + const char* name_; + + DISALLOW_COPY_AND_ASSIGN(WorkQueueSets); +}; + +} // namespace internal +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_WORK_QUEUE_SETS_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/base/work_queue_sets_unittest.cc b/third_party/WebKit/Source/platform/scheduler/base/work_queue_sets_unittest.cc new file mode 100644 index 0000000..5b10711 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/base/work_queue_sets_unittest.cc
@@ -0,0 +1,261 @@ +// 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 "platform/scheduler/base/work_queue_sets.h" + +#include <stddef.h> + +#include "base/memory/ptr_util.h" +#include "platform/scheduler/base/work_queue.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace blink { +namespace scheduler { +class TimeDomain; + +namespace internal { + +class WorkQueueSetsTest : public testing::Test { + public: + void SetUp() override { + work_queue_sets_.reset(new WorkQueueSets(kNumSets, "test")); + } + + void TearDown() override { + for (std::unique_ptr<WorkQueue>& work_queue : work_queues_) { + if (work_queue->work_queue_sets()) + work_queue_sets_->RemoveQueue(work_queue.get()); + } + } + + protected: + enum { + kNumSets = 5 // An arbitary choice. + }; + + WorkQueue* NewTaskQueue(const char* queue_name) { + WorkQueue* queue = new WorkQueue(nullptr, "test"); + work_queues_.push_back(base::WrapUnique(queue)); + work_queue_sets_->AddQueue(queue, TaskQueue::CONTROL_PRIORITY); + return queue; + } + + TaskQueueImpl::Task FakeTaskWithEnqueueOrder(int enqueue_order) { + TaskQueueImpl::Task fake_task(FROM_HERE, base::Closure(), base::TimeTicks(), + 0, true); + fake_task.set_enqueue_order(enqueue_order); + return fake_task; + } + + std::vector<std::unique_ptr<WorkQueue>> work_queues_; + std::unique_ptr<WorkQueueSets> work_queue_sets_; +}; + +TEST_F(WorkQueueSetsTest, ChangeSetIndex) { + WorkQueue* work_queue = NewTaskQueue("queue"); + size_t set = TaskQueue::NORMAL_PRIORITY; + work_queue_sets_->ChangeSetIndex(work_queue, set); + + EXPECT_EQ(set, work_queue->work_queue_set_index()); +} + +TEST_F(WorkQueueSetsTest, GetOldestQueueInSet_QueueEmpty) { + WorkQueue* work_queue = NewTaskQueue("queue"); + size_t set = TaskQueue::NORMAL_PRIORITY; + work_queue_sets_->ChangeSetIndex(work_queue, set); + + WorkQueue* selected_work_queue; + EXPECT_FALSE( + work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue)); +} + +TEST_F(WorkQueueSetsTest, OnPushQueue) { + WorkQueue* work_queue = NewTaskQueue("queue"); + size_t set = TaskQueue::NORMAL_PRIORITY; + work_queue_sets_->ChangeSetIndex(work_queue, set); + + WorkQueue* selected_work_queue; + EXPECT_FALSE( + work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue)); + + work_queue->Push(FakeTaskWithEnqueueOrder(10)); + work_queue_sets_->OnPushQueue(work_queue); + + EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue)); + EXPECT_EQ(work_queue, selected_work_queue); +} + +TEST_F(WorkQueueSetsTest, GetOldestQueueInSet_SingleTaskInSet) { + WorkQueue* work_queue = NewTaskQueue("queue"); + work_queue->Push(FakeTaskWithEnqueueOrder(10)); + size_t set = 1; + work_queue_sets_->ChangeSetIndex(work_queue, set); + + WorkQueue* selected_work_queue; + EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue)); + EXPECT_EQ(work_queue, selected_work_queue); +} + +TEST_F(WorkQueueSetsTest, GetOldestQueueInSet_MultipleAgesInSet) { + WorkQueue* queue1 = NewTaskQueue("queue1"); + WorkQueue* queue2 = NewTaskQueue("queue2"); + WorkQueue* queue3 = NewTaskQueue("queue2"); + queue1->Push(FakeTaskWithEnqueueOrder(6)); + queue2->Push(FakeTaskWithEnqueueOrder(5)); + queue3->Push(FakeTaskWithEnqueueOrder(4)); + size_t set = 2; + work_queue_sets_->ChangeSetIndex(queue1, set); + work_queue_sets_->ChangeSetIndex(queue2, set); + work_queue_sets_->ChangeSetIndex(queue3, set); + + WorkQueue* selected_work_queue; + EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue)); + EXPECT_EQ(queue3, selected_work_queue); +} + +TEST_F(WorkQueueSetsTest, OnPopQueue) { + WorkQueue* queue1 = NewTaskQueue("queue1"); + WorkQueue* queue2 = NewTaskQueue("queue2"); + WorkQueue* queue3 = NewTaskQueue("queue3"); + queue1->Push(FakeTaskWithEnqueueOrder(6)); + queue2->Push(FakeTaskWithEnqueueOrder(3)); + queue2->Push(FakeTaskWithEnqueueOrder(1)); + queue3->Push(FakeTaskWithEnqueueOrder(4)); + size_t set = 3; + work_queue_sets_->ChangeSetIndex(queue1, set); + work_queue_sets_->ChangeSetIndex(queue2, set); + work_queue_sets_->ChangeSetIndex(queue3, set); + + WorkQueue* selected_work_queue; + EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue)); + EXPECT_EQ(queue2, selected_work_queue); + + queue2->PopTaskForTest(); + work_queue_sets_->OnPopQueue(queue2); + + EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue)); + EXPECT_EQ(queue2, selected_work_queue); +} + +TEST_F(WorkQueueSetsTest, OnPopQueue_QueueBecomesEmpty) { + WorkQueue* queue1 = NewTaskQueue("queue"); + WorkQueue* queue2 = NewTaskQueue("queue"); + WorkQueue* queue3 = NewTaskQueue("queue"); + queue1->Push(FakeTaskWithEnqueueOrder(6)); + queue2->Push(FakeTaskWithEnqueueOrder(5)); + queue3->Push(FakeTaskWithEnqueueOrder(4)); + size_t set = 4; + work_queue_sets_->ChangeSetIndex(queue1, set); + work_queue_sets_->ChangeSetIndex(queue2, set); + work_queue_sets_->ChangeSetIndex(queue3, set); + + WorkQueue* selected_work_queue; + EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue)); + EXPECT_EQ(queue3, selected_work_queue); + + queue3->PopTaskForTest(); + work_queue_sets_->OnPopQueue(queue3); + + EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue)); + EXPECT_EQ(queue2, selected_work_queue); +} + +TEST_F(WorkQueueSetsTest, + GetOldestQueueInSet_MultipleAgesInSetIntegerRollover) { + WorkQueue* queue1 = NewTaskQueue("queue1"); + WorkQueue* queue2 = NewTaskQueue("queue2"); + WorkQueue* queue3 = NewTaskQueue("queue3"); + queue1->Push(FakeTaskWithEnqueueOrder(0x7ffffff1)); + queue2->Push(FakeTaskWithEnqueueOrder(0x7ffffff0)); + queue3->Push(FakeTaskWithEnqueueOrder(-0x7ffffff1)); + size_t set = 1; + work_queue_sets_->ChangeSetIndex(queue1, set); + work_queue_sets_->ChangeSetIndex(queue2, set); + work_queue_sets_->ChangeSetIndex(queue3, set); + + WorkQueue* selected_work_queue; + EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue)); + EXPECT_EQ(queue2, selected_work_queue); +} + +TEST_F(WorkQueueSetsTest, GetOldestQueueInSet_MultipleAgesInSet_RemoveQueue) { + WorkQueue* queue1 = NewTaskQueue("queue1"); + WorkQueue* queue2 = NewTaskQueue("queue2"); + WorkQueue* queue3 = NewTaskQueue("queue3"); + queue1->Push(FakeTaskWithEnqueueOrder(6)); + queue2->Push(FakeTaskWithEnqueueOrder(5)); + queue3->Push(FakeTaskWithEnqueueOrder(4)); + size_t set = 1; + work_queue_sets_->ChangeSetIndex(queue1, set); + work_queue_sets_->ChangeSetIndex(queue2, set); + work_queue_sets_->ChangeSetIndex(queue3, set); + work_queue_sets_->RemoveQueue(queue3); + + WorkQueue* selected_work_queue; + EXPECT_TRUE(work_queue_sets_->GetOldestQueueInSet(set, &selected_work_queue)); + EXPECT_EQ(queue2, selected_work_queue); +} + +TEST_F(WorkQueueSetsTest, ChangeSetIndex_Complex) { + WorkQueue* queue1 = NewTaskQueue("queue1"); + WorkQueue* queue2 = NewTaskQueue("queue2"); + WorkQueue* queue3 = NewTaskQueue("queue3"); + WorkQueue* queue4 = NewTaskQueue("queue4"); + queue1->Push(FakeTaskWithEnqueueOrder(6)); + queue2->Push(FakeTaskWithEnqueueOrder(5)); + queue3->Push(FakeTaskWithEnqueueOrder(4)); + queue4->Push(FakeTaskWithEnqueueOrder(3)); + size_t set1 = 1; + size_t set2 = 2; + work_queue_sets_->ChangeSetIndex(queue1, set1); + work_queue_sets_->ChangeSetIndex(queue2, set1); + work_queue_sets_->ChangeSetIndex(queue3, set2); + work_queue_sets_->ChangeSetIndex(queue4, set2); + + WorkQueue* selected_work_queue; + EXPECT_TRUE( + work_queue_sets_->GetOldestQueueInSet(set1, &selected_work_queue)); + EXPECT_EQ(queue2, selected_work_queue); + + EXPECT_TRUE( + work_queue_sets_->GetOldestQueueInSet(set2, &selected_work_queue)); + EXPECT_EQ(queue4, selected_work_queue); + + work_queue_sets_->ChangeSetIndex(queue4, set1); + + EXPECT_TRUE( + work_queue_sets_->GetOldestQueueInSet(set1, &selected_work_queue)); + EXPECT_EQ(queue4, selected_work_queue); + + EXPECT_TRUE( + work_queue_sets_->GetOldestQueueInSet(set2, &selected_work_queue)); + EXPECT_EQ(queue3, selected_work_queue); +} + +TEST_F(WorkQueueSetsTest, IsSetEmpty_NoWork) { + size_t set = 2; + EXPECT_TRUE(work_queue_sets_->IsSetEmpty(set)); + + WorkQueue* work_queue = NewTaskQueue("queue"); + work_queue_sets_->ChangeSetIndex(work_queue, set); + EXPECT_TRUE(work_queue_sets_->IsSetEmpty(set)); +} + +TEST_F(WorkQueueSetsTest, IsSetEmpty_Work) { + size_t set = 2; + EXPECT_TRUE(work_queue_sets_->IsSetEmpty(set)); + + WorkQueue* work_queue = NewTaskQueue("queue"); + work_queue->Push(FakeTaskWithEnqueueOrder(1)); + work_queue_sets_->ChangeSetIndex(work_queue, set); + EXPECT_FALSE(work_queue_sets_->IsSetEmpty(set)); + + work_queue->PopTaskForTest(); + work_queue_sets_->OnPopQueue(work_queue); + EXPECT_TRUE(work_queue_sets_->IsSetEmpty(set)); +} + +} // namespace internal +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/child/DEPS b/third_party/WebKit/Source/platform/scheduler/child/DEPS new file mode 100644 index 0000000..12699101 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/child/DEPS
@@ -0,0 +1,10 @@ +include_rules = [ + "+third_party/WebKit/public/platform/scheduler/base", + "+third_party/WebKit/source/platform/scheduler/base", +] + +specific_include_rules = { + "(test_time_source|.*test)\.cc": [ + "+cc/test", + ], +}
diff --git a/components/scheduler/child/OWNERS b/third_party/WebKit/Source/platform/scheduler/child/OWNERS similarity index 100% rename from components/scheduler/child/OWNERS rename to third_party/WebKit/Source/platform/scheduler/child/OWNERS
diff --git a/third_party/WebKit/Source/platform/scheduler/child/compositor_worker_scheduler.cc b/third_party/WebKit/Source/platform/scheduler/child/compositor_worker_scheduler.cc new file mode 100644 index 0000000..251d3a9 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/child/compositor_worker_scheduler.cc
@@ -0,0 +1,168 @@ +// 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 "public/platform/scheduler/child/compositor_worker_scheduler.h" + +#include "base/message_loop/message_loop.h" +#include "base/threading/thread.h" + +namespace blink { +namespace scheduler { + +// TODO(scheduler-dev): Get rid of this asap! +namespace { +class CompositorWorkerTaskRunnerWrapper : public TaskQueue { + public: + explicit CompositorWorkerTaskRunnerWrapper( + scoped_refptr<base::SingleThreadTaskRunner> task_runner) + : task_runner_(task_runner) {} + + // TaskQueue implementation: + void UnregisterTaskQueue() override { NOTREACHED(); } + + bool RunsTasksOnCurrentThread() const override { + return task_runner_->RunsTasksOnCurrentThread(); + } + + bool PostDelayedTask(const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) override { + return task_runner_->PostDelayedTask(from_here, task, delay); + } + + bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) override { + return task_runner_->PostNonNestableDelayedTask(from_here, task, delay); + } + + void SetQueueEnabled(bool enabled) override { NOTREACHED(); } + + bool IsQueueEnabled() const override { + NOTREACHED(); + return true; + } + + bool IsEmpty() const override { + NOTREACHED(); + return false; + }; + + bool HasPendingImmediateWork() const override { + NOTREACHED(); + return false; + }; + + bool NeedsPumping() const override { + NOTREACHED(); + return false; + }; + + const char* GetName() const override { + NOTREACHED(); + return nullptr; + }; + + void SetQueuePriority(QueuePriority priority) override { NOTREACHED(); } + + QueuePriority GetQueuePriority() const override { + NOTREACHED(); + return QueuePriority::NORMAL_PRIORITY; + }; + + void SetPumpPolicy(PumpPolicy pump_policy) override { NOTREACHED(); } + + PumpPolicy GetPumpPolicy() const override { + NOTREACHED(); + return PumpPolicy::AUTO; + }; + + void PumpQueue(LazyNow*, bool may_post_dowork) override { NOTREACHED(); } + + void AddTaskObserver( + base::MessageLoop::TaskObserver* task_observer) override { + NOTREACHED(); + } + + void RemoveTaskObserver( + base::MessageLoop::TaskObserver* task_observer) override { + NOTREACHED(); + } + + void SetTimeDomain(TimeDomain* domain) override { NOTREACHED(); } + + TimeDomain* GetTimeDomain() const override { + NOTREACHED(); + return nullptr; + } + + void SetBlameContext(base::trace_event::BlameContext*) override { + NOTREACHED(); + } + + private: + ~CompositorWorkerTaskRunnerWrapper() override {} + + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; +}; +} // namespace + +CompositorWorkerScheduler::CompositorWorkerScheduler(base::Thread* thread) + : thread_(thread) {} + +CompositorWorkerScheduler::~CompositorWorkerScheduler() {} + +void CompositorWorkerScheduler::Init() {} + +scoped_refptr<TaskQueue> CompositorWorkerScheduler::DefaultTaskRunner() { + // TODO(sad): Implement a more robust scheduler that can do idle tasks for GC + // without regressing performance of the rest of the system. + return make_scoped_refptr( + new CompositorWorkerTaskRunnerWrapper(thread_->task_runner())); +} + +scoped_refptr<scheduler::SingleThreadIdleTaskRunner> +CompositorWorkerScheduler::IdleTaskRunner() { + // TODO(flackr): This posts idle tasks as regular tasks. We need to create + // an idle task runner with the semantics we want for the compositor thread + // which runs them after the current frame has been drawn before the next + // vsync. https://crbug.com/609532 + return make_scoped_refptr(new SingleThreadIdleTaskRunner( + thread_->task_runner(), thread_->task_runner(), this, + "compositor.scheduler")); +} + +bool CompositorWorkerScheduler::CanExceedIdleDeadlineIfRequired() const { + return false; +} + +bool CompositorWorkerScheduler::ShouldYieldForHighPriorityWork() { + return false; +} + +void CompositorWorkerScheduler::AddTaskObserver( + base::MessageLoop::TaskObserver* task_observer) { + thread_->message_loop()->AddTaskObserver(task_observer); +} + +void CompositorWorkerScheduler::RemoveTaskObserver( + base::MessageLoop::TaskObserver* task_observer) { + thread_->message_loop()->RemoveTaskObserver(task_observer); +} + +void CompositorWorkerScheduler::Shutdown() {} + +void CompositorWorkerScheduler::OnIdleTaskPosted() {} + +base::TimeTicks CompositorWorkerScheduler::WillProcessIdleTask() { + // TODO(flackr): Return the next frame time as the deadline instead. + // TODO(flackr): Ensure that oilpan GC does happen on the compositor thread + // even though we will have no long idle periods. https://crbug.com/609531 + return base::TimeTicks::Now() + base::TimeDelta::FromMillisecondsD(16.7); +} + +void CompositorWorkerScheduler::DidProcessIdleTask() {} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/child/idle_helper.cc b/third_party/WebKit/Source/platform/scheduler/child/idle_helper.cc new file mode 100644 index 0000000..406b959 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/child/idle_helper.cc
@@ -0,0 +1,478 @@ +// 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 "platform/scheduler/child/idle_helper.h" + +#include "base/time/time.h" +#include "base/trace_event/trace_event.h" +#include "base/trace_event/trace_event_argument.h" +#include "platform/scheduler/base/real_time_domain.h" +#include "public/platform/scheduler/base/task_queue.h" +#include "platform/scheduler/base/task_queue_manager.h" +#include "platform/scheduler/child/scheduler_helper.h" +#include "platform/scheduler/child/scheduler_tqm_delegate.h" + +namespace blink { +namespace scheduler { + +IdleHelper::IdleHelper( + SchedulerHelper* helper, + Delegate* delegate, + const char* tracing_category, + const char* disabled_by_default_tracing_category, + const char* idle_period_tracing_name, + base::TimeDelta required_quiescence_duration_before_long_idle_period) + : helper_(helper), + delegate_(delegate), + idle_queue_( + helper_->NewTaskQueue(TaskQueue::Spec("idle_tq").SetPumpPolicy( + TaskQueue::PumpPolicy::MANUAL))), + state_(helper, + delegate, + tracing_category, + disabled_by_default_tracing_category, + idle_period_tracing_name), + required_quiescence_duration_before_long_idle_period_( + required_quiescence_duration_before_long_idle_period), + disabled_by_default_tracing_category_( + disabled_by_default_tracing_category), + weak_factory_(this) { + weak_idle_helper_ptr_ = weak_factory_.GetWeakPtr(); + enable_next_long_idle_period_closure_.Reset( + base::Bind(&IdleHelper::EnableLongIdlePeriod, weak_idle_helper_ptr_)); + on_idle_task_posted_closure_.Reset(base::Bind( + &IdleHelper::OnIdleTaskPostedOnMainThread, weak_idle_helper_ptr_)); + + idle_task_runner_ = make_scoped_refptr(new SingleThreadIdleTaskRunner( + idle_queue_, helper_->ControlAfterWakeUpTaskRunner(), this, + tracing_category)); + + idle_queue_->SetQueueEnabled(false); + idle_queue_->SetQueuePriority(TaskQueue::BEST_EFFORT_PRIORITY); + + helper_->AddTaskObserver(this); +} + +IdleHelper::~IdleHelper() { + helper_->RemoveTaskObserver(this); +} + +IdleHelper::Delegate::Delegate() {} + +IdleHelper::Delegate::~Delegate() {} + +scoped_refptr<SingleThreadIdleTaskRunner> IdleHelper::IdleTaskRunner() { + helper_->CheckOnValidThread(); + return idle_task_runner_; +} + +IdleHelper::IdlePeriodState IdleHelper::ComputeNewLongIdlePeriodState( + const base::TimeTicks now, + base::TimeDelta* next_long_idle_period_delay_out) { + helper_->CheckOnValidThread(); + + if (!delegate_->CanEnterLongIdlePeriod(now, + next_long_idle_period_delay_out)) { + return IdlePeriodState::NOT_IN_IDLE_PERIOD; + } + + base::TimeTicks next_pending_delayed_task; + base::TimeDelta max_long_idle_period_duration = + base::TimeDelta::FromMilliseconds(kMaximumIdlePeriodMillis); + base::TimeDelta long_idle_period_duration; + if (helper_->real_time_domain()->NextScheduledRunTime( + &next_pending_delayed_task)) { + // Limit the idle period duration to be before the next pending task. + long_idle_period_duration = std::min(next_pending_delayed_task - now, + max_long_idle_period_duration); + } else { + long_idle_period_duration = max_long_idle_period_duration; + } + + if (long_idle_period_duration >= + base::TimeDelta::FromMilliseconds(kMinimumIdlePeriodDurationMillis)) { + *next_long_idle_period_delay_out = long_idle_period_duration; + if (!idle_queue_->HasPendingImmediateWork()) { + return IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED; + } else if (long_idle_period_duration == max_long_idle_period_duration) { + return IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE; + } else { + return IdlePeriodState::IN_LONG_IDLE_PERIOD; + } + } else { + // If we can't start the idle period yet then try again after wakeup. + *next_long_idle_period_delay_out = base::TimeDelta::FromMilliseconds( + kRetryEnableLongIdlePeriodDelayMillis); + return IdlePeriodState::NOT_IN_IDLE_PERIOD; + } +} + +bool IdleHelper::ShouldWaitForQuiescence() { + helper_->CheckOnValidThread(); + + if (helper_->IsShutdown()) + return false; + + if (required_quiescence_duration_before_long_idle_period_ == + base::TimeDelta()) + return false; + + bool system_is_quiescent = helper_->GetAndClearSystemIsQuiescentBit(); + TRACE_EVENT1(disabled_by_default_tracing_category_, "ShouldWaitForQuiescence", + "system_is_quiescent", system_is_quiescent); + return !system_is_quiescent; +} + +void IdleHelper::EnableLongIdlePeriod() { + TRACE_EVENT0(disabled_by_default_tracing_category_, "EnableLongIdlePeriod"); + helper_->CheckOnValidThread(); + if (helper_->IsShutdown()) + return; + + // End any previous idle period. + EndIdlePeriod(); + + if (ShouldWaitForQuiescence()) { + helper_->ControlTaskRunner()->PostDelayedTask( + FROM_HERE, enable_next_long_idle_period_closure_.callback(), + required_quiescence_duration_before_long_idle_period_); + delegate_->IsNotQuiescent(); + return; + } + + base::TimeTicks now(helper_->scheduler_tqm_delegate()->NowTicks()); + base::TimeDelta next_long_idle_period_delay; + IdlePeriodState new_idle_period_state = + ComputeNewLongIdlePeriodState(now, &next_long_idle_period_delay); + if (IsInIdlePeriod(new_idle_period_state)) { + StartIdlePeriod(new_idle_period_state, now, + now + next_long_idle_period_delay); + } else { + // Otherwise wait for the next long idle period delay before trying again. + helper_->ControlTaskRunner()->PostDelayedTask( + FROM_HERE, enable_next_long_idle_period_closure_.callback(), + next_long_idle_period_delay); + } +} + +void IdleHelper::StartIdlePeriod(IdlePeriodState new_state, + base::TimeTicks now, + base::TimeTicks idle_period_deadline) { + DCHECK_GT(idle_period_deadline, now); + helper_->CheckOnValidThread(); + DCHECK(IsInIdlePeriod(new_state)); + + base::TimeDelta idle_period_duration(idle_period_deadline - now); + if (idle_period_duration < + base::TimeDelta::FromMilliseconds(kMinimumIdlePeriodDurationMillis)) { + TRACE_EVENT1(disabled_by_default_tracing_category_, + "NotStartingIdlePeriodBecauseDeadlineIsTooClose", + "idle_period_duration_ms", + idle_period_duration.InMillisecondsF()); + return; + } + + TRACE_EVENT0(disabled_by_default_tracing_category_, "StartIdlePeriod"); + idle_queue_->SetQueueEnabled(true); + LazyNow lazy_now(now); + idle_queue_->PumpQueue(&lazy_now, true); + + state_.UpdateState(new_state, idle_period_deadline, now); +} + +void IdleHelper::EndIdlePeriod() { + helper_->CheckOnValidThread(); + TRACE_EVENT0(disabled_by_default_tracing_category_, "EndIdlePeriod"); + + enable_next_long_idle_period_closure_.Cancel(); + on_idle_task_posted_closure_.Cancel(); + + // If we weren't already within an idle period then early-out. + if (!IsInIdlePeriod(state_.idle_period_state())) + return; + + idle_queue_->SetQueueEnabled(false); + state_.UpdateState(IdlePeriodState::NOT_IN_IDLE_PERIOD, base::TimeTicks(), + base::TimeTicks()); +} + +void IdleHelper::WillProcessTask(const base::PendingTask& pending_task) {} + +void IdleHelper::DidProcessTask(const base::PendingTask& pending_task) { + helper_->CheckOnValidThread(); + TRACE_EVENT0(disabled_by_default_tracing_category_, "DidProcessTask"); + if (IsInIdlePeriod(state_.idle_period_state()) && + state_.idle_period_state() != + IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED && + helper_->scheduler_tqm_delegate()->NowTicks() >= + state_.idle_period_deadline()) { + // If the idle period deadline has now been reached, either end the idle + // period or trigger a new long-idle period. + if (IsInLongIdlePeriod(state_.idle_period_state())) { + EnableLongIdlePeriod(); + } else { + DCHECK(IdlePeriodState::IN_SHORT_IDLE_PERIOD == + state_.idle_period_state()); + EndIdlePeriod(); + } + } +} + +void IdleHelper::UpdateLongIdlePeriodStateAfterIdleTask() { + helper_->CheckOnValidThread(); + DCHECK(IsInLongIdlePeriod(state_.idle_period_state())); + TRACE_EVENT0(disabled_by_default_tracing_category_, + "UpdateLongIdlePeriodStateAfterIdleTask"); + + if (!idle_queue_->HasPendingImmediateWork()) { + // If there are no more idle tasks then pause long idle period ticks until a + // new idle task is posted. + state_.UpdateState(IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED, + state_.idle_period_deadline(), base::TimeTicks()); + } else if (idle_queue_->NeedsPumping()) { + // If there is still idle work to do then just start the next idle period. + base::TimeDelta next_long_idle_period_delay; + if (state_.idle_period_state() == + IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE) { + // If we are in a max deadline long idle period then start the next + // idle period immediately. + next_long_idle_period_delay = base::TimeDelta(); + } else { + // Otherwise ensure that we kick the scheduler at the right time to + // initiate the next idle period. + next_long_idle_period_delay = std::max( + base::TimeDelta(), state_.idle_period_deadline() - + helper_->scheduler_tqm_delegate()->NowTicks()); + } + if (next_long_idle_period_delay.is_zero()) { + EnableLongIdlePeriod(); + } else { + helper_->ControlTaskRunner()->PostDelayedTask( + FROM_HERE, enable_next_long_idle_period_closure_.callback(), + next_long_idle_period_delay); + } + } +} + +base::TimeTicks IdleHelper::CurrentIdleTaskDeadline() const { + helper_->CheckOnValidThread(); + return state_.idle_period_deadline(); +} + +void IdleHelper::OnIdleTaskPosted() { + TRACE_EVENT0(disabled_by_default_tracing_category_, "OnIdleTaskPosted"); + if (idle_task_runner_->RunsTasksOnCurrentThread()) { + OnIdleTaskPostedOnMainThread(); + } else { + helper_->ControlTaskRunner()->PostTask( + FROM_HERE, on_idle_task_posted_closure_.callback()); + } +} + +void IdleHelper::OnIdleTaskPostedOnMainThread() { + TRACE_EVENT0(disabled_by_default_tracing_category_, + "OnIdleTaskPostedOnMainThread"); + if (state_.idle_period_state() == + IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED) { + // Restart long idle period ticks. + helper_->ControlTaskRunner()->PostTask( + FROM_HERE, enable_next_long_idle_period_closure_.callback()); + } +} + +base::TimeTicks IdleHelper::WillProcessIdleTask() { + helper_->CheckOnValidThread(); + state_.TraceIdleIdleTaskStart(); + return CurrentIdleTaskDeadline(); +} + +void IdleHelper::DidProcessIdleTask() { + helper_->CheckOnValidThread(); + state_.TraceIdleIdleTaskEnd(); + if (IsInLongIdlePeriod(state_.idle_period_state())) { + UpdateLongIdlePeriodStateAfterIdleTask(); + } +} + +// static +bool IdleHelper::IsInIdlePeriod(IdlePeriodState state) { + return state != IdlePeriodState::NOT_IN_IDLE_PERIOD; +} + +// static +bool IdleHelper::IsInLongIdlePeriod(IdlePeriodState state) { + return state == IdlePeriodState::IN_LONG_IDLE_PERIOD || + state == IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE || + state == IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED; +} + +bool IdleHelper::CanExceedIdleDeadlineIfRequired() const { + TRACE_EVENT0(disabled_by_default_tracing_category_, + "CanExceedIdleDeadlineIfRequired"); + helper_->CheckOnValidThread(); + return state_.idle_period_state() == + IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE; +} + +IdleHelper::IdlePeriodState IdleHelper::SchedulerIdlePeriodState() const { + return state_.idle_period_state(); +} + +IdleHelper::State::State(SchedulerHelper* helper, + Delegate* delegate, + const char* tracing_category, + const char* disabled_by_default_tracing_category, + const char* idle_period_tracing_name) + : helper_(helper), + delegate_(delegate), + idle_period_state_(IdlePeriodState::NOT_IN_IDLE_PERIOD), + idle_period_trace_event_started_(false), + running_idle_task_for_tracing_(false), + tracing_category_(tracing_category), + disabled_by_default_tracing_category_( + disabled_by_default_tracing_category), + idle_period_tracing_name_(idle_period_tracing_name) {} + +IdleHelper::State::~State() {} + +IdleHelper::IdlePeriodState IdleHelper::State::idle_period_state() const { + helper_->CheckOnValidThread(); + return idle_period_state_; +} + +base::TimeTicks IdleHelper::State::idle_period_deadline() const { + helper_->CheckOnValidThread(); + return idle_period_deadline_; +} + +void IdleHelper::State::UpdateState(IdlePeriodState new_state, + base::TimeTicks new_deadline, + base::TimeTicks optional_now) { + IdlePeriodState old_idle_period_state = idle_period_state_; + + helper_->CheckOnValidThread(); + if (new_state == idle_period_state_) { + DCHECK_EQ(new_deadline, idle_period_deadline_); + return; + } + + bool is_tracing; + TRACE_EVENT_CATEGORY_GROUP_ENABLED(tracing_category_, &is_tracing); + if (is_tracing) { + base::TimeTicks now(optional_now.is_null() + ? helper_->scheduler_tqm_delegate()->NowTicks() + : optional_now); + TraceEventIdlePeriodStateChange(new_state, running_idle_task_for_tracing_, + idle_period_deadline_, now); + } + + idle_period_state_ = new_state; + idle_period_deadline_ = new_deadline; + + // Inform the delegate if we are starting or ending an idle period. + if (IsInIdlePeriod(new_state) && !IsInIdlePeriod(old_idle_period_state)) { + delegate_->OnIdlePeriodStarted(); + } else if (!IsInIdlePeriod(new_state) && + IsInIdlePeriod(old_idle_period_state)) { + delegate_->OnIdlePeriodEnded(); + } +} + +void IdleHelper::State::TraceIdleIdleTaskStart() { + helper_->CheckOnValidThread(); + + bool is_tracing; + TRACE_EVENT_CATEGORY_GROUP_ENABLED(tracing_category_, &is_tracing); + if (is_tracing) { + TraceEventIdlePeriodStateChange(idle_period_state_, true, + idle_period_deadline_, + base::TimeTicks::Now()); + } +} + +void IdleHelper::State::TraceIdleIdleTaskEnd() { + helper_->CheckOnValidThread(); + + bool is_tracing; + TRACE_EVENT_CATEGORY_GROUP_ENABLED(tracing_category_, &is_tracing); + if (is_tracing) { + TraceEventIdlePeriodStateChange(idle_period_state_, false, + idle_period_deadline_, + base::TimeTicks::Now()); + } +} + +void IdleHelper::State::TraceEventIdlePeriodStateChange( + IdlePeriodState new_state, + bool new_running_idle_task, + base::TimeTicks new_deadline, + base::TimeTicks now) { + TRACE_EVENT2(disabled_by_default_tracing_category_, "SetIdlePeriodState", + "old_state", + IdleHelper::IdlePeriodStateToString(idle_period_state_), + "new_state", IdleHelper::IdlePeriodStateToString(new_state)); + + if (idle_period_trace_event_started_ && running_idle_task_for_tracing_ && + !new_running_idle_task) { + running_idle_task_for_tracing_ = false; + if (!idle_period_deadline_.is_null() && now > idle_period_deadline_) { + TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0( + tracing_category_, idle_period_tracing_name_, this, "DeadlineOverrun", + std::max(idle_period_deadline_, last_idle_task_trace_time_) + .ToInternalValue()); + } + } + + if (IsInIdlePeriod(new_state)) { + if (!idle_period_trace_event_started_) { + idle_period_trace_event_started_ = true; + TRACE_EVENT_ASYNC_BEGIN1(tracing_category_, idle_period_tracing_name_, + this, "idle_period_length_ms", + (new_deadline - now).ToInternalValue()); + } + + if (new_running_idle_task) { + last_idle_task_trace_time_ = now; + running_idle_task_for_tracing_ = true; + TRACE_EVENT_ASYNC_STEP_INTO0(tracing_category_, idle_period_tracing_name_, + this, "RunningIdleTask"); + } else if (new_state == IdlePeriodState::IN_SHORT_IDLE_PERIOD) { + TRACE_EVENT_ASYNC_STEP_INTO0(tracing_category_, idle_period_tracing_name_, + this, "ShortIdlePeriod"); + } else if (IsInLongIdlePeriod(new_state) && + new_state != IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED) { + TRACE_EVENT_ASYNC_STEP_INTO0(tracing_category_, idle_period_tracing_name_, + this, "LongIdlePeriod"); + } else if (new_state == IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED) { + TRACE_EVENT_ASYNC_STEP_INTO0(tracing_category_, idle_period_tracing_name_, + this, "LongIdlePeriodPaused"); + } + } else if (idle_period_trace_event_started_) { + idle_period_trace_event_started_ = false; + TRACE_EVENT_ASYNC_END0(tracing_category_, idle_period_tracing_name_, this); + } +} + +// static +const char* IdleHelper::IdlePeriodStateToString( + IdlePeriodState idle_period_state) { + switch (idle_period_state) { + case IdlePeriodState::NOT_IN_IDLE_PERIOD: + return "not_in_idle_period"; + case IdlePeriodState::IN_SHORT_IDLE_PERIOD: + return "in_short_idle_period"; + case IdlePeriodState::IN_LONG_IDLE_PERIOD: + return "in_long_idle_period"; + case IdlePeriodState::IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE: + return "in_long_idle_period_with_max_deadline"; + case IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED: + return "in_long_idle_period_paused"; + default: + NOTREACHED(); + return nullptr; + } +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/child/idle_helper.h b/third_party/WebKit/Source/platform/scheduler/child/idle_helper.h new file mode 100644 index 0000000..47fc8cf --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/child/idle_helper.h
@@ -0,0 +1,223 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_CHILD_IDLE_HELPER_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_CHILD_IDLE_HELPER_H_ + +#include "base/macros.h" +#include "base/message_loop/message_loop.h" +#include "platform/scheduler/base/cancelable_closure_holder.h" +#include "platform/scheduler/base/task_queue_selector.h" +#include "platform/scheduler/child/scheduler_helper.h" +#include "public/platform/scheduler/child/single_thread_idle_task_runner.h" +#include "public/platform/WebCommon.h" + +namespace blink { +namespace scheduler { + +class SchedulerHelper; + +// Common scheduler functionality for Idle tasks. +class BLINK_PLATFORM_EXPORT IdleHelper + : public base::MessageLoop::TaskObserver, + public SingleThreadIdleTaskRunner::Delegate { + public: + // Used to by scheduler implementations to customize idle behaviour. + class BLINK_PLATFORM_EXPORT Delegate { + public: + Delegate(); + virtual ~Delegate(); + + // If it's ok to enter a long idle period, return true. Otherwise return + // false and set next_long_idle_period_delay_out so we know when to try + // again. + virtual bool CanEnterLongIdlePeriod( + base::TimeTicks now, + base::TimeDelta* next_long_idle_period_delay_out) = 0; + + // Signals that the Long Idle Period hasn't started yet because the system + // isn't quiescent. + virtual void IsNotQuiescent() = 0; + + // Signals that we have started an Idle Period. + virtual void OnIdlePeriodStarted() = 0; + + // Signals that we have finished an Idle Period. + virtual void OnIdlePeriodEnded() = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(Delegate); + }; + + // Keep IdleHelper::IdlePeriodStateToString in sync with this enum. + enum class IdlePeriodState { + NOT_IN_IDLE_PERIOD, + IN_SHORT_IDLE_PERIOD, + IN_LONG_IDLE_PERIOD, + IN_LONG_IDLE_PERIOD_WITH_MAX_DEADLINE, + IN_LONG_IDLE_PERIOD_PAUSED, + // Must be the last entry. + IDLE_PERIOD_STATE_COUNT, + FIRST_IDLE_PERIOD_STATE = NOT_IN_IDLE_PERIOD, + }; + + // The maximum length of an idle period. + static const int kMaximumIdlePeriodMillis = 50; + + // |helper| and |delegate| are not owned by IdleHelper object and must + // outlive it. + IdleHelper( + SchedulerHelper* helper, + Delegate* delegate, + const char* tracing_category, + const char* disabled_by_default_tracing_category, + const char* idle_period_tracing_name, + base::TimeDelta required_quiescence_duration_before_long_idle_period); + ~IdleHelper() override; + + // Returns the idle task runner. Tasks posted to this runner may be reordered + // relative to other task types and may be starved for an arbitrarily long + // time if no idle time is available. + scoped_refptr<SingleThreadIdleTaskRunner> IdleTaskRunner(); + + // If |required_quiescence_duration_before_long_idle_period_| is zero then + // immediately initiate a long idle period, otherwise check if any tasks have + // run recently and if so, check again after a delay of + // |required_quiescence_duration_before_long_idle_period_|. + // Calling this function will end any previous idle period immediately, and + // potentially again later if + // |required_quiescence_duration_before_long_idle_period_| is non-zero. + // NOTE EndIdlePeriod will disable the long idle periods. + void EnableLongIdlePeriod(); + + // Start an idle period with a given idle period deadline. + void StartIdlePeriod(IdlePeriodState new_idle_period_state, + base::TimeTicks now, + base::TimeTicks idle_period_deadline); + + // This will end an idle period either started with StartIdlePeriod or + // EnableLongIdlePeriod. + void EndIdlePeriod(); + + // Returns true if a currently running idle task could exceed its deadline + // without impacting user experience too much. This should only be used if + // there is a task which cannot be pre-empted and is likely to take longer + // than the largest expected idle task deadline. It should NOT be polled to + // check whether more work can be performed on the current idle task after + // its deadline has expired - post a new idle task for the continuation of the + // work in this case. + // Must be called from the thread this class was created on. + bool CanExceedIdleDeadlineIfRequired() const; + + // Returns the deadline for the current idle task. + base::TimeTicks CurrentIdleTaskDeadline() const; + + // SingleThreadIdleTaskRunner::Delegate implementation: + void OnIdleTaskPosted() override; + base::TimeTicks WillProcessIdleTask() override; + void DidProcessIdleTask() override; + + // base::MessageLoop::TaskObserver implementation: + void WillProcessTask(const base::PendingTask& pending_task) override; + void DidProcessTask(const base::PendingTask& pending_task) override; + + IdlePeriodState SchedulerIdlePeriodState() const; + static const char* IdlePeriodStateToString(IdlePeriodState state); + + private: + friend class BaseIdleHelperTest; + friend class IdleHelperTest; + + class State { + public: + State(SchedulerHelper* helper, + Delegate* delegate, + const char* tracing_category, + const char* disabled_by_default_tracing_category, + const char* idle_period_tracing_name); + virtual ~State(); + + void UpdateState(IdlePeriodState new_state, + base::TimeTicks new_deadline, + base::TimeTicks optional_now); + bool IsIdlePeriodPaused() const; + + IdlePeriodState idle_period_state() const; + base::TimeTicks idle_period_deadline() const; + + void TraceIdleIdleTaskStart(); + void TraceIdleIdleTaskEnd(); + + private: + void TraceEventIdlePeriodStateChange(IdlePeriodState new_state, + bool new_running_idle_task, + base::TimeTicks new_deadline, + base::TimeTicks optional_now); + + SchedulerHelper* helper_; // NOT OWNED + Delegate* delegate_; // NOT OWNED + + IdlePeriodState idle_period_state_; + base::TimeTicks idle_period_deadline_; + + base::TimeTicks last_idle_task_trace_time_; + bool idle_period_trace_event_started_; + bool running_idle_task_for_tracing_; + const char* tracing_category_; + const char* disabled_by_default_tracing_category_; + const char* idle_period_tracing_name_; + + DISALLOW_COPY_AND_ASSIGN(State); + }; + + // The minimum duration of an idle period. + static const int kMinimumIdlePeriodDurationMillis = 1; + + // The minimum delay to wait between retrying to initiate a long idle time. + static const int kRetryEnableLongIdlePeriodDelayMillis = 1; + + // Returns the new idle period state for the next long idle period. Fills in + // |next_long_idle_period_delay_out| with the next time we should try to + // initiate the next idle period. + IdlePeriodState ComputeNewLongIdlePeriodState( + const base::TimeTicks now, + base::TimeDelta* next_long_idle_period_delay_out); + + bool ShouldWaitForQuiescence(); + void OnIdleTaskPostedOnMainThread(); + void UpdateLongIdlePeriodStateAfterIdleTask(); + + void SetIdlePeriodState(IdlePeriodState new_state, + base::TimeTicks new_deadline, + base::TimeTicks optional_now); + + // Returns true if |state| represents being within an idle period state. + static bool IsInIdlePeriod(IdlePeriodState state); + // Returns true if |state| represents being within a long idle period state. + static bool IsInLongIdlePeriod(IdlePeriodState state); + + SchedulerHelper* helper_; // NOT OWNED + Delegate* delegate_; // NOT OWNED + scoped_refptr<TaskQueue> idle_queue_; + scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_; + + CancelableClosureHolder enable_next_long_idle_period_closure_; + CancelableClosureHolder on_idle_task_posted_closure_; + + State state_; + + base::TimeDelta required_quiescence_duration_before_long_idle_period_; + + const char* disabled_by_default_tracing_category_; + + base::WeakPtr<IdleHelper> weak_idle_helper_ptr_; + base::WeakPtrFactory<IdleHelper> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(IdleHelper); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_CHILD_IDLE_HELPER_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/child/idle_helper_unittest.cc b/third_party/WebKit/Source/platform/scheduler/child/idle_helper_unittest.cc new file mode 100644 index 0000000..cdf37b783 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/child/idle_helper_unittest.cc
@@ -0,0 +1,1159 @@ +// 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 "platform/scheduler/child/idle_helper.h" + +#include <utility> + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "base/run_loop.h" +#include "base/test/simple_test_tick_clock.h" +#include "cc/test/ordered_simple_task_runner.h" +#include "platform/scheduler/base/real_time_domain.h" +#include "public/platform/scheduler/base/task_queue.h" +#include "platform/scheduler/base/task_queue_manager.h" +#include "platform/scheduler/base/test_time_source.h" +#include "platform/scheduler/child/scheduler_helper.h" +#include "platform/scheduler/child/scheduler_tqm_delegate_for_test.h" +#include "platform/scheduler/child/scheduler_tqm_delegate_impl.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::_; +using testing::AnyNumber; +using testing::AtLeast; +using testing::Exactly; +using testing::Invoke; +using testing::Return; + +namespace blink { +namespace scheduler { + +namespace { +void AppendToVectorTestTask(std::vector<std::string>* vector, + std::string value) { + vector->push_back(value); +} + +void AppendToVectorIdleTestTask(std::vector<std::string>* vector, + std::string value, + base::TimeTicks deadline) { + AppendToVectorTestTask(vector, value); +} + +void NullTask() {} + +void NullIdleTask(base::TimeTicks deadline) {} + +void AppendToVectorReentrantTask(base::SingleThreadTaskRunner* task_runner, + std::vector<int>* vector, + int* reentrant_count, + int max_reentrant_count) { + vector->push_back((*reentrant_count)++); + if (*reentrant_count < max_reentrant_count) { + task_runner->PostTask( + FROM_HERE, + base::Bind(AppendToVectorReentrantTask, base::Unretained(task_runner), + vector, reentrant_count, max_reentrant_count)); + } +} + +void IdleTestTask(int* run_count, + base::TimeTicks* deadline_out, + base::TimeTicks deadline) { + (*run_count)++; + *deadline_out = deadline; +} + +int max_idle_task_reposts = 2; + +void RepostingIdleTestTask(SingleThreadIdleTaskRunner* idle_task_runner, + int* run_count, + base::TimeTicks* deadline_out, + base::TimeTicks deadline) { + if ((*run_count + 1) < max_idle_task_reposts) { + idle_task_runner->PostIdleTask( + FROM_HERE, + base::Bind(&RepostingIdleTestTask, base::Unretained(idle_task_runner), + run_count, deadline_out)); + } + *deadline_out = deadline; + (*run_count)++; +} + +void RepostingUpdateClockIdleTestTask( + SingleThreadIdleTaskRunner* idle_task_runner, + int* run_count, + base::SimpleTestTickClock* clock, + base::TimeDelta advance_time, + std::vector<base::TimeTicks>* deadlines, + base::TimeTicks deadline) { + if ((*run_count + 1) < max_idle_task_reposts) { + idle_task_runner->PostIdleTask( + FROM_HERE, base::Bind(&RepostingUpdateClockIdleTestTask, + base::Unretained(idle_task_runner), run_count, + clock, advance_time, deadlines)); + } + deadlines->push_back(deadline); + (*run_count)++; + clock->Advance(advance_time); +} + +void RepeatingTask(base::SingleThreadTaskRunner* task_runner, + int num_repeats, + base::TimeDelta delay) { + if (num_repeats > 1) { + task_runner->PostDelayedTask( + FROM_HERE, base::Bind(&RepeatingTask, base::Unretained(task_runner), + num_repeats - 1, delay), + delay); + } +} + +void UpdateClockIdleTestTask(base::SimpleTestTickClock* clock, + int* run_count, + base::TimeTicks set_time, + base::TimeTicks deadline) { + clock->Advance(set_time - clock->NowTicks()); + (*run_count)++; +} + +void UpdateClockToDeadlineIdleTestTask(base::SimpleTestTickClock* clock, + int* run_count, + base::TimeTicks deadline) { + UpdateClockIdleTestTask(clock, run_count, deadline, deadline); +} + +void EndIdlePeriodIdleTask(IdleHelper* idle_helper, base::TimeTicks deadline) { + idle_helper->EndIdlePeriod(); +} + +scoped_refptr<SchedulerTqmDelegate> CreateTaskRunnerDelegate( + base::MessageLoop* message_loop, + scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner, + std::unique_ptr<TestTimeSource> test_time_source) { + if (message_loop) + return SchedulerTqmDelegateImpl::Create(message_loop, + std::move(test_time_source)); + + return SchedulerTqmDelegateForTest::Create(mock_task_runner, + std::move(test_time_source)); +} + +}; // namespace + +class IdleHelperForTest : public IdleHelper, public IdleHelper::Delegate { + public: + explicit IdleHelperForTest( + SchedulerHelper* scheduler_helper, + base::TimeDelta required_quiescence_duration_before_long_idle_period) + : IdleHelper(scheduler_helper, + this, + "test.idle", + TRACE_DISABLED_BY_DEFAULT("test.idle"), + "TestSchedulerIdlePeriod", + required_quiescence_duration_before_long_idle_period) {} + + ~IdleHelperForTest() override {} + + // SchedulerHelperDelegate implementation: + MOCK_METHOD2(CanEnterLongIdlePeriod, + bool(base::TimeTicks now, + base::TimeDelta* next_long_idle_period_delay_out)); + + MOCK_METHOD0(IsNotQuiescent, void()); + MOCK_METHOD0(OnIdlePeriodStarted, void()); + MOCK_METHOD0(OnIdlePeriodEnded, void()); +}; + +class BaseIdleHelperTest : public testing::Test { + public: + BaseIdleHelperTest( + base::MessageLoop* message_loop, + base::TimeDelta required_quiescence_duration_before_long_idle_period) + : clock_(new base::SimpleTestTickClock()), + mock_task_runner_( + message_loop + ? nullptr + : new cc::OrderedSimpleTaskRunner(clock_.get(), false)), + message_loop_(message_loop), + main_task_runner_(CreateTaskRunnerDelegate( + message_loop, + mock_task_runner_, + base::WrapUnique(new TestTimeSource(clock_.get())))), + scheduler_helper_( + new SchedulerHelper(main_task_runner_, + "test.idle", + TRACE_DISABLED_BY_DEFAULT("test.idle"), + TRACE_DISABLED_BY_DEFAULT("test.idle.debug"))), + idle_helper_(new IdleHelperForTest( + scheduler_helper_.get(), + required_quiescence_duration_before_long_idle_period)), + default_task_runner_(scheduler_helper_->DefaultTaskRunner()), + idle_task_runner_(idle_helper_->IdleTaskRunner()) { + clock_->Advance(base::TimeDelta::FromMicroseconds(5000)); + } + + ~BaseIdleHelperTest() override {} + + void SetUp() override { + EXPECT_CALL(*idle_helper_, OnIdlePeriodStarted()).Times(AnyNumber()); + EXPECT_CALL(*idle_helper_, OnIdlePeriodEnded()).Times(AnyNumber()); + EXPECT_CALL(*idle_helper_, CanEnterLongIdlePeriod(_, _)) + .Times(AnyNumber()) + .WillRepeatedly(Return(true)); + } + + void TearDown() override { + DCHECK(!mock_task_runner_.get() || !message_loop_.get()); + if (mock_task_runner_.get()) { + // Check that all tests stop posting tasks. + mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true); + while (mock_task_runner_->RunUntilIdle()) { + } + } else { + base::RunLoop().RunUntilIdle(); + } + } + + void RunUntilIdle() { + // Only one of mock_task_runner_ or message_loop_ should be set. + DCHECK(!mock_task_runner_.get() || !message_loop_.get()); + if (mock_task_runner_.get()) + mock_task_runner_->RunUntilIdle(); + else + base::RunLoop().RunUntilIdle(); + } + + template <typename E> + static void CallForEachEnumValue(E first, + E last, + const char* (*function)(E)) { + for (E val = first; val < last; + val = static_cast<E>(static_cast<int>(val) + 1)) { + (*function)(val); + } + } + + static void CheckAllTaskQueueIdToString() { + CallForEachEnumValue<IdleHelper::IdlePeriodState>( + IdleHelper::IdlePeriodState::FIRST_IDLE_PERIOD_STATE, + IdleHelper::IdlePeriodState::IDLE_PERIOD_STATE_COUNT, + &IdleHelper::IdlePeriodStateToString); + } + + bool IsInIdlePeriod() const { + return idle_helper_->IsInIdlePeriod( + idle_helper_->SchedulerIdlePeriodState()); + } + + protected: + static base::TimeDelta maximum_idle_period_duration() { + return base::TimeDelta::FromMilliseconds( + IdleHelper::kMaximumIdlePeriodMillis); + } + + static base::TimeDelta retry_enable_long_idle_period_delay() { + return base::TimeDelta::FromMilliseconds( + IdleHelper::kRetryEnableLongIdlePeriodDelayMillis); + } + + static base::TimeDelta minimum_idle_period_duration() { + return base::TimeDelta::FromMilliseconds( + IdleHelper::kMinimumIdlePeriodDurationMillis); + } + + base::TimeTicks CurrentIdleTaskDeadline() { + return idle_helper_->CurrentIdleTaskDeadline(); + } + + void CheckIdlePeriodStateIs(const char* expected) { + EXPECT_STREQ(expected, IdleHelper::IdlePeriodStateToString( + idle_helper_->SchedulerIdlePeriodState())); + } + + std::unique_ptr<base::SimpleTestTickClock> clock_; + // Only one of mock_task_runner_ or message_loop_ will be set. + scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_; + std::unique_ptr<base::MessageLoop> message_loop_; + + scoped_refptr<SchedulerTqmDelegate> main_task_runner_; + std::unique_ptr<SchedulerHelper> scheduler_helper_; + std::unique_ptr<IdleHelperForTest> idle_helper_; + scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_; + scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_; + + DISALLOW_COPY_AND_ASSIGN(BaseIdleHelperTest); +}; + +class IdleHelperTest : public BaseIdleHelperTest { + public: + IdleHelperTest() : BaseIdleHelperTest(nullptr, base::TimeDelta()) {} + + ~IdleHelperTest() override {} + + TaskQueueManager* task_queue_manager() const { + return scheduler_helper_->GetTaskQueueManagerForTesting(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(IdleHelperTest); +}; + +TEST_F(IdleHelperTest, TestPostIdleTask) { + int run_count = 0; + base::TimeTicks expected_deadline = + clock_->NowTicks() + base::TimeDelta::FromMilliseconds(2300); + base::TimeTicks deadline_in_task; + + clock_->Advance(base::TimeDelta::FromMilliseconds(100)); + idle_task_runner_->PostIdleTask( + FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + + RunUntilIdle(); + EXPECT_EQ(0, run_count); + + idle_helper_->StartIdlePeriod( + IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), + expected_deadline); + RunUntilIdle(); + EXPECT_EQ(1, run_count); + EXPECT_EQ(expected_deadline, deadline_in_task); +} + +TEST_F(IdleHelperTest, TestPostIdleTask_EndIdlePeriod) { + int run_count = 0; + base::TimeTicks deadline_in_task; + + clock_->Advance(base::TimeDelta::FromMilliseconds(100)); + idle_task_runner_->PostIdleTask( + FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + + RunUntilIdle(); + EXPECT_EQ(0, run_count); + + idle_helper_->StartIdlePeriod( + IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), + clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); + idle_helper_->EndIdlePeriod(); + RunUntilIdle(); + EXPECT_EQ(0, run_count); +} + +TEST_F(IdleHelperTest, TestRepostingIdleTask) { + base::TimeTicks actual_deadline; + int run_count = 0; + + max_idle_task_reposts = 2; + idle_task_runner_->PostIdleTask( + FROM_HERE, + base::Bind(&RepostingIdleTestTask, base::RetainedRef(idle_task_runner_), + &run_count, &actual_deadline)); + idle_helper_->StartIdlePeriod( + IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), + clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); + RunUntilIdle(); + EXPECT_EQ(1, run_count); + + // Reposted tasks shouldn't run until next idle period. + RunUntilIdle(); + EXPECT_EQ(1, run_count); + + idle_helper_->StartIdlePeriod( + IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), + clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); + RunUntilIdle(); + EXPECT_EQ(2, run_count); +} + +TEST_F(IdleHelperTest, TestIdleTaskExceedsDeadline) { + int run_count = 0; + + // Post two UpdateClockToDeadlineIdleTestTask tasks. + idle_task_runner_->PostIdleTask( + FROM_HERE, + base::Bind(&UpdateClockToDeadlineIdleTestTask, clock_.get(), &run_count)); + idle_task_runner_->PostIdleTask( + FROM_HERE, + base::Bind(&UpdateClockToDeadlineIdleTestTask, clock_.get(), &run_count)); + + idle_helper_->StartIdlePeriod( + IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), + clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); + RunUntilIdle(); + // Only the first idle task should execute since it's used up the deadline. + EXPECT_EQ(1, run_count); + + idle_helper_->EndIdlePeriod(); + idle_helper_->StartIdlePeriod( + IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), + clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); + RunUntilIdle(); + // Second task should be run on the next idle period. + EXPECT_EQ(2, run_count); +} + +TEST_F(IdleHelperTest, TestPostIdleTaskAfterWakeup) { + base::TimeTicks deadline_in_task; + int run_count = 0; + + idle_task_runner_->PostIdleTaskAfterWakeup( + FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + + idle_helper_->StartIdlePeriod( + IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), + clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); + RunUntilIdle(); + // Shouldn't run yet as no other task woke up the scheduler. + EXPECT_EQ(0, run_count); + + // Must start a new idle period before idle task runs. + idle_task_runner_->PostIdleTaskAfterWakeup( + FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + + idle_helper_->StartIdlePeriod( + IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), + clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); + RunUntilIdle(); + // Another after wakeup idle task shouldn't wake the scheduler. + EXPECT_EQ(0, run_count); + + default_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask)); + + RunUntilIdle(); + idle_helper_->StartIdlePeriod( + IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), + clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); + RunUntilIdle(); + // Execution of default task queue task should trigger execution of idle task. + EXPECT_EQ(2, run_count); +} + +TEST_F(IdleHelperTest, TestPostIdleTaskAfterWakeupWhileAwake) { + base::TimeTicks deadline_in_task; + int run_count = 0; + + idle_task_runner_->PostIdleTaskAfterWakeup( + FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + default_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask)); + + RunUntilIdle(); + // Must start a new idle period before idle task runs. + idle_helper_->StartIdlePeriod( + IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), + clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); + RunUntilIdle(); + // Should run as the scheduler was already awakened by the normal task. + EXPECT_EQ(1, run_count); +} + +TEST_F(IdleHelperTest, TestPostIdleTaskWakesAfterWakeupIdleTask) { + base::TimeTicks deadline_in_task; + int run_count = 0; + + idle_task_runner_->PostIdleTaskAfterWakeup( + FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + idle_task_runner_->PostIdleTask( + FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + + idle_helper_->StartIdlePeriod( + IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), + clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); + RunUntilIdle(); + // Must start a new idle period before after-wakeup idle task runs. + idle_helper_->StartIdlePeriod( + IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), + clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); + RunUntilIdle(); + // Normal idle task should wake up after-wakeup idle task. + EXPECT_EQ(2, run_count); +} + +class IdleHelperTestWithIdlePeriodObserver : public BaseIdleHelperTest { + public: + IdleHelperTestWithIdlePeriodObserver() + : BaseIdleHelperTest(nullptr, base::TimeDelta()) {} + + ~IdleHelperTestWithIdlePeriodObserver() override {} + + void SetUp() override { + // Don't set expectations on IdleHelper::Delegate. + } + + TaskQueueManager* task_queue_manager() const { + return scheduler_helper_->GetTaskQueueManagerForTesting(); + } + + void ExpectIdlePeriodStartsButNeverEnds() { + EXPECT_CALL(*idle_helper_, OnIdlePeriodStarted()).Times(1); + EXPECT_CALL(*idle_helper_, OnIdlePeriodEnded()).Times(0); + } + + void ExpectIdlePeriodStartsAndEnds(const testing::Cardinality& cardinality) { + EXPECT_CALL(*idle_helper_, OnIdlePeriodStarted()).Times(cardinality); + EXPECT_CALL(*idle_helper_, OnIdlePeriodEnded()).Times(cardinality); + } + + private: + DISALLOW_COPY_AND_ASSIGN(IdleHelperTestWithIdlePeriodObserver); +}; + +TEST_F(IdleHelperTestWithIdlePeriodObserver, TestEnterButNotExitIdlePeriod) { + ExpectIdlePeriodStartsButNeverEnds(); + + idle_helper_->StartIdlePeriod( + IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), + clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); +} + +TEST_F(IdleHelperTestWithIdlePeriodObserver, TestEnterAndExitIdlePeriod) { + BaseIdleHelperTest* fixture = this; + ON_CALL(*idle_helper_, OnIdlePeriodStarted()) + .WillByDefault( + Invoke([fixture]() { EXPECT_TRUE(fixture->IsInIdlePeriod()); })); + ON_CALL(*idle_helper_, OnIdlePeriodEnded()) + .WillByDefault( + Invoke([fixture]() { EXPECT_FALSE(fixture->IsInIdlePeriod()); })); + + ExpectIdlePeriodStartsAndEnds(Exactly(1)); + + idle_helper_->StartIdlePeriod( + IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), + clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); + idle_helper_->EndIdlePeriod(); +} + +class IdleHelperWithMessageLoopTest : public BaseIdleHelperTest { + public: + IdleHelperWithMessageLoopTest() + : BaseIdleHelperTest(new base::MessageLoop(), base::TimeDelta()) {} + ~IdleHelperWithMessageLoopTest() override {} + + void PostFromNestedRunloop( + std::vector<std::pair<SingleThreadIdleTaskRunner::IdleTask, bool>>* + tasks) { + base::MessageLoop::ScopedNestableTaskAllower allow(message_loop_.get()); + for (std::pair<SingleThreadIdleTaskRunner::IdleTask, bool>& pair : *tasks) { + if (pair.second) { + idle_task_runner_->PostIdleTask(FROM_HERE, pair.first); + } else { + idle_task_runner_->PostNonNestableIdleTask(FROM_HERE, pair.first); + } + } + idle_helper_->StartIdlePeriod( + IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), + clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); + base::RunLoop().RunUntilIdle(); + } + + void SetUp() override { + EXPECT_CALL(*idle_helper_, OnIdlePeriodStarted()).Times(AnyNumber()); + EXPECT_CALL(*idle_helper_, OnIdlePeriodEnded()).Times(AnyNumber()); + } + + private: + DISALLOW_COPY_AND_ASSIGN(IdleHelperWithMessageLoopTest); +}; + +TEST_F(IdleHelperWithMessageLoopTest, + NonNestableIdleTaskDoesntExecuteInNestedLoop) { + std::vector<std::string> order; + idle_task_runner_->PostIdleTask( + FROM_HERE, + base::Bind(&AppendToVectorIdleTestTask, &order, std::string("1"))); + idle_task_runner_->PostIdleTask( + FROM_HERE, + base::Bind(&AppendToVectorIdleTestTask, &order, std::string("2"))); + + std::vector<std::pair<SingleThreadIdleTaskRunner::IdleTask, bool>> + tasks_to_post_from_nested_loop; + tasks_to_post_from_nested_loop.push_back(std::make_pair( + base::Bind(&AppendToVectorIdleTestTask, &order, std::string("3")), + false)); + tasks_to_post_from_nested_loop.push_back(std::make_pair( + base::Bind(&AppendToVectorIdleTestTask, &order, std::string("4")), true)); + tasks_to_post_from_nested_loop.push_back(std::make_pair( + base::Bind(&AppendToVectorIdleTestTask, &order, std::string("5")), true)); + + default_task_runner_->PostTask( + FROM_HERE, + base::Bind(&IdleHelperWithMessageLoopTest::PostFromNestedRunloop, + base::Unretained(this), + base::Unretained(&tasks_to_post_from_nested_loop))); + + idle_helper_->StartIdlePeriod( + IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), + clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); + RunUntilIdle(); + // Note we expect task 3 to run last because it's non-nestable. + EXPECT_THAT(order, testing::ElementsAre(std::string("1"), std::string("2"), + std::string("4"), std::string("5"), + std::string("3"))); +} + +TEST_F(IdleHelperTestWithIdlePeriodObserver, TestLongIdlePeriod) { + base::TimeTicks expected_deadline = + clock_->NowTicks() + maximum_idle_period_duration(); + base::TimeTicks deadline_in_task; + int run_count = 0; + + idle_task_runner_->PostIdleTask( + FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + + EXPECT_CALL(*idle_helper_, CanEnterLongIdlePeriod(_, _)) + .Times(1) + .WillRepeatedly(Return(true)); + ExpectIdlePeriodStartsButNeverEnds(); + + RunUntilIdle(); + EXPECT_EQ(0, run_count); // Shouldn't run yet as no idle period. + + idle_helper_->EnableLongIdlePeriod(); + RunUntilIdle(); + EXPECT_EQ(1, run_count); // Should have run in a long idle time. + EXPECT_EQ(expected_deadline, deadline_in_task); +} + +TEST_F(IdleHelperTest, TestLongIdlePeriodWithPendingDelayedTask) { + base::TimeDelta pending_task_delay = base::TimeDelta::FromMilliseconds(30); + base::TimeTicks expected_deadline = clock_->NowTicks() + pending_task_delay; + base::TimeTicks deadline_in_task; + int run_count = 0; + + idle_task_runner_->PostIdleTask( + FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask), + pending_task_delay); + + idle_helper_->EnableLongIdlePeriod(); + RunUntilIdle(); + EXPECT_EQ(1, run_count); // Should have run in a long idle time. + EXPECT_EQ(expected_deadline, deadline_in_task); +} + +TEST_F(IdleHelperTest, TestLongIdlePeriodWithLatePendingDelayedTask) { + base::TimeDelta pending_task_delay = base::TimeDelta::FromMilliseconds(10); + base::TimeTicks deadline_in_task; + int run_count = 0; + + default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask), + pending_task_delay); + + // Advance clock until after delayed task was meant to be run. + clock_->Advance(base::TimeDelta::FromMilliseconds(20)); + + // Post an idle task and then EnableLongIdlePeriod. Since there is a late + // pending delayed task this shouldn't actually start an idle period. + idle_task_runner_->PostIdleTask( + FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + idle_helper_->EnableLongIdlePeriod(); + RunUntilIdle(); + EXPECT_EQ(0, run_count); + + // After the delayed task has been run we should trigger an idle period. + clock_->Advance(maximum_idle_period_duration()); + RunUntilIdle(); + EXPECT_EQ(1, run_count); +} + +TEST_F(IdleHelperTestWithIdlePeriodObserver, TestLongIdlePeriodRepeating) { + mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true); + std::vector<base::TimeTicks> actual_deadlines; + int run_count = 0; + + EXPECT_CALL(*idle_helper_, CanEnterLongIdlePeriod(_, _)) + .Times(4) + .WillRepeatedly(Return(true)); + ExpectIdlePeriodStartsAndEnds(AtLeast(2)); + + max_idle_task_reposts = 3; + base::TimeTicks clock_before(clock_->NowTicks()); + base::TimeDelta idle_task_runtime(base::TimeDelta::FromMilliseconds(10)); + idle_task_runner_->PostIdleTask( + FROM_HERE, + base::Bind(&RepostingUpdateClockIdleTestTask, + base::RetainedRef(idle_task_runner_), &run_count, clock_.get(), + idle_task_runtime, &actual_deadlines)); + + // Check each idle task runs in their own idle period. + idle_helper_->EnableLongIdlePeriod(); + RunUntilIdle(); + EXPECT_EQ(3, run_count); + EXPECT_THAT( + actual_deadlines, + testing::ElementsAre( + clock_before + maximum_idle_period_duration(), + clock_before + idle_task_runtime + maximum_idle_period_duration(), + clock_before + (2 * idle_task_runtime) + + maximum_idle_period_duration())); + + max_idle_task_reposts = 5; + idle_task_runner_->PostIdleTask( + FROM_HERE, + base::Bind(&RepostingUpdateClockIdleTestTask, + base::RetainedRef(idle_task_runner_), &run_count, clock_.get(), + idle_task_runtime, &actual_deadlines)); + idle_task_runner_->PostIdleTask( + FROM_HERE, + base::Bind(&EndIdlePeriodIdleTask, base::Unretained(idle_helper_.get()))); + + // Ensure that reposting tasks stop after EndIdlePeriod is called. + RunUntilIdle(); + EXPECT_EQ(4, run_count); +} + +TEST_F(IdleHelperTest, TestLongIdlePeriodDoesNotWakeScheduler) { + base::TimeTicks deadline_in_task; + int run_count = 0; + + // Start a long idle period and get the time it should end. + idle_helper_->EnableLongIdlePeriod(); + // The scheduler should not run the enable_next_long_idle_period task if + // there are no idle tasks and no other task woke up the scheduler, thus + // the idle period deadline shouldn't update at the end of the current long + // idle period. + base::TimeTicks idle_period_deadline = CurrentIdleTaskDeadline(); + clock_->Advance(maximum_idle_period_duration()); + RunUntilIdle(); + + base::TimeTicks new_idle_period_deadline = CurrentIdleTaskDeadline(); + EXPECT_EQ(idle_period_deadline, new_idle_period_deadline); + + // Posting a after-wakeup idle task also shouldn't wake the scheduler or + // initiate the next long idle period. + idle_task_runner_->PostIdleTaskAfterWakeup( + FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + RunUntilIdle(); + new_idle_period_deadline = CurrentIdleTaskDeadline(); + EXPECT_EQ(idle_period_deadline, new_idle_period_deadline); + EXPECT_EQ(0, run_count); + + // Running a normal task should initiate a new long idle period though. + default_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask)); + RunUntilIdle(); + new_idle_period_deadline = CurrentIdleTaskDeadline(); + EXPECT_EQ(idle_period_deadline + maximum_idle_period_duration(), + new_idle_period_deadline); + + EXPECT_EQ(1, run_count); +} + +TEST_F(IdleHelperTestWithIdlePeriodObserver, + TestLongIdlePeriodWhenNotCanEnterLongIdlePeriod) { + base::TimeDelta delay = base::TimeDelta::FromMilliseconds(1000); + base::TimeDelta halfDelay = base::TimeDelta::FromMilliseconds(500); + base::TimeTicks delayOver = clock_->NowTicks() + delay; + base::TimeTicks deadline_in_task; + int run_count = 0; + + ON_CALL(*idle_helper_, CanEnterLongIdlePeriod(_, _)) + .WillByDefault(Invoke( + [delay, delayOver](base::TimeTicks now, + base::TimeDelta* next_long_idle_period_delay_out) { + if (now >= delayOver) + return true; + *next_long_idle_period_delay_out = delay; + return false; + })); + + EXPECT_CALL(*idle_helper_, CanEnterLongIdlePeriod(_, _)).Times(2); + EXPECT_CALL(*idle_helper_, OnIdlePeriodStarted()).Times(AnyNumber()); + + idle_task_runner_->PostIdleTask( + FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + + // Make sure Idle tasks don't run until the delay has occurred. + idle_helper_->EnableLongIdlePeriod(); + RunUntilIdle(); + EXPECT_EQ(0, run_count); + + clock_->Advance(halfDelay); + RunUntilIdle(); + EXPECT_EQ(0, run_count); + + // Delay is finished, idle task should run. + clock_->Advance(halfDelay); + RunUntilIdle(); + EXPECT_EQ(1, run_count); +} + +TEST_F(IdleHelperTest, TestLongIdlePeriodImmediatelyRestartsIfMaxDeadline) { + std::vector<base::TimeTicks> actual_deadlines; + int run_count = 0; + + base::TimeTicks clock_before(clock_->NowTicks()); + base::TimeDelta idle_task_runtime(base::TimeDelta::FromMilliseconds(10)); + + // The second idle period should happen immediately after the first the + // they have max deadlines. + max_idle_task_reposts = 2; + idle_task_runner_->PostIdleTask( + FROM_HERE, + base::Bind(&RepostingUpdateClockIdleTestTask, + base::RetainedRef(idle_task_runner_), &run_count, clock_.get(), + idle_task_runtime, &actual_deadlines)); + + idle_helper_->EnableLongIdlePeriod(); + RunUntilIdle(); + EXPECT_EQ(2, run_count); + EXPECT_THAT( + actual_deadlines, + testing::ElementsAre( + clock_before + maximum_idle_period_duration(), + clock_before + idle_task_runtime + maximum_idle_period_duration())); +} + +TEST_F(IdleHelperTest, TestLongIdlePeriodRestartWaitsIfNotMaxDeadline) { + base::TimeTicks actual_deadline; + int run_count = 0; + + base::TimeDelta pending_task_delay(base::TimeDelta::FromMilliseconds(20)); + base::TimeDelta idle_task_duration(base::TimeDelta::FromMilliseconds(10)); + base::TimeTicks expected_deadline(clock_->NowTicks() + pending_task_delay + + maximum_idle_period_duration() + + retry_enable_long_idle_period_delay()); + + // Post delayed task to ensure idle period doesn't have a max deadline. + default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask), + pending_task_delay); + + max_idle_task_reposts = 2; + idle_task_runner_->PostIdleTask( + FROM_HERE, + base::Bind(&RepostingIdleTestTask, base::RetainedRef(idle_task_runner_), + &run_count, &actual_deadline)); + idle_helper_->EnableLongIdlePeriod(); + RunUntilIdle(); + EXPECT_EQ(1, run_count); + clock_->Advance(idle_task_duration); + + // Next idle period shouldn't happen until the pending task has been run. + RunUntilIdle(); + EXPECT_EQ(1, run_count); + + // Once the pending task is run the new idle period should start. + clock_->Advance(pending_task_delay - idle_task_duration); + + // Since the idle period tried to start before the pending task ran we have to + // wait for the idle helper to retry starting the long idle period. + clock_->Advance(retry_enable_long_idle_period_delay()); + RunUntilIdle(); + + EXPECT_EQ(2, run_count); + EXPECT_EQ(expected_deadline, actual_deadline); +} + +TEST_F(IdleHelperTest, TestLongIdlePeriodPaused) { + mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true); + std::vector<base::TimeTicks> actual_deadlines; + int run_count = 0; + + // If there are no idle tasks posted we should start in the paused state. + idle_helper_->EnableLongIdlePeriod(); + CheckIdlePeriodStateIs("in_long_idle_period_paused"); + // There shouldn't be any delayed tasks posted by the idle helper when paused. + base::TimeTicks next_pending_delayed_task; + EXPECT_FALSE(scheduler_helper_->real_time_domain()->NextScheduledRunTime( + &next_pending_delayed_task)); + + // Posting a task should transition us to the an active state. + max_idle_task_reposts = 2; + base::TimeTicks clock_before(clock_->NowTicks()); + base::TimeDelta idle_task_runtime(base::TimeDelta::FromMilliseconds(10)); + idle_task_runner_->PostIdleTask( + FROM_HERE, + base::Bind(&RepostingUpdateClockIdleTestTask, + base::RetainedRef(idle_task_runner_), &run_count, clock_.get(), + idle_task_runtime, &actual_deadlines)); + RunUntilIdle(); + EXPECT_EQ(2, run_count); + EXPECT_THAT( + actual_deadlines, + testing::ElementsAre( + clock_before + maximum_idle_period_duration(), + clock_before + idle_task_runtime + maximum_idle_period_duration())); + + // Once all task have been run we should go back to the paused state. + CheckIdlePeriodStateIs("in_long_idle_period_paused"); + EXPECT_FALSE(scheduler_helper_->real_time_domain()->NextScheduledRunTime( + &next_pending_delayed_task)); + + idle_helper_->EndIdlePeriod(); + CheckIdlePeriodStateIs("not_in_idle_period"); +} + +TEST_F(IdleHelperTest, TestLongIdlePeriodWhenShutdown) { + base::TimeTicks deadline_in_task; + int run_count = 0; + + idle_task_runner_->PostIdleTask( + FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + scheduler_helper_->Shutdown(); + + // We shouldn't be able to enter a long idle period when shutdown + idle_helper_->EnableLongIdlePeriod(); + RunUntilIdle(); + CheckIdlePeriodStateIs("not_in_idle_period"); + EXPECT_EQ(0, run_count); +} + +void TestCanExceedIdleDeadlineIfRequiredTask(IdleHelperForTest* idle_helper, + bool* can_exceed_idle_deadline_out, + int* run_count, + base::TimeTicks deadline) { + *can_exceed_idle_deadline_out = + idle_helper->CanExceedIdleDeadlineIfRequired(); + (*run_count)++; +} + +TEST_F(IdleHelperTest, CanExceedIdleDeadlineIfRequired) { + int run_count = 0; + bool can_exceed_idle_deadline = false; + + // Should return false if not in an idle period. + EXPECT_FALSE(idle_helper_->CanExceedIdleDeadlineIfRequired()); + + // Should return false for short idle periods. + idle_task_runner_->PostIdleTask( + FROM_HERE, + base::Bind(&TestCanExceedIdleDeadlineIfRequiredTask, idle_helper_.get(), + &can_exceed_idle_deadline, &run_count)); + idle_helper_->StartIdlePeriod( + IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), + clock_->NowTicks() + base::TimeDelta::FromMilliseconds(10)); + RunUntilIdle(); + EXPECT_EQ(1, run_count); + EXPECT_FALSE(can_exceed_idle_deadline); + + // Should return false for a long idle period which is shortened due to a + // pending delayed task. + default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask), + base::TimeDelta::FromMilliseconds(10)); + idle_task_runner_->PostIdleTask( + FROM_HERE, + base::Bind(&TestCanExceedIdleDeadlineIfRequiredTask, idle_helper_.get(), + &can_exceed_idle_deadline, &run_count)); + idle_helper_->EnableLongIdlePeriod(); + RunUntilIdle(); + EXPECT_EQ(2, run_count); + EXPECT_FALSE(can_exceed_idle_deadline); + + // Next long idle period will be for the maximum time, so + // CanExceedIdleDeadlineIfRequired should return true. + clock_->Advance(maximum_idle_period_duration()); + idle_task_runner_->PostIdleTask( + FROM_HERE, + base::Bind(&TestCanExceedIdleDeadlineIfRequiredTask, idle_helper_.get(), + &can_exceed_idle_deadline, &run_count)); + RunUntilIdle(); + EXPECT_EQ(3, run_count); + EXPECT_TRUE(can_exceed_idle_deadline); +} + +class IdleHelperWithQuiescencePeriodTest : public BaseIdleHelperTest { + public: + enum { + kQuiescenceDelayMs = 100, + kLongIdlePeriodMs = 50, + }; + + IdleHelperWithQuiescencePeriodTest() + : BaseIdleHelperTest( + nullptr, + base::TimeDelta::FromMilliseconds(kQuiescenceDelayMs)) {} + + ~IdleHelperWithQuiescencePeriodTest() override {} + + void SetUp() override { + EXPECT_CALL(*idle_helper_, OnIdlePeriodStarted()).Times(AnyNumber()); + EXPECT_CALL(*idle_helper_, OnIdlePeriodEnded()).Times(AnyNumber()); + EXPECT_CALL(*idle_helper_, CanEnterLongIdlePeriod(_, _)) + .Times(AnyNumber()) + .WillRepeatedly(Return(true)); + EXPECT_CALL(*idle_helper_, IsNotQuiescent()).Times(AnyNumber()); + } + + void MakeNonQuiescent() { + // Run an arbitrary task so we're deemed to be not quiescent. + default_task_runner_->PostTask(FROM_HERE, base::Bind(NullTask)); + RunUntilIdle(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(IdleHelperWithQuiescencePeriodTest); +}; + +class IdleHelperWithQuiescencePeriodTestWithIdlePeriodObserver + : public IdleHelperWithQuiescencePeriodTest { + public: + IdleHelperWithQuiescencePeriodTestWithIdlePeriodObserver() + : IdleHelperWithQuiescencePeriodTest() {} + + ~IdleHelperWithQuiescencePeriodTestWithIdlePeriodObserver() override {} + + void SetUp() override { + // Don't set expectations on IdleHelper::Delegate. + } + + private: + DISALLOW_COPY_AND_ASSIGN( + IdleHelperWithQuiescencePeriodTestWithIdlePeriodObserver); +}; + +TEST_F(IdleHelperWithQuiescencePeriodTest, + LongIdlePeriodStartsImmediatelyIfQuiescent) { + base::TimeTicks actual_deadline; + int run_count = 0; + max_idle_task_reposts = 1; + idle_task_runner_->PostIdleTask( + FROM_HERE, + base::Bind(&RepostingIdleTestTask, base::RetainedRef(idle_task_runner_), + &run_count, &actual_deadline)); + + idle_helper_->EnableLongIdlePeriod(); + RunUntilIdle(); + + EXPECT_EQ(1, run_count); +} + +TEST_F(IdleHelperWithQuiescencePeriodTestWithIdlePeriodObserver, + LongIdlePeriodDoesNotStartsImmediatelyIfBusy) { + MakeNonQuiescent(); + EXPECT_CALL(*idle_helper_, OnIdlePeriodStarted()).Times(0); + EXPECT_CALL(*idle_helper_, OnIdlePeriodEnded()).Times(0); + EXPECT_CALL(*idle_helper_, CanEnterLongIdlePeriod(_, _)).Times(0); + EXPECT_CALL(*idle_helper_, IsNotQuiescent()).Times(AtLeast(1)); + + base::TimeTicks actual_deadline; + int run_count = 0; + max_idle_task_reposts = 1; + idle_task_runner_->PostIdleTask( + FROM_HERE, + base::Bind(&RepostingIdleTestTask, base::RetainedRef(idle_task_runner_), + &run_count, &actual_deadline)); + + idle_helper_->EnableLongIdlePeriod(); + RunUntilIdle(); + + EXPECT_EQ(0, run_count); + + scheduler_helper_->Shutdown(); +} + +TEST_F(IdleHelperWithQuiescencePeriodTest, + LongIdlePeriodStartsAfterQuiescence) { + MakeNonQuiescent(); + mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true); + + // Run a repeating task so we're deemed to be busy for the next 400ms. + default_task_runner_->PostTask( + FROM_HERE, + base::Bind(&RepeatingTask, base::Unretained(default_task_runner_.get()), + 10, base::TimeDelta::FromMilliseconds(40))); + + int run_count = 0; + // In this scenario EnableLongIdlePeriod deems us not to be quiescent 5x in + // a row. + base::TimeTicks expected_deadline = + clock_->NowTicks() + base::TimeDelta::FromMilliseconds( + 5 * kQuiescenceDelayMs + kLongIdlePeriodMs); + base::TimeTicks deadline_in_task; + idle_task_runner_->PostIdleTask( + FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + + idle_helper_->EnableLongIdlePeriod(); + RunUntilIdle(); + EXPECT_EQ(1, run_count); + EXPECT_EQ(expected_deadline, deadline_in_task); +} + +TEST_F(IdleHelperWithQuiescencePeriodTest, + QuescienceCheckedForAfterLongIdlePeriodEnds) { + mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true); + + idle_task_runner_->PostIdleTask(FROM_HERE, base::Bind(&NullIdleTask)); + idle_helper_->EnableLongIdlePeriod(); + RunUntilIdle(); + + // Post a normal task to make the scheduler non-quiescent. + default_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask)); + RunUntilIdle(); + + // Post an idle task. The idle task won't run initially because the system is + // not judged to be quiescent, but should be run after the quiescence delay. + int run_count = 0; + base::TimeTicks deadline_in_task; + base::TimeTicks expected_deadline = + clock_->NowTicks() + + base::TimeDelta::FromMilliseconds(kQuiescenceDelayMs + kLongIdlePeriodMs); + idle_task_runner_->PostIdleTask( + FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + idle_helper_->EnableLongIdlePeriod(); + RunUntilIdle(); + + EXPECT_EQ(1, run_count); + EXPECT_EQ(expected_deadline, deadline_in_task); +} + +TEST_F(IdleHelperTest, NoShortIdlePeriodWhenDeadlineTooClose) { + int run_count = 0; + base::TimeTicks deadline_in_task; + + idle_task_runner_->PostIdleTask( + FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + + base::TimeDelta half_a_ms(base::TimeDelta::FromMicroseconds(50)); + base::TimeTicks less_than_min_deadline( + clock_->NowTicks() + minimum_idle_period_duration() - half_a_ms); + base::TimeTicks more_than_min_deadline( + clock_->NowTicks() + minimum_idle_period_duration() + half_a_ms); + + idle_helper_->StartIdlePeriod( + IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), + less_than_min_deadline); + RunUntilIdle(); + EXPECT_EQ(0, run_count); + + idle_helper_->StartIdlePeriod( + IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), + more_than_min_deadline); + RunUntilIdle(); + EXPECT_EQ(1, run_count); +} + +TEST_F(IdleHelperTest, NoLongIdlePeriodWhenDeadlineTooClose) { + int run_count = 0; + base::TimeTicks deadline_in_task; + + base::TimeDelta half_a_ms(base::TimeDelta::FromMicroseconds(50)); + base::TimeDelta less_than_min_deadline_duration( + minimum_idle_period_duration() - half_a_ms); + base::TimeDelta more_than_min_deadline_duration( + minimum_idle_period_duration() + half_a_ms); + + idle_task_runner_->PostIdleTask( + FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask), + less_than_min_deadline_duration); + + idle_helper_->EnableLongIdlePeriod(); + RunUntilIdle(); + EXPECT_EQ(0, run_count); + + idle_helper_->EndIdlePeriod(); + clock_->Advance(maximum_idle_period_duration()); + RunUntilIdle(); + EXPECT_EQ(0, run_count); + + default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask), + more_than_min_deadline_duration); + idle_helper_->EnableLongIdlePeriod(); + RunUntilIdle(); + EXPECT_EQ(1, run_count); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/child/scheduler_helper.cc b/third_party/WebKit/Source/platform/scheduler/child/scheduler_helper.cc new file mode 100644 index 0000000..8f8c8a0 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/child/scheduler_helper.cc
@@ -0,0 +1,165 @@ +// 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 "platform/scheduler/child/scheduler_helper.h" + +#include "base/time/default_tick_clock.h" +#include "base/trace_event/trace_event.h" +#include "base/trace_event/trace_event_argument.h" +#include "platform/scheduler/base/task_queue_impl.h" +#include "platform/scheduler/child/scheduler_tqm_delegate.h" + +namespace blink { +namespace scheduler { + +SchedulerHelper::SchedulerHelper( + scoped_refptr<SchedulerTqmDelegate> task_queue_manager_delegate, + const char* tracing_category, + const char* disabled_by_default_tracing_category, + const char* disabled_by_default_verbose_tracing_category) + : task_queue_manager_delegate_(task_queue_manager_delegate), + task_queue_manager_( + new TaskQueueManager(task_queue_manager_delegate, + tracing_category, + disabled_by_default_tracing_category, + disabled_by_default_verbose_tracing_category)), + control_task_runner_(NewTaskQueue( + TaskQueue::Spec("control_tq") + .SetWakeupPolicy(TaskQueue::WakeupPolicy::DONT_WAKE_OTHER_QUEUES) + .SetShouldNotifyObservers(false))), + control_after_wakeup_task_runner_(NewTaskQueue( + TaskQueue::Spec("control_after_wakeup_tq") + .SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP) + .SetWakeupPolicy(TaskQueue::WakeupPolicy::DONT_WAKE_OTHER_QUEUES) + .SetShouldNotifyObservers(false))), + default_task_runner_(NewTaskQueue( + TaskQueue::Spec("default_tq").SetShouldMonitorQuiescence(true))), + observer_(nullptr), + tracing_category_(tracing_category), + disabled_by_default_tracing_category_( + disabled_by_default_tracing_category) { + control_task_runner_->SetQueuePriority(TaskQueue::CONTROL_PRIORITY); + control_after_wakeup_task_runner_->SetQueuePriority( + TaskQueue::CONTROL_PRIORITY); + + task_queue_manager_->SetWorkBatchSize(4); + + DCHECK(task_queue_manager_delegate_); + task_queue_manager_delegate_->SetDefaultTaskRunner( + default_task_runner_.get()); +} + +SchedulerHelper::~SchedulerHelper() { + Shutdown(); +} + +void SchedulerHelper::Shutdown() { + CheckOnValidThread(); + if (task_queue_manager_) + task_queue_manager_->SetObserver(nullptr); + task_queue_manager_.reset(); + task_queue_manager_delegate_->RestoreDefaultTaskRunner(); +} + +scoped_refptr<TaskQueue> SchedulerHelper::NewTaskQueue( + const TaskQueue::Spec& spec) { + DCHECK(task_queue_manager_.get()); + return task_queue_manager_->NewTaskQueue(spec); +} + +scoped_refptr<TaskQueue> SchedulerHelper::DefaultTaskRunner() { + CheckOnValidThread(); + return default_task_runner_; +} + +scoped_refptr<TaskQueue> SchedulerHelper::ControlTaskRunner() { + return control_task_runner_; +} + +scoped_refptr<TaskQueue> SchedulerHelper::ControlAfterWakeUpTaskRunner() { + return control_after_wakeup_task_runner_; +} + +void SchedulerHelper::SetWorkBatchSizeForTesting(size_t work_batch_size) { + CheckOnValidThread(); + DCHECK(task_queue_manager_.get()); + task_queue_manager_->SetWorkBatchSize(work_batch_size); +} + +TaskQueueManager* SchedulerHelper::GetTaskQueueManagerForTesting() { + CheckOnValidThread(); + return task_queue_manager_.get(); +} + +const scoped_refptr<SchedulerTqmDelegate>& +SchedulerHelper::scheduler_tqm_delegate() const { + return task_queue_manager_delegate_; +} + +bool SchedulerHelper::GetAndClearSystemIsQuiescentBit() { + CheckOnValidThread(); + DCHECK(task_queue_manager_.get()); + return task_queue_manager_->GetAndClearSystemIsQuiescentBit(); +} + +void SchedulerHelper::AddTaskObserver( + base::MessageLoop::TaskObserver* task_observer) { + CheckOnValidThread(); + if (task_queue_manager_) + task_queue_manager_->AddTaskObserver(task_observer); +} + +void SchedulerHelper::RemoveTaskObserver( + base::MessageLoop::TaskObserver* task_observer) { + CheckOnValidThread(); + if (task_queue_manager_) + task_queue_manager_->RemoveTaskObserver(task_observer); +} + +void SchedulerHelper::SetObserver(Observer* observer) { + CheckOnValidThread(); + observer_ = observer; + DCHECK(task_queue_manager_); + task_queue_manager_->SetObserver(this); +} + +RealTimeDomain* SchedulerHelper::real_time_domain() const { + CheckOnValidThread(); + DCHECK(task_queue_manager_); + return task_queue_manager_->real_time_domain(); +} + +void SchedulerHelper::RegisterTimeDomain(TimeDomain* time_domain) { + CheckOnValidThread(); + DCHECK(task_queue_manager_); + task_queue_manager_->RegisterTimeDomain(time_domain); +} + +void SchedulerHelper::UnregisterTimeDomain(TimeDomain* time_domain) { + CheckOnValidThread(); + if (task_queue_manager_) + task_queue_manager_->UnregisterTimeDomain(time_domain); +} + +void SchedulerHelper::OnUnregisterTaskQueue( + const scoped_refptr<TaskQueue>& queue) { + if (observer_) + observer_->OnUnregisterTaskQueue(queue); +} + +void SchedulerHelper::OnTriedToExecuteBlockedTask( + const TaskQueue& queue, + const base::PendingTask& task) { + if (observer_) + observer_->OnTriedToExecuteBlockedTask(queue, task); +} + +TaskQueue* SchedulerHelper::CurrentlyExecutingTaskQueue() const { + if (!task_queue_manager_) + return nullptr; + return task_queue_manager_->currently_executing_task_queue(); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/child/scheduler_helper.h b/third_party/WebKit/Source/platform/scheduler/child/scheduler_helper.h new file mode 100644 index 0000000..c1991af --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/child/scheduler_helper.h
@@ -0,0 +1,132 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_CHILD_SCHEDULER_HELPER_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_CHILD_SCHEDULER_HELPER_H_ + +#include <stddef.h> + +#include "base/macros.h" +#include "base/time/tick_clock.h" +#include "platform/scheduler/base/task_queue_manager.h" +#include "platform/scheduler/base/task_queue_selector.h" + +namespace base { +class TickClock; +} + +namespace blink { +namespace scheduler { + +class SchedulerTqmDelegate; + +// Common scheduler functionality for default tasks. +class BLINK_PLATFORM_EXPORT SchedulerHelper + : public TaskQueueManager::Observer { + public: + // Category strings must have application lifetime (statics or + // literals). They may not include " chars. + SchedulerHelper( + scoped_refptr<SchedulerTqmDelegate> task_queue_manager_delegate, + const char* tracing_category, + const char* disabled_by_default_tracing_category, + const char* disabled_by_default_verbose_tracing_category); + ~SchedulerHelper() override; + + // TaskQueueManager::Observer implementation: + void OnUnregisterTaskQueue(const scoped_refptr<TaskQueue>& queue) override; + void OnTriedToExecuteBlockedTask(const TaskQueue& queue, + const base::PendingTask& task) override; + + // Returns the default task runner. + scoped_refptr<TaskQueue> DefaultTaskRunner(); + + // Returns the control task runner. Tasks posted to this runner are executed + // with the highest priority. Care must be taken to avoid starvation of other + // task queues. + scoped_refptr<TaskQueue> ControlTaskRunner(); + + // Returns the control task after wakeup runner. Tasks posted to this runner + // are executed with the highest priority but do not cause the scheduler to + // wake up. Care must be taken to avoid starvation of other task queues. + scoped_refptr<TaskQueue> ControlAfterWakeUpTaskRunner(); + + // Adds or removes a task observer from the scheduler. The observer will be + // notified before and after every executed task. These functions can only be + // called on the thread this class was created on. + void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer); + void RemoveTaskObserver(base::MessageLoop::TaskObserver* task_observer); + + void SetTaskTimeTracker(TaskTimeTracker* task_time_tracker) { + if (task_queue_manager_) + task_queue_manager_->SetTaskTimeTracker(task_time_tracker); + } + + // Shuts down the scheduler by dropping any remaining pending work in the work + // queues. After this call any work posted to the task runners will be + // silently dropped. + void Shutdown(); + + // Returns true if Shutdown() has been called. Otherwise returns false. + bool IsShutdown() const { return !task_queue_manager_.get(); } + + void CheckOnValidThread() const { + DCHECK(thread_checker_.CalledOnValidThread()); + } + + // Creates a new TaskQueue with the given |spec|. + scoped_refptr<TaskQueue> NewTaskQueue(const TaskQueue::Spec& spec); + + class BLINK_PLATFORM_EXPORT Observer { + public: + virtual ~Observer() {} + + // Called when |queue| is unregistered. + virtual void OnUnregisterTaskQueue( + const scoped_refptr<TaskQueue>& queue) = 0; + + // Called when the scheduler tried to execute a task from a disabled + // queue. See TaskQueue::Spec::SetShouldReportWhenExecutionBlocked. + virtual void OnTriedToExecuteBlockedTask(const TaskQueue& queue, + const base::PendingTask& task) = 0; + }; + + // Called once to set the Observer. This function is called on the main + // thread. If |observer| is null, then no callbacks will occur. + // Note |observer| is expected to outlive the SchedulerHelper. + void SetObserver(Observer* observer); + + // Accessor methods. + RealTimeDomain* real_time_domain() const; + void RegisterTimeDomain(TimeDomain* time_domain); + void UnregisterTimeDomain(TimeDomain* time_domain); + const scoped_refptr<SchedulerTqmDelegate>& scheduler_tqm_delegate() const; + bool GetAndClearSystemIsQuiescentBit(); + TaskQueue* CurrentlyExecutingTaskQueue() const; + + // Test helpers. + void SetWorkBatchSizeForTesting(size_t work_batch_size); + TaskQueueManager* GetTaskQueueManagerForTesting(); + + private: + friend class SchedulerHelperTest; + + base::ThreadChecker thread_checker_; + scoped_refptr<SchedulerTqmDelegate> task_queue_manager_delegate_; + std::unique_ptr<TaskQueueManager> task_queue_manager_; + scoped_refptr<TaskQueue> control_task_runner_; + scoped_refptr<TaskQueue> control_after_wakeup_task_runner_; + scoped_refptr<TaskQueue> default_task_runner_; + + Observer* observer_; // NOT OWNED + const char* tracing_category_; + const char* disabled_by_default_tracing_category_; + + DISALLOW_COPY_AND_ASSIGN(SchedulerHelper); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_CHILD_SCHEDULER_HELPER_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/child/scheduler_helper_unittest.cc b/third_party/WebKit/Source/platform/scheduler/child/scheduler_helper_unittest.cc new file mode 100644 index 0000000..2ef59ae --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/child/scheduler_helper_unittest.cc
@@ -0,0 +1,230 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "platform/scheduler/child/scheduler_helper.h" + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "base/test/simple_test_tick_clock.h" +#include "cc/test/ordered_simple_task_runner.h" +#include "public/platform/scheduler/base/task_queue.h" +#include "platform/scheduler/base/lazy_now.h" +#include "platform/scheduler/base/test_time_source.h" +#include "platform/scheduler/child/scheduler_tqm_delegate_for_test.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::_; +using testing::AnyNumber; +using testing::Invoke; +using testing::Return; + +namespace blink { +namespace scheduler { + +namespace { +void AppendToVectorTestTask(std::vector<std::string>* vector, + std::string value) { + vector->push_back(value); +} + +void AppendToVectorReentrantTask(base::SingleThreadTaskRunner* task_runner, + std::vector<int>* vector, + int* reentrant_count, + int max_reentrant_count) { + vector->push_back((*reentrant_count)++); + if (*reentrant_count < max_reentrant_count) { + task_runner->PostTask( + FROM_HERE, + base::Bind(AppendToVectorReentrantTask, base::Unretained(task_runner), + vector, reentrant_count, max_reentrant_count)); + } +} + +}; // namespace + +class SchedulerHelperTest : public testing::Test { + public: + SchedulerHelperTest() + : clock_(new base::SimpleTestTickClock()), + mock_task_runner_(new cc::OrderedSimpleTaskRunner(clock_.get(), false)), + main_task_runner_(SchedulerTqmDelegateForTest::Create( + mock_task_runner_, + base::WrapUnique(new TestTimeSource(clock_.get())))), + scheduler_helper_(new SchedulerHelper( + main_task_runner_, + "test.scheduler", + TRACE_DISABLED_BY_DEFAULT("test.scheduler"), + TRACE_DISABLED_BY_DEFAULT("test.scheduler.dbg"))), + default_task_runner_(scheduler_helper_->DefaultTaskRunner()) { + clock_->Advance(base::TimeDelta::FromMicroseconds(5000)); + } + + ~SchedulerHelperTest() override {} + + void TearDown() override { + // Check that all tests stop posting tasks. + mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true); + while (mock_task_runner_->RunUntilIdle()) { + } + } + + void RunUntilIdle() { mock_task_runner_->RunUntilIdle(); } + + template <typename E> + static void CallForEachEnumValue(E first, + E last, + const char* (*function)(E)) { + for (E val = first; val < last; + val = static_cast<E>(static_cast<int>(val) + 1)) { + (*function)(val); + } + } + + protected: + std::unique_ptr<base::SimpleTestTickClock> clock_; + scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_; + + scoped_refptr<SchedulerTqmDelegateForTest> main_task_runner_; + std::unique_ptr<SchedulerHelper> scheduler_helper_; + scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_; + + DISALLOW_COPY_AND_ASSIGN(SchedulerHelperTest); +}; + +TEST_F(SchedulerHelperTest, TestPostDefaultTask) { + std::vector<std::string> run_order; + default_task_runner_->PostTask( + FROM_HERE, base::Bind(&AppendToVectorTestTask, &run_order, "D1")); + default_task_runner_->PostTask( + FROM_HERE, base::Bind(&AppendToVectorTestTask, &run_order, "D2")); + default_task_runner_->PostTask( + FROM_HERE, base::Bind(&AppendToVectorTestTask, &run_order, "D3")); + default_task_runner_->PostTask( + FROM_HERE, base::Bind(&AppendToVectorTestTask, &run_order, "D4")); + + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("D1"), std::string("D2"), + std::string("D3"), std::string("D4"))); +} + +TEST_F(SchedulerHelperTest, TestRentrantTask) { + int count = 0; + std::vector<int> run_order; + default_task_runner_->PostTask( + FROM_HERE, base::Bind(AppendToVectorReentrantTask, + base::RetainedRef(default_task_runner_), &run_order, + &count, 5)); + RunUntilIdle(); + + EXPECT_THAT(run_order, testing::ElementsAre(0, 1, 2, 3, 4)); +} + +TEST_F(SchedulerHelperTest, IsShutdown) { + EXPECT_FALSE(scheduler_helper_->IsShutdown()); + + scheduler_helper_->Shutdown(); + EXPECT_TRUE(scheduler_helper_->IsShutdown()); +} + +TEST_F(SchedulerHelperTest, DefaultTaskRunnerRegistration) { + EXPECT_EQ(main_task_runner_->default_task_runner(), + scheduler_helper_->DefaultTaskRunner()); + scheduler_helper_->Shutdown(); + EXPECT_EQ(nullptr, main_task_runner_->default_task_runner()); +} + +namespace { +class MockTaskObserver : public base::MessageLoop::TaskObserver { + public: + MOCK_METHOD1(DidProcessTask, void(const base::PendingTask& task)); + MOCK_METHOD1(WillProcessTask, void(const base::PendingTask& task)); +}; + +void NopTask() {} +} // namespace + +TEST_F(SchedulerHelperTest, ObserversNotifiedFor_DefaultTaskRunner) { + MockTaskObserver observer; + scheduler_helper_->AddTaskObserver(&observer); + + scheduler_helper_->DefaultTaskRunner()->PostTask(FROM_HERE, + base::Bind(&NopTask)); + + EXPECT_CALL(observer, WillProcessTask(_)).Times(1); + EXPECT_CALL(observer, DidProcessTask(_)).Times(1); + RunUntilIdle(); +} + +TEST_F(SchedulerHelperTest, ObserversNotNotifiedFor_ControlTaskRunner) { + MockTaskObserver observer; + scheduler_helper_->AddTaskObserver(&observer); + + scheduler_helper_->ControlTaskRunner()->PostTask(FROM_HERE, + base::Bind(&NopTask)); + + EXPECT_CALL(observer, WillProcessTask(_)).Times(0); + EXPECT_CALL(observer, DidProcessTask(_)).Times(0); + RunUntilIdle(); +} + +TEST_F(SchedulerHelperTest, + ObserversNotNotifiedFor_ControlAfterWakeUpTaskRunner) { + MockTaskObserver observer; + scheduler_helper_->AddTaskObserver(&observer); + + scheduler_helper_->ControlAfterWakeUpTaskRunner()->PostTask( + FROM_HERE, base::Bind(&NopTask)); + + EXPECT_CALL(observer, WillProcessTask(_)).Times(0); + EXPECT_CALL(observer, DidProcessTask(_)).Times(0); + LazyNow lazy_now(clock_.get()); + scheduler_helper_->ControlAfterWakeUpTaskRunner()->PumpQueue(&lazy_now, true); + RunUntilIdle(); +} + +namespace { + +class MockObserver : public SchedulerHelper::Observer { + public: + MOCK_METHOD1(OnUnregisterTaskQueue, + void(const scoped_refptr<TaskQueue>& queue)); + MOCK_METHOD2(OnTriedToExecuteBlockedTask, + void(const TaskQueue& queue, const base::PendingTask& task)); +}; + +} // namespace + +TEST_F(SchedulerHelperTest, OnUnregisterTaskQueue) { + MockObserver observer; + scheduler_helper_->SetObserver(&observer); + + scoped_refptr<TaskQueue> task_queue = + scheduler_helper_->NewTaskQueue(TaskQueue::Spec("test_queue")); + + EXPECT_CALL(observer, OnUnregisterTaskQueue(_)).Times(1); + task_queue->UnregisterTaskQueue(); + + scheduler_helper_->SetObserver(nullptr); +} + +TEST_F(SchedulerHelperTest, OnTriedToExecuteBlockedTask) { + MockObserver observer; + scheduler_helper_->SetObserver(&observer); + + scoped_refptr<TaskQueue> task_queue = scheduler_helper_->NewTaskQueue( + TaskQueue::Spec("test_queue").SetShouldReportWhenExecutionBlocked(true)); + task_queue->SetQueueEnabled(false); + task_queue->PostTask(FROM_HERE, base::Bind(&NopTask)); + + EXPECT_CALL(observer, OnTriedToExecuteBlockedTask(_, _)).Times(1); + RunUntilIdle(); + + scheduler_helper_->SetObserver(nullptr); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate.h b/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate.h new file mode 100644 index 0000000..79c2c774 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate.h
@@ -0,0 +1,39 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_CHILD_SCHEDULER_TQM_DELEGATE_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_CHILD_SCHEDULER_TQM_DELEGATE_H_ + +#include "base/macros.h" +#include "base/message_loop/message_loop.h" +#include "platform/scheduler/base/task_queue_manager_delegate.h" + +namespace blink { +namespace scheduler { + +class BLINK_PLATFORM_EXPORT SchedulerTqmDelegate + : public TaskQueueManagerDelegate { + public: + SchedulerTqmDelegate() {} + + // If the underlying task runner supports the concept of a default task + // runner, the delegate should implement this function to redirect that task + // runner to the scheduler. + virtual void SetDefaultTaskRunner( + scoped_refptr<base::SingleThreadTaskRunner> task_runner) = 0; + + // Similarly this method can be used to restore the original task runner when + // the scheduler no longer wants to intercept tasks. + virtual void RestoreDefaultTaskRunner() = 0; + + protected: + ~SchedulerTqmDelegate() override {} + + DISALLOW_COPY_AND_ASSIGN(SchedulerTqmDelegate); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_CHILD_SCHEDULER_TQM_DELEGATE_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate_for_test.cc b/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate_for_test.cc new file mode 100644 index 0000000..2f9aaa0 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate_for_test.cc
@@ -0,0 +1,69 @@ +// 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 "platform/scheduler/child/scheduler_tqm_delegate_for_test.h" + +#include <utility> + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "platform/scheduler/base/task_queue_manager_delegate_for_test.h" + +namespace blink { +namespace scheduler { + +// static +scoped_refptr<SchedulerTqmDelegateForTest> SchedulerTqmDelegateForTest::Create( + scoped_refptr<base::SingleThreadTaskRunner> task_runner, + std::unique_ptr<base::TickClock> time_source) { + return make_scoped_refptr( + new SchedulerTqmDelegateForTest(task_runner, std::move(time_source))); +} + +SchedulerTqmDelegateForTest::SchedulerTqmDelegateForTest( + scoped_refptr<base::SingleThreadTaskRunner> task_runner, + std::unique_ptr<base::TickClock> time_source) + : task_runner_( + TaskQueueManagerDelegateForTest::Create(task_runner, + std::move(time_source))) {} + +SchedulerTqmDelegateForTest::~SchedulerTqmDelegateForTest() {} + +void SchedulerTqmDelegateForTest::SetDefaultTaskRunner( + scoped_refptr<base::SingleThreadTaskRunner> task_runner) { + default_task_runner_ = std::move(task_runner); +} + +void SchedulerTqmDelegateForTest::RestoreDefaultTaskRunner() { + default_task_runner_ = nullptr; +} + +bool SchedulerTqmDelegateForTest::PostDelayedTask( + const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) { + return task_runner_->PostDelayedTask(from_here, task, delay); +} + +bool SchedulerTqmDelegateForTest::PostNonNestableDelayedTask( + const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) { + return task_runner_->PostNonNestableDelayedTask(from_here, task, delay); +} + +bool SchedulerTqmDelegateForTest::RunsTasksOnCurrentThread() const { + return task_runner_->RunsTasksOnCurrentThread(); +} + +bool SchedulerTqmDelegateForTest::IsNested() const { + return task_runner_->IsNested(); +} + +base::TimeTicks SchedulerTqmDelegateForTest::NowTicks() { + return task_runner_->NowTicks(); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate_for_test.h b/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate_for_test.h new file mode 100644 index 0000000..939704d --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate_for_test.h
@@ -0,0 +1,61 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_CHILD_SCHEDULER_TQM_DELEGATE_FOR_TEST_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_CHILD_SCHEDULER_TQM_DELEGATE_FOR_TEST_H_ + +#include <memory> + +#include "base/macros.h" +#include "base/test/simple_test_tick_clock.h" +#include "platform/scheduler/child/scheduler_tqm_delegate.h" + +namespace blink { +namespace scheduler { + +class TaskQueueManagerDelegateForTest; + +class SchedulerTqmDelegateForTest : public SchedulerTqmDelegate { + public: + static scoped_refptr<SchedulerTqmDelegateForTest> Create( + scoped_refptr<base::SingleThreadTaskRunner> task_runner, + std::unique_ptr<base::TickClock> time_source); + + // SchedulerTqmDelegate implementation + void SetDefaultTaskRunner( + scoped_refptr<base::SingleThreadTaskRunner> task_runner) override; + void RestoreDefaultTaskRunner() override; + bool PostDelayedTask(const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) override; + bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) override; + bool RunsTasksOnCurrentThread() const override; + bool IsNested() const override; + base::TimeTicks NowTicks() override; + + base::SingleThreadTaskRunner* default_task_runner() const { + return default_task_runner_.get(); + } + + protected: + ~SchedulerTqmDelegateForTest() override; + + private: + SchedulerTqmDelegateForTest( + scoped_refptr<base::SingleThreadTaskRunner> task_runner, + std::unique_ptr<base::TickClock> time_source); + + scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_; + + scoped_refptr<TaskQueueManagerDelegateForTest> task_runner_; + + DISALLOW_COPY_AND_ASSIGN(SchedulerTqmDelegateForTest); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_CHILD_SCHEDULER_TQM_DELEGATE_FOR_TEST_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate_impl.cc b/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate_impl.cc new file mode 100644 index 0000000..e387399 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate_impl.cc
@@ -0,0 +1,69 @@ +// 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 "platform/scheduler/child/scheduler_tqm_delegate_impl.h" + +#include <utility> + +namespace blink { +namespace scheduler { + +// static +scoped_refptr<SchedulerTqmDelegateImpl> SchedulerTqmDelegateImpl::Create( + base::MessageLoop* message_loop, + std::unique_ptr<base::TickClock> time_source) { + return make_scoped_refptr( + new SchedulerTqmDelegateImpl(message_loop, std::move(time_source))); +} + +SchedulerTqmDelegateImpl::SchedulerTqmDelegateImpl( + base::MessageLoop* message_loop, + std::unique_ptr<base::TickClock> time_source) + : message_loop_(message_loop), + message_loop_task_runner_(message_loop->task_runner()), + time_source_(std::move(time_source)) {} + +SchedulerTqmDelegateImpl::~SchedulerTqmDelegateImpl() { + RestoreDefaultTaskRunner(); +} + +void SchedulerTqmDelegateImpl::SetDefaultTaskRunner( + scoped_refptr<base::SingleThreadTaskRunner> task_runner) { + message_loop_->SetTaskRunner(task_runner); +} + +void SchedulerTqmDelegateImpl::RestoreDefaultTaskRunner() { + if (base::MessageLoop::current() == message_loop_) + message_loop_->SetTaskRunner(message_loop_task_runner_); +} + +bool SchedulerTqmDelegateImpl::PostDelayedTask( + const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) { + return message_loop_task_runner_->PostDelayedTask(from_here, task, delay); +} + +bool SchedulerTqmDelegateImpl::PostNonNestableDelayedTask( + const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) { + return message_loop_task_runner_->PostNonNestableDelayedTask(from_here, task, + delay); +} + +bool SchedulerTqmDelegateImpl::RunsTasksOnCurrentThread() const { + return message_loop_task_runner_->RunsTasksOnCurrentThread(); +} + +bool SchedulerTqmDelegateImpl::IsNested() const { + return message_loop_->IsNested(); +} + +base::TimeTicks SchedulerTqmDelegateImpl::NowTicks() { + return time_source_->NowTicks(); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate_impl.h b/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate_impl.h new file mode 100644 index 0000000..23188c87 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate_impl.h
@@ -0,0 +1,58 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_CHILD_SCHEDULER_TQM_DELEGATE_IMPL_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_CHILD_SCHEDULER_TQM_DELEGATE_IMPL_H_ + +#include <memory> + +#include "base/macros.h" +#include "base/message_loop/message_loop.h" +#include "base/time/tick_clock.h" +#include "platform/scheduler/child/scheduler_tqm_delegate.h" + +namespace blink { +namespace scheduler { + +class BLINK_PLATFORM_EXPORT SchedulerTqmDelegateImpl + : public SchedulerTqmDelegate { + public: + // |message_loop| is not owned and must outlive the lifetime of this object. + static scoped_refptr<SchedulerTqmDelegateImpl> Create( + base::MessageLoop* message_loop, + std::unique_ptr<base::TickClock> time_source); + + // SchedulerTqmDelegate implementation + void SetDefaultTaskRunner( + scoped_refptr<base::SingleThreadTaskRunner> task_runner) override; + void RestoreDefaultTaskRunner() override; + bool PostDelayedTask(const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) override; + bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) override; + bool RunsTasksOnCurrentThread() const override; + bool IsNested() const override; + base::TimeTicks NowTicks() override; + + protected: + ~SchedulerTqmDelegateImpl() override; + + private: + SchedulerTqmDelegateImpl(base::MessageLoop* message_loop, + std::unique_ptr<base::TickClock> time_source); + + // Not owned. + base::MessageLoop* message_loop_; + scoped_refptr<SingleThreadTaskRunner> message_loop_task_runner_; + std::unique_ptr<base::TickClock> time_source_; + + DISALLOW_COPY_AND_ASSIGN(SchedulerTqmDelegateImpl); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_CHILD_SCHEDULER_TQM_DELEGATE_IMPL_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate_impl_unittest.cc b/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate_impl_unittest.cc new file mode 100644 index 0000000..46fe15d --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/child/scheduler_tqm_delegate_impl_unittest.cc
@@ -0,0 +1,33 @@ +// 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 "platform/scheduler/child/scheduler_tqm_delegate_impl.h" + +#include "base/memory/ptr_util.h" +#include "base/message_loop/message_loop.h" +#include "base/test/test_simple_task_runner.h" +#include "base/time/default_tick_clock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace blink { +namespace scheduler { + +TEST(SchedulerTqmDelegateImplTest, TestTaskRunnerOverriding) { + base::MessageLoop loop; + scoped_refptr<base::SingleThreadTaskRunner> original_runner( + loop.task_runner()); + scoped_refptr<base::SingleThreadTaskRunner> custom_runner( + new base::TestSimpleTaskRunner()); + { + scoped_refptr<SchedulerTqmDelegateImpl> delegate( + SchedulerTqmDelegateImpl::Create( + &loop, base::WrapUnique(new base::DefaultTickClock()))); + delegate->SetDefaultTaskRunner(custom_runner); + DCHECK_EQ(custom_runner, loop.task_runner()); + } + DCHECK_EQ(original_runner, loop.task_runner()); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/child/single_thread_idle_task_runner.cc b/third_party/WebKit/Source/platform/scheduler/child/single_thread_idle_task_runner.cc new file mode 100644 index 0000000..dfb50c3 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/child/single_thread_idle_task_runner.cc
@@ -0,0 +1,89 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "public/platform/scheduler/child/single_thread_idle_task_runner.h" + +#include "base/location.h" +#include "base/trace_event/blame_context.h" +#include "base/trace_event/trace_event.h" + +namespace blink { +namespace scheduler { + +SingleThreadIdleTaskRunner::SingleThreadIdleTaskRunner( + scoped_refptr<base::SingleThreadTaskRunner> idle_priority_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> after_wakeup_task_runner, + Delegate* delegate, + const char* tracing_category) + : idle_priority_task_runner_(idle_priority_task_runner), + after_wakeup_task_runner_(after_wakeup_task_runner), + delegate_(delegate), + tracing_category_(tracing_category), + blame_context_(nullptr), + weak_factory_(this) { + DCHECK(!idle_priority_task_runner_ || + idle_priority_task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!after_wakeup_task_runner_ || + after_wakeup_task_runner_->RunsTasksOnCurrentThread()); + weak_scheduler_ptr_ = weak_factory_.GetWeakPtr(); +} + +SingleThreadIdleTaskRunner::~SingleThreadIdleTaskRunner() {} + +SingleThreadIdleTaskRunner::Delegate::Delegate() {} + +SingleThreadIdleTaskRunner::Delegate::~Delegate() {} + +bool SingleThreadIdleTaskRunner::RunsTasksOnCurrentThread() const { + return idle_priority_task_runner_->RunsTasksOnCurrentThread(); +} + +void SingleThreadIdleTaskRunner::PostIdleTask( + const tracked_objects::Location& from_here, + const IdleTask& idle_task) { + delegate_->OnIdleTaskPosted(); + idle_priority_task_runner_->PostTask( + from_here, base::Bind(&SingleThreadIdleTaskRunner::RunTask, + weak_scheduler_ptr_, idle_task)); +} + +void SingleThreadIdleTaskRunner::PostNonNestableIdleTask( + const tracked_objects::Location& from_here, + const IdleTask& idle_task) { + delegate_->OnIdleTaskPosted(); + idle_priority_task_runner_->PostNonNestableTask( + from_here, base::Bind(&SingleThreadIdleTaskRunner::RunTask, + weak_scheduler_ptr_, idle_task)); +} + +void SingleThreadIdleTaskRunner::PostIdleTaskAfterWakeup( + const tracked_objects::Location& from_here, + const IdleTask& idle_task) { + // Don't signal posting of idle task to the delegate here, wait until the + // after-wakeup task posts the real idle task. + after_wakeup_task_runner_->PostTask( + FROM_HERE, base::Bind(&SingleThreadIdleTaskRunner::PostIdleTask, + weak_scheduler_ptr_, from_here, idle_task)); +} + +void SingleThreadIdleTaskRunner::RunTask(IdleTask idle_task) { + base::TimeTicks deadline = delegate_->WillProcessIdleTask(); + TRACE_EVENT1(tracing_category_, "SingleThreadIdleTaskRunner::RunTask", + "allotted_time_ms", + (deadline - base::TimeTicks::Now()).InMillisecondsF()); + if (blame_context_) + blame_context_->Enter(); + idle_task.Run(deadline); + if (blame_context_) + blame_context_->Leave(); + delegate_->DidProcessIdleTask(); +} + +void SingleThreadIdleTaskRunner::SetBlameContext( + base::trace_event::BlameContext* blame_context) { + blame_context_ = blame_context; +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/child/web_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/child/web_scheduler_impl.cc new file mode 100644 index 0000000..8e53ec21 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/child/web_scheduler_impl.cc
@@ -0,0 +1,90 @@ +// 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 "platform/scheduler/child/web_scheduler_impl.h" + +#include "base/bind.h" +#include "base/memory/ptr_util.h" +#include "base/single_thread_task_runner.h" +#include "platform/scheduler/child/web_task_runner_impl.h" +#include "public/platform/WebTraceLocation.h" +#include "public/platform/WebViewScheduler.h" +#include "public/platform/scheduler/child/worker_scheduler.h" + +namespace blink { +namespace scheduler { + +WebSchedulerImpl::WebSchedulerImpl( + ChildScheduler* child_scheduler, + scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner, + scoped_refptr<TaskQueue> loading_task_runner, + scoped_refptr<TaskQueue> timer_task_runner) + : child_scheduler_(child_scheduler), + idle_task_runner_(idle_task_runner), + timer_task_runner_(timer_task_runner), + loading_web_task_runner_(new WebTaskRunnerImpl(loading_task_runner)), + timer_web_task_runner_(new WebTaskRunnerImpl(timer_task_runner)) {} + +WebSchedulerImpl::~WebSchedulerImpl() {} + +void WebSchedulerImpl::shutdown() { + child_scheduler_->Shutdown(); +} + +bool WebSchedulerImpl::shouldYieldForHighPriorityWork() { + return child_scheduler_->ShouldYieldForHighPriorityWork(); +} + +bool WebSchedulerImpl::canExceedIdleDeadlineIfRequired() { + return child_scheduler_->CanExceedIdleDeadlineIfRequired(); +} + +void WebSchedulerImpl::runIdleTask( + std::unique_ptr<blink::WebThread::IdleTask> task, + base::TimeTicks deadline) { + task->run((deadline - base::TimeTicks()).InSecondsF()); +} + +void WebSchedulerImpl::postIdleTask(const blink::WebTraceLocation& location, + blink::WebThread::IdleTask* task) { + DCHECK(idle_task_runner_); + idle_task_runner_->PostIdleTask( + location, base::Bind(&WebSchedulerImpl::runIdleTask, + base::Passed(base::WrapUnique(task)))); +} + +void WebSchedulerImpl::postNonNestableIdleTask( + const blink::WebTraceLocation& location, + blink::WebThread::IdleTask* task) { + DCHECK(idle_task_runner_); + idle_task_runner_->PostNonNestableIdleTask( + location, base::Bind(&WebSchedulerImpl::runIdleTask, + base::Passed(base::WrapUnique(task)))); +} + +void WebSchedulerImpl::postIdleTaskAfterWakeup( + const blink::WebTraceLocation& location, + blink::WebThread::IdleTask* task) { + DCHECK(idle_task_runner_); + idle_task_runner_->PostIdleTaskAfterWakeup( + location, base::Bind(&WebSchedulerImpl::runIdleTask, + base::Passed(base::WrapUnique(task)))); +} + +blink::WebTaskRunner* WebSchedulerImpl::loadingTaskRunner() { + return loading_web_task_runner_.get(); +} + +blink::WebTaskRunner* WebSchedulerImpl::timerTaskRunner() { + return timer_web_task_runner_.get(); +} + +std::unique_ptr<blink::WebViewScheduler> +WebSchedulerImpl::createWebViewScheduler(InterventionReporter*) { + NOTREACHED(); + return nullptr; +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/child/web_scheduler_impl.h b/third_party/WebKit/Source/platform/scheduler/child/web_scheduler_impl.h new file mode 100644 index 0000000..c256b1a --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/child/web_scheduler_impl.h
@@ -0,0 +1,67 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_CHILD_WEB_SCHEDULER_IMPL_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_CHILD_WEB_SCHEDULER_IMPL_H_ + +#include <memory> + +#include "base/memory/ref_counted.h" +#include "base/time/time.h" +#include "public/platform/WebCommon.h" +#include "public/platform/WebScheduler.h" +#include "public/platform/WebThread.h" + +namespace blink { +namespace scheduler { + +class ChildScheduler; +class SingleThreadIdleTaskRunner; +class TaskQueue; +class WebTaskRunnerImpl; + +class BLINK_PLATFORM_EXPORT WebSchedulerImpl : public WebScheduler { + public: + WebSchedulerImpl(ChildScheduler* child_scheduler, + scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner, + scoped_refptr<TaskQueue> loading_task_runner, + scoped_refptr<TaskQueue> timer_task_runner); + ~WebSchedulerImpl() override; + + // WebScheduler implementation: + void shutdown() override; + bool shouldYieldForHighPriorityWork() override; + bool canExceedIdleDeadlineIfRequired() override; + void postIdleTask(const WebTraceLocation& location, + WebThread::IdleTask* task) override; + void postNonNestableIdleTask(const WebTraceLocation& location, + WebThread::IdleTask* task) override; + void postIdleTaskAfterWakeup(const WebTraceLocation& location, + WebThread::IdleTask* task) override; + WebTaskRunner* loadingTaskRunner() override; + WebTaskRunner* timerTaskRunner() override; + std::unique_ptr<WebViewScheduler> createWebViewScheduler( + InterventionReporter*) override; + void suspendTimerQueue() override {} + void resumeTimerQueue() override {} + void addPendingNavigation(WebScheduler::NavigatingFrameType type) override {} + void removePendingNavigation( + WebScheduler::NavigatingFrameType type) override {} + void onNavigationStarted() override {} + + private: + static void runIdleTask(std::unique_ptr<WebThread::IdleTask> task, + base::TimeTicks deadline); + + ChildScheduler* child_scheduler_; // NOT OWNED + scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_; + scoped_refptr<TaskQueue> timer_task_runner_; + std::unique_ptr<WebTaskRunnerImpl> loading_web_task_runner_; + std::unique_ptr<WebTaskRunnerImpl> timer_web_task_runner_; +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_CHILD_WEB_SCHEDULER_IMPL_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/child/web_task_runner_impl.cc b/third_party/WebKit/Source/platform/scheduler/child/web_task_runner_impl.cc new file mode 100644 index 0000000..3144fca --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/child/web_task_runner_impl.cc
@@ -0,0 +1,75 @@ +// 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 "platform/scheduler/child/web_task_runner_impl.h" + +#include "base/bind.h" +#include "base/location.h" +#include "base/memory/ptr_util.h" +#include "public/platform/scheduler/base/task_queue.h" +#include "platform/scheduler/base/time_domain.h" +#include "public/platform/WebTraceLocation.h" + +namespace blink { +namespace scheduler { + +WebTaskRunnerImpl::WebTaskRunnerImpl(scoped_refptr<TaskQueue> task_queue) + : task_queue_(task_queue) {} + +WebTaskRunnerImpl::~WebTaskRunnerImpl() {} + +void WebTaskRunnerImpl::postTask(const blink::WebTraceLocation& location, + blink::WebTaskRunner::Task* task) { + task_queue_->PostTask(location, + base::Bind(&WebTaskRunnerImpl::runTask, + base::Passed(base::WrapUnique(task)))); +} + +void WebTaskRunnerImpl::postDelayedTask(const blink::WebTraceLocation& location, + blink::WebTaskRunner::Task* task, + double delayMs) { + DCHECK_GE(delayMs, 0.0); + task_queue_->PostDelayedTask(location, + base::Bind(&WebTaskRunnerImpl::runTask, + base::Passed(base::WrapUnique(task))), + base::TimeDelta::FromMillisecondsD(delayMs)); +} + +bool WebTaskRunnerImpl::runsTasksOnCurrentThread() { + return task_queue_->RunsTasksOnCurrentThread(); +} + +double WebTaskRunnerImpl::virtualTimeSeconds() const { + return (Now() - base::TimeTicks::UnixEpoch()).InSecondsF(); +} + +double WebTaskRunnerImpl::monotonicallyIncreasingVirtualTimeSeconds() const { + return Now().ToInternalValue() / + static_cast<double>(base::Time::kMicrosecondsPerSecond); +} + +base::TimeTicks WebTaskRunnerImpl::Now() const { + TimeDomain* time_domain = task_queue_->GetTimeDomain(); + // It's possible task_queue_ has been Unregistered which can lead to a null + // TimeDomain. If that happens just return the current real time. + if (!time_domain) + return base::TimeTicks::Now(); + return time_domain->Now(); +} + +std::unique_ptr<blink::WebTaskRunner> WebTaskRunnerImpl::clone() { + return base::WrapUnique(new WebTaskRunnerImpl(task_queue_)); +} + +base::SingleThreadTaskRunner* WebTaskRunnerImpl::taskRunner() { + return task_queue_.get(); +} + +void WebTaskRunnerImpl::runTask( + std::unique_ptr<blink::WebTaskRunner::Task> task) { + task->run(); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/child/web_task_runner_impl.h b/third_party/WebKit/Source/platform/scheduler/child/web_task_runner_impl.h new file mode 100644 index 0000000..ac3cfab --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/child/web_task_runner_impl.h
@@ -0,0 +1,57 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_CHILD_WEB_TASK_RUNNER_IMPL_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_CHILD_WEB_TASK_RUNNER_IMPL_H_ + +#include <memory> + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/time/time.h" +#include "public/platform/WebCommon.h" +#include "public/platform/WebTaskRunner.h" + +namespace blink { +namespace scheduler { +class TaskQueue; + +class BLINK_PLATFORM_EXPORT WebTaskRunnerImpl : public WebTaskRunner { + public: + explicit WebTaskRunnerImpl(scoped_refptr<TaskQueue> task_queue); + + ~WebTaskRunnerImpl() override; + + // WebTaskRunner implementation: + void postTask(const WebTraceLocation& web_location, + WebTaskRunner::Task* task) override; + void postDelayedTask(const WebTraceLocation& web_location, + WebTaskRunner::Task* task, + double delayMs) override; + bool runsTasksOnCurrentThread() override; + double virtualTimeSeconds() const override; + double monotonicallyIncreasingVirtualTimeSeconds() const override; + std::unique_ptr<WebTaskRunner> clone() override; + base::SingleThreadTaskRunner* taskRunner() override; + + // WebTaskRunner::Task should be wrapped by base::Passed() when + // used with base::Bind(). See https://crbug.com/551356. + // runTask() is a helper to call WebTaskRunner::Task::run from + // std::unique_ptr<WebTaskRunner::Task>. + // runTask() is placed here because std::unique_ptr<> cannot be used from + // Blink. + static void runTask(std::unique_ptr<WebTaskRunner::Task>); + + private: + base::TimeTicks Now() const; + + scoped_refptr<TaskQueue> task_queue_; + + DISALLOW_COPY_AND_ASSIGN(WebTaskRunnerImpl); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_CHILD_WEB_TASK_RUNNER_IMPL_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/child/webthread_base.cc b/third_party/WebKit/Source/platform/scheduler/child/webthread_base.cc new file mode 100644 index 0000000..c27706f --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/child/webthread_base.cc
@@ -0,0 +1,103 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// An implementation of WebThread in terms of base::MessageLoop and +// base::Thread + +#include "public/platform/scheduler/child/webthread_base.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/memory/ptr_util.h" +#include "base/pending_task.h" +#include "base/threading/platform_thread.h" +#include "public/platform/scheduler/child/single_thread_idle_task_runner.h" +#include "public/platform/WebTraceLocation.h" + +namespace blink { +namespace scheduler { + +class WebThreadBase::TaskObserverAdapter + : public base::MessageLoop::TaskObserver { + public: + explicit TaskObserverAdapter(WebThread::TaskObserver* observer) + : observer_(observer) {} + + void WillProcessTask(const base::PendingTask& pending_task) override { + observer_->willProcessTask(); + } + + void DidProcessTask(const base::PendingTask& pending_task) override { + observer_->didProcessTask(); + } + + private: + WebThread::TaskObserver* observer_; +}; + +WebThreadBase::WebThreadBase() {} + +WebThreadBase::~WebThreadBase() { + for (auto& observer_entry : task_observer_map_) { + delete observer_entry.second; + } +} + +void WebThreadBase::addTaskObserver(TaskObserver* observer) { + CHECK(isCurrentThread()); + std::pair<TaskObserverMap::iterator, bool> result = + task_observer_map_.insert(std::make_pair(observer, nullptr)); + if (result.second) + result.first->second = new TaskObserverAdapter(observer); + AddTaskObserverInternal(result.first->second); +} + +void WebThreadBase::removeTaskObserver(TaskObserver* observer) { + CHECK(isCurrentThread()); + TaskObserverMap::iterator iter = task_observer_map_.find(observer); + if (iter == task_observer_map_.end()) + return; + RemoveTaskObserverInternal(iter->second); + delete iter->second; + task_observer_map_.erase(iter); +} + +void WebThreadBase::AddTaskObserverInternal( + base::MessageLoop::TaskObserver* observer) { + base::MessageLoop::current()->AddTaskObserver(observer); +} + +void WebThreadBase::RemoveTaskObserverInternal( + base::MessageLoop::TaskObserver* observer) { + base::MessageLoop::current()->RemoveTaskObserver(observer); +} + +// static +void WebThreadBase::RunWebThreadIdleTask( + std::unique_ptr<blink::WebThread::IdleTask> idle_task, + base::TimeTicks deadline) { + idle_task->run((deadline - base::TimeTicks()).InSecondsF()); +} + +void WebThreadBase::postIdleTask(const blink::WebTraceLocation& location, + IdleTask* idle_task) { + GetIdleTaskRunner()->PostIdleTask( + location, base::Bind(&WebThreadBase::RunWebThreadIdleTask, + base::Passed(base::WrapUnique(idle_task)))); +} + +void WebThreadBase::postIdleTaskAfterWakeup( + const blink::WebTraceLocation& location, + IdleTask* idle_task) { + GetIdleTaskRunner()->PostIdleTaskAfterWakeup( + location, base::Bind(&WebThreadBase::RunWebThreadIdleTask, + base::Passed(base::WrapUnique(idle_task)))); +} + +bool WebThreadBase::isCurrentThread() const { + return GetTaskRunner()->BelongsToCurrentThread(); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/child/webthread_impl_for_worker_scheduler.cc b/third_party/WebKit/Source/platform/scheduler/child/webthread_impl_for_worker_scheduler.cc new file mode 100644 index 0000000..0299297 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/child/webthread_impl_for_worker_scheduler.cc
@@ -0,0 +1,131 @@ +// 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 "public/platform/scheduler/child/webthread_impl_for_worker_scheduler.h" + +#include "base/bind.h" +#include "base/location.h" +#include "base/memory/ptr_util.h" +#include "base/single_thread_task_runner.h" +#include "base/synchronization/waitable_event.h" +#include "base/time/default_tick_clock.h" +#include "public/platform/scheduler/base/task_queue.h" +#include "platform/scheduler/child/scheduler_tqm_delegate_impl.h" +#include "platform/scheduler/child/web_scheduler_impl.h" +#include "platform/scheduler/child/web_task_runner_impl.h" +#include "platform/scheduler/child/worker_scheduler_impl.h" +#include "public/platform/WebTraceLocation.h" + +namespace blink { +namespace scheduler { + +WebThreadImplForWorkerScheduler::WebThreadImplForWorkerScheduler( + const char* name) + : WebThreadImplForWorkerScheduler(name, base::Thread::Options()) {} + +WebThreadImplForWorkerScheduler::WebThreadImplForWorkerScheduler( + const char* name, + base::Thread::Options options) + : thread_(new base::Thread(name ? name : std::string())) { + bool started = thread_->StartWithOptions(options); + CHECK(started); + thread_task_runner_ = thread_->task_runner(); +} + +void WebThreadImplForWorkerScheduler::Init() { + base::WaitableEvent completion( + base::WaitableEvent::ResetPolicy::AUTOMATIC, + base::WaitableEvent::InitialState::NOT_SIGNALED); + thread_task_runner_->PostTask( + FROM_HERE, base::Bind(&WebThreadImplForWorkerScheduler::InitOnThread, + base::Unretained(this), &completion)); + completion.Wait(); +} + +WebThreadImplForWorkerScheduler::~WebThreadImplForWorkerScheduler() { + if (task_runner_delegate_) { + base::WaitableEvent completion( + base::WaitableEvent::ResetPolicy::AUTOMATIC, + base::WaitableEvent::InitialState::NOT_SIGNALED); + // Restore the original task runner so that the thread can tear itself down. + thread_task_runner_->PostTask( + FROM_HERE, + base::Bind(&WebThreadImplForWorkerScheduler::RestoreTaskRunnerOnThread, + base::Unretained(this), &completion)); + completion.Wait(); + } + thread_->Stop(); +} + +void WebThreadImplForWorkerScheduler::InitOnThread( + base::WaitableEvent* completion) { + // TODO(alexclarke): Do we need to unify virtual time for workers and the + // main thread? + worker_scheduler_ = CreateWorkerScheduler(); + worker_scheduler_->Init(); + task_runner_ = worker_scheduler_->DefaultTaskRunner(); + idle_task_runner_ = worker_scheduler_->IdleTaskRunner(); + web_scheduler_.reset(new WebSchedulerImpl( + worker_scheduler_.get(), worker_scheduler_->IdleTaskRunner(), + worker_scheduler_->DefaultTaskRunner(), + worker_scheduler_->DefaultTaskRunner())); + base::MessageLoop::current()->AddDestructionObserver(this); + web_task_runner_ = base::WrapUnique(new WebTaskRunnerImpl(task_runner_)); + completion->Signal(); +} + +void WebThreadImplForWorkerScheduler::RestoreTaskRunnerOnThread( + base::WaitableEvent* completion) { + task_runner_delegate_->RestoreDefaultTaskRunner(); + completion->Signal(); +} + +void WebThreadImplForWorkerScheduler::WillDestroyCurrentMessageLoop() { + task_runner_ = nullptr; + idle_task_runner_ = nullptr; + web_scheduler_.reset(); + worker_scheduler_.reset(); +} + +std::unique_ptr<scheduler::WorkerScheduler> +WebThreadImplForWorkerScheduler::CreateWorkerScheduler() { + task_runner_delegate_ = SchedulerTqmDelegateImpl::Create( + thread_->message_loop(), base::WrapUnique(new base::DefaultTickClock())); + return WorkerScheduler::Create(task_runner_delegate_); +} + +blink::PlatformThreadId WebThreadImplForWorkerScheduler::threadId() const { + return thread_->GetThreadId(); +} + +blink::WebScheduler* WebThreadImplForWorkerScheduler::scheduler() const { + return web_scheduler_.get(); +} + +base::SingleThreadTaskRunner* WebThreadImplForWorkerScheduler::GetTaskRunner() + const { + return task_runner_.get(); +} + +SingleThreadIdleTaskRunner* WebThreadImplForWorkerScheduler::GetIdleTaskRunner() + const { + return idle_task_runner_.get(); +} + +blink::WebTaskRunner* WebThreadImplForWorkerScheduler::getWebTaskRunner() { + return web_task_runner_.get(); +} + +void WebThreadImplForWorkerScheduler::AddTaskObserverInternal( + base::MessageLoop::TaskObserver* observer) { + worker_scheduler_->AddTaskObserver(observer); +} + +void WebThreadImplForWorkerScheduler::RemoveTaskObserverInternal( + base::MessageLoop::TaskObserver* observer) { + worker_scheduler_->RemoveTaskObserver(observer); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/child/webthread_impl_for_worker_scheduler_unittest.cc b/third_party/WebKit/Source/platform/scheduler/child/webthread_impl_for_worker_scheduler_unittest.cc new file mode 100644 index 0000000..0177879 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/child/webthread_impl_for_worker_scheduler_unittest.cc
@@ -0,0 +1,208 @@ +// 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 "public/platform/scheduler/child/webthread_impl_for_worker_scheduler.h" + +#include "base/macros.h" +#include "base/synchronization/waitable_event.h" +#include "platform/scheduler/child/web_scheduler_impl.h" +#include "platform/scheduler/child/worker_scheduler_impl.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "public/platform/WebTraceLocation.h" + +using testing::_; +using testing::AnyOf; +using testing::ElementsAre; +using testing::Invoke; + +namespace blink { +namespace scheduler { +namespace { + +class NopTask : public blink::WebTaskRunner::Task { + public: + ~NopTask() override {} + + void run() override {} +}; + +class MockTask : public blink::WebTaskRunner::Task { + public: + ~MockTask() override {} + + MOCK_METHOD0(run, void()); +}; + +class MockIdleTask : public blink::WebThread::IdleTask { + public: + ~MockIdleTask() override {} + + MOCK_METHOD1(run, void(double deadline)); +}; + +class TestObserver : public blink::WebThread::TaskObserver { + public: + explicit TestObserver(std::string* calls) : calls_(calls) {} + + ~TestObserver() override {} + + void willProcessTask() override { calls_->append(" willProcessTask"); } + + void didProcessTask() override { calls_->append(" didProcessTask"); } + + private: + std::string* calls_; // NOT OWNED +}; + +class TestTask : public blink::WebTaskRunner::Task { + public: + explicit TestTask(std::string* calls) : calls_(calls) {} + + ~TestTask() override {} + + void run() override { calls_->append(" run"); } + + private: + std::string* calls_; // NOT OWNED +}; + +void addTaskObserver(WebThreadImplForWorkerScheduler* thread, + TestObserver* observer) { + thread->addTaskObserver(observer); +} + +void removeTaskObserver(WebThreadImplForWorkerScheduler* thread, + TestObserver* observer) { + thread->removeTaskObserver(observer); +} + +void shutdownOnThread(WebThreadImplForWorkerScheduler* thread) { + WebSchedulerImpl* web_scheduler_impl = + static_cast<WebSchedulerImpl*>(thread->scheduler()); + web_scheduler_impl->shutdown(); +} + +} // namespace + +class WebThreadImplForWorkerSchedulerTest : public testing::Test { + public: + WebThreadImplForWorkerSchedulerTest() {} + + ~WebThreadImplForWorkerSchedulerTest() override {} + + void SetUp() override { + thread_.reset(new WebThreadImplForWorkerScheduler("test thread")); + thread_->Init(); + } + + void RunOnWorkerThread(const tracked_objects::Location& from_here, + const base::Closure& task) { + base::WaitableEvent completion( + base::WaitableEvent::ResetPolicy::AUTOMATIC, + base::WaitableEvent::InitialState::NOT_SIGNALED); + thread_->GetTaskRunner()->PostTask( + from_here, + base::Bind(&WebThreadImplForWorkerSchedulerTest::RunOnWorkerThreadTask, + base::Unretained(this), task, &completion)); + completion.Wait(); + } + + protected: + void RunOnWorkerThreadTask(const base::Closure& task, + base::WaitableEvent* completion) { + task.Run(); + completion->Signal(); + } + + std::unique_ptr<WebThreadImplForWorkerScheduler> thread_; + + DISALLOW_COPY_AND_ASSIGN(WebThreadImplForWorkerSchedulerTest); +}; + +TEST_F(WebThreadImplForWorkerSchedulerTest, TestDefaultTask) { + std::unique_ptr<MockTask> task(new MockTask()); + base::WaitableEvent completion( + base::WaitableEvent::ResetPolicy::AUTOMATIC, + base::WaitableEvent::InitialState::NOT_SIGNALED); + + EXPECT_CALL(*task, run()); + ON_CALL(*task, run()) + .WillByDefault(Invoke([&completion]() { completion.Signal(); })); + + thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(), + task.release()); + completion.Wait(); +} + +TEST_F(WebThreadImplForWorkerSchedulerTest, + TestTaskExecutedBeforeThreadDeletion) { + std::unique_ptr<MockTask> task(new MockTask()); + base::WaitableEvent completion( + base::WaitableEvent::ResetPolicy::AUTOMATIC, + base::WaitableEvent::InitialState::NOT_SIGNALED); + + EXPECT_CALL(*task, run()); + ON_CALL(*task, run()) + .WillByDefault(Invoke([&completion]() { completion.Signal(); })); + + thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(), + task.release()); + thread_.reset(); +} + +TEST_F(WebThreadImplForWorkerSchedulerTest, TestIdleTask) { + std::unique_ptr<MockIdleTask> task(new MockIdleTask()); + base::WaitableEvent completion( + base::WaitableEvent::ResetPolicy::AUTOMATIC, + base::WaitableEvent::InitialState::NOT_SIGNALED); + + EXPECT_CALL(*task, run(_)); + ON_CALL(*task, run(_)) + .WillByDefault(Invoke([&completion](double) { completion.Signal(); })); + + thread_->postIdleTask(blink::WebTraceLocation(), task.release()); + // We need to post a wakeup task or idle work will never happen. + thread_->getWebTaskRunner()->postDelayedTask(blink::WebTraceLocation(), + new NopTask(), 50ll); + + completion.Wait(); +} + +TEST_F(WebThreadImplForWorkerSchedulerTest, TestTaskObserver) { + std::string calls; + TestObserver observer(&calls); + + RunOnWorkerThread(FROM_HERE, + base::Bind(&addTaskObserver, thread_.get(), &observer)); + thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(), + new TestTask(&calls)); + RunOnWorkerThread(FROM_HERE, + base::Bind(&removeTaskObserver, thread_.get(), &observer)); + + // We need to be careful what we test here. We want to make sure the + // observers are un in the expected order before and after the task. + // Sometimes we get an internal scheduler task running before or after + // TestTask as well. This is not a bug, and we need to make sure the test + // doesn't fail when that happens. + EXPECT_THAT(calls, testing::HasSubstr("willProcessTask run didProcessTask")); +} + +TEST_F(WebThreadImplForWorkerSchedulerTest, TestShutdown) { + std::unique_ptr<MockTask> task(new MockTask()); + std::unique_ptr<MockTask> delayed_task(new MockTask()); + + EXPECT_CALL(*task, run()).Times(0); + EXPECT_CALL(*delayed_task, run()).Times(0); + + RunOnWorkerThread(FROM_HERE, base::Bind(&shutdownOnThread, thread_.get())); + thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(), + task.release()); + thread_->getWebTaskRunner()->postDelayedTask(blink::WebTraceLocation(), + task.release(), 50ll); + thread_.reset(); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler.cc b/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler.cc new file mode 100644 index 0000000..ce4f9b29 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler.cc
@@ -0,0 +1,28 @@ +// 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 "public/platform/scheduler/child/worker_scheduler.h" + +#include <utility> + +#include "base/memory/ptr_util.h" +#include "base/message_loop/message_loop.h" +#include "platform/scheduler/child/scheduler_tqm_delegate.h" +#include "platform/scheduler/child/worker_scheduler_impl.h" + +namespace blink { +namespace scheduler { + +WorkerScheduler::WorkerScheduler() {} + +WorkerScheduler::~WorkerScheduler() {} + +// static +std::unique_ptr<WorkerScheduler> WorkerScheduler::Create( + scoped_refptr<SchedulerTqmDelegate> main_task_runner) { + return base::WrapUnique(new WorkerSchedulerImpl(std::move(main_task_runner))); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl.cc new file mode 100644 index 0000000..636c10fe --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl.cc
@@ -0,0 +1,95 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "platform/scheduler/child/worker_scheduler_impl.h" + +#include "base/bind.h" +#include "base/trace_event/trace_event.h" +#include "base/trace_event/trace_event_argument.h" +#include "public/platform/scheduler/base/task_queue.h" +#include "platform/scheduler/child/scheduler_tqm_delegate.h" + +namespace blink { +namespace scheduler { + +WorkerSchedulerImpl::WorkerSchedulerImpl( + scoped_refptr<SchedulerTqmDelegate> main_task_runner) + : helper_(main_task_runner, + "worker.scheduler", + TRACE_DISABLED_BY_DEFAULT("worker.scheduler"), + TRACE_DISABLED_BY_DEFAULT("worker.scheduler.debug")), + idle_helper_(&helper_, + this, + "worker.scheduler", + TRACE_DISABLED_BY_DEFAULT("worker.scheduler"), + "WorkerSchedulerIdlePeriod", + base::TimeDelta::FromMilliseconds(300)) { + initialized_ = false; + TRACE_EVENT_OBJECT_CREATED_WITH_ID( + TRACE_DISABLED_BY_DEFAULT("worker.scheduler"), "WorkerScheduler", this); +} + +WorkerSchedulerImpl::~WorkerSchedulerImpl() { + TRACE_EVENT_OBJECT_DELETED_WITH_ID( + TRACE_DISABLED_BY_DEFAULT("worker.scheduler"), "WorkerScheduler", this); +} + +void WorkerSchedulerImpl::Init() { + initialized_ = true; + idle_helper_.EnableLongIdlePeriod(); +} + +scoped_refptr<TaskQueue> WorkerSchedulerImpl::DefaultTaskRunner() { + DCHECK(initialized_); + return helper_.DefaultTaskRunner(); +} + +scoped_refptr<SingleThreadIdleTaskRunner> +WorkerSchedulerImpl::IdleTaskRunner() { + DCHECK(initialized_); + return idle_helper_.IdleTaskRunner(); +} + +bool WorkerSchedulerImpl::CanExceedIdleDeadlineIfRequired() const { + DCHECK(initialized_); + return idle_helper_.CanExceedIdleDeadlineIfRequired(); +} + +bool WorkerSchedulerImpl::ShouldYieldForHighPriorityWork() { + // We don't consider any work as being high priority on workers. + return false; +} + +void WorkerSchedulerImpl::AddTaskObserver( + base::MessageLoop::TaskObserver* task_observer) { + DCHECK(initialized_); + helper_.AddTaskObserver(task_observer); +} + +void WorkerSchedulerImpl::RemoveTaskObserver( + base::MessageLoop::TaskObserver* task_observer) { + DCHECK(initialized_); + helper_.RemoveTaskObserver(task_observer); +} + +void WorkerSchedulerImpl::Shutdown() { + DCHECK(initialized_); + helper_.Shutdown(); +} + +SchedulerHelper* WorkerSchedulerImpl::GetSchedulerHelperForTesting() { + return &helper_; +} + +bool WorkerSchedulerImpl::CanEnterLongIdlePeriod(base::TimeTicks, + base::TimeDelta*) { + return true; +} + +base::TimeTicks WorkerSchedulerImpl::CurrentIdleTaskDeadlineForTesting() const { + return idle_helper_.CurrentIdleTaskDeadline(); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl.h b/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl.h new file mode 100644 index 0000000..c006c29 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl.h
@@ -0,0 +1,67 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_CHILD_WORKER_SCHEDULER_IMPL_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_CHILD_WORKER_SCHEDULER_IMPL_H_ + +#include "base/macros.h" +#include "platform/scheduler/child/idle_helper.h" +#include "platform/scheduler/child/scheduler_helper.h" +#include "public/platform/scheduler/child/worker_scheduler.h" + +namespace base { +namespace trace_event { +class ConvertableToTraceFormat; +} +} + +namespace blink { +namespace scheduler { + +class SchedulerTqmDelegate; + +class BLINK_PLATFORM_EXPORT WorkerSchedulerImpl : public WorkerScheduler, + public IdleHelper::Delegate { + public: + explicit WorkerSchedulerImpl( + scoped_refptr<SchedulerTqmDelegate> main_task_runner); + ~WorkerSchedulerImpl() override; + + // WorkerScheduler implementation: + scoped_refptr<TaskQueue> DefaultTaskRunner() override; + scoped_refptr<SingleThreadIdleTaskRunner> IdleTaskRunner() override; + bool CanExceedIdleDeadlineIfRequired() const override; + bool ShouldYieldForHighPriorityWork() override; + void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer) override; + void RemoveTaskObserver( + base::MessageLoop::TaskObserver* task_observer) override; + void Init() override; + void Shutdown() override; + + SchedulerHelper* GetSchedulerHelperForTesting(); + base::TimeTicks CurrentIdleTaskDeadlineForTesting() const; + + protected: + // IdleHelper::Delegate implementation: + bool CanEnterLongIdlePeriod( + base::TimeTicks now, + base::TimeDelta* next_long_idle_period_delay_out) override; + void IsNotQuiescent() override {} + void OnIdlePeriodStarted() override {} + void OnIdlePeriodEnded() override {} + + private: + void MaybeStartLongIdlePeriod(); + + SchedulerHelper helper_; + IdleHelper idle_helper_; + bool initialized_; + + DISALLOW_COPY_AND_ASSIGN(WorkerSchedulerImpl); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_CHILD_WORKER_SCHEDULER_IMPL_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl_unittest.cc b/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl_unittest.cc new file mode 100644 index 0000000..1214e6c --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl_unittest.cc
@@ -0,0 +1,380 @@ +// 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 "platform/scheduler/child/worker_scheduler_impl.h" + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "base/strings/stringprintf.h" +#include "base/test/simple_test_tick_clock.h" +#include "cc/test/ordered_simple_task_runner.h" +#include "platform/scheduler/base/test_time_source.h" +#include "platform/scheduler/child/scheduler_tqm_delegate_for_test.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::ElementsAreArray; + +namespace blink { +namespace scheduler { + +namespace { +void NopTask() {} + +int TimeTicksToIntMs(const base::TimeTicks& time) { + return static_cast<int>((time - base::TimeTicks()).InMilliseconds()); +} + +void RecordTimelineTask(std::vector<std::string>* timeline, + base::SimpleTestTickClock* clock) { + timeline->push_back(base::StringPrintf("run RecordTimelineTask @ %d", + TimeTicksToIntMs(clock->NowTicks()))); +} + +void AppendToVectorTestTask(std::vector<std::string>* vector, + std::string value) { + vector->push_back(value); +} + +void AppendToVectorIdleTestTask(std::vector<std::string>* vector, + std::string value, + base::TimeTicks deadline) { + AppendToVectorTestTask(vector, value); +} + +void TimelineIdleTestTask(std::vector<std::string>* timeline, + base::TimeTicks deadline) { + timeline->push_back(base::StringPrintf("run TimelineIdleTestTask deadline %d", + TimeTicksToIntMs(deadline))); +} + +}; // namespace + +class WorkerSchedulerImplForTest : public WorkerSchedulerImpl { + public: + WorkerSchedulerImplForTest( + scoped_refptr<SchedulerTqmDelegate> main_task_runner, + base::SimpleTestTickClock* clock_) + : WorkerSchedulerImpl(main_task_runner), + clock_(clock_), + timeline_(nullptr) {} + + void RecordTimelineEvents(std::vector<std::string>* timeline) { + timeline_ = timeline; + } + + private: + bool CanEnterLongIdlePeriod( + base::TimeTicks now, + base::TimeDelta* next_long_idle_period_delay_out) override { + if (timeline_) { + timeline_->push_back(base::StringPrintf("CanEnterLongIdlePeriod @ %d", + TimeTicksToIntMs(now))); + } + return WorkerSchedulerImpl::CanEnterLongIdlePeriod( + now, next_long_idle_period_delay_out); + } + + void IsNotQuiescent() override { + if (timeline_) { + timeline_->push_back(base::StringPrintf( + "IsNotQuiescent @ %d", TimeTicksToIntMs(clock_->NowTicks()))); + } + WorkerSchedulerImpl::IsNotQuiescent(); + } + + base::SimpleTestTickClock* clock_; // NOT OWNED + std::vector<std::string>* timeline_; // NOT OWNED +}; + +class WorkerSchedulerImplTest : public testing::Test { + public: + WorkerSchedulerImplTest() + : clock_(new base::SimpleTestTickClock()), + mock_task_runner_(new cc::OrderedSimpleTaskRunner(clock_.get(), true)), + main_task_runner_(SchedulerTqmDelegateForTest::Create( + mock_task_runner_, + base::WrapUnique(new TestTimeSource(clock_.get())))), + scheduler_( + new WorkerSchedulerImplForTest(main_task_runner_, clock_.get())), + timeline_(nullptr) { + clock_->Advance(base::TimeDelta::FromMicroseconds(5000)); + } + + ~WorkerSchedulerImplTest() override {} + + void TearDown() override { + // Check that all tests stop posting tasks. + while (mock_task_runner_->RunUntilIdle()) { + } + } + + void Init() { + scheduler_->Init(); + default_task_runner_ = scheduler_->DefaultTaskRunner(); + idle_task_runner_ = scheduler_->IdleTaskRunner(); + timeline_ = nullptr; + } + + void RecordTimelineEvents(std::vector<std::string>* timeline) { + timeline_ = timeline; + scheduler_->RecordTimelineEvents(timeline); + } + + void RunUntilIdle() { + if (timeline_) { + timeline_->push_back(base::StringPrintf( + "RunUntilIdle begin @ %d", TimeTicksToIntMs(clock_->NowTicks()))); + } + mock_task_runner_->RunUntilIdle(); + if (timeline_) { + timeline_->push_back(base::StringPrintf( + "RunUntilIdle end @ %d", TimeTicksToIntMs(clock_->NowTicks()))); + } + } + + // Helper for posting several tasks of specific types. |task_descriptor| is a + // string with space delimited task identifiers. The first letter of each + // task identifier specifies the task type: + // - 'D': Default task + // - 'I': Idle task + void PostTestTasks(std::vector<std::string>* run_order, + const std::string& task_descriptor) { + std::istringstream stream(task_descriptor); + while (!stream.eof()) { + std::string task; + stream >> task; + switch (task[0]) { + case 'D': + default_task_runner_->PostTask( + FROM_HERE, base::Bind(&AppendToVectorTestTask, run_order, task)); + break; + case 'I': + idle_task_runner_->PostIdleTask( + FROM_HERE, + base::Bind(&AppendToVectorIdleTestTask, run_order, task)); + break; + default: + NOTREACHED(); + } + } + } + + static base::TimeDelta maximum_idle_period_duration() { + return base::TimeDelta::FromMilliseconds( + IdleHelper::kMaximumIdlePeriodMillis); + } + + protected: + std::unique_ptr<base::SimpleTestTickClock> clock_; + // Only one of mock_task_runner_ or message_loop_ will be set. + scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_; + + scoped_refptr<SchedulerTqmDelegate> main_task_runner_; + std::unique_ptr<WorkerSchedulerImplForTest> scheduler_; + scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_; + scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_; + std::vector<std::string>* timeline_; // NOT OWNED + + DISALLOW_COPY_AND_ASSIGN(WorkerSchedulerImplTest); +}; + +TEST_F(WorkerSchedulerImplTest, TestPostDefaultTask) { + Init(); + + std::vector<std::string> run_order; + PostTestTasks(&run_order, "D1 D2 D3 D4"); + + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("D1"), std::string("D2"), + std::string("D3"), std::string("D4"))); +} + +TEST_F(WorkerSchedulerImplTest, TestPostIdleTask) { + Init(); + + std::vector<std::string> run_order; + PostTestTasks(&run_order, "I1"); + + RunUntilIdle(); + EXPECT_THAT(run_order, testing::ElementsAre(std::string("I1"))); +} + +TEST_F(WorkerSchedulerImplTest, TestPostDefaultAndIdleTasks) { + Init(); + + std::vector<std::string> run_order; + PostTestTasks(&run_order, "I1 D2 D3 D4"); + + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("D2"), std::string("D3"), + std::string("D4"), std::string("I1"))); +} + +TEST_F(WorkerSchedulerImplTest, TestPostDefaultDelayedAndIdleTasks) { + Init(); + + std::vector<std::string> run_order; + PostTestTasks(&run_order, "I1 D2 D3 D4"); + + default_task_runner_->PostDelayedTask( + FROM_HERE, base::Bind(&AppendToVectorTestTask, &run_order, "DELAYED"), + base::TimeDelta::FromMilliseconds(1000)); + + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("D2"), std::string("D3"), + std::string("D4"), std::string("I1"), + std::string("DELAYED"))); +} + +TEST_F(WorkerSchedulerImplTest, TestIdleTaskWhenIsNotQuiescent) { + std::vector<std::string> timeline; + RecordTimelineEvents(&timeline); + Init(); + + timeline.push_back("Post default task"); + // Post a delayed task timed to occur mid way during the long idle period. + default_task_runner_->PostTask( + FROM_HERE, base::Bind(&RecordTimelineTask, base::Unretained(&timeline), + base::Unretained(clock_.get()))); + RunUntilIdle(); + + timeline.push_back("Post idle task"); + idle_task_runner_->PostIdleTask(FROM_HERE, + base::Bind(&TimelineIdleTestTask, &timeline)); + + RunUntilIdle(); + + std::string expected_timeline[] = {"CanEnterLongIdlePeriod @ 5", + "Post default task", + "run RecordTimelineTask @ 5", + "Post idle task", + "IsNotQuiescent @ 5", + "CanEnterLongIdlePeriod @ 305", + "run TimelineIdleTestTask deadline 355"}; + + EXPECT_THAT(timeline, ElementsAreArray(expected_timeline)); +} + +TEST_F(WorkerSchedulerImplTest, TestIdleDeadlineWithPendingDelayedTask) { + std::vector<std::string> timeline; + RecordTimelineEvents(&timeline); + Init(); + + timeline.push_back("Post delayed and idle tasks"); + // Post a delayed task timed to occur mid way during the long idle period. + default_task_runner_->PostDelayedTask( + FROM_HERE, base::Bind(&RecordTimelineTask, base::Unretained(&timeline), + base::Unretained(clock_.get())), + base::TimeDelta::FromMilliseconds(20)); + idle_task_runner_->PostIdleTask(FROM_HERE, + base::Bind(&TimelineIdleTestTask, &timeline)); + + RunUntilIdle(); + + std::string expected_timeline[] = { + "CanEnterLongIdlePeriod @ 5", "Post delayed and idle tasks", + "CanEnterLongIdlePeriod @ 5", + "run TimelineIdleTestTask deadline 25", // Note the short 20ms deadline. + "run RecordTimelineTask @ 25"}; + + EXPECT_THAT(timeline, ElementsAreArray(expected_timeline)); +} + +TEST_F(WorkerSchedulerImplTest, + TestIdleDeadlineWithPendingDelayedTaskFarInTheFuture) { + std::vector<std::string> timeline; + RecordTimelineEvents(&timeline); + Init(); + + timeline.push_back("Post delayed and idle tasks"); + // Post a delayed task timed to occur well after the long idle period. + default_task_runner_->PostDelayedTask( + FROM_HERE, base::Bind(&RecordTimelineTask, base::Unretained(&timeline), + base::Unretained(clock_.get())), + base::TimeDelta::FromMilliseconds(500)); + idle_task_runner_->PostIdleTask(FROM_HERE, + base::Bind(&TimelineIdleTestTask, &timeline)); + + RunUntilIdle(); + + std::string expected_timeline[] = { + "CanEnterLongIdlePeriod @ 5", "Post delayed and idle tasks", + "CanEnterLongIdlePeriod @ 5", + "run TimelineIdleTestTask deadline 55", // Note the full 50ms deadline. + "run RecordTimelineTask @ 505"}; + + EXPECT_THAT(timeline, ElementsAreArray(expected_timeline)); +} + +TEST_F(WorkerSchedulerImplTest, TestPostIdleTaskAfterRunningUntilIdle) { + Init(); + + default_task_runner_->PostDelayedTask( + FROM_HERE, base::Bind(&NopTask), base::TimeDelta::FromMilliseconds(1000)); + RunUntilIdle(); + + std::vector<std::string> run_order; + PostTestTasks(&run_order, "I1 I2 D3"); + + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("D3"), std::string("I1"), + std::string("I2"))); +} + +TEST_F(WorkerSchedulerImplTest, TestLongIdlePeriodTimeline) { + Init(); + + std::vector<std::string> timeline; + RecordTimelineEvents(&timeline); + + // The scheduler should not run the initiate_next_long_idle_period task if + // there are no idle tasks and no other task woke up the scheduler, thus + // the idle period deadline shouldn't update at the end of the current long + // idle period. + base::TimeTicks idle_period_deadline = + scheduler_->CurrentIdleTaskDeadlineForTesting(); + clock_->Advance(maximum_idle_period_duration()); + RunUntilIdle(); + + base::TimeTicks new_idle_period_deadline = + scheduler_->CurrentIdleTaskDeadlineForTesting(); + EXPECT_EQ(idle_period_deadline, new_idle_period_deadline); + + // Posting a after-wakeup idle task also shouldn't wake the scheduler or + // initiate the next long idle period. + timeline.push_back("PostIdleTaskAfterWakeup"); + idle_task_runner_->PostIdleTaskAfterWakeup( + FROM_HERE, base::Bind(&TimelineIdleTestTask, &timeline)); + RunUntilIdle(); + new_idle_period_deadline = scheduler_->CurrentIdleTaskDeadlineForTesting(); + + // Running a normal task should initiate a new long idle period after waiting + // 300ms for quiescence. + timeline.push_back("Post RecordTimelineTask"); + default_task_runner_->PostTask( + FROM_HERE, base::Bind(&RecordTimelineTask, base::Unretained(&timeline), + base::Unretained(clock_.get()))); + RunUntilIdle(); + + std::string expected_timeline[] = { + "RunUntilIdle begin @ 55", "RunUntilIdle end @ 55", + "PostIdleTaskAfterWakeup", + "RunUntilIdle begin @ 55", // NOTE idle task doesn't run till later. + "RunUntilIdle end @ 55", "Post RecordTimelineTask", + "RunUntilIdle begin @ 55", "run RecordTimelineTask @ 55", + "IsNotQuiescent @ 55", // NOTE we have to wait for quiescence. + "CanEnterLongIdlePeriod @ 355", "run TimelineIdleTestTask deadline 405", + "RunUntilIdle end @ 355"}; + + EXPECT_THAT(timeline, ElementsAreArray(expected_timeline)); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/DEPS b/third_party/WebKit/Source/platform/scheduler/renderer/DEPS new file mode 100644 index 0000000..1a5c72e --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/DEPS
@@ -0,0 +1,13 @@ +include_rules = [ + "+platform/scheduler/base", + "+platform/scheduler/child", + "+source/platform/scheduler/base", + "+source/platform/scheduler/child", + "+cc", +] + +specific_include_rules = { + ".*test\.cc": [ + "+cc/test", + ], +}
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain.cc b/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain.cc new file mode 100644 index 0000000..06e07586 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain.cc
@@ -0,0 +1,45 @@ +// 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 "platform/scheduler/renderer/auto_advancing_virtual_time_domain.h" + +namespace blink { +namespace scheduler { + +AutoAdvancingVirtualTimeDomain::AutoAdvancingVirtualTimeDomain( + base::TimeTicks initial_time) + : VirtualTimeDomain(nullptr, initial_time), + can_advance_virtual_time_(true) {} + +AutoAdvancingVirtualTimeDomain::~AutoAdvancingVirtualTimeDomain() {} + +bool AutoAdvancingVirtualTimeDomain::MaybeAdvanceTime() { + base::TimeTicks run_time; + if (!can_advance_virtual_time_ || !NextScheduledRunTime(&run_time)) { + return false; + } + AdvanceTo(run_time); + return true; +} + +void AutoAdvancingVirtualTimeDomain::RequestWakeup(base::TimeTicks now, + base::TimeDelta delay) { + base::TimeTicks dummy; + if (can_advance_virtual_time_ && !NextScheduledRunTime(&dummy)) + RequestDoWork(); +} + +void AutoAdvancingVirtualTimeDomain::SetCanAdvanceVirtualTime( + bool can_advance_virtual_time) { + can_advance_virtual_time_ = can_advance_virtual_time; + if (can_advance_virtual_time_) + RequestDoWork(); +} + +const char* AutoAdvancingVirtualTimeDomain::GetName() const { + return "AutoAdvancingVirtualTimeDomain"; +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain.h b/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain.h new file mode 100644 index 0000000..ffd880ee --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain.h
@@ -0,0 +1,47 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_AUTO_ADVANCING_VIRTUAL_TIME_DOMAIN_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_AUTO_ADVANCING_VIRTUAL_TIME_DOMAIN_H_ + +#include "base/macros.h" +#include "platform/scheduler/base/virtual_time_domain.h" + +namespace blink { +namespace scheduler { + +// A time domain that runs tasks sequentially in time order but doesn't sleep +// between delayed tasks. +// +// KEY: A-E are delayed tasks +// | A B C D E (Execution with RealTimeDomain) +// |-----------------------------> time +// +// |ABCDE (Execution with AutoAdvancingVirtualTimeDomain) +// |-----------------------------> time +class BLINK_PLATFORM_EXPORT AutoAdvancingVirtualTimeDomain + : public VirtualTimeDomain { + public: + explicit AutoAdvancingVirtualTimeDomain(base::TimeTicks initial_time); + ~AutoAdvancingVirtualTimeDomain() override; + + // TimeDomain implementation: + bool MaybeAdvanceTime() override; + void RequestWakeup(base::TimeTicks now, base::TimeDelta delay) override; + const char* GetName() const override; + + // Controls whether or not virtual time is allowed to advance, when the + // TaskQueueManager runs out of immediate work to do. + void SetCanAdvanceVirtualTime(bool can_advance_virtual_time); + + private: + bool can_advance_virtual_time_; + + DISALLOW_COPY_AND_ASSIGN(AutoAdvancingVirtualTimeDomain); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_AUTO_ADVANCING_VIRTUAL_TIME_DOMAIN_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain_unittest.cc new file mode 100644 index 0000000..474c041 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain_unittest.cc
@@ -0,0 +1,99 @@ +// 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 "platform/scheduler/renderer/auto_advancing_virtual_time_domain.h" + +#include "base/memory/ptr_util.h" +#include "base/test/simple_test_tick_clock.h" +#include "cc/test/ordered_simple_task_runner.h" +#include "platform/scheduler/base/task_queue_manager.h" +#include "platform/scheduler/base/test_task_time_tracker.h" +#include "platform/scheduler/base/test_time_source.h" +#include "platform/scheduler/child/scheduler_tqm_delegate_for_test.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace blink { +namespace scheduler { + +class AutoAdvancingVirtualTimeDomainTest : public testing::Test { + public: + AutoAdvancingVirtualTimeDomainTest() {} + ~AutoAdvancingVirtualTimeDomainTest() override {} + + void SetUp() override { + clock_.reset(new base::SimpleTestTickClock()); + clock_->Advance(base::TimeDelta::FromMicroseconds(5000)); + + test_time_source_.reset(new TestTimeSource(clock_.get())); + mock_task_runner_ = make_scoped_refptr( + new cc::OrderedSimpleTaskRunner(clock_.get(), false)); + main_task_runner_ = SchedulerTqmDelegateForTest::Create( + mock_task_runner_, base::WrapUnique(new TestTimeSource(clock_.get()))); + + manager_ = base::WrapUnique( + new TaskQueueManager(main_task_runner_, "test.scheduler", + "test.scheduler", "test.scheduler.debug")); + manager_->SetTaskTimeTracker(&test_task_time_tracker_); + task_runner_ = manager_->NewTaskQueue(TaskQueue::Spec("test_task_queue")); + initial_time_ = clock_->NowTicks(); + auto_advancing_time_domain_.reset( + new AutoAdvancingVirtualTimeDomain(initial_time_)); + manager_->RegisterTimeDomain(auto_advancing_time_domain_.get()); + task_runner_->SetTimeDomain(auto_advancing_time_domain_.get()); + } + + void TearDown() override { + task_runner_->UnregisterTaskQueue(); + manager_->UnregisterTimeDomain(auto_advancing_time_domain_.get()); + } + + base::TimeTicks initial_time_; + std::unique_ptr<base::SimpleTestTickClock> clock_; + std::unique_ptr<TestTimeSource> test_time_source_; + scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_; + scoped_refptr<SchedulerTqmDelegate> main_task_runner_; + std::unique_ptr<TaskQueueManager> manager_; + scoped_refptr<TaskQueue> task_runner_; + std::unique_ptr<AutoAdvancingVirtualTimeDomain> auto_advancing_time_domain_; + TestTaskTimeTracker test_task_time_tracker_; +}; + +namespace { +void NopTask(bool* task_run) { + *task_run = true; +} +} // namesapce + +TEST_F(AutoAdvancingVirtualTimeDomainTest, VirtualTimeAdvances) { + base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10); + bool task_run = false; + task_runner_->PostDelayedTask(FROM_HERE, base::Bind(NopTask, &task_run), + delay); + + mock_task_runner_->RunUntilIdle(); + + EXPECT_EQ(initial_time_, clock_->NowTicks()); + EXPECT_EQ(initial_time_ + delay, + auto_advancing_time_domain_->CreateLazyNow().Now()); + EXPECT_TRUE(task_run); +} + +TEST_F(AutoAdvancingVirtualTimeDomainTest, VirtualTimeDoesNotAdvance) { + base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10); + bool task_run = false; + task_runner_->PostDelayedTask(FROM_HERE, base::Bind(NopTask, &task_run), + delay); + + auto_advancing_time_domain_->SetCanAdvanceVirtualTime(false); + + mock_task_runner_->RunUntilIdle(); + + EXPECT_EQ(initial_time_, clock_->NowTicks()); + EXPECT_EQ(initial_time_, auto_advancing_time_domain_->CreateLazyNow().Now()); + EXPECT_FALSE(task_run); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/deadline_task_runner.cc b/third_party/WebKit/Source/platform/scheduler/renderer/deadline_task_runner.cc new file mode 100644 index 0000000..0f4b4e1 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/deadline_task_runner.cc
@@ -0,0 +1,41 @@ +// 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 "platform/scheduler/renderer/deadline_task_runner.h" + +#include "base/bind.h" + +namespace blink { +namespace scheduler { + +DeadlineTaskRunner::DeadlineTaskRunner( + const base::Closure& callback, + scoped_refptr<base::SingleThreadTaskRunner> task_runner) + : callback_(callback), task_runner_(task_runner) { + cancelable_run_internal_.Reset( + base::Bind(&DeadlineTaskRunner::RunInternal, base::Unretained(this))); +} + +DeadlineTaskRunner::~DeadlineTaskRunner() {} + +void DeadlineTaskRunner::SetDeadline(const tracked_objects::Location& from_here, + base::TimeDelta delay, + base::TimeTicks now) { + DCHECK(delay > base::TimeDelta()); + base::TimeTicks deadline = now + delay; + if (deadline_.is_null() || deadline < deadline_) { + deadline_ = deadline; + cancelable_run_internal_.Cancel(); + task_runner_->PostDelayedTask(from_here, + cancelable_run_internal_.callback(), delay); + } +} + +void DeadlineTaskRunner::RunInternal() { + deadline_ = base::TimeTicks(); + callback_.Run(); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/deadline_task_runner.h b/third_party/WebKit/Source/platform/scheduler/renderer/deadline_task_runner.h new file mode 100644 index 0000000..41937ae --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/deadline_task_runner.h
@@ -0,0 +1,52 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_DEADLINE_TASK_RUNNER_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_DEADLINE_TASK_RUNNER_H_ + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "base/single_thread_task_runner.h" +#include "base/time/time.h" +#include "platform/scheduler/base/cancelable_closure_holder.h" +#include "public/platform/WebCommon.h" + +namespace blink { +namespace scheduler { + +// Runs a posted task at latest by a given deadline, but possibly sooner. +class BLINK_PLATFORM_EXPORT DeadlineTaskRunner { + public: + DeadlineTaskRunner(const base::Closure& callback, + scoped_refptr<base::SingleThreadTaskRunner> task_runner); + + ~DeadlineTaskRunner(); + + // If there is no outstanding task then a task is posted to run after |delay|. + // If there is an outstanding task which is scheduled to run: + // a) sooner - then this is a NOP. + // b) later - then the outstanding task is cancelled and a new task is + // posted to run after |delay|. + // + // Once the deadline task has run, we reset. + void SetDeadline(const tracked_objects::Location& from_here, + base::TimeDelta delay, + base::TimeTicks now); + + private: + void RunInternal(); + + CancelableClosureHolder cancelable_run_internal_; + base::Closure callback_; + base::TimeTicks deadline_; + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + + DISALLOW_COPY_AND_ASSIGN(DeadlineTaskRunner); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_DEADLINE_TASK_RUNNER_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/deadline_task_runner_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/deadline_task_runner_unittest.cc new file mode 100644 index 0000000..635eb19 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/deadline_task_runner_unittest.cc
@@ -0,0 +1,103 @@ +// 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 "platform/scheduler/renderer/deadline_task_runner.h" + +#include <memory> + +#include "base/test/simple_test_tick_clock.h" +#include "cc/test/ordered_simple_task_runner.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace blink { +namespace scheduler { + +class DeadlineTaskRunnerTest : public testing::Test { + public: + DeadlineTaskRunnerTest() {} + ~DeadlineTaskRunnerTest() override {} + + void SetUp() override { + clock_.reset(new base::SimpleTestTickClock()); + clock_->Advance(base::TimeDelta::FromMicroseconds(5000)); + mock_task_runner_ = new cc::OrderedSimpleTaskRunner(clock_.get(), true); + deadline_task_runner_.reset(new DeadlineTaskRunner( + base::Bind(&DeadlineTaskRunnerTest::TestTask, base::Unretained(this)), + mock_task_runner_)); + run_times_.clear(); + } + + bool RunUntilIdle() { return mock_task_runner_->RunUntilIdle(); } + + void TestTask() { run_times_.push_back(clock_->NowTicks()); } + + std::unique_ptr<base::SimpleTestTickClock> clock_; + scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_; + std::unique_ptr<DeadlineTaskRunner> deadline_task_runner_; + std::vector<base::TimeTicks> run_times_; +}; + +TEST_F(DeadlineTaskRunnerTest, RunOnce) { + base::TimeTicks start_time = clock_->NowTicks(); + base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10); + deadline_task_runner_->SetDeadline(FROM_HERE, delay, clock_->NowTicks()); + RunUntilIdle(); + + EXPECT_THAT(run_times_, testing::ElementsAre(start_time + delay)); +}; + +TEST_F(DeadlineTaskRunnerTest, RunTwice) { + base::TimeDelta delay1 = base::TimeDelta::FromMilliseconds(10); + base::TimeTicks deadline1 = clock_->NowTicks() + delay1; + deadline_task_runner_->SetDeadline(FROM_HERE, delay1, clock_->NowTicks()); + RunUntilIdle(); + + base::TimeDelta delay2 = base::TimeDelta::FromMilliseconds(100); + base::TimeTicks deadline2 = clock_->NowTicks() + delay2; + deadline_task_runner_->SetDeadline(FROM_HERE, delay2, clock_->NowTicks()); + RunUntilIdle(); + + EXPECT_THAT(run_times_, testing::ElementsAre(deadline1, deadline2)); +}; + +TEST_F(DeadlineTaskRunnerTest, EarlierDeadlinesTakePrecidence) { + base::TimeTicks start_time = clock_->NowTicks(); + base::TimeDelta delay1 = base::TimeDelta::FromMilliseconds(1); + base::TimeDelta delay10 = base::TimeDelta::FromMilliseconds(10); + base::TimeDelta delay100 = base::TimeDelta::FromMilliseconds(100); + deadline_task_runner_->SetDeadline(FROM_HERE, delay100, clock_->NowTicks()); + deadline_task_runner_->SetDeadline(FROM_HERE, delay10, clock_->NowTicks()); + deadline_task_runner_->SetDeadline(FROM_HERE, delay1, clock_->NowTicks()); + + RunUntilIdle(); + + EXPECT_THAT(run_times_, testing::ElementsAre(start_time + delay1)); +}; + +TEST_F(DeadlineTaskRunnerTest, LaterDeadlinesIgnored) { + base::TimeTicks start_time = clock_->NowTicks(); + base::TimeDelta delay100 = base::TimeDelta::FromMilliseconds(100); + base::TimeDelta delay10000 = base::TimeDelta::FromMilliseconds(10000); + deadline_task_runner_->SetDeadline(FROM_HERE, delay100, clock_->NowTicks()); + deadline_task_runner_->SetDeadline(FROM_HERE, delay10000, clock_->NowTicks()); + + RunUntilIdle(); + + EXPECT_THAT(run_times_, testing::ElementsAre(start_time + delay100)); +}; + +TEST_F(DeadlineTaskRunnerTest, DeleteDeadlineTaskRunnerAfterPosting) { + deadline_task_runner_->SetDeadline( + FROM_HERE, base::TimeDelta::FromMilliseconds(10), clock_->NowTicks()); + + // Deleting the pending task should cancel it. + deadline_task_runner_.reset(nullptr); + RunUntilIdle(); + + EXPECT_TRUE(run_times_.empty()); +}; + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/idle_time_estimator.cc b/third_party/WebKit/Source/platform/scheduler/renderer/idle_time_estimator.cc new file mode 100644 index 0000000..b40f8e2a --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/idle_time_estimator.cc
@@ -0,0 +1,76 @@ +// 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 "platform/scheduler/renderer/idle_time_estimator.h" + +#include "base/time/default_tick_clock.h" + +namespace blink { +namespace scheduler { + +IdleTimeEstimator::IdleTimeEstimator( + const scoped_refptr<TaskQueue>& compositor_task_runner, + base::TickClock* time_source, + int sample_count, + double estimation_percentile) + : compositor_task_runner_(compositor_task_runner), + per_frame_compositor_task_runtime_(sample_count), + time_source_(time_source), + estimation_percentile_(estimation_percentile), + nesting_level_(0), + did_commit_(false) { + compositor_task_runner_->AddTaskObserver(this); +} + +IdleTimeEstimator::~IdleTimeEstimator() { + compositor_task_runner_->RemoveTaskObserver(this); +} + +base::TimeDelta IdleTimeEstimator::GetExpectedIdleDuration( + base::TimeDelta compositor_frame_interval) const { + base::TimeDelta expected_compositor_task_runtime_ = + per_frame_compositor_task_runtime_.Percentile(estimation_percentile_); + return std::max(base::TimeDelta(), compositor_frame_interval - + expected_compositor_task_runtime_); +} + +void IdleTimeEstimator::DidCommitFrameToCompositor() { + // This will run inside of a WillProcessTask / DidProcessTask pair, let + // DidProcessTask know a frame was comitted. + if (nesting_level_ == 1) + did_commit_ = true; +} + +void IdleTimeEstimator::Clear() { + task_start_time_ = base::TimeTicks(); + prev_commit_time_ = base::TimeTicks(); + cumulative_compositor_runtime_ = base::TimeDelta(); + per_frame_compositor_task_runtime_.Clear(); + did_commit_ = false; +} + +void IdleTimeEstimator::WillProcessTask(const base::PendingTask& pending_task) { + nesting_level_++; + if (nesting_level_ == 1) + task_start_time_ = time_source_->NowTicks(); +} + +void IdleTimeEstimator::DidProcessTask(const base::PendingTask& pending_task) { + nesting_level_--; + DCHECK_GE(nesting_level_, 0); + if (nesting_level_ != 0) + return; + + cumulative_compositor_runtime_ += time_source_->NowTicks() - task_start_time_; + + if (did_commit_) { + per_frame_compositor_task_runtime_.InsertSample( + cumulative_compositor_runtime_); + cumulative_compositor_runtime_ = base::TimeDelta(); + did_commit_ = false; + } +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/idle_time_estimator.h b/third_party/WebKit/Source/platform/scheduler/renderer/idle_time_estimator.h new file mode 100644 index 0000000..4c13857d --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/idle_time_estimator.h
@@ -0,0 +1,60 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_IDLE_TIME_ESTIMATOR_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_IDLE_TIME_ESTIMATOR_H_ + +#include "base/macros.h" +#include "base/message_loop/message_loop.h" +#include "base/time/tick_clock.h" +#include "cc/base/rolling_time_delta_history.h" +#include "public/platform/scheduler/base/task_queue.h" +#include "public/platform/WebCommon.h" + +namespace blink { +namespace scheduler { + +// Estimates how much idle time there is available. Ignores nested tasks. +class BLINK_PLATFORM_EXPORT IdleTimeEstimator + : public base::MessageLoop::TaskObserver { + public: + IdleTimeEstimator(const scoped_refptr<TaskQueue>& compositor_task_runner, + base::TickClock* time_source, + int sample_count, + double estimation_percentile); + + ~IdleTimeEstimator() override; + + // Expected Idle time is defined as: |compositor_frame_interval| minus + // expected compositor task duration. + base::TimeDelta GetExpectedIdleDuration( + base::TimeDelta compositor_frame_interval) const; + + void DidCommitFrameToCompositor(); + + void Clear(); + + // TaskObserver implementation: + void WillProcessTask(const base::PendingTask& pending_task) override; + void DidProcessTask(const base::PendingTask& pending_task) override; + + private: + scoped_refptr<TaskQueue> compositor_task_runner_; + cc::RollingTimeDeltaHistory per_frame_compositor_task_runtime_; + base::TickClock* time_source_; // NOT OWNED + double estimation_percentile_; + + base::TimeTicks task_start_time_; + base::TimeTicks prev_commit_time_; + base::TimeDelta cumulative_compositor_runtime_; + int nesting_level_; + bool did_commit_; + + DISALLOW_COPY_AND_ASSIGN(IdleTimeEstimator); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_IDLE_TIME_ESTIMATOR_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/idle_time_estimator_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/idle_time_estimator_unittest.cc new file mode 100644 index 0000000..ac73fe0 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/idle_time_estimator_unittest.cc
@@ -0,0 +1,170 @@ +// 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 "platform/scheduler/renderer/idle_time_estimator.h" + +#include "base/memory/ptr_util.h" +#include "base/test/simple_test_tick_clock.h" +#include "cc/test/ordered_simple_task_runner.h" +#include "platform/scheduler/base/task_queue_manager.h" +#include "platform/scheduler/base/test_task_time_tracker.h" +#include "platform/scheduler/base/test_time_source.h" +#include "platform/scheduler/child/scheduler_tqm_delegate_for_test.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace blink { +namespace scheduler { + +class IdleTimeEstimatorForTest : public IdleTimeEstimator { + public: + IdleTimeEstimatorForTest( + const scoped_refptr<TaskQueue>& compositor_task_runner, + TestTimeSource* test_time_source, + int sample_count, + double estimation_percentile) + : IdleTimeEstimator(compositor_task_runner, + test_time_source, + sample_count, + estimation_percentile) {} +}; + +class IdleTimeEstimatorTest : public testing::Test { + public: + IdleTimeEstimatorTest() + : frame_length_(base::TimeDelta::FromMilliseconds(16)) {} + + ~IdleTimeEstimatorTest() override {} + + void SetUp() override { + clock_.reset(new base::SimpleTestTickClock()); + clock_->Advance(base::TimeDelta::FromMicroseconds(5000)); + test_time_source_.reset(new TestTimeSource(clock_.get())); + mock_task_runner_ = make_scoped_refptr( + new cc::OrderedSimpleTaskRunner(clock_.get(), false)); + main_task_runner_ = SchedulerTqmDelegateForTest::Create( + mock_task_runner_, base::MakeUnique<TestTimeSource>(clock_.get())); + manager_ = base::MakeUnique<TaskQueueManager>( + main_task_runner_, "test.scheduler", "test.scheduler", + "test.scheduler.debug"); + compositor_task_runner_ = + manager_->NewTaskQueue(TaskQueue::Spec("compositor_tq")); + estimator_.reset(new IdleTimeEstimatorForTest( + compositor_task_runner_, test_time_source_.get(), 10, 50)); + } + + void SimulateFrameWithOneCompositorTask(int compositor_time) { + base::TimeDelta non_idle_time = + base::TimeDelta::FromMilliseconds(compositor_time); + base::PendingTask task(FROM_HERE, base::Closure()); + estimator_->WillProcessTask(task); + clock_->Advance(non_idle_time); + estimator_->DidCommitFrameToCompositor(); + estimator_->DidProcessTask(task); + if (non_idle_time < frame_length_) + clock_->Advance(frame_length_ - non_idle_time); + } + + void SimulateFrameWithTwoCompositorTasks(int compositor_time1, + int compositor_time2) { + base::TimeDelta non_idle_time1 = + base::TimeDelta::FromMilliseconds(compositor_time1); + base::TimeDelta non_idle_time2 = + base::TimeDelta::FromMilliseconds(compositor_time2); + base::PendingTask task(FROM_HERE, base::Closure()); + estimator_->WillProcessTask(task); + clock_->Advance(non_idle_time1); + estimator_->DidProcessTask(task); + + estimator_->WillProcessTask(task); + clock_->Advance(non_idle_time2); + estimator_->DidCommitFrameToCompositor(); + estimator_->DidProcessTask(task); + + base::TimeDelta idle_time = frame_length_ - non_idle_time1 - non_idle_time2; + clock_->Advance(idle_time); + } + + std::unique_ptr<base::SimpleTestTickClock> clock_; + std::unique_ptr<TestTimeSource> test_time_source_; + scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_; + scoped_refptr<SchedulerTqmDelegate> main_task_runner_; + std::unique_ptr<TaskQueueManager> manager_; + scoped_refptr<TaskQueue> compositor_task_runner_; + std::unique_ptr<IdleTimeEstimatorForTest> estimator_; + const base::TimeDelta frame_length_; + TestTaskTimeTracker test_task_time_tracker_; +}; + +TEST_F(IdleTimeEstimatorTest, InitialTimeEstimateWithNoData) { + EXPECT_EQ(frame_length_, estimator_->GetExpectedIdleDuration(frame_length_)); +} + +TEST_F(IdleTimeEstimatorTest, BasicEstimation_SteadyState) { + SimulateFrameWithOneCompositorTask(5); + SimulateFrameWithOneCompositorTask(5); + + EXPECT_EQ(base::TimeDelta::FromMilliseconds(11), + estimator_->GetExpectedIdleDuration(frame_length_)); +} + +TEST_F(IdleTimeEstimatorTest, BasicEstimation_Variable) { + SimulateFrameWithOneCompositorTask(5); + SimulateFrameWithOneCompositorTask(6); + SimulateFrameWithOneCompositorTask(7); + SimulateFrameWithOneCompositorTask(7); + SimulateFrameWithOneCompositorTask(7); + SimulateFrameWithOneCompositorTask(8); + + // We expect it to return the median. + EXPECT_EQ(base::TimeDelta::FromMilliseconds(9), + estimator_->GetExpectedIdleDuration(frame_length_)); +} + +TEST_F(IdleTimeEstimatorTest, NoIdleTime) { + SimulateFrameWithOneCompositorTask(100); + SimulateFrameWithOneCompositorTask(100); + + EXPECT_EQ(base::TimeDelta::FromMilliseconds(0), + estimator_->GetExpectedIdleDuration(frame_length_)); +} + +TEST_F(IdleTimeEstimatorTest, Clear) { + SimulateFrameWithOneCompositorTask(5); + SimulateFrameWithOneCompositorTask(5); + + EXPECT_EQ(base::TimeDelta::FromMilliseconds(11), + estimator_->GetExpectedIdleDuration(frame_length_)); + estimator_->Clear(); + + EXPECT_EQ(frame_length_, estimator_->GetExpectedIdleDuration(frame_length_)); +} + +TEST_F(IdleTimeEstimatorTest, Estimation_MultipleTasks) { + SimulateFrameWithTwoCompositorTasks(1, 4); + SimulateFrameWithTwoCompositorTasks(1, 4); + + EXPECT_EQ(base::TimeDelta::FromMilliseconds(11), + estimator_->GetExpectedIdleDuration(frame_length_)); +} + +TEST_F(IdleTimeEstimatorTest, IgnoresNestedTasks) { + SimulateFrameWithOneCompositorTask(5); + SimulateFrameWithOneCompositorTask(5); + + base::PendingTask task(FROM_HERE, base::Closure()); + estimator_->WillProcessTask(task); + SimulateFrameWithTwoCompositorTasks(4, 4); + SimulateFrameWithTwoCompositorTasks(4, 4); + SimulateFrameWithTwoCompositorTasks(4, 4); + SimulateFrameWithTwoCompositorTasks(4, 4); + estimator_->DidCommitFrameToCompositor(); + estimator_->DidProcessTask(task); + + EXPECT_EQ(base::TimeDelta::FromMilliseconds(11), + estimator_->GetExpectedIdleDuration(frame_length_)); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/render_widget_scheduling_state.cc b/third_party/WebKit/Source/platform/scheduler/renderer/render_widget_scheduling_state.cc new file mode 100644 index 0000000..9c375a82 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/render_widget_scheduling_state.cc
@@ -0,0 +1,67 @@ +// 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 "public/platform/scheduler/renderer/render_widget_scheduling_state.h" + +#include "platform/scheduler/renderer/render_widget_signals.h" + +namespace blink { +namespace scheduler { + +RenderWidgetSchedulingState::RenderWidgetSchedulingState( + RenderWidgetSignals* render_widget_scheduling_signals) + : render_widget_signals_(render_widget_scheduling_signals), + hidden_(false), + has_touch_handler_(false) { + render_widget_signals_->IncNumVisibleRenderWidgets(); +} + +RenderWidgetSchedulingState::~RenderWidgetSchedulingState() { + if (hidden_) + return; + + render_widget_signals_->DecNumVisibleRenderWidgets(); + + if (has_touch_handler_) { + render_widget_signals_->DecNumVisibleRenderWidgetsWithTouchHandlers(); + } +} + +void RenderWidgetSchedulingState::SetHidden(bool hidden) { + if (hidden_ == hidden) + return; + + hidden_ = hidden; + + if (hidden_) { + render_widget_signals_->DecNumVisibleRenderWidgets(); + if (has_touch_handler_) { + render_widget_signals_->DecNumVisibleRenderWidgetsWithTouchHandlers(); + } + } else { + render_widget_signals_->IncNumVisibleRenderWidgets(); + if (has_touch_handler_) { + render_widget_signals_->IncNumVisibleRenderWidgetsWithTouchHandlers(); + } + } +} + +void RenderWidgetSchedulingState::SetHasTouchHandler(bool has_touch_handler) { + if (has_touch_handler_ == has_touch_handler) + return; + + has_touch_handler_ = has_touch_handler; + + if (hidden_) + return; + + if (has_touch_handler_) { + render_widget_signals_->IncNumVisibleRenderWidgetsWithTouchHandlers(); + } else { + render_widget_signals_->DecNumVisibleRenderWidgetsWithTouchHandlers(); + } +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/render_widget_signals.cc b/third_party/WebKit/Source/platform/scheduler/renderer/render_widget_signals.cc new file mode 100644 index 0000000..7b6abc10 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/render_widget_signals.cc
@@ -0,0 +1,64 @@ +// 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 "platform/scheduler/renderer/render_widget_signals.h" + +#include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "public/platform/scheduler/renderer/render_widget_scheduling_state.h" + +namespace blink { +namespace scheduler { + +RenderWidgetSignals::RenderWidgetSignals(Observer* observer) + : observer_(observer), + num_visible_render_widgets_(0), + num_visible_render_widgets_with_touch_handlers_(0) {} + +std::unique_ptr<RenderWidgetSchedulingState> +RenderWidgetSignals::NewRenderWidgetSchedulingState() { + return base::WrapUnique(new RenderWidgetSchedulingState(this)); +} + +void RenderWidgetSignals::IncNumVisibleRenderWidgets() { + num_visible_render_widgets_++; + + if (num_visible_render_widgets_ == 1) + observer_->SetAllRenderWidgetsHidden(false); +} + +void RenderWidgetSignals::DecNumVisibleRenderWidgets() { + num_visible_render_widgets_--; + DCHECK_GE(num_visible_render_widgets_, 0); + + if (num_visible_render_widgets_ == 0) + observer_->SetAllRenderWidgetsHidden(true); +} + +void RenderWidgetSignals::IncNumVisibleRenderWidgetsWithTouchHandlers() { + num_visible_render_widgets_with_touch_handlers_++; + + if (num_visible_render_widgets_with_touch_handlers_ == 1) + observer_->SetHasVisibleRenderWidgetWithTouchHandler(true); +} + +void RenderWidgetSignals::DecNumVisibleRenderWidgetsWithTouchHandlers() { + num_visible_render_widgets_with_touch_handlers_--; + DCHECK_GE(num_visible_render_widgets_with_touch_handlers_, 0); + + if (num_visible_render_widgets_with_touch_handlers_ == 0) + observer_->SetHasVisibleRenderWidgetWithTouchHandler(false); +} + +void RenderWidgetSignals::AsValueInto( + base::trace_event::TracedValue* state) const { + state->BeginDictionary("renderer_widget_signals"); + state->SetInteger("num_visible_render_widgets", num_visible_render_widgets_); + state->SetInteger("num_visible_render_widgets_with_touch_handlers", + num_visible_render_widgets_with_touch_handlers_); + state->EndDictionary(); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/render_widget_signals.h b/third_party/WebKit/Source/platform/scheduler/renderer/render_widget_signals.h new file mode 100644 index 0000000..ba9d7c0 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/render_widget_signals.h
@@ -0,0 +1,60 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_RENDER_WIDGET_SIGNALS_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_RENDER_WIDGET_SIGNALS_H_ + +#include <memory> + +#include "base/trace_event/trace_event.h" +#include "base/trace_event/trace_event_argument.h" +#include "public/platform/WebCommon.h" + +namespace blink { +namespace scheduler { + +class RenderWidgetSchedulingState; + +class BLINK_PLATFORM_EXPORT RenderWidgetSignals { + public: + class BLINK_PLATFORM_EXPORT Observer { + public: + virtual ~Observer() {} + + // If |hidden| is true then all render widgets managed by this renderer + // process have been hidden. + // If |hidden| is false at least one render widget managed by this renderer + // process has become visible and the renderer is no longer hidden. + // Will be called on the main thread. + virtual void SetAllRenderWidgetsHidden(bool hidden) = 0; + + // Tells the observer whether or not we have at least one touch handler on + // a visible render widget. Will be called on the main thread. + virtual void SetHasVisibleRenderWidgetWithTouchHandler( + bool has_visible_render_widget_with_touch_handler) = 0; + }; + + explicit RenderWidgetSignals(Observer* observer); + + std::unique_ptr<RenderWidgetSchedulingState> NewRenderWidgetSchedulingState(); + + void AsValueInto(base::trace_event::TracedValue* state) const; + + private: + friend class RenderWidgetSchedulingState; + + void IncNumVisibleRenderWidgets(); + void DecNumVisibleRenderWidgets(); + void IncNumVisibleRenderWidgetsWithTouchHandlers(); + void DecNumVisibleRenderWidgetsWithTouchHandlers(); + + Observer* observer_; // NOT OWNED + int num_visible_render_widgets_; + int num_visible_render_widgets_with_touch_handlers_; +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_RENDER_WIDGET_SIGNALS_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/render_widget_signals_unittest.cpp b/third_party/WebKit/Source/platform/scheduler/renderer/render_widget_signals_unittest.cpp new file mode 100644 index 0000000..bf473ec --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/render_widget_signals_unittest.cpp
@@ -0,0 +1,266 @@ +// 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 "platform/scheduler/renderer/render_widget_signals.h" + +#include "base/macros.h" +#include "public/platform/scheduler/renderer/render_widget_scheduling_state.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::AnyNumber; +using testing::Mock; +using testing::_; + +namespace scheduler { + +namespace { +class MockObserver : public RenderWidgetSignals::Observer { + public: + MockObserver() {} + virtual ~MockObserver() {} + + MOCK_METHOD1(SetAllRenderWidgetsHidden, void(bool hidden)); + MOCK_METHOD1(SetHasVisibleRenderWidgetWithTouchHandler, + void(bool has_visible_render_widget_with_touch_handler)); + + private: + DISALLOW_COPY_AND_ASSIGN(MockObserver); +}; +} + +class RenderWidgetSignalsTest : public testing::Test { + public: + RenderWidgetSignalsTest() {} + ~RenderWidgetSignalsTest() override {} + + void SetUp() override { + mock_observer_.reset(new MockObserver()); + render_widget_signals_.reset(new RenderWidgetSignals(mock_observer_.get())); + } + + void IgnoreWidgetCreationCallbacks() { + EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(false)) + .Times(AnyNumber()); + } + + void IgnoreWidgetDestructionCallbacks() { + EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(true)) + .Times(AnyNumber()); + } + + std::unique_ptr<MockObserver> mock_observer_; + std::unique_ptr<RenderWidgetSignals> render_widget_signals_; +}; + +TEST_F(RenderWidgetSignalsTest, RenderWidgetSchedulingStateLifeCycle) { + EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(false)).Times(1); + std::unique_ptr<RenderWidgetSchedulingState> widget1_state = + render_widget_signals_->NewRenderWidgetSchedulingState(); + Mock::VerifyAndClearExpectations(mock_observer_.get()); + + EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(true)).Times(1); +} + +TEST_F(RenderWidgetSignalsTest, RenderWidget_Hidden) { + IgnoreWidgetCreationCallbacks(); + std::unique_ptr<RenderWidgetSchedulingState> widget1_state = + render_widget_signals_->NewRenderWidgetSchedulingState(); + Mock::VerifyAndClearExpectations(mock_observer_.get()); + + EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(true)).Times(1); + widget1_state->SetHidden(true); + Mock::VerifyAndClearExpectations(mock_observer_.get()); + + IgnoreWidgetDestructionCallbacks(); +} + +TEST_F(RenderWidgetSignalsTest, RenderWidget_HiddenThreeTimesShownOnce) { + IgnoreWidgetCreationCallbacks(); + std::unique_ptr<RenderWidgetSchedulingState> widget1_state = + render_widget_signals_->NewRenderWidgetSchedulingState(); + Mock::VerifyAndClearExpectations(mock_observer_.get()); + + EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(true)).Times(1); + widget1_state->SetHidden(true); + widget1_state->SetHidden(true); + widget1_state->SetHidden(true); + Mock::VerifyAndClearExpectations(mock_observer_.get()); + + EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(false)).Times(1); + widget1_state->SetHidden(false); + Mock::VerifyAndClearExpectations(mock_observer_.get()); + + IgnoreWidgetDestructionCallbacks(); +} + +TEST_F(RenderWidgetSignalsTest, MultipleRenderWidgetsBecomeHiddenThenVisible) { + IgnoreWidgetCreationCallbacks(); + std::unique_ptr<RenderWidgetSchedulingState> widget1_state = + render_widget_signals_->NewRenderWidgetSchedulingState(); + std::unique_ptr<RenderWidgetSchedulingState> widget2_state = + render_widget_signals_->NewRenderWidgetSchedulingState(); + std::unique_ptr<RenderWidgetSchedulingState> widget3_state = + render_widget_signals_->NewRenderWidgetSchedulingState(); + Mock::VerifyAndClearExpectations(mock_observer_.get()); + + // Widgets are initially assumed to be visible so start hiding them, we should + // not get any calls to SetAllRenderWidgetsHidden till the last one is hidden. + EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(_)).Times(0); + widget1_state->SetHidden(true); + widget2_state->SetHidden(true); + Mock::VerifyAndClearExpectations(mock_observer_.get()); + + EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(true)).Times(1); + widget3_state->SetHidden(true); + Mock::VerifyAndClearExpectations(mock_observer_.get()); + + // We should get a call back once the first widget is unhidden and no more + // after that. + EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(false)).Times(1); + widget1_state->SetHidden(false); + Mock::VerifyAndClearExpectations(mock_observer_.get()); + + EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(_)).Times(0); + widget2_state->SetHidden(false); + widget3_state->SetHidden(false); + Mock::VerifyAndClearExpectations(mock_observer_.get()); + + IgnoreWidgetDestructionCallbacks(); +} + +TEST_F(RenderWidgetSignalsTest, TouchHandlerAddedAndRemoved_VisibleWidget) { + IgnoreWidgetCreationCallbacks(); + + std::unique_ptr<RenderWidgetSchedulingState> widget_state = + render_widget_signals_->NewRenderWidgetSchedulingState(); + Mock::VerifyAndClearExpectations(mock_observer_.get()); + + EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(true)) + .Times(1); + widget_state->SetHasTouchHandler(true); + Mock::VerifyAndClearExpectations(mock_observer_.get()); + + EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(false)) + .Times(1); + widget_state->SetHasTouchHandler(false); + Mock::VerifyAndClearExpectations(mock_observer_.get()); + + IgnoreWidgetDestructionCallbacks(); +} + +TEST_F(RenderWidgetSignalsTest, + TouchHandlerAddedThriceAndRemovedOnce_VisibleWidget) { + IgnoreWidgetCreationCallbacks(); + + std::unique_ptr<RenderWidgetSchedulingState> widget_state = + render_widget_signals_->NewRenderWidgetSchedulingState(); + Mock::VerifyAndClearExpectations(mock_observer_.get()); + + EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(true)) + .Times(1); + widget_state->SetHasTouchHandler(true); + widget_state->SetHasTouchHandler(true); + widget_state->SetHasTouchHandler(true); + Mock::VerifyAndClearExpectations(mock_observer_.get()); + + EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(false)) + .Times(1); + widget_state->SetHasTouchHandler(false); + Mock::VerifyAndClearExpectations(mock_observer_.get()); + + IgnoreWidgetDestructionCallbacks(); +} + +TEST_F(RenderWidgetSignalsTest, TouchHandlerAddedAndRemoved_HiddenWidget) { + IgnoreWidgetCreationCallbacks(); + + std::unique_ptr<RenderWidgetSchedulingState> widget_state = + render_widget_signals_->NewRenderWidgetSchedulingState(); + EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(true)).Times(1); + widget_state->SetHidden(true); + Mock::VerifyAndClearExpectations(mock_observer_.get()); + + EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(_)) + .Times(0); + widget_state->SetHasTouchHandler(true); + widget_state->SetHasTouchHandler(false); + Mock::VerifyAndClearExpectations(mock_observer_.get()); + + IgnoreWidgetDestructionCallbacks(); +} + +TEST_F(RenderWidgetSignalsTest, + MultipleTouchHandlerAddedAndRemoved_VisibleWidgets) { + IgnoreWidgetCreationCallbacks(); + + std::unique_ptr<RenderWidgetSchedulingState> widget1_state = + render_widget_signals_->NewRenderWidgetSchedulingState(); + std::unique_ptr<RenderWidgetSchedulingState> widget2_state = + render_widget_signals_->NewRenderWidgetSchedulingState(); + std::unique_ptr<RenderWidgetSchedulingState> widget3_state = + render_widget_signals_->NewRenderWidgetSchedulingState(); + Mock::VerifyAndClearExpectations(mock_observer_.get()); + + // We should only get a callback for the first widget with a touch handler. + EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(true)) + .Times(1); + widget1_state->SetHasTouchHandler(true); + Mock::VerifyAndClearExpectations(mock_observer_.get()); + + EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(_)) + .Times(0); + widget2_state->SetHasTouchHandler(true); + widget3_state->SetHasTouchHandler(true); + Mock::VerifyAndClearExpectations(mock_observer_.get()); + + // We should only get a callback when the last touch handler is removed. + EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(_)) + .Times(0); + widget1_state->SetHasTouchHandler(false); + widget2_state->SetHasTouchHandler(false); + Mock::VerifyAndClearExpectations(mock_observer_.get()); + + EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(false)) + .Times(1); + widget3_state->SetHasTouchHandler(false); + Mock::VerifyAndClearExpectations(mock_observer_.get()); + + IgnoreWidgetDestructionCallbacks(); +} + +TEST_F(RenderWidgetSignalsTest, + TouchHandlerAddedThenWigetDeleted_VisibleWidget) { + IgnoreWidgetCreationCallbacks(); + + std::unique_ptr<RenderWidgetSchedulingState> widget_state = + render_widget_signals_->NewRenderWidgetSchedulingState(); + Mock::VerifyAndClearExpectations(mock_observer_.get()); + + EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(true)) + .Times(1); + widget_state->SetHasTouchHandler(true); + Mock::VerifyAndClearExpectations(mock_observer_.get()); + + EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(false)) + .Times(1); + IgnoreWidgetDestructionCallbacks(); +} + +TEST_F(RenderWidgetSignalsTest, + TouchHandlerAddedThenWigetDeleted_HiddenWidget) { + IgnoreWidgetCreationCallbacks(); + + std::unique_ptr<RenderWidgetSchedulingState> widget_state = + render_widget_signals_->NewRenderWidgetSchedulingState(); + EXPECT_CALL(*mock_observer_, SetAllRenderWidgetsHidden(true)).Times(1); + widget_state->SetHidden(true); + Mock::VerifyAndClearExpectations(mock_observer_.get()); + + EXPECT_CALL(*mock_observer_, SetHasVisibleRenderWidgetWithTouchHandler(_)) + .Times(0); + IgnoreWidgetDestructionCallbacks(); +} + +} // namespace scheduler
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler.cc new file mode 100644 index 0000000..5ad331f --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler.cc
@@ -0,0 +1,76 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "public/platform/scheduler/renderer/renderer_scheduler.h" + +#include "base/command_line.h" +#include "base/feature_list.h" +#include "base/memory/ptr_util.h" +#include "base/message_loop/message_loop.h" +#include "base/metrics/field_trial.h" +#include "base/time/default_tick_clock.h" +#include "base/trace_event/trace_event.h" +#include "base/trace_event/trace_event_impl.h" +#include "platform/scheduler/child/scheduler_tqm_delegate_impl.h" +#include "platform/scheduler/renderer/renderer_scheduler_impl.h" + +namespace blink { +namespace scheduler { +namespace { +const base::Feature kExpensiveTaskBlockingPolicyFeature{ + "SchedulerExpensiveTaskBlocking", base::FEATURE_ENABLED_BY_DEFAULT}; +} + +RendererScheduler::RendererScheduler() {} + +RendererScheduler::~RendererScheduler() {} + +RendererScheduler::RAILModeObserver::~RAILModeObserver() = default; + +// static +std::unique_ptr<RendererScheduler> RendererScheduler::Create() { + // Ensure worker.scheduler, worker.scheduler.debug and + // renderer.scheduler.debug appear as an option in about://tracing + base::trace_event::TraceLog::GetCategoryGroupEnabled( + TRACE_DISABLED_BY_DEFAULT("worker.scheduler")); + base::trace_event::TraceLog::GetCategoryGroupEnabled( + TRACE_DISABLED_BY_DEFAULT("worker.scheduler.debug")); + base::trace_event::TraceLog::GetCategoryGroupEnabled( + TRACE_DISABLED_BY_DEFAULT("renderer.scheduler.debug")); + + base::MessageLoop* message_loop = base::MessageLoop::current(); + std::unique_ptr<RendererSchedulerImpl> scheduler( + new RendererSchedulerImpl(SchedulerTqmDelegateImpl::Create( + message_loop, base::WrapUnique(new base::DefaultTickClock())))); + + // Runtime features are not currently available in html_viewer. + if (base::FeatureList::GetInstance()) { + bool blocking_allowed = + base::FeatureList::IsEnabled(kExpensiveTaskBlockingPolicyFeature); + // Also check the old style FieldTrial API for perf waterfall compatibility. + const std::string group_name = base::FieldTrialList::FindFullName( + kExpensiveTaskBlockingPolicyFeature.name); + blocking_allowed |= base::StartsWith(group_name, "Enabled", + base::CompareCase::INSENSITIVE_ASCII); + scheduler->SetExpensiveTaskBlockingAllowed(blocking_allowed); + } + return base::WrapUnique<RendererScheduler>(scheduler.release()); +} + +// static +const char* RendererScheduler::InputEventStateToString( + InputEventState input_event_state) { + switch (input_event_state) { + case InputEventState::EVENT_CONSUMED_BY_COMPOSITOR: + return "event_consumed_by_compositor"; + case InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD: + return "event_forwarded_to_main_thread"; + default: + NOTREACHED(); + return nullptr; + } +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc new file mode 100644 index 0000000..a9cebe83 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
@@ -0,0 +1,1506 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "platform/scheduler/renderer/renderer_scheduler_impl.h" + +#include "base/bind.h" +#include "base/debug/stack_trace.h" +#include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "base/metrics/histogram_macros.h" +#include "base/trace_event/trace_event.h" +#include "base/trace_event/trace_event_argument.h" +#include "cc/output/begin_frame_args.h" +#include "platform/scheduler/base/task_queue_impl.h" +#include "platform/scheduler/base/task_queue_selector.h" +#include "platform/scheduler/base/virtual_time_domain.h" +#include "platform/scheduler/child/scheduler_tqm_delegate.h" +#include "platform/scheduler/renderer/auto_advancing_virtual_time_domain.h" +#include "platform/scheduler/renderer/web_view_scheduler_impl.h" +#include "platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.h" + +namespace blink { +namespace scheduler { +namespace { +// The run time of loading tasks is strongly bimodal. The vast majority are +// very cheap, but there are usually a handful of very expensive tasks (e.g ~1 +// second on a mobile device) so we take a very pessimistic view when estimating +// the cost of loading tasks. +const int kLoadingTaskEstimationSampleCount = 1000; +const double kLoadingTaskEstimationPercentile = 99; +const int kTimerTaskEstimationSampleCount = 1000; +const double kTimerTaskEstimationPercentile = 99; +const int kShortIdlePeriodDurationSampleCount = 10; +const double kShortIdlePeriodDurationPercentile = 50; +// Amount of idle time left in a frame (as a ratio of the vsync interval) above +// which main thread compositing can be considered fast. +const double kFastCompositingIdleTimeThreshold = .2; +} // namespace + +RendererSchedulerImpl::RendererSchedulerImpl( + scoped_refptr<SchedulerTqmDelegate> main_task_runner) + : helper_(main_task_runner, + "renderer.scheduler", + TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), + TRACE_DISABLED_BY_DEFAULT("renderer.scheduler.debug")), + idle_helper_(&helper_, + this, + "renderer.scheduler", + TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), + "RendererSchedulerIdlePeriod", + base::TimeDelta()), + render_widget_scheduler_signals_(this), + control_task_runner_(helper_.ControlTaskRunner()), + compositor_task_runner_(helper_.NewTaskQueue( + TaskQueue::Spec("compositor_tq").SetShouldMonitorQuiescence(true))), + delayed_update_policy_runner_( + base::Bind(&RendererSchedulerImpl::UpdatePolicy, + base::Unretained(this)), + helper_.ControlTaskRunner()), + main_thread_only_(this, + compositor_task_runner_, + helper_.scheduler_tqm_delegate().get()), + policy_may_need_update_(&any_thread_lock_), + weak_factory_(this) { + throttling_helper_.reset(new ThrottlingHelper(this, "renderer.scheduler")); + update_policy_closure_ = base::Bind(&RendererSchedulerImpl::UpdatePolicy, + weak_factory_.GetWeakPtr()); + end_renderer_hidden_idle_period_closure_.Reset(base::Bind( + &RendererSchedulerImpl::EndIdlePeriod, weak_factory_.GetWeakPtr())); + + suspend_timers_when_backgrounded_closure_.Reset( + base::Bind(&RendererSchedulerImpl::SuspendTimerQueueWhenBackgrounded, + weak_factory_.GetWeakPtr())); + + default_loading_task_runner_ = NewLoadingTaskRunner("default_loading_tq"); + default_timer_task_runner_ = NewTimerTaskRunner("default_timer_tq"); + + TRACE_EVENT_OBJECT_CREATED_WITH_ID( + TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", + this); + + helper_.SetObserver(this); + helper_.SetTaskTimeTracker(this); +} + +RendererSchedulerImpl::~RendererSchedulerImpl() { + TRACE_EVENT_OBJECT_DELETED_WITH_ID( + TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", + this); + + for (const scoped_refptr<TaskQueue>& loading_queue : loading_task_runners_) { + loading_queue->RemoveTaskObserver( + &MainThreadOnly().loading_task_cost_estimator); + } + for (const scoped_refptr<TaskQueue>& timer_queue : timer_task_runners_) { + timer_queue->RemoveTaskObserver( + &MainThreadOnly().timer_task_cost_estimator); + } + + if (virtual_time_domain_) + UnregisterTimeDomain(virtual_time_domain_.get()); + + // Ensure the renderer scheduler was shut down explicitly, because otherwise + // we could end up having stale pointers to the Blink heap which has been + // terminated by this point. + DCHECK(MainThreadOnly().was_shutdown); +} + +RendererSchedulerImpl::MainThreadOnly::MainThreadOnly( + RendererSchedulerImpl* renderer_scheduler_impl, + const scoped_refptr<TaskQueue>& compositor_task_runner, + base::TickClock* time_source) + : loading_task_cost_estimator(time_source, + kLoadingTaskEstimationSampleCount, + kLoadingTaskEstimationPercentile), + timer_task_cost_estimator(time_source, + kTimerTaskEstimationSampleCount, + kTimerTaskEstimationPercentile), + queueing_time_estimator(renderer_scheduler_impl, + base::TimeDelta::FromSeconds(1)), + idle_time_estimator(compositor_task_runner, + time_source, + kShortIdlePeriodDurationSampleCount, + kShortIdlePeriodDurationPercentile), + current_use_case(UseCase::NONE), + timer_queue_suspend_count(0), + navigation_task_expected_count(0), + expensive_task_policy(ExpensiveTaskPolicy::RUN), + renderer_hidden(false), + renderer_backgrounded(false), + renderer_suspended(false), + timer_queue_suspension_when_backgrounded_enabled(false), + timer_queue_suspended_when_backgrounded(false), + was_shutdown(false), + loading_tasks_seem_expensive(false), + timer_tasks_seem_expensive(false), + touchstart_expected_soon(false), + have_seen_a_begin_main_frame(false), + have_reported_blocking_intervention_in_current_policy(false), + have_reported_blocking_intervention_since_navigation(false), + has_visible_render_widget_with_touch_handler(false), + begin_frame_not_expected_soon(false), + expensive_task_blocking_allowed(true), + in_idle_period_for_testing(false), + use_virtual_time(false), + rail_mode_observer(nullptr) {} + +RendererSchedulerImpl::MainThreadOnly::~MainThreadOnly() {} + +RendererSchedulerImpl::AnyThread::AnyThread() + : awaiting_touch_start_response(false), + in_idle_period(false), + begin_main_frame_on_critical_path(false), + last_gesture_was_compositor_driven(false), + default_gesture_prevented(true), + have_seen_touchstart(false) {} + +RendererSchedulerImpl::AnyThread::~AnyThread() {} + +RendererSchedulerImpl::CompositorThreadOnly::CompositorThreadOnly() + : last_input_type(blink::WebInputEvent::Undefined) {} + +RendererSchedulerImpl::CompositorThreadOnly::~CompositorThreadOnly() {} + +void RendererSchedulerImpl::Shutdown() { + throttling_helper_.reset(); + helper_.Shutdown(); + MainThreadOnly().was_shutdown = true; + MainThreadOnly().rail_mode_observer = nullptr; +} + +std::unique_ptr<blink::WebThread> RendererSchedulerImpl::CreateMainThread() { + return base::WrapUnique(new WebThreadImplForRendererScheduler(this)); +} + +scoped_refptr<TaskQueue> RendererSchedulerImpl::DefaultTaskRunner() { + return helper_.DefaultTaskRunner(); +} + +scoped_refptr<TaskQueue> RendererSchedulerImpl::CompositorTaskRunner() { + helper_.CheckOnValidThread(); + return compositor_task_runner_; +} + +scoped_refptr<SingleThreadIdleTaskRunner> +RendererSchedulerImpl::IdleTaskRunner() { + return idle_helper_.IdleTaskRunner(); +} + +scoped_refptr<TaskQueue> RendererSchedulerImpl::LoadingTaskRunner() { + helper_.CheckOnValidThread(); + return default_loading_task_runner_; +} + +scoped_refptr<TaskQueue> RendererSchedulerImpl::TimerTaskRunner() { + helper_.CheckOnValidThread(); + return default_timer_task_runner_; +} + +scoped_refptr<TaskQueue> RendererSchedulerImpl::ControlTaskRunner() { + helper_.CheckOnValidThread(); + return helper_.ControlTaskRunner(); +} + +scoped_refptr<TaskQueue> RendererSchedulerImpl::NewLoadingTaskRunner( + const char* name) { + helper_.CheckOnValidThread(); + scoped_refptr<TaskQueue> loading_task_queue(helper_.NewTaskQueue( + TaskQueue::Spec(name).SetShouldMonitorQuiescence(true).SetTimeDomain( + MainThreadOnly().use_virtual_time ? GetVirtualTimeDomain() + : nullptr))); + loading_task_runners_.insert(loading_task_queue); + loading_task_queue->SetQueueEnabled( + MainThreadOnly().current_policy.loading_queue_policy.is_enabled); + loading_task_queue->SetQueuePriority( + MainThreadOnly().current_policy.loading_queue_policy.priority); + if (MainThreadOnly().current_policy.loading_queue_policy.time_domain_type == + TimeDomainType::THROTTLED) { + throttling_helper_->IncreaseThrottleRefCount(loading_task_queue.get()); + } + loading_task_queue->AddTaskObserver( + &MainThreadOnly().loading_task_cost_estimator); + return loading_task_queue; +} + +scoped_refptr<TaskQueue> RendererSchedulerImpl::NewTimerTaskRunner( + const char* name) { + helper_.CheckOnValidThread(); + // TODO(alexclarke): Consider using ApplyTaskQueuePolicy() for brevity. + scoped_refptr<TaskQueue> timer_task_queue( + helper_.NewTaskQueue(TaskQueue::Spec(name) + .SetShouldMonitorQuiescence(true) + .SetShouldReportWhenExecutionBlocked(true) + .SetTimeDomain(MainThreadOnly().use_virtual_time + ? GetVirtualTimeDomain() + : nullptr))); + timer_task_runners_.insert(timer_task_queue); + timer_task_queue->SetQueueEnabled( + MainThreadOnly().current_policy.timer_queue_policy.is_enabled); + timer_task_queue->SetQueuePriority( + MainThreadOnly().current_policy.timer_queue_policy.priority); + if (MainThreadOnly().current_policy.timer_queue_policy.time_domain_type == + TimeDomainType::THROTTLED) { + throttling_helper_->IncreaseThrottleRefCount(timer_task_queue.get()); + } + timer_task_queue->AddTaskObserver( + &MainThreadOnly().timer_task_cost_estimator); + return timer_task_queue; +} + +scoped_refptr<TaskQueue> RendererSchedulerImpl::NewUnthrottledTaskRunner( + const char* name) { + helper_.CheckOnValidThread(); + scoped_refptr<TaskQueue> unthrottled_task_queue(helper_.NewTaskQueue( + TaskQueue::Spec(name).SetShouldMonitorQuiescence(true).SetTimeDomain( + MainThreadOnly().use_virtual_time ? GetVirtualTimeDomain() + : nullptr))); + unthrottled_task_runners_.insert(unthrottled_task_queue); + return unthrottled_task_queue; +} + +std::unique_ptr<RenderWidgetSchedulingState> +RendererSchedulerImpl::NewRenderWidgetSchedulingState() { + return render_widget_scheduler_signals_.NewRenderWidgetSchedulingState(); +} + +void RendererSchedulerImpl::OnUnregisterTaskQueue( + const scoped_refptr<TaskQueue>& task_queue) { + if (throttling_helper_.get()) + throttling_helper_->UnregisterTaskQueue(task_queue.get()); + + if (loading_task_runners_.find(task_queue) != loading_task_runners_.end()) { + task_queue->RemoveTaskObserver( + &MainThreadOnly().loading_task_cost_estimator); + loading_task_runners_.erase(task_queue); + } else if (timer_task_runners_.find(task_queue) != + timer_task_runners_.end()) { + task_queue->RemoveTaskObserver(&MainThreadOnly().timer_task_cost_estimator); + timer_task_runners_.erase(task_queue); + } else if (unthrottled_task_runners_.find(task_queue) != + unthrottled_task_runners_.end()) { + unthrottled_task_runners_.erase(task_queue); + } +} + +bool RendererSchedulerImpl::CanExceedIdleDeadlineIfRequired() const { + return idle_helper_.CanExceedIdleDeadlineIfRequired(); +} + +void RendererSchedulerImpl::AddTaskObserver( + base::MessageLoop::TaskObserver* task_observer) { + helper_.AddTaskObserver(task_observer); +} + +void RendererSchedulerImpl::RemoveTaskObserver( + base::MessageLoop::TaskObserver* task_observer) { + helper_.RemoveTaskObserver(task_observer); +} + +void RendererSchedulerImpl::WillBeginFrame(const cc::BeginFrameArgs& args) { + TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), + "RendererSchedulerImpl::WillBeginFrame", "args", args.AsValue()); + helper_.CheckOnValidThread(); + if (helper_.IsShutdown()) + return; + + EndIdlePeriod(); + MainThreadOnly().estimated_next_frame_begin = args.frame_time + args.interval; + MainThreadOnly().have_seen_a_begin_main_frame = true; + MainThreadOnly().begin_frame_not_expected_soon = false; + MainThreadOnly().compositor_frame_interval = args.interval; + { + base::AutoLock lock(any_thread_lock_); + AnyThread().begin_main_frame_on_critical_path = args.on_critical_path; + } +} + +void RendererSchedulerImpl::DidCommitFrameToCompositor() { + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), + "RendererSchedulerImpl::DidCommitFrameToCompositor"); + helper_.CheckOnValidThread(); + if (helper_.IsShutdown()) + return; + + base::TimeTicks now(helper_.scheduler_tqm_delegate()->NowTicks()); + if (now < MainThreadOnly().estimated_next_frame_begin) { + // TODO(rmcilroy): Consider reducing the idle period based on the runtime of + // the next pending delayed tasks (as currently done in for long idle times) + idle_helper_.StartIdlePeriod( + IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, now, + MainThreadOnly().estimated_next_frame_begin); + } + + MainThreadOnly().idle_time_estimator.DidCommitFrameToCompositor(); +} + +void RendererSchedulerImpl::BeginFrameNotExpectedSoon() { + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), + "RendererSchedulerImpl::BeginFrameNotExpectedSoon"); + helper_.CheckOnValidThread(); + if (helper_.IsShutdown()) + return; + + MainThreadOnly().begin_frame_not_expected_soon = true; + idle_helper_.EnableLongIdlePeriod(); + { + base::AutoLock lock(any_thread_lock_); + AnyThread().begin_main_frame_on_critical_path = false; + } +} + +void RendererSchedulerImpl::SetAllRenderWidgetsHidden(bool hidden) { + TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), + "RendererSchedulerImpl::SetAllRenderWidgetsHidden", "hidden", + hidden); + + helper_.CheckOnValidThread(); + + if (helper_.IsShutdown() || MainThreadOnly().renderer_hidden == hidden) + return; + + end_renderer_hidden_idle_period_closure_.Cancel(); + + if (hidden) { + idle_helper_.EnableLongIdlePeriod(); + + // Ensure that we stop running idle tasks after a few seconds of being + // hidden. + base::TimeDelta end_idle_when_hidden_delay = + base::TimeDelta::FromMilliseconds(kEndIdleWhenHiddenDelayMillis); + control_task_runner_->PostDelayedTask( + FROM_HERE, end_renderer_hidden_idle_period_closure_.callback(), + end_idle_when_hidden_delay); + MainThreadOnly().renderer_hidden = true; + } else { + MainThreadOnly().renderer_hidden = false; + EndIdlePeriod(); + } + + // TODO(alexclarke): Should we update policy here? + TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( + TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", + this, AsValue(helper_.scheduler_tqm_delegate()->NowTicks())); +} + +void RendererSchedulerImpl::SetHasVisibleRenderWidgetWithTouchHandler( + bool has_visible_render_widget_with_touch_handler) { + helper_.CheckOnValidThread(); + if (has_visible_render_widget_with_touch_handler == + MainThreadOnly().has_visible_render_widget_with_touch_handler) + return; + + MainThreadOnly().has_visible_render_widget_with_touch_handler = + has_visible_render_widget_with_touch_handler; + + base::AutoLock lock(any_thread_lock_); + UpdatePolicyLocked(UpdateType::FORCE_UPDATE); +} + +void RendererSchedulerImpl::OnRendererBackgrounded() { + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), + "RendererSchedulerImpl::OnRendererBackgrounded"); + helper_.CheckOnValidThread(); + if (helper_.IsShutdown() || MainThreadOnly().renderer_backgrounded) + return; + + MainThreadOnly().renderer_backgrounded = true; + if (!MainThreadOnly().timer_queue_suspension_when_backgrounded_enabled) + return; + + suspend_timers_when_backgrounded_closure_.Cancel(); + base::TimeDelta suspend_timers_when_backgrounded_delay = + base::TimeDelta::FromMilliseconds( + kSuspendTimersWhenBackgroundedDelayMillis); + control_task_runner_->PostDelayedTask( + FROM_HERE, suspend_timers_when_backgrounded_closure_.callback(), + suspend_timers_when_backgrounded_delay); +} + +void RendererSchedulerImpl::OnRendererForegrounded() { + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), + "RendererSchedulerImpl::OnRendererForegrounded"); + helper_.CheckOnValidThread(); + if (helper_.IsShutdown() || !MainThreadOnly().renderer_backgrounded) + return; + + MainThreadOnly().renderer_backgrounded = false; + MainThreadOnly().renderer_suspended = false; + suspend_timers_when_backgrounded_closure_.Cancel(); + ResumeTimerQueueWhenForegrounded(); +} + +void RendererSchedulerImpl::SuspendRenderer() { + helper_.CheckOnValidThread(); + DCHECK(MainThreadOnly().renderer_backgrounded); + if (helper_.IsShutdown()) + return; + suspend_timers_when_backgrounded_closure_.Cancel(); + // TODO(hajimehoshi): We might need to suspend not only timer queue but also + // e.g. loading tasks or postMessage. + MainThreadOnly().renderer_suspended = true; + SuspendTimerQueueWhenBackgrounded(); +} + +void RendererSchedulerImpl::EndIdlePeriod() { + if (MainThreadOnly().in_idle_period_for_testing) + return; + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), + "RendererSchedulerImpl::EndIdlePeriod"); + helper_.CheckOnValidThread(); + idle_helper_.EndIdlePeriod(); +} + +void RendererSchedulerImpl::EndIdlePeriodForTesting( + const base::Closure& callback, + base::TimeTicks time_remaining) { + MainThreadOnly().in_idle_period_for_testing = false; + EndIdlePeriod(); + callback.Run(); +} + +bool RendererSchedulerImpl::PolicyNeedsUpdateForTesting() { + return policy_may_need_update_.IsSet(); +} + +// static +bool RendererSchedulerImpl::ShouldPrioritizeInputEvent( + const blink::WebInputEvent& web_input_event) { + // We regard MouseMove events with the left mouse button down as a signal + // that the user is doing something requiring a smooth frame rate. + if (web_input_event.type == blink::WebInputEvent::MouseMove && + (web_input_event.modifiers & blink::WebInputEvent::LeftButtonDown)) { + return true; + } + // Ignore all other mouse events because they probably don't signal user + // interaction needing a smooth framerate. NOTE isMouseEventType returns false + // for mouse wheel events, hence we regard them as user input. + // Ignore keyboard events because it doesn't really make sense to enter + // compositor priority for them. + if (blink::WebInputEvent::isMouseEventType(web_input_event.type) || + blink::WebInputEvent::isKeyboardEventType(web_input_event.type)) { + return false; + } + return true; +} + +void RendererSchedulerImpl::DidHandleInputEventOnCompositorThread( + const blink::WebInputEvent& web_input_event, + InputEventState event_state) { + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), + "RendererSchedulerImpl::DidHandleInputEventOnCompositorThread"); + if (!ShouldPrioritizeInputEvent(web_input_event)) + return; + + UpdateForInputEventOnCompositorThread(web_input_event.type, event_state); +} + +void RendererSchedulerImpl::DidAnimateForInputOnCompositorThread() { + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), + "RendererSchedulerImpl::DidAnimateForInputOnCompositorThread"); + base::AutoLock lock(any_thread_lock_); + AnyThread().fling_compositor_escalation_deadline = + helper_.scheduler_tqm_delegate()->NowTicks() + + base::TimeDelta::FromMilliseconds(kFlingEscalationLimitMillis); +} + +void RendererSchedulerImpl::UpdateForInputEventOnCompositorThread( + blink::WebInputEvent::Type type, + InputEventState input_event_state) { + base::AutoLock lock(any_thread_lock_); + base::TimeTicks now = helper_.scheduler_tqm_delegate()->NowTicks(); + + // TODO(alexclarke): Move WebInputEventTraits where we can access it from here + // and record the name rather than the integer representation. + TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), + "RendererSchedulerImpl::UpdateForInputEventOnCompositorThread", + "type", static_cast<int>(type), "input_event_state", + InputEventStateToString(input_event_state)); + + base::TimeDelta unused_policy_duration; + UseCase previous_use_case = + ComputeCurrentUseCase(now, &unused_policy_duration); + bool was_awaiting_touch_start_response = + AnyThread().awaiting_touch_start_response; + + AnyThread().user_model.DidStartProcessingInputEvent(type, now); + + if (input_event_state == InputEventState::EVENT_CONSUMED_BY_COMPOSITOR) + AnyThread().user_model.DidFinishProcessingInputEvent(now); + + if (type) { + switch (type) { + case blink::WebInputEvent::TouchStart: + AnyThread().awaiting_touch_start_response = true; + // This is just a fail-safe to reset the state of + // |last_gesture_was_compositor_driven| to the default. We don't know + // yet where the gesture will run. + AnyThread().last_gesture_was_compositor_driven = false; + AnyThread().have_seen_touchstart = true; + // Assume the default gesture is prevented until we see evidence + // otherwise. + AnyThread().default_gesture_prevented = true; + break; + + case blink::WebInputEvent::TouchMove: + // Observation of consecutive touchmoves is a strong signal that the + // page is consuming the touch sequence, in which case touchstart + // response prioritization is no longer necessary. Otherwise, the + // initial touchmove should preserve the touchstart response pending + // state. + if (AnyThread().awaiting_touch_start_response && + CompositorThreadOnly().last_input_type == + blink::WebInputEvent::TouchMove) { + AnyThread().awaiting_touch_start_response = false; + } + break; + + case blink::WebInputEvent::GesturePinchUpdate: + case blink::WebInputEvent::GestureScrollUpdate: + // If we see events for an established gesture, we can lock it to the + // appropriate thread as the gesture can no longer be cancelled. + AnyThread().last_gesture_was_compositor_driven = + input_event_state == InputEventState::EVENT_CONSUMED_BY_COMPOSITOR; + AnyThread().awaiting_touch_start_response = false; + AnyThread().default_gesture_prevented = false; + break; + + case blink::WebInputEvent::GestureFlingCancel: + AnyThread().fling_compositor_escalation_deadline = base::TimeTicks(); + break; + + case blink::WebInputEvent::GestureTapDown: + case blink::WebInputEvent::GestureShowPress: + case blink::WebInputEvent::GestureScrollEnd: + // With no observable effect, these meta events do not indicate a + // meaningful touchstart response and should not impact task priority. + break; + + default: + AnyThread().awaiting_touch_start_response = false; + break; + } + } + + // Avoid unnecessary policy updates if the use case did not change. + UseCase use_case = ComputeCurrentUseCase(now, &unused_policy_duration); + + if (use_case != previous_use_case || + was_awaiting_touch_start_response != + AnyThread().awaiting_touch_start_response) { + EnsureUrgentPolicyUpdatePostedOnMainThread(FROM_HERE); + } + CompositorThreadOnly().last_input_type = type; +} + +void RendererSchedulerImpl::DidHandleInputEventOnMainThread( + const blink::WebInputEvent& web_input_event) { + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), + "RendererSchedulerImpl::DidHandleInputEventOnMainThread"); + helper_.CheckOnValidThread(); + if (ShouldPrioritizeInputEvent(web_input_event)) { + base::AutoLock lock(any_thread_lock_); + AnyThread().user_model.DidFinishProcessingInputEvent( + helper_.scheduler_tqm_delegate()->NowTicks()); + } +} + +bool RendererSchedulerImpl::IsHighPriorityWorkAnticipated() { + helper_.CheckOnValidThread(); + if (helper_.IsShutdown()) + return false; + + MaybeUpdatePolicy(); + // The touchstart, synchronized gesture and main-thread gesture use cases + // indicate a strong likelihood of high-priority work in the near future. + UseCase use_case = MainThreadOnly().current_use_case; + return MainThreadOnly().touchstart_expected_soon || + use_case == UseCase::TOUCHSTART || + use_case == UseCase::MAIN_THREAD_GESTURE || + use_case == UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING || + use_case == UseCase::SYNCHRONIZED_GESTURE; +} + +bool RendererSchedulerImpl::ShouldYieldForHighPriorityWork() { + helper_.CheckOnValidThread(); + if (helper_.IsShutdown()) + return false; + + MaybeUpdatePolicy(); + // We only yield if there's a urgent task to be run now, or we are expecting + // one soon (touch start). + // Note: even though the control queue has the highest priority we don't yield + // for it since these tasks are not user-provided work and they are only + // intended to run before the next task, not interrupt the tasks. + switch (MainThreadOnly().current_use_case) { + case UseCase::COMPOSITOR_GESTURE: + case UseCase::NONE: + return MainThreadOnly().touchstart_expected_soon; + + case UseCase::MAIN_THREAD_GESTURE: + case UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING: + case UseCase::SYNCHRONIZED_GESTURE: + return compositor_task_runner_->HasPendingImmediateWork() || + MainThreadOnly().touchstart_expected_soon; + + case UseCase::TOUCHSTART: + return true; + + case UseCase::LOADING: + return false; + + default: + NOTREACHED(); + return false; + } +} + +base::TimeTicks RendererSchedulerImpl::CurrentIdleTaskDeadlineForTesting() + const { + return idle_helper_.CurrentIdleTaskDeadline(); +} + +void RendererSchedulerImpl::RunIdleTasksForTesting( + const base::Closure& callback) { + MainThreadOnly().in_idle_period_for_testing = true; + IdleTaskRunner()->PostIdleTask( + FROM_HERE, base::Bind(&RendererSchedulerImpl::EndIdlePeriodForTesting, + weak_factory_.GetWeakPtr(), callback)); + idle_helper_.EnableLongIdlePeriod(); +} + +void RendererSchedulerImpl::MaybeUpdatePolicy() { + helper_.CheckOnValidThread(); + if (policy_may_need_update_.IsSet()) { + UpdatePolicy(); + } +} + +void RendererSchedulerImpl::EnsureUrgentPolicyUpdatePostedOnMainThread( + const tracked_objects::Location& from_here) { + // TODO(scheduler-dev): Check that this method isn't called from the main + // thread. + any_thread_lock_.AssertAcquired(); + if (!policy_may_need_update_.IsSet()) { + policy_may_need_update_.SetWhileLocked(true); + control_task_runner_->PostTask(from_here, update_policy_closure_); + } +} + +void RendererSchedulerImpl::UpdatePolicy() { + base::AutoLock lock(any_thread_lock_); + UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED); +} + +void RendererSchedulerImpl::ForceUpdatePolicy() { + base::AutoLock lock(any_thread_lock_); + UpdatePolicyLocked(UpdateType::FORCE_UPDATE); +} + +void RendererSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) { + helper_.CheckOnValidThread(); + any_thread_lock_.AssertAcquired(); + if (helper_.IsShutdown()) + return; + + base::TimeTicks now = helper_.scheduler_tqm_delegate()->NowTicks(); + policy_may_need_update_.SetWhileLocked(false); + + base::TimeDelta expected_use_case_duration; + UseCase use_case = ComputeCurrentUseCase(now, &expected_use_case_duration); + MainThreadOnly().current_use_case = use_case; + + base::TimeDelta touchstart_expected_flag_valid_for_duration; + bool touchstart_expected_soon = false; + if (MainThreadOnly().has_visible_render_widget_with_touch_handler) { + touchstart_expected_soon = AnyThread().user_model.IsGestureExpectedSoon( + now, &touchstart_expected_flag_valid_for_duration); + } + MainThreadOnly().touchstart_expected_soon = touchstart_expected_soon; + + base::TimeDelta longest_jank_free_task_duration = + EstimateLongestJankFreeTaskDuration(); + MainThreadOnly().longest_jank_free_task_duration = + longest_jank_free_task_duration; + + bool loading_tasks_seem_expensive = false; + bool timer_tasks_seem_expensive = false; + loading_tasks_seem_expensive = + MainThreadOnly().loading_task_cost_estimator.expected_task_duration() > + longest_jank_free_task_duration; + timer_tasks_seem_expensive = + MainThreadOnly().timer_task_cost_estimator.expected_task_duration() > + longest_jank_free_task_duration; + MainThreadOnly().timer_tasks_seem_expensive = timer_tasks_seem_expensive; + MainThreadOnly().loading_tasks_seem_expensive = loading_tasks_seem_expensive; + + // The |new_policy_duration| is the minimum of |expected_use_case_duration| + // and |touchstart_expected_flag_valid_for_duration| unless one is zero in + // which case we choose the other. + base::TimeDelta new_policy_duration = expected_use_case_duration; + if (new_policy_duration.is_zero() || + (touchstart_expected_flag_valid_for_duration > base::TimeDelta() && + new_policy_duration > touchstart_expected_flag_valid_for_duration)) { + new_policy_duration = touchstart_expected_flag_valid_for_duration; + } + + if (new_policy_duration > base::TimeDelta()) { + MainThreadOnly().current_policy_expiration_time = now + new_policy_duration; + delayed_update_policy_runner_.SetDeadline(FROM_HERE, new_policy_duration, + now); + } else { + MainThreadOnly().current_policy_expiration_time = base::TimeTicks(); + } + + // Avoid prioritizing main thread compositing (e.g., rAF) if it is extremely + // slow, because that can cause starvation in other task sources. + bool main_thread_compositing_is_fast = + MainThreadOnly().idle_time_estimator.GetExpectedIdleDuration( + MainThreadOnly().compositor_frame_interval) > + MainThreadOnly().compositor_frame_interval * + kFastCompositingIdleTimeThreshold; + + Policy new_policy; + ExpensiveTaskPolicy expensive_task_policy = ExpensiveTaskPolicy::RUN; + new_policy.rail_mode = v8::PERFORMANCE_ANIMATION; + + switch (use_case) { + case UseCase::COMPOSITOR_GESTURE: + if (touchstart_expected_soon) { + new_policy.rail_mode = v8::PERFORMANCE_RESPONSE; + expensive_task_policy = ExpensiveTaskPolicy::BLOCK; + new_policy.compositor_queue_policy.priority = TaskQueue::HIGH_PRIORITY; + } else { + // What we really want to do is priorize loading tasks, but that doesn't + // seem to be safe. Instead we do that by proxy by deprioritizing + // compositor tasks. This should be safe since we've already gone to the + // pain of fixing ordering issues with them. + new_policy.compositor_queue_policy.priority = + TaskQueue::BEST_EFFORT_PRIORITY; + } + break; + + case UseCase::SYNCHRONIZED_GESTURE: + new_policy.compositor_queue_policy.priority = + main_thread_compositing_is_fast ? TaskQueue::HIGH_PRIORITY + : TaskQueue::NORMAL_PRIORITY; + if (touchstart_expected_soon) { + new_policy.rail_mode = v8::PERFORMANCE_RESPONSE; + expensive_task_policy = ExpensiveTaskPolicy::BLOCK; + } else { + expensive_task_policy = ExpensiveTaskPolicy::THROTTLE; + } + break; + + case UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING: + // In main thread input handling scenarios we don't have perfect knowledge + // about which things we should be prioritizing, so we don't attempt to + // block expensive tasks because we don't know whether they were integral + // to the page's functionality or not. + new_policy.compositor_queue_policy.priority = + main_thread_compositing_is_fast ? TaskQueue::HIGH_PRIORITY + : TaskQueue::NORMAL_PRIORITY; + break; + + case UseCase::MAIN_THREAD_GESTURE: + // A main thread gesture is for example a scroll gesture which is handled + // by the main thread. Since we know the established gesture type, we can + // be a little more aggressive about prioritizing compositing and input + // handling over other tasks. + new_policy.compositor_queue_policy.priority = TaskQueue::HIGH_PRIORITY; + if (touchstart_expected_soon) { + new_policy.rail_mode = v8::PERFORMANCE_RESPONSE; + expensive_task_policy = ExpensiveTaskPolicy::BLOCK; + } else { + expensive_task_policy = ExpensiveTaskPolicy::THROTTLE; + } + break; + + case UseCase::TOUCHSTART: + new_policy.rail_mode = v8::PERFORMANCE_RESPONSE; + new_policy.compositor_queue_policy.priority = TaskQueue::HIGH_PRIORITY; + new_policy.loading_queue_policy.is_enabled = false; + new_policy.timer_queue_policy.is_enabled = false; + // NOTE this is a nop due to the above. + expensive_task_policy = ExpensiveTaskPolicy::BLOCK; + break; + + case UseCase::NONE: + // It's only safe to block tasks that if we are expecting a compositor + // driven gesture. + if (touchstart_expected_soon && + AnyThread().last_gesture_was_compositor_driven) { + new_policy.rail_mode = v8::PERFORMANCE_RESPONSE; + expensive_task_policy = ExpensiveTaskPolicy::BLOCK; + } + break; + + case UseCase::LOADING: + new_policy.rail_mode = v8::PERFORMANCE_LOAD; + new_policy.loading_queue_policy.priority = TaskQueue::HIGH_PRIORITY; + new_policy.default_queue_policy.priority = TaskQueue::HIGH_PRIORITY; + break; + + default: + NOTREACHED(); + } + + // TODO(skyostil): Add an idle state for foreground tabs too. + if (MainThreadOnly().renderer_hidden) + new_policy.rail_mode = v8::PERFORMANCE_IDLE; + + if (expensive_task_policy == ExpensiveTaskPolicy::BLOCK && + (!MainThreadOnly().expensive_task_blocking_allowed || + !MainThreadOnly().have_seen_a_begin_main_frame || + MainThreadOnly().navigation_task_expected_count > 0)) { + expensive_task_policy = ExpensiveTaskPolicy::RUN; + } + + switch (expensive_task_policy) { + case ExpensiveTaskPolicy::RUN: + break; + + case ExpensiveTaskPolicy::BLOCK: + if (loading_tasks_seem_expensive) + new_policy.loading_queue_policy.is_enabled = false; + if (timer_tasks_seem_expensive) + new_policy.timer_queue_policy.is_enabled = false; + break; + + case ExpensiveTaskPolicy::THROTTLE: + if (loading_tasks_seem_expensive) { + new_policy.loading_queue_policy.time_domain_type = + TimeDomainType::THROTTLED; + } + if (timer_tasks_seem_expensive) { + new_policy.timer_queue_policy.time_domain_type = + TimeDomainType::THROTTLED; + } + break; + } + MainThreadOnly().expensive_task_policy = expensive_task_policy; + + if (MainThreadOnly().timer_queue_suspend_count != 0 || + MainThreadOnly().timer_queue_suspended_when_backgrounded) { + new_policy.timer_queue_policy.is_enabled = false; + // TODO(alexclarke): Figure out if we really need to do this. + new_policy.timer_queue_policy.time_domain_type = TimeDomainType::REAL; + } + + if (MainThreadOnly().renderer_suspended) { + new_policy.loading_queue_policy.is_enabled = false; + DCHECK(!new_policy.timer_queue_policy.is_enabled); + } + + if (MainThreadOnly().use_virtual_time) { + new_policy.compositor_queue_policy.time_domain_type = + TimeDomainType::VIRTUAL; + new_policy.default_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; + new_policy.loading_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; + new_policy.timer_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; + } + + // Tracing is done before the early out check, because it's quite possible we + // will otherwise miss this information in traces. + TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( + TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler", + this, AsValueLocked(now)); + TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "use_case", + use_case); + TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "rail_mode", + new_policy.rail_mode); + TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), + "touchstart_expected_soon", + MainThreadOnly().touchstart_expected_soon); + TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), + "expensive_task_policy", expensive_task_policy); + TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), + "RendererScheduler.loading_tasks_seem_expensive", + MainThreadOnly().loading_tasks_seem_expensive); + TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), + "RendererScheduler.timer_tasks_seem_expensive", + MainThreadOnly().timer_tasks_seem_expensive); + + // TODO(alexclarke): Can we get rid of force update now? + if (update_type == UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED && + new_policy == MainThreadOnly().current_policy) { + return; + } + + ApplyTaskQueuePolicy(compositor_task_runner_.get(), + MainThreadOnly().current_policy.compositor_queue_policy, + new_policy.compositor_queue_policy); + + for (const scoped_refptr<TaskQueue>& loading_queue : loading_task_runners_) { + ApplyTaskQueuePolicy(loading_queue.get(), + MainThreadOnly().current_policy.loading_queue_policy, + new_policy.loading_queue_policy); + } + + for (const scoped_refptr<TaskQueue>& timer_queue : timer_task_runners_) { + ApplyTaskQueuePolicy(timer_queue.get(), + MainThreadOnly().current_policy.timer_queue_policy, + new_policy.timer_queue_policy); + } + MainThreadOnly().have_reported_blocking_intervention_in_current_policy = + false; + + // TODO(alexclarke): We shouldn't have to prioritize the default queue, but it + // appears to be necessary since the order of loading tasks and IPCs (which + // are mostly dispatched on the default queue) need to be preserved. + ApplyTaskQueuePolicy(helper_.DefaultTaskRunner().get(), + MainThreadOnly().current_policy.default_queue_policy, + new_policy.default_queue_policy); + if (MainThreadOnly().rail_mode_observer && + new_policy.rail_mode != MainThreadOnly().current_policy.rail_mode) { + MainThreadOnly().rail_mode_observer->OnRAILModeChanged( + new_policy.rail_mode); + } + + DCHECK(compositor_task_runner_->IsQueueEnabled()); + MainThreadOnly().current_policy = new_policy; +} + +void RendererSchedulerImpl::ApplyTaskQueuePolicy( + TaskQueue* task_queue, + const TaskQueuePolicy& old_task_queue_policy, + const TaskQueuePolicy& new_task_queue_policy) const { + if (old_task_queue_policy.is_enabled != new_task_queue_policy.is_enabled) { + throttling_helper_->SetQueueEnabled(task_queue, + new_task_queue_policy.is_enabled); + } + + if (old_task_queue_policy.priority != new_task_queue_policy.priority) + task_queue->SetQueuePriority(new_task_queue_policy.priority); + + if (old_task_queue_policy.time_domain_type != + new_task_queue_policy.time_domain_type) { + if (old_task_queue_policy.time_domain_type == TimeDomainType::THROTTLED) { + throttling_helper_->DecreaseThrottleRefCount(task_queue); + } else if (new_task_queue_policy.time_domain_type == + TimeDomainType::THROTTLED) { + throttling_helper_->IncreaseThrottleRefCount(task_queue); + } else if (new_task_queue_policy.time_domain_type == + TimeDomainType::VIRTUAL) { + DCHECK(virtual_time_domain_); + task_queue->SetTimeDomain(virtual_time_domain_.get()); + } + } +} + +RendererSchedulerImpl::UseCase RendererSchedulerImpl::ComputeCurrentUseCase( + base::TimeTicks now, + base::TimeDelta* expected_use_case_duration) const { + any_thread_lock_.AssertAcquired(); + // Special case for flings. This is needed because we don't get notification + // of a fling ending (although we do for cancellation). + if (AnyThread().fling_compositor_escalation_deadline > now && + !AnyThread().awaiting_touch_start_response) { + *expected_use_case_duration = + AnyThread().fling_compositor_escalation_deadline - now; + return UseCase::COMPOSITOR_GESTURE; + } + // Above all else we want to be responsive to user input. + *expected_use_case_duration = + AnyThread().user_model.TimeLeftInUserGesture(now); + if (*expected_use_case_duration > base::TimeDelta()) { + // Has a gesture been fully established? + if (AnyThread().awaiting_touch_start_response) { + // No, so arrange for compositor tasks to be run at the highest priority. + return UseCase::TOUCHSTART; + } + + // Yes a gesture has been established. Based on how the gesture is handled + // we need to choose between one of four use cases: + // 1. COMPOSITOR_GESTURE where the gesture is processed only on the + // compositor thread. + // 2. MAIN_THREAD_GESTURE where the gesture is processed only on the main + // thread. + // 3. MAIN_THREAD_CUSTOM_INPUT_HANDLING where the main thread processes a + // stream of input events and has prevented a default gesture from being + // started. + // 4. SYNCHRONIZED_GESTURE where the gesture is processed on both threads. + // TODO(skyostil): Consider removing in_idle_period_ and + // HadAnIdlePeriodRecently() unless we need them here. + if (AnyThread().last_gesture_was_compositor_driven) { + if (AnyThread().begin_main_frame_on_critical_path) { + return UseCase::SYNCHRONIZED_GESTURE; + } else { + return UseCase::COMPOSITOR_GESTURE; + } + } + if (AnyThread().default_gesture_prevented) { + return UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING; + } else { + return UseCase::MAIN_THREAD_GESTURE; + } + } + + // TODO(alexclarke): return UseCase::LOADING if signals suggest the system is + // in the initial 1s of RAIL loading. + return UseCase::NONE; +} + +base::TimeDelta RendererSchedulerImpl::EstimateLongestJankFreeTaskDuration() + const { + switch (MainThreadOnly().current_use_case) { + case UseCase::TOUCHSTART: + case UseCase::COMPOSITOR_GESTURE: + case UseCase::LOADING: + case UseCase::NONE: + return base::TimeDelta::FromMilliseconds(kRailsResponseTimeMillis); + + case UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING: + case UseCase::MAIN_THREAD_GESTURE: + case UseCase::SYNCHRONIZED_GESTURE: + return MainThreadOnly().idle_time_estimator.GetExpectedIdleDuration( + MainThreadOnly().compositor_frame_interval); + + default: + NOTREACHED(); + return base::TimeDelta::FromMilliseconds(kRailsResponseTimeMillis); + } +} + +bool RendererSchedulerImpl::CanEnterLongIdlePeriod( + base::TimeTicks now, + base::TimeDelta* next_long_idle_period_delay_out) { + helper_.CheckOnValidThread(); + + MaybeUpdatePolicy(); + if (MainThreadOnly().current_use_case == UseCase::TOUCHSTART) { + // Don't start a long idle task in touch start priority, try again when + // the policy is scheduled to end. + *next_long_idle_period_delay_out = + std::max(base::TimeDelta(), + MainThreadOnly().current_policy_expiration_time - now); + return false; + } + return true; +} + +SchedulerHelper* RendererSchedulerImpl::GetSchedulerHelperForTesting() { + return &helper_; +} + +TaskCostEstimator* +RendererSchedulerImpl::GetLoadingTaskCostEstimatorForTesting() { + return &MainThreadOnly().loading_task_cost_estimator; +} + +TaskCostEstimator* +RendererSchedulerImpl::GetTimerTaskCostEstimatorForTesting() { + return &MainThreadOnly().timer_task_cost_estimator; +} + +IdleTimeEstimator* RendererSchedulerImpl::GetIdleTimeEstimatorForTesting() { + return &MainThreadOnly().idle_time_estimator; +} + +void RendererSchedulerImpl::SuspendTimerQueue() { + MainThreadOnly().timer_queue_suspend_count++; + ForceUpdatePolicy(); +#ifndef NDEBUG + DCHECK(!default_timer_task_runner_->IsQueueEnabled()); + for (const auto& runner : timer_task_runners_) { + DCHECK(!runner->IsQueueEnabled()); + } +#endif +} + +void RendererSchedulerImpl::ResumeTimerQueue() { + MainThreadOnly().timer_queue_suspend_count--; + DCHECK_GE(MainThreadOnly().timer_queue_suspend_count, 0); + ForceUpdatePolicy(); +} + +void RendererSchedulerImpl::SetTimerQueueSuspensionWhenBackgroundedEnabled( + bool enabled) { + // Note that this will only take effect for the next backgrounded signal. + MainThreadOnly().timer_queue_suspension_when_backgrounded_enabled = enabled; +} + +std::unique_ptr<base::trace_event::ConvertableToTraceFormat> +RendererSchedulerImpl::AsValue(base::TimeTicks optional_now) const { + base::AutoLock lock(any_thread_lock_); + return AsValueLocked(optional_now); +} + +// static +const char* RendererSchedulerImpl::ExpensiveTaskPolicyToString( + ExpensiveTaskPolicy expensive_task_policy) { + switch (expensive_task_policy) { + case ExpensiveTaskPolicy::RUN: + return "RUN"; + case ExpensiveTaskPolicy::BLOCK: + return "BLOCK"; + case ExpensiveTaskPolicy::THROTTLE: + return "THROTTLE"; + default: + NOTREACHED(); + return nullptr; + } +} + +std::unique_ptr<base::trace_event::ConvertableToTraceFormat> +RendererSchedulerImpl::AsValueLocked(base::TimeTicks optional_now) const { + helper_.CheckOnValidThread(); + any_thread_lock_.AssertAcquired(); + + if (optional_now.is_null()) + optional_now = helper_.scheduler_tqm_delegate()->NowTicks(); + std::unique_ptr<base::trace_event::TracedValue> state( + new base::trace_event::TracedValue()); + state->SetBoolean( + "has_visible_render_widget_with_touch_handler", + MainThreadOnly().has_visible_render_widget_with_touch_handler); + state->SetString("current_use_case", + UseCaseToString(MainThreadOnly().current_use_case)); + state->SetString("rail_mode", + RAILModeToString(MainThreadOnly().current_policy.rail_mode)); + state->SetBoolean("expensive_task_blocking_allowed", + MainThreadOnly().expensive_task_blocking_allowed); + state->SetBoolean("loading_tasks_seem_expensive", + MainThreadOnly().loading_tasks_seem_expensive); + state->SetBoolean("timer_tasks_seem_expensive", + MainThreadOnly().timer_tasks_seem_expensive); + state->SetBoolean("begin_frame_not_expected_soon", + MainThreadOnly().begin_frame_not_expected_soon); + state->SetBoolean("touchstart_expected_soon", + MainThreadOnly().touchstart_expected_soon); + state->SetString("idle_period_state", + IdleHelper::IdlePeriodStateToString( + idle_helper_.SchedulerIdlePeriodState())); + state->SetBoolean("renderer_hidden", MainThreadOnly().renderer_hidden); + state->SetBoolean("have_seen_a_begin_main_frame", + MainThreadOnly().have_seen_a_begin_main_frame); + state->SetBoolean( + "have_reported_blocking_intervention_in_current_policy", + MainThreadOnly().have_reported_blocking_intervention_in_current_policy); + state->SetBoolean( + "have_reported_blocking_intervention_since_navigation", + MainThreadOnly().have_reported_blocking_intervention_since_navigation); + state->SetBoolean("renderer_backgrounded", + MainThreadOnly().renderer_backgrounded); + state->SetBoolean("timer_queue_suspended_when_backgrounded", + MainThreadOnly().timer_queue_suspended_when_backgrounded); + state->SetInteger("timer_queue_suspend_count", + MainThreadOnly().timer_queue_suspend_count); + state->SetDouble("now", (optional_now - base::TimeTicks()).InMillisecondsF()); + state->SetDouble( + "rails_loading_priority_deadline", + (AnyThread().rails_loading_priority_deadline - base::TimeTicks()) + .InMillisecondsF()); + state->SetDouble( + "fling_compositor_escalation_deadline", + (AnyThread().fling_compositor_escalation_deadline - base::TimeTicks()) + .InMillisecondsF()); + state->SetInteger("navigation_task_expected_count", + MainThreadOnly().navigation_task_expected_count); + state->SetDouble("last_idle_period_end_time", + (AnyThread().last_idle_period_end_time - base::TimeTicks()) + .InMillisecondsF()); + state->SetBoolean("awaiting_touch_start_response", + AnyThread().awaiting_touch_start_response); + state->SetBoolean("begin_main_frame_on_critical_path", + AnyThread().begin_main_frame_on_critical_path); + state->SetBoolean("last_gesture_was_compositor_driven", + AnyThread().last_gesture_was_compositor_driven); + state->SetBoolean("default_gesture_prevented", + AnyThread().default_gesture_prevented); + state->SetDouble("expected_loading_task_duration", + MainThreadOnly() + .loading_task_cost_estimator.expected_task_duration() + .InMillisecondsF()); + state->SetDouble("expected_timer_task_duration", + MainThreadOnly() + .timer_task_cost_estimator.expected_task_duration() + .InMillisecondsF()); + // TODO(skyostil): Can we somehow trace how accurate these estimates were? + state->SetDouble( + "longest_jank_free_task_duration", + MainThreadOnly().longest_jank_free_task_duration.InMillisecondsF()); + state->SetDouble( + "compositor_frame_interval", + MainThreadOnly().compositor_frame_interval.InMillisecondsF()); + state->SetDouble( + "estimated_next_frame_begin", + (MainThreadOnly().estimated_next_frame_begin - base::TimeTicks()) + .InMillisecondsF()); + state->SetBoolean("in_idle_period", AnyThread().in_idle_period); + + state->SetString( + "expensive_task_policy", + ExpensiveTaskPolicyToString(MainThreadOnly().expensive_task_policy)); + + AnyThread().user_model.AsValueInto(state.get()); + render_widget_scheduler_signals_.AsValueInto(state.get()); + + return std::move(state); +} + +void RendererSchedulerImpl::OnIdlePeriodStarted() { + base::AutoLock lock(any_thread_lock_); + AnyThread().in_idle_period = true; + UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED); +} + +void RendererSchedulerImpl::OnIdlePeriodEnded() { + base::AutoLock lock(any_thread_lock_); + AnyThread().last_idle_period_end_time = + helper_.scheduler_tqm_delegate()->NowTicks(); + AnyThread().in_idle_period = false; + UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED); +} + +void RendererSchedulerImpl::AddPendingNavigation( + WebScheduler::NavigatingFrameType type) { + helper_.CheckOnValidThread(); + if (type == blink::WebScheduler::NavigatingFrameType::kMainFrame) { + MainThreadOnly().navigation_task_expected_count++; + UpdatePolicy(); + } +} + +void RendererSchedulerImpl::RemovePendingNavigation( + WebScheduler::NavigatingFrameType type) { + helper_.CheckOnValidThread(); + DCHECK_GT(MainThreadOnly().navigation_task_expected_count, 0); + if (type == blink::WebScheduler::NavigatingFrameType::kMainFrame && + MainThreadOnly().navigation_task_expected_count > 0) { + MainThreadOnly().navigation_task_expected_count--; + UpdatePolicy(); + } +} + +void RendererSchedulerImpl::OnNavigationStarted() { + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), + "RendererSchedulerImpl::OnNavigationStarted"); + base::AutoLock lock(any_thread_lock_); + AnyThread().rails_loading_priority_deadline = + helper_.scheduler_tqm_delegate()->NowTicks() + + base::TimeDelta::FromMilliseconds( + kRailsInitialLoadingPrioritizationMillis); + ResetForNavigationLocked(); +} + +bool RendererSchedulerImpl::HadAnIdlePeriodRecently(base::TimeTicks now) const { + return (now - AnyThread().last_idle_period_end_time) <= + base::TimeDelta::FromMilliseconds( + kIdlePeriodStarvationThresholdMillis); +} + +void RendererSchedulerImpl::SuspendTimerQueueWhenBackgrounded() { + DCHECK(MainThreadOnly().renderer_backgrounded); + if (MainThreadOnly().timer_queue_suspended_when_backgrounded) + return; + + MainThreadOnly().timer_queue_suspended_when_backgrounded = true; + ForceUpdatePolicy(); +} + +void RendererSchedulerImpl::ResumeTimerQueueWhenForegrounded() { + DCHECK(!MainThreadOnly().renderer_backgrounded); + if (!MainThreadOnly().timer_queue_suspended_when_backgrounded) + return; + + MainThreadOnly().timer_queue_suspended_when_backgrounded = false; + ForceUpdatePolicy(); +} + +void RendererSchedulerImpl::ResetForNavigationLocked() { + helper_.CheckOnValidThread(); + any_thread_lock_.AssertAcquired(); + AnyThread().user_model.Reset(helper_.scheduler_tqm_delegate()->NowTicks()); + AnyThread().have_seen_touchstart = false; + MainThreadOnly().loading_task_cost_estimator.Clear(); + MainThreadOnly().timer_task_cost_estimator.Clear(); + MainThreadOnly().idle_time_estimator.Clear(); + MainThreadOnly().have_seen_a_begin_main_frame = false; + MainThreadOnly().have_reported_blocking_intervention_since_navigation = false; + UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED); +} + +void RendererSchedulerImpl::SetTopLevelBlameContext( + base::trace_event::BlameContext* blame_context) { + // Any task that runs in the default task runners belongs to the context of + // all frames (as opposed to a particular frame). Note that the task itself + // may still enter a more specific blame context if necessary. + // + // Per-frame task runners (loading, timers, etc.) are configured with a more + // specific blame context by WebFrameSchedulerImpl. + control_task_runner_->SetBlameContext(blame_context); + DefaultTaskRunner()->SetBlameContext(blame_context); + default_loading_task_runner_->SetBlameContext(blame_context); + default_timer_task_runner_->SetBlameContext(blame_context); + compositor_task_runner_->SetBlameContext(blame_context); + idle_helper_.IdleTaskRunner()->SetBlameContext(blame_context); +} + +void RendererSchedulerImpl::SetRAILModeObserver(RAILModeObserver* observer) { + MainThreadOnly().rail_mode_observer = observer; +} + +void RendererSchedulerImpl::RegisterTimeDomain(TimeDomain* time_domain) { + helper_.RegisterTimeDomain(time_domain); +} + +void RendererSchedulerImpl::UnregisterTimeDomain(TimeDomain* time_domain) { + helper_.UnregisterTimeDomain(time_domain); +} + +void RendererSchedulerImpl::SetExpensiveTaskBlockingAllowed(bool allowed) { + MainThreadOnly().expensive_task_blocking_allowed = allowed; +} + +base::TickClock* RendererSchedulerImpl::tick_clock() const { + return helper_.scheduler_tqm_delegate().get(); +} + +void RendererSchedulerImpl::AddWebViewScheduler( + WebViewSchedulerImpl* web_view_scheduler) { + MainThreadOnly().web_view_schedulers.insert(web_view_scheduler); +} + +void RendererSchedulerImpl::RemoveWebViewScheduler( + WebViewSchedulerImpl* web_view_scheduler) { + DCHECK(MainThreadOnly().web_view_schedulers.find(web_view_scheduler) != + MainThreadOnly().web_view_schedulers.end()); + MainThreadOnly().web_view_schedulers.erase(web_view_scheduler); +} + +void RendererSchedulerImpl::BroadcastIntervention(const std::string& message) { + helper_.CheckOnValidThread(); + for (auto* web_view_scheduler : MainThreadOnly().web_view_schedulers) + web_view_scheduler->ReportIntervention(message); +} + +void RendererSchedulerImpl::OnTriedToExecuteBlockedTask( + const TaskQueue& queue, + const base::PendingTask& task) { + if (!MainThreadOnly().expensive_task_blocking_allowed || + MainThreadOnly().current_use_case == UseCase::TOUCHSTART || + MainThreadOnly().longest_jank_free_task_duration < + base::TimeDelta::FromMilliseconds(kRailsResponseTimeMillis) || + MainThreadOnly().timer_queue_suspend_count || + MainThreadOnly().timer_queue_suspended_when_backgrounded) { + return; + } + if (!MainThreadOnly().timer_tasks_seem_expensive && + !MainThreadOnly().loading_tasks_seem_expensive) { + return; + } + if (!MainThreadOnly().have_reported_blocking_intervention_in_current_policy) { + MainThreadOnly().have_reported_blocking_intervention_in_current_policy = + true; + TRACE_EVENT_INSTANT0("renderer.scheduler", + "RendererSchedulerImpl::TaskBlocked", + TRACE_EVENT_SCOPE_THREAD); + } + + if (!MainThreadOnly().have_reported_blocking_intervention_since_navigation) { + { + base::AutoLock lock(any_thread_lock_); + if (!AnyThread().have_seen_touchstart) + return; + } + MainThreadOnly().have_reported_blocking_intervention_since_navigation = + true; + BroadcastIntervention( + "Blink deferred a task in order to make scrolling smoother. " + "Your timer and network tasks should take less than 50ms to run " + "to avoid this. Please see " + "https://developers.google.com/web/tools/chrome-devtools/profile/evaluate-performance/rail" + " and https://crbug.com/574343#c40 for more information."); + } +} + +void RendererSchedulerImpl::ReportTaskTime(base::TimeTicks start_time, + base::TimeTicks end_time) { + MainThreadOnly().queueing_time_estimator.OnToplevelTaskCompleted(start_time, + end_time); + MainThreadOnly().long_task_tracker.RecordLongTask( + start_time, end_time - start_time); + UMA_HISTOGRAM_CUSTOM_COUNTS("RendererScheduler.TaskTime", + (end_time - start_time).InMicroseconds(), 1, + 1000000, 50); +} + +LongTaskTracker::LongTaskTiming RendererSchedulerImpl::GetLongTaskTiming() { + return MainThreadOnly().long_task_tracker.GetLongTaskTiming(); +} + +void RendererSchedulerImpl::OnQueueingTimeForWindowEstimated( + base::TimeDelta queueing_time) { + UMA_HISTOGRAM_TIMES("RendererScheduler.ExpectedTaskQueueingDuration", + queueing_time); + TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), + "estimated_queueing_time_for_window", + queueing_time.InMillisecondsF()); +} + +AutoAdvancingVirtualTimeDomain* RendererSchedulerImpl::GetVirtualTimeDomain() { + if (!virtual_time_domain_) { + virtual_time_domain_.reset( + new AutoAdvancingVirtualTimeDomain(tick_clock()->NowTicks())); + RegisterTimeDomain(virtual_time_domain_.get()); + } + return virtual_time_domain_.get(); +} + +void RendererSchedulerImpl::EnableVirtualTime() { + MainThreadOnly().use_virtual_time = true; + + // The |unthrottled_task_runners_| are not actively managed by UpdatePolicy(). + AutoAdvancingVirtualTimeDomain* time_domain = GetVirtualTimeDomain(); + for (const scoped_refptr<TaskQueue>& task_queue : unthrottled_task_runners_) + task_queue->SetTimeDomain(time_domain); + + throttling_helper_->EnableVirtualTime(); + + ForceUpdatePolicy(); +} + +// static +const char* RendererSchedulerImpl::UseCaseToString(UseCase use_case) { + switch (use_case) { + case UseCase::NONE: + return "none"; + case UseCase::COMPOSITOR_GESTURE: + return "compositor_gesture"; + case UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING: + return "main_thread_custom_input_handling"; + case UseCase::SYNCHRONIZED_GESTURE: + return "synchronized_gesture"; + case UseCase::TOUCHSTART: + return "touchstart"; + case UseCase::LOADING: + return "loading"; + case UseCase::MAIN_THREAD_GESTURE: + return "main_thread_gesture"; + default: + NOTREACHED(); + return nullptr; + } +} + +// static +const char* RendererSchedulerImpl::RAILModeToString(v8::RAILMode rail_mode) { + switch (rail_mode) { + case v8::PERFORMANCE_RESPONSE: + return "response"; + case v8::PERFORMANCE_ANIMATION: + return "animation"; + case v8::PERFORMANCE_IDLE: + return "idle"; + case v8::PERFORMANCE_LOAD: + return "load"; + default: + NOTREACHED(); + return nullptr; + } +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h new file mode 100644 index 0000000..f7bf7fa --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h
@@ -0,0 +1,490 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_RENDERER_SCHEDULER_IMPL_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_RENDERER_SCHEDULER_IMPL_H_ + +#include "base/atomicops.h" +#include "base/macros.h" +#include "base/synchronization/lock.h" +#include "platform/scheduler/base/long_task_tracker.h" +#include "platform/scheduler/base/pollable_thread_safe_flag.h" +#include "platform/scheduler/base/queueing_time_estimator.h" +#include "platform/scheduler/base/task_time_tracker.h" +#include "platform/scheduler/child/idle_helper.h" +#include "platform/scheduler/child/scheduler_helper.h" +#include "platform/scheduler/renderer/deadline_task_runner.h" +#include "platform/scheduler/renderer/idle_time_estimator.h" +#include "platform/scheduler/renderer/render_widget_signals.h" +#include "public/platform/scheduler/renderer/renderer_scheduler.h" +#include "platform/scheduler/renderer/task_cost_estimator.h" +#include "platform/scheduler/renderer/throttling_helper.h" +#include "platform/scheduler/renderer/user_model.h" +#include "platform/scheduler/renderer/web_view_scheduler_impl.h" + +namespace base { +namespace trace_event { +class ConvertableToTraceFormat; +} +} + +namespace blink { +namespace scheduler { +class AutoAdvancingVirtualTimeDomain; +class RenderWidgetSchedulingState; +class WebViewSchedulerImpl; +class ThrottlingHelper; + +class BLINK_PLATFORM_EXPORT RendererSchedulerImpl + : public RendererScheduler, + public IdleHelper::Delegate, + public SchedulerHelper::Observer, + public RenderWidgetSignals::Observer, + public TaskTimeTracker, + public QueueingTimeEstimator::Client { + public: + // Keep RendererScheduler::UseCaseToString in sync with this enum. + enum class UseCase { + // No active use case detected. + NONE, + // A continuous gesture (e.g., scroll, pinch) which is being driven by the + // compositor thread. + COMPOSITOR_GESTURE, + // An unspecified touch gesture which is being handled by the main thread. + // Note that since we don't have a full view of the use case, we should be + // careful to prioritize all work equally. + MAIN_THREAD_CUSTOM_INPUT_HANDLING, + // A continuous gesture (e.g., scroll, pinch) which is being driven by the + // compositor thread but also observed by the main thread. An example is + // synchronized scrolling where a scroll listener on the main thread changes + // page layout based on the current scroll position. + SYNCHRONIZED_GESTURE, + // A gesture has recently started and we are about to run main thread touch + // listeners to find out the actual gesture type. To minimize touch latency, + // only input handling work should run in this state. + TOUCHSTART, + // The page is loading. + LOADING, + // A continuous gesture (e.g., scroll) which is being handled by the main + // thread. + MAIN_THREAD_GESTURE, + // Must be the last entry. + USE_CASE_COUNT, + FIRST_USE_CASE = NONE, + }; + static const char* UseCaseToString(UseCase use_case); + static const char* RAILModeToString(v8::RAILMode rail_mode); + + RendererSchedulerImpl(scoped_refptr<SchedulerTqmDelegate> main_task_runner); + ~RendererSchedulerImpl() override; + + // RendererScheduler implementation: + std::unique_ptr<WebThread> CreateMainThread() override; + scoped_refptr<TaskQueue> DefaultTaskRunner() override; + scoped_refptr<SingleThreadIdleTaskRunner> IdleTaskRunner() override; + scoped_refptr<TaskQueue> CompositorTaskRunner() override; + scoped_refptr<TaskQueue> LoadingTaskRunner() override; + scoped_refptr<TaskQueue> TimerTaskRunner() override; + scoped_refptr<TaskQueue> NewLoadingTaskRunner(const char* name) override; + scoped_refptr<TaskQueue> NewTimerTaskRunner(const char* name) override; + scoped_refptr<TaskQueue> NewUnthrottledTaskRunner(const char* name) override; + std::unique_ptr<RenderWidgetSchedulingState> NewRenderWidgetSchedulingState() + override; + void WillBeginFrame(const cc::BeginFrameArgs& args) override; + void BeginFrameNotExpectedSoon() override; + void DidCommitFrameToCompositor() override; + void DidHandleInputEventOnCompositorThread( + const WebInputEvent& web_input_event, + InputEventState event_state) override; + void DidHandleInputEventOnMainThread( + const WebInputEvent& web_input_event) override; + void DidAnimateForInputOnCompositorThread() override; + void OnRendererBackgrounded() override; + void OnRendererForegrounded() override; + void SuspendRenderer() override; + void AddPendingNavigation(WebScheduler::NavigatingFrameType type) override; + void RemovePendingNavigation(WebScheduler::NavigatingFrameType type) override; + void OnNavigationStarted() override; + bool IsHighPriorityWorkAnticipated() override; + bool ShouldYieldForHighPriorityWork() override; + bool CanExceedIdleDeadlineIfRequired() const override; + void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer) override; + void RemoveTaskObserver( + base::MessageLoop::TaskObserver* task_observer) override; + void Shutdown() override; + void SuspendTimerQueue() override; + void ResumeTimerQueue() override; + void SetTimerQueueSuspensionWhenBackgroundedEnabled(bool enabled) override; + void SetTopLevelBlameContext( + base::trace_event::BlameContext* blame_context) override; + void SetRAILModeObserver(RAILModeObserver* observer) override; + + // RenderWidgetSignals::Observer implementation: + void SetAllRenderWidgetsHidden(bool hidden) override; + void SetHasVisibleRenderWidgetWithTouchHandler( + bool has_visible_render_widget_with_touch_handler) override; + + // SchedulerHelper::Observer implementation: + void OnUnregisterTaskQueue(const scoped_refptr<TaskQueue>& queue) override; + void OnTriedToExecuteBlockedTask(const TaskQueue& queue, + const base::PendingTask& task) override; + + // TaskTimeTracker implementation: + void ReportTaskTime(base::TimeTicks start_time, + base::TimeTicks end_time) override; + + // QueueingTimeEstimator::Client implementation: + void OnQueueingTimeForWindowEstimated(base::TimeDelta queueing_time) override; + + // Returns a task runner where tasks run at the highest possible priority. + scoped_refptr<TaskQueue> ControlTaskRunner(); + + void RegisterTimeDomain(TimeDomain* time_domain); + void UnregisterTimeDomain(TimeDomain* time_domain); + + // Tells the scheduler that all TaskQueues should use virtual time. + void EnableVirtualTime(); + + void SetExpensiveTaskBlockingAllowed(bool allowed); + + void AddWebViewScheduler(WebViewSchedulerImpl* web_view_scheduler); + void RemoveWebViewScheduler(WebViewSchedulerImpl* web_view_scheduler); + + LongTaskTracker::LongTaskTiming GetLongTaskTiming(); + + // Test helpers. + SchedulerHelper* GetSchedulerHelperForTesting(); + TaskCostEstimator* GetLoadingTaskCostEstimatorForTesting(); + TaskCostEstimator* GetTimerTaskCostEstimatorForTesting(); + IdleTimeEstimator* GetIdleTimeEstimatorForTesting(); + base::TimeTicks CurrentIdleTaskDeadlineForTesting() const; + void RunIdleTasksForTesting(const base::Closure& callback); + void EndIdlePeriodForTesting(const base::Closure& callback, + base::TimeTicks time_remaining); + bool PolicyNeedsUpdateForTesting(); + + base::TickClock* tick_clock() const; + + RealTimeDomain* real_time_domain() const { + return helper_.real_time_domain(); + } + + AutoAdvancingVirtualTimeDomain* GetVirtualTimeDomain(); + + ThrottlingHelper* throttling_helper() { return throttling_helper_.get(); } + + private: + friend class RendererSchedulerImplTest; + friend class RendererSchedulerImplForTest; + friend class RenderWidgetSchedulingState; + + enum class ExpensiveTaskPolicy { RUN, BLOCK, THROTTLE }; + + enum class TimeDomainType { + REAL, + THROTTLED, + VIRTUAL, + }; + + struct TaskQueuePolicy { + TaskQueuePolicy() + : is_enabled(true), + priority(TaskQueue::NORMAL_PRIORITY), + time_domain_type(TimeDomainType::REAL) {} + + bool is_enabled; + TaskQueue::QueuePriority priority; + TimeDomainType time_domain_type; + + bool operator==(const TaskQueuePolicy& other) const { + return is_enabled == other.is_enabled && priority == other.priority && + time_domain_type == other.time_domain_type; + } + }; + + struct Policy { + TaskQueuePolicy compositor_queue_policy; + TaskQueuePolicy loading_queue_policy; + TaskQueuePolicy timer_queue_policy; + TaskQueuePolicy default_queue_policy; + v8::RAILMode rail_mode = v8::PERFORMANCE_ANIMATION; + + bool operator==(const Policy& other) const { + return compositor_queue_policy == other.compositor_queue_policy && + loading_queue_policy == other.loading_queue_policy && + timer_queue_policy == other.timer_queue_policy && + default_queue_policy == other.default_queue_policy && + rail_mode == other.rail_mode; + } + }; + + class PollableNeedsUpdateFlag { + public: + PollableNeedsUpdateFlag(base::Lock* write_lock); + ~PollableNeedsUpdateFlag(); + + // Set the flag. May only be called if |write_lock| is held. + void SetWhileLocked(bool value); + + // Returns true iff the flag is set to true. + bool IsSet() const; + + private: + base::subtle::Atomic32 flag_; + base::Lock* write_lock_; // Not owned. + + DISALLOW_COPY_AND_ASSIGN(PollableNeedsUpdateFlag); + }; + + // IdleHelper::Delegate implementation: + bool CanEnterLongIdlePeriod( + base::TimeTicks now, + base::TimeDelta* next_long_idle_period_delay_out) override; + void IsNotQuiescent() override {} + void OnIdlePeriodStarted() override; + void OnIdlePeriodEnded() override; + + void EndIdlePeriod(); + + // Returns the serialized scheduler state for tracing. + std::unique_ptr<base::trace_event::ConvertableToTraceFormat> AsValue( + base::TimeTicks optional_now) const; + std::unique_ptr<base::trace_event::ConvertableToTraceFormat> AsValueLocked( + base::TimeTicks optional_now) const; + + static bool ShouldPrioritizeInputEvent(const WebInputEvent& web_input_event); + + // The amount of time which idle periods can continue being scheduled when the + // renderer has been hidden, before going to sleep for good. + static const int kEndIdleWhenHiddenDelayMillis = 10000; + + // The amount of time for which loading tasks will be prioritized over + // other tasks during the initial page load. + static const int kRailsInitialLoadingPrioritizationMillis = 1000; + + // The amount of time in milliseconds we have to respond to user input as + // defined by RAILS. + static const int kRailsResponseTimeMillis = 50; + + // For the purposes of deciding whether or not it's safe to turn timers and + // loading tasks on only in idle periods, we regard the system as being as + // being "idle period" starved if there hasn't been an idle period in the last + // 10 seconds. This was chosen to be long enough to cover most anticipated + // user gestures. + static const int kIdlePeriodStarvationThresholdMillis = 10000; + + // The amount of time to wait before suspending shared timers after the + // renderer has been backgrounded. This is used only if background suspension + // of shared timers is enabled. + static const int kSuspendTimersWhenBackgroundedDelayMillis = 5 * 60 * 1000; + + // The time we should stay in a priority-escalated mode after a call to + // DidAnimateForInputOnCompositorThread(). + static const int kFlingEscalationLimitMillis = 100; + + // Schedules an immediate PolicyUpdate, if there isn't one already pending and + // sets |policy_may_need_update_|. Note |any_thread_lock_| must be + // locked. + void EnsureUrgentPolicyUpdatePostedOnMainThread( + const tracked_objects::Location& from_here); + + // Update the policy if a new signal has arrived. Must be called from the main + // thread. + void MaybeUpdatePolicy(); + + // Locks |any_thread_lock_| and updates the scheduler policy. May early + // out if the policy is unchanged. Must be called from the main thread. + void UpdatePolicy(); + + // Like UpdatePolicy, except it doesn't early out. + void ForceUpdatePolicy(); + + enum class UpdateType { + MAY_EARLY_OUT_IF_POLICY_UNCHANGED, + FORCE_UPDATE, + }; + + // The implelemtation of UpdatePolicy & ForceUpdatePolicy. It is allowed to + // early out if |update_type| is MAY_EARLY_OUT_IF_POLICY_UNCHANGED. + virtual void UpdatePolicyLocked(UpdateType update_type); + + // Helper for computing the use case. |expected_usecase_duration| will be + // filled with the amount of time after which the use case should be updated + // again. If the duration is zero, a new use case update should not be + // scheduled. Must be called with |any_thread_lock_| held. Can be called from + // any thread. + UseCase ComputeCurrentUseCase( + base::TimeTicks now, + base::TimeDelta* expected_use_case_duration) const; + + // An input event of some sort happened, the policy may need updating. + void UpdateForInputEventOnCompositorThread(WebInputEvent::Type type, + InputEventState input_event_state); + + // Returns true if there has been at least one idle period in the last + // |kIdlePeriodStarvationThresholdMillis|. + bool HadAnIdlePeriodRecently(base::TimeTicks now) const; + + // Helpers for safely suspending/resuming the timer queue after a + // background/foreground signal. + void SuspendTimerQueueWhenBackgrounded(); + void ResumeTimerQueueWhenForegrounded(); + + // The task cost estimators and the UserModel need to be reset upon page + // nagigation. This function does that. Must be called from the main thread. + void ResetForNavigationLocked(); + + // Estimates the maximum task length that won't cause a jank based on the + // current system state. Must be called from the main thread. + base::TimeDelta EstimateLongestJankFreeTaskDuration() const; + + // Report an intervention to all WebViews in this process. + void BroadcastIntervention(const std::string& message); + + void ApplyTaskQueuePolicy(TaskQueue* task_queue, + const TaskQueuePolicy& old_task_queue_policy, + const TaskQueuePolicy& new_task_queue_policy) const; + + static const char* ExpensiveTaskPolicyToString( + ExpensiveTaskPolicy expensive_task_policy); + + SchedulerHelper helper_; + IdleHelper idle_helper_; + std::unique_ptr<ThrottlingHelper> throttling_helper_; + RenderWidgetSignals render_widget_scheduler_signals_; + + const scoped_refptr<TaskQueue> control_task_runner_; + const scoped_refptr<TaskQueue> compositor_task_runner_; + std::set<scoped_refptr<TaskQueue>> loading_task_runners_; + std::set<scoped_refptr<TaskQueue>> timer_task_runners_; + std::set<scoped_refptr<TaskQueue>> unthrottled_task_runners_; + scoped_refptr<TaskQueue> default_loading_task_runner_; + scoped_refptr<TaskQueue> default_timer_task_runner_; + + // Note |virtual_time_domain_| is lazily created. + std::unique_ptr<AutoAdvancingVirtualTimeDomain> virtual_time_domain_; + + base::Closure update_policy_closure_; + DeadlineTaskRunner delayed_update_policy_runner_; + CancelableClosureHolder end_renderer_hidden_idle_period_closure_; + CancelableClosureHolder suspend_timers_when_backgrounded_closure_; + + // We have decided to improve thread safety at the cost of some boilerplate + // (the accessors) for the following data members. + + struct MainThreadOnly { + MainThreadOnly(RendererSchedulerImpl* renderer_scheduler_impl, + const scoped_refptr<TaskQueue>& compositor_task_runner, + base::TickClock* time_source); + ~MainThreadOnly(); + + TaskCostEstimator loading_task_cost_estimator; + TaskCostEstimator timer_task_cost_estimator; + QueueingTimeEstimator queueing_time_estimator; + LongTaskTracker long_task_tracker; + IdleTimeEstimator idle_time_estimator; + UseCase current_use_case; + Policy current_policy; + base::TimeTicks current_policy_expiration_time; + base::TimeTicks estimated_next_frame_begin; + base::TimeDelta compositor_frame_interval; + base::TimeDelta longest_jank_free_task_duration; + int timer_queue_suspend_count; // TIMER_TASK_QUEUE suspended if non-zero. + int navigation_task_expected_count; + ExpensiveTaskPolicy expensive_task_policy; + bool renderer_hidden; + bool renderer_backgrounded; + bool renderer_suspended; + bool timer_queue_suspension_when_backgrounded_enabled; + bool timer_queue_suspended_when_backgrounded; + bool was_shutdown; + bool loading_tasks_seem_expensive; + bool timer_tasks_seem_expensive; + bool touchstart_expected_soon; + bool have_seen_a_begin_main_frame; + bool have_reported_blocking_intervention_in_current_policy; + bool have_reported_blocking_intervention_since_navigation; + bool has_visible_render_widget_with_touch_handler; + bool begin_frame_not_expected_soon; + bool expensive_task_blocking_allowed; + bool in_idle_period_for_testing; + bool use_virtual_time; + std::set<WebViewSchedulerImpl*> web_view_schedulers; // Not owned. + RAILModeObserver* rail_mode_observer; // Not owned. + }; + + struct AnyThread { + AnyThread(); + ~AnyThread(); + + base::TimeTicks last_idle_period_end_time; + base::TimeTicks rails_loading_priority_deadline; + base::TimeTicks fling_compositor_escalation_deadline; + UserModel user_model; + bool awaiting_touch_start_response; + bool in_idle_period; + bool begin_main_frame_on_critical_path; + bool last_gesture_was_compositor_driven; + bool default_gesture_prevented; + bool have_seen_touchstart; + }; + + struct CompositorThreadOnly { + CompositorThreadOnly(); + ~CompositorThreadOnly(); + + WebInputEvent::Type last_input_type; + std::unique_ptr<base::ThreadChecker> compositor_thread_checker; + + void CheckOnValidThread() { +#if DCHECK_IS_ON() + // We don't actually care which thread this called from, just so long as + // its consistent. + if (!compositor_thread_checker) + compositor_thread_checker.reset(new base::ThreadChecker()); + DCHECK(compositor_thread_checker->CalledOnValidThread()); +#endif + } + }; + + // Don't access main_thread_only_, instead use MainThreadOnly(). + MainThreadOnly main_thread_only_; + MainThreadOnly& MainThreadOnly() { + helper_.CheckOnValidThread(); + return main_thread_only_; + } + const struct MainThreadOnly& MainThreadOnly() const { + helper_.CheckOnValidThread(); + return main_thread_only_; + } + + mutable base::Lock any_thread_lock_; + // Don't access any_thread_, instead use AnyThread(). + AnyThread any_thread_; + AnyThread& AnyThread() { + any_thread_lock_.AssertAcquired(); + return any_thread_; + } + const struct AnyThread& AnyThread() const { + any_thread_lock_.AssertAcquired(); + return any_thread_; + } + + // Don't access compositor_thread_only_, instead use CompositorThreadOnly(). + CompositorThreadOnly compositor_thread_only_; + CompositorThreadOnly& CompositorThreadOnly() { + compositor_thread_only_.CheckOnValidThread(); + return compositor_thread_only_; + } + + PollableThreadSafeFlag policy_may_need_update_; + base::WeakPtrFactory<RendererSchedulerImpl> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(RendererSchedulerImpl); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_RENDERER_SCHEDULER_IMPL_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc new file mode 100644 index 0000000..ec488b96 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc
@@ -0,0 +1,3447 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "platform/scheduler/renderer/renderer_scheduler_impl.h" + +#include <utility> + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "base/run_loop.h" +#include "base/test/simple_test_tick_clock.h" +#include "cc/output/begin_frame_args.h" +#include "cc/test/ordered_simple_task_runner.h" +#include "platform/scheduler/base/test_time_source.h" +#include "platform/scheduler/child/scheduler_tqm_delegate_for_test.h" +#include "platform/scheduler/child/scheduler_tqm_delegate_impl.h" +#include "platform/scheduler/renderer/auto_advancing_virtual_time_domain.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace blink { +namespace scheduler { + +namespace { +class FakeInputEvent : public blink::WebInputEvent { + public: + explicit FakeInputEvent(blink::WebInputEvent::Type event_type) + : WebInputEvent(sizeof(FakeInputEvent)) { + type = event_type; + } + + FakeInputEvent(blink::WebInputEvent::Type event_type, int event_modifiers) + : WebInputEvent(sizeof(FakeInputEvent)) { + type = event_type; + modifiers = event_modifiers; + } +}; + +void AppendToVectorTestTask(std::vector<std::string>* vector, + std::string value) { + vector->push_back(value); +} + +void AppendToVectorIdleTestTask(std::vector<std::string>* vector, + std::string value, + base::TimeTicks deadline) { + AppendToVectorTestTask(vector, value); +} + +void NullTask() {} + +void AppendToVectorReentrantTask(base::SingleThreadTaskRunner* task_runner, + std::vector<int>* vector, + int* reentrant_count, + int max_reentrant_count) { + vector->push_back((*reentrant_count)++); + if (*reentrant_count < max_reentrant_count) { + task_runner->PostTask( + FROM_HERE, + base::Bind(AppendToVectorReentrantTask, base::Unretained(task_runner), + vector, reentrant_count, max_reentrant_count)); + } +} + +void IdleTestTask(int* run_count, + base::TimeTicks* deadline_out, + base::TimeTicks deadline) { + (*run_count)++; + *deadline_out = deadline; +} + +int max_idle_task_reposts = 2; + +void RepostingIdleTestTask(SingleThreadIdleTaskRunner* idle_task_runner, + int* run_count, + base::TimeTicks deadline) { + if ((*run_count + 1) < max_idle_task_reposts) { + idle_task_runner->PostIdleTask( + FROM_HERE, base::Bind(&RepostingIdleTestTask, + base::Unretained(idle_task_runner), run_count)); + } + (*run_count)++; +} + +void RepostingUpdateClockIdleTestTask( + SingleThreadIdleTaskRunner* idle_task_runner, + int* run_count, + base::SimpleTestTickClock* clock, + base::TimeDelta advance_time, + std::vector<base::TimeTicks>* deadlines, + base::TimeTicks deadline) { + if ((*run_count + 1) < max_idle_task_reposts) { + idle_task_runner->PostIdleTask( + FROM_HERE, base::Bind(&RepostingUpdateClockIdleTestTask, + base::Unretained(idle_task_runner), run_count, + clock, advance_time, deadlines)); + } + deadlines->push_back(deadline); + (*run_count)++; + clock->Advance(advance_time); +} + +void WillBeginFrameIdleTask(RendererScheduler* scheduler, + base::SimpleTestTickClock* clock, + base::TimeTicks deadline) { + scheduler->WillBeginFrame(cc::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, clock->NowTicks(), base::TimeTicks(), + base::TimeDelta::FromMilliseconds(1000), cc::BeginFrameArgs::NORMAL)); +} + +void UpdateClockToDeadlineIdleTestTask(base::SimpleTestTickClock* clock, + int* run_count, + base::TimeTicks deadline) { + clock->Advance(deadline - clock->NowTicks()); + (*run_count)++; +} + +void PostingYieldingTestTask(RendererSchedulerImpl* scheduler, + base::SingleThreadTaskRunner* task_runner, + bool simulate_input, + bool* should_yield_before, + bool* should_yield_after) { + *should_yield_before = scheduler->ShouldYieldForHighPriorityWork(); + task_runner->PostTask(FROM_HERE, base::Bind(NullTask)); + if (simulate_input) { + scheduler->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchMove), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + } + *should_yield_after = scheduler->ShouldYieldForHighPriorityWork(); +} + +enum class SimulateInputType { + None, + TouchStart, + TouchEnd, + GestureScrollBegin, + GestureScrollEnd +}; + +void AnticipationTestTask(RendererSchedulerImpl* scheduler, + SimulateInputType simulate_input, + bool* is_anticipated_before, + bool* is_anticipated_after) { + *is_anticipated_before = scheduler->IsHighPriorityWorkAnticipated(); + switch (simulate_input) { + case SimulateInputType::None: + break; + + case SimulateInputType::TouchStart: + scheduler->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchStart), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + break; + + case SimulateInputType::TouchEnd: + scheduler->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchEnd), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + break; + + case SimulateInputType::GestureScrollBegin: + scheduler->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureScrollBegin), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + break; + + case SimulateInputType::GestureScrollEnd: + scheduler->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureScrollEnd), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + break; + } + *is_anticipated_after = scheduler->IsHighPriorityWorkAnticipated(); +} + +}; // namespace + +class RendererSchedulerImplForTest : public RendererSchedulerImpl { + public: + using RendererSchedulerImpl::OnIdlePeriodEnded; + using RendererSchedulerImpl::OnIdlePeriodStarted; + using RendererSchedulerImpl::EstimateLongestJankFreeTaskDuration; + + RendererSchedulerImplForTest( + scoped_refptr<SchedulerTqmDelegate> main_task_runner) + : RendererSchedulerImpl(main_task_runner), update_policy_count_(0) {} + + void UpdatePolicyLocked(UpdateType update_type) override { + update_policy_count_++; + RendererSchedulerImpl::UpdatePolicyLocked(update_type); + + std::string use_case = RendererSchedulerImpl::UseCaseToString( + MainThreadOnly().current_use_case); + if (MainThreadOnly().touchstart_expected_soon) { + use_cases_.push_back(use_case + " touchstart expected"); + } else { + use_cases_.push_back(use_case); + } + } + + void EnsureUrgentPolicyUpdatePostedOnMainThread() { + base::AutoLock lock(any_thread_lock_); + RendererSchedulerImpl::EnsureUrgentPolicyUpdatePostedOnMainThread( + FROM_HERE); + } + + void ScheduleDelayedPolicyUpdate(base::TimeTicks now, base::TimeDelta delay) { + delayed_update_policy_runner_.SetDeadline(FROM_HERE, delay, now); + } + + bool BeginMainFrameOnCriticalPath() { + base::AutoLock lock(any_thread_lock_); + return AnyThread().begin_main_frame_on_critical_path; + } + + int update_policy_count_; + std::vector<std::string> use_cases_; +}; + +// Lets gtest print human readable Policy values. +::std::ostream& operator<<(::std::ostream& os, + const RendererSchedulerImpl::UseCase& use_case) { + return os << RendererSchedulerImpl::UseCaseToString(use_case); +} + +class RendererSchedulerImplTest : public testing::Test { + public: + using UseCase = RendererSchedulerImpl::UseCase; + + RendererSchedulerImplTest() : clock_(new base::SimpleTestTickClock()) { + clock_->Advance(base::TimeDelta::FromMicroseconds(5000)); + } + + RendererSchedulerImplTest(base::MessageLoop* message_loop) + : clock_(new base::SimpleTestTickClock()), message_loop_(message_loop) { + clock_->Advance(base::TimeDelta::FromMicroseconds(5000)); + } + + ~RendererSchedulerImplTest() override {} + + void SetUp() override { + if (message_loop_) { + main_task_runner_ = SchedulerTqmDelegateImpl::Create( + message_loop_.get(), + base::WrapUnique(new TestTimeSource(clock_.get()))); + } else { + mock_task_runner_ = make_scoped_refptr( + new cc::OrderedSimpleTaskRunner(clock_.get(), false)); + main_task_runner_ = SchedulerTqmDelegateForTest::Create( + mock_task_runner_, + base::WrapUnique(new TestTimeSource(clock_.get()))); + } + Initialize( + base::WrapUnique(new RendererSchedulerImplForTest(main_task_runner_))); + } + + void Initialize(std::unique_ptr<RendererSchedulerImplForTest> scheduler) { + scheduler_ = std::move(scheduler); + default_task_runner_ = scheduler_->DefaultTaskRunner(); + compositor_task_runner_ = scheduler_->CompositorTaskRunner(); + loading_task_runner_ = scheduler_->LoadingTaskRunner(); + idle_task_runner_ = scheduler_->IdleTaskRunner(); + timer_task_runner_ = scheduler_->TimerTaskRunner(); + } + + void TearDown() override { + DCHECK(!mock_task_runner_.get() || !message_loop_.get()); + scheduler_->Shutdown(); + if (mock_task_runner_.get()) { + // Check that all tests stop posting tasks. + mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true); + while (mock_task_runner_->RunUntilIdle()) { + } + } else { + base::RunLoop().RunUntilIdle(); + } + scheduler_.reset(); + } + + void RunUntilIdle() { + // Only one of mock_task_runner_ or message_loop_ should be set. + DCHECK(!mock_task_runner_.get() || !message_loop_.get()); + if (mock_task_runner_.get()) + mock_task_runner_->RunUntilIdle(); + else + base::RunLoop().RunUntilIdle(); + } + + void DoMainFrame() { + cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), + base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); + begin_frame_args.on_critical_path = false; + scheduler_->WillBeginFrame(begin_frame_args); + scheduler_->DidCommitFrameToCompositor(); + } + + void DoMainFrameOnCriticalPath() { + cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), + base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); + begin_frame_args.on_critical_path = true; + scheduler_->WillBeginFrame(begin_frame_args); + } + + void ForceTouchStartToBeExpectedSoon() { + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureScrollEnd), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + clock_->Advance(priority_escalation_after_input_duration() * 2); + scheduler_->ForceUpdatePolicy(); + } + + void SimulateExpensiveTasks( + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) { + // RunUntilIdle won't actually run all of the SimpleTestTickClock::Advance + // tasks unless we set AutoAdvanceNow to true :/ + mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true); + + // Simulate a bunch of expensive tasks + for (int i = 0; i < 10; i++) { + task_runner->PostTask(FROM_HERE, + base::Bind(&base::SimpleTestTickClock::Advance, + base::Unretained(clock_.get()), + base::TimeDelta::FromMilliseconds(500))); + } + + RunUntilIdle(); + + // Switch back to not auto-advancing because we want to be in control of + // when time advances. + mock_task_runner_->SetAutoAdvanceNowToPendingTasks(false); + } + + enum class TouchEventPolicy { + SEND_TOUCH_START, + DONT_SEND_TOUCH_START, + }; + + void SimulateCompositorGestureStart(TouchEventPolicy touch_event_policy) { + if (touch_event_policy == TouchEventPolicy::SEND_TOUCH_START) { + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchStart), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchMove), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchMove), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + } + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureScrollBegin), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + } + + // Simulate a gesture where there is an active compositor scroll, but no + // scroll updates are generated. Instead, the main thread handles + // non-canceleable touch events, making this an effectively main thread + // driven gesture. + void SimulateMainThreadGestureWithoutScrollUpdates() { + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchStart), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchMove), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureScrollBegin), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchMove), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + } + + // Simulate a gesture where the main thread handles touch events but does not + // preventDefault(), allowing the gesture to turn into a compositor driven + // gesture. This function also verifies the necessary policy updates are + // scheduled. + void SimulateMainThreadGestureWithoutPreventDefault() { + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchStart), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + + // Touchstart policy update. + EXPECT_TRUE(scheduler_->PolicyNeedsUpdateForTesting()); + EXPECT_EQ(UseCase::TOUCHSTART, ForceUpdatePolicyAndGetCurrentUseCase()); + EXPECT_FALSE(scheduler_->PolicyNeedsUpdateForTesting()); + + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchMove), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureTapCancel), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureScrollBegin), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + + // Main thread gesture policy update. + EXPECT_TRUE(scheduler_->PolicyNeedsUpdateForTesting()); + EXPECT_EQ(UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, + ForceUpdatePolicyAndGetCurrentUseCase()); + EXPECT_FALSE(scheduler_->PolicyNeedsUpdateForTesting()); + + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchScrollStarted), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchMove), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + + // Compositor thread gesture policy update. + EXPECT_TRUE(scheduler_->PolicyNeedsUpdateForTesting()); + EXPECT_EQ(UseCase::COMPOSITOR_GESTURE, + ForceUpdatePolicyAndGetCurrentUseCase()); + EXPECT_FALSE(scheduler_->PolicyNeedsUpdateForTesting()); + } + + void SimulateMainThreadGestureStart(TouchEventPolicy touch_event_policy, + blink::WebInputEvent::Type gesture_type) { + if (touch_event_policy == TouchEventPolicy::SEND_TOUCH_START) { + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchStart), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + scheduler_->DidHandleInputEventOnMainThread( + FakeInputEvent(blink::WebInputEvent::TouchStart)); + + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchMove), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + scheduler_->DidHandleInputEventOnMainThread( + FakeInputEvent(blink::WebInputEvent::TouchMove)); + + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchMove), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + scheduler_->DidHandleInputEventOnMainThread( + FakeInputEvent(blink::WebInputEvent::TouchMove)); + } + if (gesture_type != blink::WebInputEvent::Undefined) { + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(gesture_type), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + scheduler_->DidHandleInputEventOnMainThread(FakeInputEvent(gesture_type)); + } + } + + void SimulateMainThreadInputHandlingCompositorTask( + base::TimeDelta begin_main_frame_duration) { + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchMove), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + clock_->Advance(begin_main_frame_duration); + scheduler_->DidHandleInputEventOnMainThread( + FakeInputEvent(blink::WebInputEvent::TouchMove)); + scheduler_->DidCommitFrameToCompositor(); + } + + void SimulateMainThreadCompositorTask( + base::TimeDelta begin_main_frame_duration) { + clock_->Advance(begin_main_frame_duration); + scheduler_->DidCommitFrameToCompositor(); + simulate_compositor_task_ran_ = true; + } + + bool SimulatedCompositorTaskPending() const { + return !simulate_compositor_task_ran_; + } + + void SimulateTimerTask(base::TimeDelta duration) { + clock_->Advance(duration); + simulate_timer_task_ran_ = true; + } + + void EnableIdleTasks() { DoMainFrame(); } + + UseCase CurrentUseCase() { + return scheduler_->MainThreadOnly().current_use_case; + } + + UseCase ForceUpdatePolicyAndGetCurrentUseCase() { + scheduler_->ForceUpdatePolicy(); + return scheduler_->MainThreadOnly().current_use_case; + } + + v8::RAILMode RAILMode() { + return scheduler_->MainThreadOnly().current_policy.rail_mode; + } + + bool BeginFrameNotExpectedSoon() { + return scheduler_->MainThreadOnly().begin_frame_not_expected_soon; + } + + bool TouchStartExpectedSoon() { + return scheduler_->MainThreadOnly().touchstart_expected_soon; + } + + bool HaveSeenABeginMainframe() { + return scheduler_->MainThreadOnly().have_seen_a_begin_main_frame; + } + + bool LoadingTasksSeemExpensive() { + return scheduler_->MainThreadOnly().loading_tasks_seem_expensive; + } + + bool TimerTasksSeemExpensive() { + return scheduler_->MainThreadOnly().timer_tasks_seem_expensive; + } + + base::TimeTicks EstimatedNextFrameBegin() { + return scheduler_->MainThreadOnly().estimated_next_frame_begin; + } + + int NavigationTaskExpectedCount() { + return scheduler_->MainThreadOnly().navigation_task_expected_count; + } + + // Helper for posting several tasks of specific types. |task_descriptor| is a + // string with space delimited task identifiers. The first letter of each + // task identifier specifies the task type: + // - 'D': Default task + // - 'C': Compositor task + // - 'L': Loading task + // - 'I': Idle task + // - 'T': Timer task + void PostTestTasks(std::vector<std::string>* run_order, + const std::string& task_descriptor) { + std::istringstream stream(task_descriptor); + while (!stream.eof()) { + std::string task; + stream >> task; + switch (task[0]) { + case 'D': + default_task_runner_->PostTask( + FROM_HERE, base::Bind(&AppendToVectorTestTask, run_order, task)); + break; + case 'C': + compositor_task_runner_->PostTask( + FROM_HERE, base::Bind(&AppendToVectorTestTask, run_order, task)); + break; + case 'L': + loading_task_runner_->PostTask( + FROM_HERE, base::Bind(&AppendToVectorTestTask, run_order, task)); + break; + case 'I': + idle_task_runner_->PostIdleTask( + FROM_HERE, + base::Bind(&AppendToVectorIdleTestTask, run_order, task)); + break; + case 'T': + timer_task_runner_->PostTask( + FROM_HERE, base::Bind(&AppendToVectorTestTask, run_order, task)); + break; + default: + NOTREACHED(); + } + } + } + + protected: + static base::TimeDelta priority_escalation_after_input_duration() { + return base::TimeDelta::FromMilliseconds( + UserModel::kGestureEstimationLimitMillis); + } + + static base::TimeDelta subsequent_input_expected_after_input_duration() { + return base::TimeDelta::FromMilliseconds( + UserModel::kExpectSubsequentGestureMillis); + } + + static base::TimeDelta maximum_idle_period_duration() { + return base::TimeDelta::FromMilliseconds( + IdleHelper::kMaximumIdlePeriodMillis); + } + + static base::TimeDelta end_idle_when_hidden_delay() { + return base::TimeDelta::FromMilliseconds( + RendererSchedulerImpl::kEndIdleWhenHiddenDelayMillis); + } + + static base::TimeDelta idle_period_starvation_threshold() { + return base::TimeDelta::FromMilliseconds( + RendererSchedulerImpl::kIdlePeriodStarvationThresholdMillis); + } + + static base::TimeDelta suspend_timers_when_backgrounded_delay() { + return base::TimeDelta::FromMilliseconds( + RendererSchedulerImpl::kSuspendTimersWhenBackgroundedDelayMillis); + } + + static base::TimeDelta rails_response_time() { + return base::TimeDelta::FromMilliseconds( + RendererSchedulerImpl::kRailsResponseTimeMillis); + } + + template <typename E> + static void CallForEachEnumValue(E first, + E last, + const char* (*function)(E)) { + for (E val = first; val < last; + val = static_cast<E>(static_cast<int>(val) + 1)) { + (*function)(val); + } + } + + static void CheckAllUseCaseToString() { + CallForEachEnumValue<RendererSchedulerImpl::UseCase>( + RendererSchedulerImpl::UseCase::FIRST_USE_CASE, + RendererSchedulerImpl::UseCase::USE_CASE_COUNT, + &RendererSchedulerImpl::UseCaseToString); + } + + std::unique_ptr<base::SimpleTestTickClock> clock_; + // Only one of mock_task_runner_ or message_loop_ will be set. + scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_; + std::unique_ptr<base::MessageLoop> message_loop_; + + scoped_refptr<SchedulerTqmDelegate> main_task_runner_; + std::unique_ptr<RendererSchedulerImplForTest> scheduler_; + scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_; + scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_; + scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner_; + scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_; + scoped_refptr<base::SingleThreadTaskRunner> timer_task_runner_; + bool simulate_timer_task_ran_; + bool simulate_compositor_task_ran_; + + DISALLOW_COPY_AND_ASSIGN(RendererSchedulerImplTest); +}; + +TEST_F(RendererSchedulerImplTest, TestPostDefaultTask) { + std::vector<std::string> run_order; + PostTestTasks(&run_order, "D1 D2 D3 D4"); + + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("D1"), std::string("D2"), + std::string("D3"), std::string("D4"))); +} + +TEST_F(RendererSchedulerImplTest, TestPostDefaultAndCompositor) { + std::vector<std::string> run_order; + PostTestTasks(&run_order, "D1 C1"); + RunUntilIdle(); + EXPECT_THAT(run_order, testing::Contains("D1")); + EXPECT_THAT(run_order, testing::Contains("C1")); +} + +TEST_F(RendererSchedulerImplTest, TestRentrantTask) { + int count = 0; + std::vector<int> run_order; + default_task_runner_->PostTask( + FROM_HERE, base::Bind(AppendToVectorReentrantTask, + base::RetainedRef(default_task_runner_), &run_order, + &count, 5)); + RunUntilIdle(); + + EXPECT_THAT(run_order, testing::ElementsAre(0, 1, 2, 3, 4)); +} + +TEST_F(RendererSchedulerImplTest, TestPostIdleTask) { + int run_count = 0; + base::TimeTicks expected_deadline = + clock_->NowTicks() + base::TimeDelta::FromMilliseconds(2300); + base::TimeTicks deadline_in_task; + + clock_->Advance(base::TimeDelta::FromMilliseconds(100)); + idle_task_runner_->PostIdleTask( + FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + + RunUntilIdle(); + EXPECT_EQ(0, run_count); // Shouldn't run yet as no WillBeginFrame. + + scheduler_->WillBeginFrame(cc::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), + base::TimeDelta::FromMilliseconds(1000), cc::BeginFrameArgs::NORMAL)); + RunUntilIdle(); + EXPECT_EQ(0, run_count); // Shouldn't run as no DidCommitFrameToCompositor. + + clock_->Advance(base::TimeDelta::FromMilliseconds(1200)); + scheduler_->DidCommitFrameToCompositor(); + RunUntilIdle(); + EXPECT_EQ(0, run_count); // We missed the deadline. + + scheduler_->WillBeginFrame(cc::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), + base::TimeDelta::FromMilliseconds(1000), cc::BeginFrameArgs::NORMAL)); + clock_->Advance(base::TimeDelta::FromMilliseconds(800)); + scheduler_->DidCommitFrameToCompositor(); + RunUntilIdle(); + EXPECT_EQ(1, run_count); + EXPECT_EQ(expected_deadline, deadline_in_task); +} + +TEST_F(RendererSchedulerImplTest, TestRepostingIdleTask) { + int run_count = 0; + + max_idle_task_reposts = 2; + idle_task_runner_->PostIdleTask( + FROM_HERE, base::Bind(&RepostingIdleTestTask, + base::RetainedRef(idle_task_runner_), &run_count)); + EnableIdleTasks(); + RunUntilIdle(); + EXPECT_EQ(1, run_count); + + // Reposted tasks shouldn't run until next idle period. + RunUntilIdle(); + EXPECT_EQ(1, run_count); + + EnableIdleTasks(); + RunUntilIdle(); + EXPECT_EQ(2, run_count); +} + +TEST_F(RendererSchedulerImplTest, TestIdleTaskExceedsDeadline) { + mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true); + int run_count = 0; + + // Post two UpdateClockToDeadlineIdleTestTask tasks. + idle_task_runner_->PostIdleTask( + FROM_HERE, + base::Bind(&UpdateClockToDeadlineIdleTestTask, clock_.get(), &run_count)); + idle_task_runner_->PostIdleTask( + FROM_HERE, + base::Bind(&UpdateClockToDeadlineIdleTestTask, clock_.get(), &run_count)); + + EnableIdleTasks(); + RunUntilIdle(); + // Only the first idle task should execute since it's used up the deadline. + EXPECT_EQ(1, run_count); + + EnableIdleTasks(); + RunUntilIdle(); + // Second task should be run on the next idle period. + EXPECT_EQ(2, run_count); +} + +TEST_F(RendererSchedulerImplTest, TestPostIdleTaskAfterWakeup) { + base::TimeTicks deadline_in_task; + int run_count = 0; + + idle_task_runner_->PostIdleTaskAfterWakeup( + FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + + EnableIdleTasks(); + RunUntilIdle(); + // Shouldn't run yet as no other task woke up the scheduler. + EXPECT_EQ(0, run_count); + + idle_task_runner_->PostIdleTaskAfterWakeup( + FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + + EnableIdleTasks(); + RunUntilIdle(); + // Another after wakeup idle task shouldn't wake the scheduler. + EXPECT_EQ(0, run_count); + + default_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask)); + + RunUntilIdle(); + EnableIdleTasks(); // Must start a new idle period before idle task runs. + RunUntilIdle(); + // Execution of default task queue task should trigger execution of idle task. + EXPECT_EQ(2, run_count); +} + +TEST_F(RendererSchedulerImplTest, TestPostIdleTaskAfterWakeupWhileAwake) { + base::TimeTicks deadline_in_task; + int run_count = 0; + + idle_task_runner_->PostIdleTaskAfterWakeup( + FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + default_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask)); + + RunUntilIdle(); + EnableIdleTasks(); // Must start a new idle period before idle task runs. + RunUntilIdle(); + // Should run as the scheduler was already awakened by the normal task. + EXPECT_EQ(1, run_count); +} + +TEST_F(RendererSchedulerImplTest, TestPostIdleTaskWakesAfterWakeupIdleTask) { + base::TimeTicks deadline_in_task; + int run_count = 0; + + idle_task_runner_->PostIdleTaskAfterWakeup( + FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + idle_task_runner_->PostIdleTask( + FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + + EnableIdleTasks(); + RunUntilIdle(); + // Must start a new idle period before after-wakeup idle task runs. + EnableIdleTasks(); + RunUntilIdle(); + // Normal idle task should wake up after-wakeup idle task. + EXPECT_EQ(2, run_count); +} + +TEST_F(RendererSchedulerImplTest, TestDelayedEndIdlePeriodCanceled) { + int run_count = 0; + + base::TimeTicks deadline_in_task; + idle_task_runner_->PostIdleTask( + FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + + // Trigger the beginning of an idle period for 1000ms. + scheduler_->WillBeginFrame(cc::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), + base::TimeDelta::FromMilliseconds(1000), cc::BeginFrameArgs::NORMAL)); + DoMainFrame(); + + // End the idle period early (after 500ms), and send a WillBeginFrame which + // specifies that the next idle period should end 1000ms from now. + clock_->Advance(base::TimeDelta::FromMilliseconds(500)); + scheduler_->WillBeginFrame(cc::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), + base::TimeDelta::FromMilliseconds(1000), cc::BeginFrameArgs::NORMAL)); + + RunUntilIdle(); + EXPECT_EQ(0, run_count); // Not currently in an idle period. + + // Trigger the start of the idle period before the task to end the previous + // idle period has been triggered. + clock_->Advance(base::TimeDelta::FromMilliseconds(400)); + scheduler_->DidCommitFrameToCompositor(); + + // Post a task which simulates running until after the previous end idle + // period delayed task was scheduled for + scheduler_->DefaultTaskRunner()->PostTask(FROM_HERE, base::Bind(NullTask)); + clock_->Advance(base::TimeDelta::FromMilliseconds(300)); + + RunUntilIdle(); + EXPECT_EQ(1, run_count); // We should still be in the new idle period. +} + +TEST_F(RendererSchedulerImplTest, TestDefaultPolicy) { + std::vector<std::string> run_order; + PostTestTasks(&run_order, "L1 I1 D1 C1 D2 C2"); + + EnableIdleTasks(); + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("L1"), std::string("D1"), + std::string("C1"), std::string("D2"), + std::string("C2"), std::string("I1"))); + EXPECT_EQ(RendererSchedulerImpl::UseCase::NONE, CurrentUseCase()); +} + +TEST_F(RendererSchedulerImplTest, + TestCompositorPolicy_CompositorHandlesInput_WithTouchHandler) { + std::vector<std::string> run_order; + PostTestTasks(&run_order, "L1 I1 D1 C1 D2 C2"); + + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + EnableIdleTasks(); + SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START); + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("L1"), std::string("D1"), + std::string("D2"), std::string("I1"), + std::string("C1"), std::string("C2"))); + EXPECT_EQ(RendererSchedulerImpl::UseCase::COMPOSITOR_GESTURE, + CurrentUseCase()); +} + +TEST_F(RendererSchedulerImplTest, + TestCompositorPolicy_MainThreadHandlesInput_WithoutScrollUpdates) { + std::vector<std::string> run_order; + PostTestTasks(&run_order, "L1 I1 D1 C1 D2 C2"); + + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + EnableIdleTasks(); + SimulateMainThreadGestureWithoutScrollUpdates(); + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("C1"), std::string("C2"), + std::string("L1"), std::string("D1"), + std::string("D2"), std::string("I1"))); + EXPECT_EQ(RendererSchedulerImpl::UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, + CurrentUseCase()); +} + +TEST_F(RendererSchedulerImplTest, + TestCompositorPolicy_MainThreadHandlesInput_WithoutPreventDefault) { + std::vector<std::string> run_order; + PostTestTasks(&run_order, "L1 I1 D1 C1 D2 C2"); + + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + EnableIdleTasks(); + SimulateMainThreadGestureWithoutPreventDefault(); + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("L1"), std::string("D1"), + std::string("D2"), std::string("I1"), + std::string("C1"), std::string("C2"))); + EXPECT_EQ(RendererSchedulerImpl::UseCase::COMPOSITOR_GESTURE, + CurrentUseCase()); +} + +TEST_F(RendererSchedulerImplTest, + TestCompositorPolicy_CompositorHandlesInput_LongGestureDuration) { + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + EnableIdleTasks(); + SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START); + + base::TimeTicks loop_end_time = + clock_->NowTicks() + base::TimeDelta::FromMilliseconds( + UserModel::kMedianGestureDurationMillis * 2); + + // The UseCase::COMPOSITOR_GESTURE usecase initially deprioritizes compositor + // tasks (see TestCompositorPolicy_CompositorHandlesInput_WithTouchHandler) + // but if the gesture is long enough, compositor tasks get prioritized again. + while (clock_->NowTicks() < loop_end_time) { + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchMove), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + clock_->Advance(base::TimeDelta::FromMilliseconds(16)); + RunUntilIdle(); + } + + std::vector<std::string> run_order; + PostTestTasks(&run_order, "L1 I1 D1 C1 D2 C2"); + + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("C1"), std::string("C2"), + std::string("L1"), std::string("D1"), + std::string("D2"))); + EXPECT_EQ(RendererSchedulerImpl::UseCase::COMPOSITOR_GESTURE, + CurrentUseCase()); +} + +TEST_F(RendererSchedulerImplTest, + TestCompositorPolicy_CompositorHandlesInput_WithoutTouchHandler) { + std::vector<std::string> run_order; + PostTestTasks(&run_order, "L1 I1 D1 C1 D2 C2"); + + EnableIdleTasks(); + SimulateCompositorGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START); + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("L1"), std::string("D1"), + std::string("D2"), std::string("I1"), + std::string("C1"), std::string("C2"))); + EXPECT_EQ(RendererSchedulerImpl::UseCase::COMPOSITOR_GESTURE, + CurrentUseCase()); +} + +TEST_F(RendererSchedulerImplTest, + TestCompositorPolicy_MainThreadHandlesInput_WithTouchHandler) { + std::vector<std::string> run_order; + PostTestTasks(&run_order, "L1 I1 D1 C1 D2 C2"); + + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + EnableIdleTasks(); + SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START, + blink::WebInputEvent::GestureScrollBegin); + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("C1"), std::string("C2"), + std::string("L1"), std::string("D1"), + std::string("D2"), std::string("I1"))); + EXPECT_EQ(RendererSchedulerImpl::UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, + CurrentUseCase()); + scheduler_->DidHandleInputEventOnMainThread( + FakeInputEvent(blink::WebInputEvent::GestureFlingStart)); +} + +TEST_F(RendererSchedulerImplTest, + TestCompositorPolicy_MainThreadHandlesInput_WithoutTouchHandler) { + std::vector<std::string> run_order; + PostTestTasks(&run_order, "L1 I1 D1 C1 D2 C2"); + + EnableIdleTasks(); + SimulateMainThreadGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START, + blink::WebInputEvent::GestureScrollBegin); + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("C1"), std::string("C2"), + std::string("L1"), std::string("D1"), + std::string("D2"), std::string("I1"))); + EXPECT_EQ(RendererSchedulerImpl::UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, + CurrentUseCase()); + scheduler_->DidHandleInputEventOnMainThread( + FakeInputEvent(blink::WebInputEvent::GestureFlingStart)); +} + +TEST_F(RendererSchedulerImplTest, TestCompositorPolicy_DidAnimateForInput) { + std::vector<std::string> run_order; + PostTestTasks(&run_order, "I1 D1 C1 D2 C2"); + + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + scheduler_->DidAnimateForInputOnCompositorThread(); + // Note DidAnimateForInputOnCompositorThread does not by itself trigger a + // policy update. + EXPECT_EQ(RendererSchedulerImpl::UseCase::COMPOSITOR_GESTURE, + ForceUpdatePolicyAndGetCurrentUseCase()); + EnableIdleTasks(); + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("D1"), std::string("D2"), + std::string("I1"), std::string("C1"), + std::string("C2"))); + EXPECT_EQ(RendererSchedulerImpl::UseCase::COMPOSITOR_GESTURE, + CurrentUseCase()); +} + +TEST_F(RendererSchedulerImplTest, Navigation_ResetsTaskCostEstimations) { + std::vector<std::string> run_order; + + SimulateExpensiveTasks(timer_task_runner_); + scheduler_->OnNavigationStarted(); + PostTestTasks(&run_order, "C1 T1"); + + SimulateMainThreadGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START, + blink::WebInputEvent::GestureScrollBegin); + scheduler_->DidCommitFrameToCompositor(); // Starts Idle Period + RunUntilIdle(); + + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("C1"), std::string("T1"))); +} + +TEST_F(RendererSchedulerImplTest, + ExpensiveTimersDontRunWhenMainThreadScrolling) { + std::vector<std::string> run_order; + + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + SimulateExpensiveTasks(timer_task_runner_); + DoMainFrame(); + SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START, + blink::WebInputEvent::GestureScrollUpdate); + + PostTestTasks(&run_order, "C1 T1"); + + RunUntilIdle(); + EXPECT_FALSE(TouchStartExpectedSoon()); + EXPECT_EQ(RendererSchedulerImpl::UseCase::MAIN_THREAD_GESTURE, + CurrentUseCase()); + + EXPECT_THAT(run_order, testing::ElementsAre(std::string("C1"))); +} + +TEST_F(RendererSchedulerImplTest, + ExpensiveTimersDoRunWhenMainThreadInputHandling) { + std::vector<std::string> run_order; + + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + SimulateExpensiveTasks(timer_task_runner_); + DoMainFrame(); + SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START, + blink::WebInputEvent::Undefined); + + PostTestTasks(&run_order, "C1 T1"); + + RunUntilIdle(); + EXPECT_FALSE(TouchStartExpectedSoon()); + EXPECT_EQ(RendererSchedulerImpl::UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, + CurrentUseCase()); + + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("C1"), std::string("T1"))); +} + +TEST_F(RendererSchedulerImplTest, + ExpensiveTimersDoRunWhenMainThreadScrolling_AndOnCriticalPath) { + std::vector<std::string> run_order; + + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + SimulateExpensiveTasks(timer_task_runner_); + DoMainFrameOnCriticalPath(); + SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START, + blink::WebInputEvent::GestureScrollBegin); + + PostTestTasks(&run_order, "C1 T1"); + + RunUntilIdle(); + EXPECT_FALSE(TouchStartExpectedSoon()); + EXPECT_EQ(RendererSchedulerImpl::UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, + CurrentUseCase()); + + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("C1"), std::string("T1"))); +} + +TEST_F(RendererSchedulerImplTest, TestTouchstartPolicy_Compositor) { + std::vector<std::string> run_order; + PostTestTasks(&run_order, "L1 D1 C1 D2 C2 T1 T2"); + + // Observation of touchstart should defer execution of timer, idle and loading + // tasks. + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchStart), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + EnableIdleTasks(); + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("C1"), std::string("C2"), + std::string("D1"), std::string("D2"))); + + // Animation or meta events like TapDown/FlingCancel shouldn't affect the + // priority. + run_order.clear(); + scheduler_->DidAnimateForInputOnCompositorThread(); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureFlingCancel), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureTapDown), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + RunUntilIdle(); + EXPECT_TRUE(run_order.empty()); + + // Action events like ScrollBegin will kick us back into compositor priority, + // allowing service of the timer, loading and idle queues. + run_order.clear(); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureScrollBegin), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + RunUntilIdle(); + + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("L1"), std::string("T1"), + std::string("T2"))); +} + +TEST_F(RendererSchedulerImplTest, TestTouchstartPolicy_MainThread) { + std::vector<std::string> run_order; + PostTestTasks(&run_order, "L1 D1 C1 D2 C2 T1 T2"); + + // Observation of touchstart should defer execution of timer, idle and loading + // tasks. + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchStart), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + scheduler_->DidHandleInputEventOnMainThread( + FakeInputEvent(blink::WebInputEvent::TouchStart)); + EnableIdleTasks(); + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("C1"), std::string("C2"), + std::string("D1"), std::string("D2"))); + + // Meta events like TapDown/FlingCancel shouldn't affect the priority. + run_order.clear(); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureFlingCancel), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + scheduler_->DidHandleInputEventOnMainThread( + FakeInputEvent(blink::WebInputEvent::GestureFlingCancel)); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureTapDown), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + scheduler_->DidHandleInputEventOnMainThread( + FakeInputEvent(blink::WebInputEvent::GestureTapDown)); + RunUntilIdle(); + EXPECT_TRUE(run_order.empty()); + + // Action events like ScrollBegin will kick us back into compositor priority, + // allowing service of the timer, loading and idle queues. + run_order.clear(); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureScrollBegin), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + scheduler_->DidHandleInputEventOnMainThread( + FakeInputEvent(blink::WebInputEvent::GestureScrollBegin)); + RunUntilIdle(); + + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("L1"), std::string("T1"), + std::string("T2"))); +} + +// TODO(alexclarke): Reenable once we've reinstaed the Loading UseCase. +TEST_F(RendererSchedulerImplTest, DISABLED_LoadingUseCase) { + std::vector<std::string> run_order; + PostTestTasks(&run_order, "I1 D1 C1 T1 L1 D2 C2 T2 L2"); + + scheduler_->OnNavigationStarted(); + EnableIdleTasks(); + RunUntilIdle(); + + // In loading policy, loading tasks are prioritized other others. + std::string loading_policy_expected[] = { + std::string("D1"), std::string("L1"), std::string("D2"), + std::string("L2"), std::string("C1"), std::string("T1"), + std::string("C2"), std::string("T2"), std::string("I1")}; + EXPECT_THAT(run_order, testing::ElementsAreArray(loading_policy_expected)); + EXPECT_EQ(RendererSchedulerImpl::UseCase::LOADING, CurrentUseCase()); + + // Advance 15s and try again, the loading policy should have ended and the + // task order should return to the NONE use case where loading tasks are no + // longer prioritized. + clock_->Advance(base::TimeDelta::FromMilliseconds(150000)); + run_order.clear(); + PostTestTasks(&run_order, "I1 D1 C1 T1 L1 D2 C2 T2 L2"); + EnableIdleTasks(); + RunUntilIdle(); + + std::string default_order_expected[] = { + std::string("D1"), std::string("C1"), std::string("T1"), + std::string("L1"), std::string("D2"), std::string("C2"), + std::string("T2"), std::string("L2"), std::string("I1")}; + EXPECT_THAT(run_order, testing::ElementsAreArray(default_order_expected)); + EXPECT_EQ(RendererSchedulerImpl::UseCase::NONE, CurrentUseCase()); +} + +TEST_F(RendererSchedulerImplTest, + EventConsumedOnCompositorThread_IgnoresMouseMove_WhenMouseUp) { + std::vector<std::string> run_order; + PostTestTasks(&run_order, "I1 D1 C1 D2 C2"); + + EnableIdleTasks(); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::MouseMove), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + RunUntilIdle(); + // Note compositor tasks are not prioritized. + EXPECT_EQ(RendererSchedulerImpl::UseCase::NONE, CurrentUseCase()); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("D1"), std::string("C1"), + std::string("D2"), std::string("C2"), + std::string("I1"))); +} + +TEST_F(RendererSchedulerImplTest, + EventForwardedToMainThread_IgnoresMouseMove_WhenMouseUp) { + std::vector<std::string> run_order; + PostTestTasks(&run_order, "I1 D1 C1 D2 C2"); + + EnableIdleTasks(); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::MouseMove), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + RunUntilIdle(); + // Note compositor tasks are not prioritized. + EXPECT_EQ(RendererSchedulerImpl::UseCase::NONE, CurrentUseCase()); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("D1"), std::string("C1"), + std::string("D2"), std::string("C2"), + std::string("I1"))); +} + +TEST_F(RendererSchedulerImplTest, + EventConsumedOnCompositorThread_MouseMove_WhenMouseDown) { + std::vector<std::string> run_order; + PostTestTasks(&run_order, "I1 D1 C1 D2 C2"); + + EnableIdleTasks(); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::MouseMove, + blink::WebInputEvent::LeftButtonDown), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + RunUntilIdle(); + // Note compositor tasks are prioritized. + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("C1"), std::string("C2"), + std::string("D1"), std::string("D2"), + std::string("I1"))); +} + +TEST_F(RendererSchedulerImplTest, + EventForwardedToMainThread_MouseMove_WhenMouseDown) { + std::vector<std::string> run_order; + PostTestTasks(&run_order, "I1 D1 C1 D2 C2"); + + EnableIdleTasks(); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::MouseMove, + blink::WebInputEvent::LeftButtonDown), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + RunUntilIdle(); + // Note compositor tasks are prioritized. + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("C1"), std::string("C2"), + std::string("D1"), std::string("D2"), + std::string("I1"))); + scheduler_->DidHandleInputEventOnMainThread(FakeInputEvent( + blink::WebInputEvent::MouseMove, blink::WebInputEvent::LeftButtonDown)); +} + +TEST_F(RendererSchedulerImplTest, EventConsumedOnCompositorThread_MouseWheel) { + std::vector<std::string> run_order; + PostTestTasks(&run_order, "I1 D1 C1 D2 C2"); + + EnableIdleTasks(); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::MouseWheel), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + RunUntilIdle(); + // Note compositor tasks are prioritized. + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("C1"), std::string("C2"), + std::string("D1"), std::string("D2"), + std::string("I1"))); +} + +TEST_F(RendererSchedulerImplTest, EventForwardedToMainThread_MouseWheel) { + std::vector<std::string> run_order; + PostTestTasks(&run_order, "I1 D1 C1 D2 C2"); + + EnableIdleTasks(); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::MouseWheel), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + RunUntilIdle(); + // Note compositor tasks are prioritized. + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("C1"), std::string("C2"), + std::string("D1"), std::string("D2"), + std::string("I1"))); + EXPECT_EQ(RendererSchedulerImpl::UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, + CurrentUseCase()); +} + +TEST_F(RendererSchedulerImplTest, + EventConsumedOnCompositorThread_IgnoresKeyboardEvents) { + std::vector<std::string> run_order; + PostTestTasks(&run_order, "I1 D1 C1 D2 C2"); + + EnableIdleTasks(); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::KeyDown), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + RunUntilIdle(); + // Note compositor tasks are not prioritized. + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("D1"), std::string("C1"), + std::string("D2"), std::string("C2"), + std::string("I1"))); + EXPECT_EQ(RendererSchedulerImpl::UseCase::NONE, CurrentUseCase()); +} + +TEST_F(RendererSchedulerImplTest, + EventForwardedToMainThread_IgnoresKeyboardEvents) { + std::vector<std::string> run_order; + PostTestTasks(&run_order, "I1 D1 C1 D2 C2"); + + EnableIdleTasks(); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::KeyDown), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + RunUntilIdle(); + // Note compositor tasks are not prioritized. + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("D1"), std::string("C1"), + std::string("D2"), std::string("C2"), + std::string("I1"))); + EXPECT_EQ(RendererSchedulerImpl::UseCase::NONE, CurrentUseCase()); + // Note compositor tasks are not prioritized. + scheduler_->DidHandleInputEventOnMainThread( + FakeInputEvent(blink::WebInputEvent::KeyDown)); +} + +TEST_F(RendererSchedulerImplTest, + TestMainthreadScrollingUseCaseDoesNotStarveDefaultTasks) { + SimulateMainThreadGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START, + blink::WebInputEvent::GestureScrollBegin); + EnableIdleTasks(); + + std::vector<std::string> run_order; + PostTestTasks(&run_order, "D1 C1"); + + for (int i = 0; i < 20; i++) { + compositor_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask)); + } + PostTestTasks(&run_order, "C2"); + + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureFlingStart), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + RunUntilIdle(); + // Ensure that the default D1 task gets to run at some point before the final + // C2 compositor task. + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("C1"), std::string("D1"), + std::string("C2"))); +} + +TEST_F(RendererSchedulerImplTest, + TestCompositorPolicyEnds_CompositorHandlesInput) { + SimulateCompositorGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START); + EXPECT_EQ(UseCase::COMPOSITOR_GESTURE, + ForceUpdatePolicyAndGetCurrentUseCase()); + + clock_->Advance(base::TimeDelta::FromMilliseconds(1000)); + EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); +} + +TEST_F(RendererSchedulerImplTest, + TestCompositorPolicyEnds_MainThreadHandlesInput) { + SimulateMainThreadGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START, + blink::WebInputEvent::GestureScrollBegin); + EXPECT_EQ(UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, + ForceUpdatePolicyAndGetCurrentUseCase()); + + clock_->Advance(base::TimeDelta::FromMilliseconds(1000)); + EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); +} + +TEST_F(RendererSchedulerImplTest, TestTouchstartPolicyEndsAfterTimeout) { + std::vector<std::string> run_order; + PostTestTasks(&run_order, "L1 D1 C1 D2 C2"); + + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchStart), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("C1"), std::string("C2"), + std::string("D1"), std::string("D2"))); + + run_order.clear(); + clock_->Advance(base::TimeDelta::FromMilliseconds(1000)); + + // Don't post any compositor tasks to simulate a very long running event + // handler. + PostTestTasks(&run_order, "D1 D2"); + + // Touchstart policy mode should have ended now that the clock has advanced. + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("L1"), std::string("D1"), + std::string("D2"))); +} + +TEST_F(RendererSchedulerImplTest, + TestTouchstartPolicyEndsAfterConsecutiveTouchmoves) { + std::vector<std::string> run_order; + PostTestTasks(&run_order, "L1 D1 C1 D2 C2"); + + // Observation of touchstart should defer execution of idle and loading tasks. + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchStart), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("C1"), std::string("C2"), + std::string("D1"), std::string("D2"))); + + // Receiving the first touchmove will not affect scheduler priority. + run_order.clear(); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchMove), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + RunUntilIdle(); + EXPECT_TRUE(run_order.empty()); + + // Receiving the second touchmove will kick us back into compositor priority. + run_order.clear(); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchMove), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + RunUntilIdle(); + EXPECT_THAT(run_order, testing::ElementsAre(std::string("L1"))); +} + +TEST_F(RendererSchedulerImplTest, TestIsHighPriorityWorkAnticipated) { + bool is_anticipated_before = false; + bool is_anticipated_after = false; + + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + default_task_runner_->PostTask( + FROM_HERE, base::Bind(&AnticipationTestTask, scheduler_.get(), + SimulateInputType::None, &is_anticipated_before, + &is_anticipated_after)); + RunUntilIdle(); + // In its default state, without input receipt, the scheduler should indicate + // that no high-priority is anticipated. + EXPECT_FALSE(is_anticipated_before); + EXPECT_FALSE(is_anticipated_after); + + default_task_runner_->PostTask( + FROM_HERE, base::Bind(&AnticipationTestTask, scheduler_.get(), + SimulateInputType::TouchStart, + &is_anticipated_before, &is_anticipated_after)); + bool dummy; + default_task_runner_->PostTask( + FROM_HERE, base::Bind(&AnticipationTestTask, scheduler_.get(), + SimulateInputType::TouchEnd, &dummy, &dummy)); + default_task_runner_->PostTask( + FROM_HERE, + base::Bind(&AnticipationTestTask, scheduler_.get(), + SimulateInputType::GestureScrollBegin, &dummy, &dummy)); + default_task_runner_->PostTask( + FROM_HERE, + base::Bind(&AnticipationTestTask, scheduler_.get(), + SimulateInputType::GestureScrollEnd, &dummy, &dummy)); + + RunUntilIdle(); + // When input is received, the scheduler should indicate that high-priority + // work is anticipated. + EXPECT_FALSE(is_anticipated_before); + EXPECT_TRUE(is_anticipated_after); + + clock_->Advance(priority_escalation_after_input_duration() * 2); + default_task_runner_->PostTask( + FROM_HERE, base::Bind(&AnticipationTestTask, scheduler_.get(), + SimulateInputType::None, &is_anticipated_before, + &is_anticipated_after)); + RunUntilIdle(); + // Without additional input, the scheduler should go into NONE + // use case but with scrolling expected where high-priority work is still + // anticipated. + EXPECT_EQ(UseCase::NONE, CurrentUseCase()); + EXPECT_TRUE(TouchStartExpectedSoon()); + EXPECT_TRUE(is_anticipated_before); + EXPECT_TRUE(is_anticipated_after); + + clock_->Advance(subsequent_input_expected_after_input_duration() * 2); + default_task_runner_->PostTask( + FROM_HERE, base::Bind(&AnticipationTestTask, scheduler_.get(), + SimulateInputType::None, &is_anticipated_before, + &is_anticipated_after)); + RunUntilIdle(); + // Eventually the scheduler should go into the default use case where + // high-priority work is no longer anticipated. + EXPECT_EQ(UseCase::NONE, CurrentUseCase()); + EXPECT_FALSE(TouchStartExpectedSoon()); + EXPECT_FALSE(is_anticipated_before); + EXPECT_FALSE(is_anticipated_after); +} + +TEST_F(RendererSchedulerImplTest, TestShouldYield) { + bool should_yield_before = false; + bool should_yield_after = false; + + default_task_runner_->PostTask( + FROM_HERE, base::Bind(&PostingYieldingTestTask, scheduler_.get(), + base::RetainedRef(default_task_runner_), false, + &should_yield_before, &should_yield_after)); + RunUntilIdle(); + // Posting to default runner shouldn't cause yielding. + EXPECT_FALSE(should_yield_before); + EXPECT_FALSE(should_yield_after); + + default_task_runner_->PostTask( + FROM_HERE, base::Bind(&PostingYieldingTestTask, scheduler_.get(), + base::RetainedRef(compositor_task_runner_), false, + &should_yield_before, &should_yield_after)); + RunUntilIdle(); + // Posting while not mainthread scrolling shouldn't cause yielding. + EXPECT_FALSE(should_yield_before); + EXPECT_FALSE(should_yield_after); + + default_task_runner_->PostTask( + FROM_HERE, base::Bind(&PostingYieldingTestTask, scheduler_.get(), + base::RetainedRef(compositor_task_runner_), true, + &should_yield_before, &should_yield_after)); + RunUntilIdle(); + // We should be able to switch to compositor priority mid-task. + EXPECT_FALSE(should_yield_before); + EXPECT_TRUE(should_yield_after); +} + +TEST_F(RendererSchedulerImplTest, TestShouldYield_TouchStart) { + // Receiving a touchstart should immediately trigger yielding, even if + // there's no immediately pending work in the compositor queue. + EXPECT_FALSE(scheduler_->ShouldYieldForHighPriorityWork()); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchStart), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + EXPECT_TRUE(scheduler_->ShouldYieldForHighPriorityWork()); + RunUntilIdle(); +} + +TEST_F(RendererSchedulerImplTest, SlowMainThreadInputEvent) { + EXPECT_EQ(UseCase::NONE, CurrentUseCase()); + + // An input event should bump us into input priority. + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureFlingStart), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + RunUntilIdle(); + EXPECT_EQ(UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, CurrentUseCase()); + + // Simulate the input event being queued for a very long time. The compositor + // task we post here represents the enqueued input task. + clock_->Advance(priority_escalation_after_input_duration() * 2); + scheduler_->DidHandleInputEventOnMainThread( + FakeInputEvent(blink::WebInputEvent::GestureFlingStart)); + RunUntilIdle(); + + // Even though we exceeded the input priority escalation period, we should + // still be in main thread gesture since the input remains queued. + EXPECT_EQ(UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, CurrentUseCase()); + + // After the escalation period ends we should go back into normal mode. + clock_->Advance(priority_escalation_after_input_duration() * 2); + RunUntilIdle(); + EXPECT_EQ(UseCase::NONE, CurrentUseCase()); +} + +class RendererSchedulerImplWithMockSchedulerTest + : public RendererSchedulerImplTest { + public: + void SetUp() override { + mock_task_runner_ = make_scoped_refptr( + new cc::OrderedSimpleTaskRunner(clock_.get(), false)); + main_task_runner_ = SchedulerTqmDelegateForTest::Create( + mock_task_runner_, base::WrapUnique(new TestTimeSource(clock_.get()))); + mock_scheduler_ = new RendererSchedulerImplForTest(main_task_runner_); + Initialize(base::WrapUnique(mock_scheduler_)); + } + + protected: + RendererSchedulerImplForTest* mock_scheduler_; +}; + +TEST_F(RendererSchedulerImplWithMockSchedulerTest, + OnlyOnePendingUrgentPolicyUpdatey) { + mock_scheduler_->EnsureUrgentPolicyUpdatePostedOnMainThread(); + mock_scheduler_->EnsureUrgentPolicyUpdatePostedOnMainThread(); + mock_scheduler_->EnsureUrgentPolicyUpdatePostedOnMainThread(); + mock_scheduler_->EnsureUrgentPolicyUpdatePostedOnMainThread(); + + RunUntilIdle(); + + EXPECT_EQ(1, mock_scheduler_->update_policy_count_); +} + +TEST_F(RendererSchedulerImplWithMockSchedulerTest, + OnePendingDelayedAndOneUrgentUpdatePolicy) { + mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true); + + mock_scheduler_->ScheduleDelayedPolicyUpdate( + clock_->NowTicks(), base::TimeDelta::FromMilliseconds(1)); + mock_scheduler_->EnsureUrgentPolicyUpdatePostedOnMainThread(); + + RunUntilIdle(); + + // We expect both the urgent and the delayed updates to run. + EXPECT_EQ(2, mock_scheduler_->update_policy_count_); +} + +TEST_F(RendererSchedulerImplWithMockSchedulerTest, + OneUrgentAndOnePendingDelayedUpdatePolicy) { + mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true); + + mock_scheduler_->EnsureUrgentPolicyUpdatePostedOnMainThread(); + mock_scheduler_->ScheduleDelayedPolicyUpdate( + clock_->NowTicks(), base::TimeDelta::FromMilliseconds(1)); + + RunUntilIdle(); + + // We expect both the urgent and the delayed updates to run. + EXPECT_EQ(2, mock_scheduler_->update_policy_count_); +} + +TEST_F(RendererSchedulerImplWithMockSchedulerTest, + UpdatePolicyCountTriggeredByOneInputEvent) { + // We expect DidHandleInputEventOnCompositorThread to post an urgent policy + // update. + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchStart), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + EXPECT_EQ(0, mock_scheduler_->update_policy_count_); + mock_task_runner_->RunPendingTasks(); + EXPECT_EQ(1, mock_scheduler_->update_policy_count_); + + scheduler_->DidHandleInputEventOnMainThread( + FakeInputEvent(blink::WebInputEvent::TouchStart)); + EXPECT_EQ(1, mock_scheduler_->update_policy_count_); + + clock_->Advance(base::TimeDelta::FromMilliseconds(1000)); + RunUntilIdle(); + + // We finally expect a delayed policy update 100ms later. + EXPECT_EQ(2, mock_scheduler_->update_policy_count_); +} + +TEST_F(RendererSchedulerImplWithMockSchedulerTest, + UpdatePolicyCountTriggeredByThreeInputEvents) { + // We expect DidHandleInputEventOnCompositorThread to post an urgent policy + // update. + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchStart), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + EXPECT_EQ(0, mock_scheduler_->update_policy_count_); + mock_task_runner_->RunPendingTasks(); + EXPECT_EQ(1, mock_scheduler_->update_policy_count_); + + scheduler_->DidHandleInputEventOnMainThread( + FakeInputEvent(blink::WebInputEvent::TouchStart)); + EXPECT_EQ(1, mock_scheduler_->update_policy_count_); + + // The second call to DidHandleInputEventOnCompositorThread should not post a + // policy update because we are already in compositor priority. + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchMove), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + mock_task_runner_->RunPendingTasks(); + EXPECT_EQ(1, mock_scheduler_->update_policy_count_); + + // We expect DidHandleInputEvent to trigger a policy update. + scheduler_->DidHandleInputEventOnMainThread( + FakeInputEvent(blink::WebInputEvent::TouchMove)); + EXPECT_EQ(1, mock_scheduler_->update_policy_count_); + + // The third call to DidHandleInputEventOnCompositorThread should post a + // policy update because the awaiting_touch_start_response_ flag changed. + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchMove), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + EXPECT_EQ(1, mock_scheduler_->update_policy_count_); + mock_task_runner_->RunPendingTasks(); + EXPECT_EQ(2, mock_scheduler_->update_policy_count_); + + // We expect DidHandleInputEvent to trigger a policy update. + scheduler_->DidHandleInputEventOnMainThread( + FakeInputEvent(blink::WebInputEvent::TouchMove)); + EXPECT_EQ(2, mock_scheduler_->update_policy_count_); + + clock_->Advance(base::TimeDelta::FromMilliseconds(1000)); + RunUntilIdle(); + + // We finally expect a delayed policy update. + EXPECT_EQ(3, mock_scheduler_->update_policy_count_); +} + +TEST_F(RendererSchedulerImplWithMockSchedulerTest, + UpdatePolicyCountTriggeredByTwoInputEventsWithALongSeparatingDelay) { + // We expect DidHandleInputEventOnCompositorThread to post an urgent policy + // update. + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchStart), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + EXPECT_EQ(0, mock_scheduler_->update_policy_count_); + mock_task_runner_->RunPendingTasks(); + EXPECT_EQ(1, mock_scheduler_->update_policy_count_); + + scheduler_->DidHandleInputEventOnMainThread( + FakeInputEvent(blink::WebInputEvent::TouchStart)); + EXPECT_EQ(1, mock_scheduler_->update_policy_count_); + + clock_->Advance(base::TimeDelta::FromMilliseconds(1000)); + RunUntilIdle(); + // We expect a delayed policy update. + EXPECT_EQ(2, mock_scheduler_->update_policy_count_); + + // We expect the second call to DidHandleInputEventOnCompositorThread to post + // an urgent policy update because we are no longer in compositor priority. + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchMove), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + EXPECT_EQ(2, mock_scheduler_->update_policy_count_); + mock_task_runner_->RunPendingTasks(); + EXPECT_EQ(3, mock_scheduler_->update_policy_count_); + + scheduler_->DidHandleInputEventOnMainThread( + FakeInputEvent(blink::WebInputEvent::TouchMove)); + EXPECT_EQ(3, mock_scheduler_->update_policy_count_); + + clock_->Advance(base::TimeDelta::FromMilliseconds(1000)); + RunUntilIdle(); + + // We finally expect a delayed policy update. + EXPECT_EQ(4, mock_scheduler_->update_policy_count_); +} + +TEST_F(RendererSchedulerImplWithMockSchedulerTest, + EnsureUpdatePolicyNotTriggeredTooOften) { + mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true); + + EXPECT_EQ(0, mock_scheduler_->update_policy_count_); + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + EXPECT_EQ(1, mock_scheduler_->update_policy_count_); + + SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START); + + // We expect the first call to IsHighPriorityWorkAnticipated to be called + // after receiving an input event (but before the UpdateTask was processed) to + // call UpdatePolicy. + EXPECT_EQ(1, mock_scheduler_->update_policy_count_); + scheduler_->IsHighPriorityWorkAnticipated(); + EXPECT_EQ(2, mock_scheduler_->update_policy_count_); + // Subsequent calls should not call UpdatePolicy. + scheduler_->IsHighPriorityWorkAnticipated(); + scheduler_->IsHighPriorityWorkAnticipated(); + scheduler_->IsHighPriorityWorkAnticipated(); + scheduler_->ShouldYieldForHighPriorityWork(); + scheduler_->ShouldYieldForHighPriorityWork(); + scheduler_->ShouldYieldForHighPriorityWork(); + scheduler_->ShouldYieldForHighPriorityWork(); + + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureScrollEnd), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchEnd), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + + scheduler_->DidHandleInputEventOnMainThread( + FakeInputEvent(blink::WebInputEvent::TouchStart)); + scheduler_->DidHandleInputEventOnMainThread( + FakeInputEvent(blink::WebInputEvent::TouchMove)); + scheduler_->DidHandleInputEventOnMainThread( + FakeInputEvent(blink::WebInputEvent::TouchMove)); + scheduler_->DidHandleInputEventOnMainThread( + FakeInputEvent(blink::WebInputEvent::TouchEnd)); + + EXPECT_EQ(2, mock_scheduler_->update_policy_count_); + + // We expect both the urgent and the delayed updates to run in addition to the + // earlier updated cause by IsHighPriorityWorkAnticipated, a final update + // transitions from 'not_scrolling touchstart expected' to 'not_scrolling'. + RunUntilIdle(); + EXPECT_THAT( + mock_scheduler_->use_cases_, + testing::ElementsAre( + std::string("none"), std::string("compositor_gesture"), + std::string("compositor_gesture touchstart expected"), + std::string("none touchstart expected"), std::string("none"))); +} + +class RendererSchedulerImplWithMessageLoopTest + : public RendererSchedulerImplTest { + public: + RendererSchedulerImplWithMessageLoopTest() + : RendererSchedulerImplTest(new base::MessageLoop()) {} + ~RendererSchedulerImplWithMessageLoopTest() override {} + + void PostFromNestedRunloop( + std::vector<std::pair<SingleThreadIdleTaskRunner::IdleTask, bool>>* + tasks) { + base::MessageLoop::ScopedNestableTaskAllower allow(message_loop_.get()); + for (std::pair<SingleThreadIdleTaskRunner::IdleTask, bool>& pair : *tasks) { + if (pair.second) { + idle_task_runner_->PostIdleTask(FROM_HERE, pair.first); + } else { + idle_task_runner_->PostNonNestableIdleTask(FROM_HERE, pair.first); + } + } + EnableIdleTasks(); + base::RunLoop().RunUntilIdle(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(RendererSchedulerImplWithMessageLoopTest); +}; + +TEST_F(RendererSchedulerImplWithMessageLoopTest, + NonNestableIdleTaskDoesntExecuteInNestedLoop) { + std::vector<std::string> order; + idle_task_runner_->PostIdleTask( + FROM_HERE, + base::Bind(&AppendToVectorIdleTestTask, &order, std::string("1"))); + idle_task_runner_->PostIdleTask( + FROM_HERE, + base::Bind(&AppendToVectorIdleTestTask, &order, std::string("2"))); + + std::vector<std::pair<SingleThreadIdleTaskRunner::IdleTask, bool>> + tasks_to_post_from_nested_loop; + tasks_to_post_from_nested_loop.push_back(std::make_pair( + base::Bind(&AppendToVectorIdleTestTask, &order, std::string("3")), + false)); + tasks_to_post_from_nested_loop.push_back(std::make_pair( + base::Bind(&AppendToVectorIdleTestTask, &order, std::string("4")), true)); + tasks_to_post_from_nested_loop.push_back(std::make_pair( + base::Bind(&AppendToVectorIdleTestTask, &order, std::string("5")), true)); + + default_task_runner_->PostTask( + FROM_HERE, + base::Bind( + &RendererSchedulerImplWithMessageLoopTest::PostFromNestedRunloop, + base::Unretained(this), + base::Unretained(&tasks_to_post_from_nested_loop))); + + EnableIdleTasks(); + RunUntilIdle(); + // Note we expect task 3 to run last because it's non-nestable. + EXPECT_THAT(order, testing::ElementsAre(std::string("1"), std::string("2"), + std::string("4"), std::string("5"), + std::string("3"))); +} + +TEST_F(RendererSchedulerImplTest, TestLongIdlePeriod) { + base::TimeTicks expected_deadline = + clock_->NowTicks() + maximum_idle_period_duration(); + base::TimeTicks deadline_in_task; + int run_count = 0; + + idle_task_runner_->PostIdleTask( + FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + + RunUntilIdle(); + EXPECT_EQ(0, run_count); // Shouldn't run yet as no idle period. + + scheduler_->BeginFrameNotExpectedSoon(); + RunUntilIdle(); + EXPECT_EQ(1, run_count); // Should have run in a long idle time. + EXPECT_EQ(expected_deadline, deadline_in_task); +} + +TEST_F(RendererSchedulerImplTest, TestLongIdlePeriodWithPendingDelayedTask) { + base::TimeDelta pending_task_delay = base::TimeDelta::FromMilliseconds(30); + base::TimeTicks expected_deadline = clock_->NowTicks() + pending_task_delay; + base::TimeTicks deadline_in_task; + int run_count = 0; + + idle_task_runner_->PostIdleTask( + FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask), + pending_task_delay); + + scheduler_->BeginFrameNotExpectedSoon(); + RunUntilIdle(); + EXPECT_EQ(1, run_count); // Should have run in a long idle time. + EXPECT_EQ(expected_deadline, deadline_in_task); +} + +TEST_F(RendererSchedulerImplTest, + TestLongIdlePeriodWithLatePendingDelayedTask) { + base::TimeDelta pending_task_delay = base::TimeDelta::FromMilliseconds(10); + base::TimeTicks deadline_in_task; + int run_count = 0; + + default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask), + pending_task_delay); + + // Advance clock until after delayed task was meant to be run. + clock_->Advance(base::TimeDelta::FromMilliseconds(20)); + + // Post an idle task and BeginFrameNotExpectedSoon to initiate a long idle + // period. Since there is a late pending delayed task this shouldn't actually + // start an idle period. + idle_task_runner_->PostIdleTask( + FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + scheduler_->BeginFrameNotExpectedSoon(); + RunUntilIdle(); + EXPECT_EQ(0, run_count); + + // After the delayed task has been run we should trigger an idle period. + clock_->Advance(maximum_idle_period_duration()); + RunUntilIdle(); + EXPECT_EQ(1, run_count); +} + +TEST_F(RendererSchedulerImplTest, TestLongIdlePeriodRepeating) { + mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true); + std::vector<base::TimeTicks> actual_deadlines; + int run_count = 0; + + max_idle_task_reposts = 3; + base::TimeTicks clock_before(clock_->NowTicks()); + base::TimeDelta idle_task_runtime(base::TimeDelta::FromMilliseconds(10)); + idle_task_runner_->PostIdleTask( + FROM_HERE, + base::Bind(&RepostingUpdateClockIdleTestTask, + base::RetainedRef(idle_task_runner_), &run_count, clock_.get(), + idle_task_runtime, &actual_deadlines)); + scheduler_->BeginFrameNotExpectedSoon(); + RunUntilIdle(); + EXPECT_EQ(3, run_count); + EXPECT_THAT( + actual_deadlines, + testing::ElementsAre( + clock_before + maximum_idle_period_duration(), + clock_before + idle_task_runtime + maximum_idle_period_duration(), + clock_before + (2 * idle_task_runtime) + + maximum_idle_period_duration())); + + // Check that idle tasks don't run after the idle period ends with a + // new BeginMainFrame. + max_idle_task_reposts = 5; + idle_task_runner_->PostIdleTask( + FROM_HERE, + base::Bind(&RepostingUpdateClockIdleTestTask, + base::RetainedRef(idle_task_runner_), &run_count, clock_.get(), + idle_task_runtime, &actual_deadlines)); + idle_task_runner_->PostIdleTask( + FROM_HERE, base::Bind(&WillBeginFrameIdleTask, + base::Unretained(scheduler_.get()), clock_.get())); + RunUntilIdle(); + EXPECT_EQ(4, run_count); +} + +TEST_F(RendererSchedulerImplTest, TestLongIdlePeriodDoesNotWakeScheduler) { + base::TimeTicks deadline_in_task; + int run_count = 0; + + // Start a long idle period and get the time it should end. + scheduler_->BeginFrameNotExpectedSoon(); + // The scheduler should not run the initiate_next_long_idle_period task if + // there are no idle tasks and no other task woke up the scheduler, thus + // the idle period deadline shouldn't update at the end of the current long + // idle period. + base::TimeTicks idle_period_deadline = + scheduler_->CurrentIdleTaskDeadlineForTesting(); + clock_->Advance(maximum_idle_period_duration()); + RunUntilIdle(); + + base::TimeTicks new_idle_period_deadline = + scheduler_->CurrentIdleTaskDeadlineForTesting(); + EXPECT_EQ(idle_period_deadline, new_idle_period_deadline); + + // Posting a after-wakeup idle task also shouldn't wake the scheduler or + // initiate the next long idle period. + idle_task_runner_->PostIdleTaskAfterWakeup( + FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + RunUntilIdle(); + new_idle_period_deadline = scheduler_->CurrentIdleTaskDeadlineForTesting(); + EXPECT_EQ(idle_period_deadline, new_idle_period_deadline); + EXPECT_EQ(0, run_count); + + // Running a normal task should initiate a new long idle period though. + default_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask)); + RunUntilIdle(); + new_idle_period_deadline = scheduler_->CurrentIdleTaskDeadlineForTesting(); + EXPECT_EQ(idle_period_deadline + maximum_idle_period_duration(), + new_idle_period_deadline); + + EXPECT_EQ(1, run_count); +} + +TEST_F(RendererSchedulerImplTest, TestLongIdlePeriodInTouchStartPolicy) { + base::TimeTicks deadline_in_task; + int run_count = 0; + + idle_task_runner_->PostIdleTask( + FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + + // Observation of touchstart should defer the start of the long idle period. + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchStart), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + scheduler_->BeginFrameNotExpectedSoon(); + RunUntilIdle(); + EXPECT_EQ(0, run_count); + + // The long idle period should start after the touchstart policy has finished. + clock_->Advance(priority_escalation_after_input_duration()); + RunUntilIdle(); + EXPECT_EQ(1, run_count); +} + +void TestCanExceedIdleDeadlineIfRequiredTask(RendererScheduler* scheduler, + bool* can_exceed_idle_deadline_out, + int* run_count, + base::TimeTicks deadline) { + *can_exceed_idle_deadline_out = scheduler->CanExceedIdleDeadlineIfRequired(); + (*run_count)++; +} + +TEST_F(RendererSchedulerImplTest, CanExceedIdleDeadlineIfRequired) { + int run_count = 0; + bool can_exceed_idle_deadline = false; + + // Should return false if not in an idle period. + EXPECT_FALSE(scheduler_->CanExceedIdleDeadlineIfRequired()); + + // Should return false for short idle periods. + idle_task_runner_->PostIdleTask( + FROM_HERE, + base::Bind(&TestCanExceedIdleDeadlineIfRequiredTask, scheduler_.get(), + &can_exceed_idle_deadline, &run_count)); + EnableIdleTasks(); + RunUntilIdle(); + EXPECT_EQ(1, run_count); + EXPECT_FALSE(can_exceed_idle_deadline); + + // Should return false for a long idle period which is shortened due to a + // pending delayed task. + default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask), + base::TimeDelta::FromMilliseconds(10)); + idle_task_runner_->PostIdleTask( + FROM_HERE, + base::Bind(&TestCanExceedIdleDeadlineIfRequiredTask, scheduler_.get(), + &can_exceed_idle_deadline, &run_count)); + scheduler_->BeginFrameNotExpectedSoon(); + RunUntilIdle(); + EXPECT_EQ(2, run_count); + EXPECT_FALSE(can_exceed_idle_deadline); + + // Next long idle period will be for the maximum time, so + // CanExceedIdleDeadlineIfRequired should return true. + clock_->Advance(maximum_idle_period_duration()); + idle_task_runner_->PostIdleTask( + FROM_HERE, + base::Bind(&TestCanExceedIdleDeadlineIfRequiredTask, scheduler_.get(), + &can_exceed_idle_deadline, &run_count)); + RunUntilIdle(); + EXPECT_EQ(3, run_count); + EXPECT_TRUE(can_exceed_idle_deadline); + + // Next long idle period will be for the maximum time, so + // CanExceedIdleDeadlineIfRequired should return true. + scheduler_->WillBeginFrame(cc::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), + base::TimeDelta::FromMilliseconds(1000), cc::BeginFrameArgs::NORMAL)); + EXPECT_FALSE(scheduler_->CanExceedIdleDeadlineIfRequired()); +} + +TEST_F(RendererSchedulerImplTest, TestRendererHiddenIdlePeriod) { + int run_count = 0; + + max_idle_task_reposts = 2; + idle_task_runner_->PostIdleTask( + FROM_HERE, base::Bind(&RepostingIdleTestTask, + base::RetainedRef(idle_task_runner_), &run_count)); + + // Renderer should start in visible state. + RunUntilIdle(); + EXPECT_EQ(0, run_count); + + // When we hide the renderer it should start a max deadline idle period, which + // will run an idle task and then immediately start a new idle period, which + // runs the second idle task. + scheduler_->SetAllRenderWidgetsHidden(true); + RunUntilIdle(); + EXPECT_EQ(2, run_count); + + // Advance time by amount of time by the maximum amount of time we execute + // idle tasks when hidden (plus some slack) - idle period should have ended. + max_idle_task_reposts = 3; + idle_task_runner_->PostIdleTask( + FROM_HERE, base::Bind(&RepostingIdleTestTask, + base::RetainedRef(idle_task_runner_), &run_count)); + clock_->Advance(end_idle_when_hidden_delay() + + base::TimeDelta::FromMilliseconds(10)); + RunUntilIdle(); + EXPECT_EQ(2, run_count); +} + +TEST_F(RendererSchedulerImplTest, TimerQueueEnabledByDefault) { + std::vector<std::string> run_order; + PostTestTasks(&run_order, "T1 T2"); + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("T1"), std::string("T2"))); +} + +TEST_F(RendererSchedulerImplTest, SuspendAndResumeTimerQueue) { + std::vector<std::string> run_order; + PostTestTasks(&run_order, "T1 T2"); + + scheduler_->SuspendTimerQueue(); + RunUntilIdle(); + EXPECT_TRUE(run_order.empty()); + + scheduler_->ResumeTimerQueue(); + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("T1"), std::string("T2"))); +} + +TEST_F(RendererSchedulerImplTest, SuspendAndThrottleTimerQueue) { + std::vector<std::string> run_order; + PostTestTasks(&run_order, "T1 T2"); + + scheduler_->SuspendTimerQueue(); + RunUntilIdle(); + scheduler_->throttling_helper()->IncreaseThrottleRefCount( + static_cast<TaskQueue*>(timer_task_runner_.get())); + RunUntilIdle(); + EXPECT_TRUE(run_order.empty()); +} + +TEST_F(RendererSchedulerImplTest, ThrottleAndSuspendTimerQueue) { + std::vector<std::string> run_order; + PostTestTasks(&run_order, "T1 T2"); + + scheduler_->throttling_helper()->IncreaseThrottleRefCount( + static_cast<TaskQueue*>(timer_task_runner_.get())); + RunUntilIdle(); + scheduler_->SuspendTimerQueue(); + RunUntilIdle(); + EXPECT_TRUE(run_order.empty()); +} + +TEST_F(RendererSchedulerImplTest, MultipleSuspendsNeedMultipleResumes) { + std::vector<std::string> run_order; + PostTestTasks(&run_order, "T1 T2"); + + scheduler_->SuspendTimerQueue(); + scheduler_->SuspendTimerQueue(); + scheduler_->SuspendTimerQueue(); + RunUntilIdle(); + EXPECT_TRUE(run_order.empty()); + + scheduler_->ResumeTimerQueue(); + RunUntilIdle(); + EXPECT_TRUE(run_order.empty()); + + scheduler_->ResumeTimerQueue(); + RunUntilIdle(); + EXPECT_TRUE(run_order.empty()); + + scheduler_->ResumeTimerQueue(); + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("T1"), std::string("T2"))); +} + +TEST_F(RendererSchedulerImplTest, SuspendRenderer) { + // Assume that the renderer is backgrounded. + scheduler_->OnRendererBackgrounded(); + + // Tasks in some queues don't fire when the renderer is suspended. + std::vector<std::string> run_order; + PostTestTasks(&run_order, "D1 C1 L1 I1 T1"); + scheduler_->SuspendRenderer(); + EnableIdleTasks(); + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("D1"), std::string("C1"), + std::string("I1"))); + + // The rest queued tasks fire when the tab goes foregrounded. + run_order.clear(); + scheduler_->OnRendererForegrounded(); + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("L1"), std::string("T1"))); +} + +TEST_F(RendererSchedulerImplTest, UseCaseToString) { + CheckAllUseCaseToString(); +} + +TEST_F(RendererSchedulerImplTest, MismatchedDidHandleInputEventOnMainThread) { + // This should not DCHECK because there was no corresponding compositor side + // call to DidHandleInputEventOnCompositorThread with + // INPUT_EVENT_ACK_STATE_NOT_CONSUMED. There are legitimate reasons for the + // compositor to not be there and we don't want to make debugging impossible. + scheduler_->DidHandleInputEventOnMainThread( + FakeInputEvent(blink::WebInputEvent::GestureFlingStart)); +} + +TEST_F(RendererSchedulerImplTest, BeginMainFrameOnCriticalPath) { + ASSERT_FALSE(scheduler_->BeginMainFrameOnCriticalPath()); + + cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), + base::TimeDelta::FromMilliseconds(1000), cc::BeginFrameArgs::NORMAL); + scheduler_->WillBeginFrame(begin_frame_args); + ASSERT_TRUE(scheduler_->BeginMainFrameOnCriticalPath()); + + begin_frame_args.on_critical_path = false; + scheduler_->WillBeginFrame(begin_frame_args); + ASSERT_FALSE(scheduler_->BeginMainFrameOnCriticalPath()); +} + +TEST_F(RendererSchedulerImplTest, ShutdownPreventsPostingOfNewTasks) { + scheduler_->Shutdown(); + std::vector<std::string> run_order; + PostTestTasks(&run_order, "D1 C1"); + RunUntilIdle(); + EXPECT_TRUE(run_order.empty()); +} + +TEST_F(RendererSchedulerImplTest, TestRendererBackgroundedTimerSuspension) { + scheduler_->SetTimerQueueSuspensionWhenBackgroundedEnabled(true); + + std::vector<std::string> run_order; + PostTestTasks(&run_order, "T1 T2"); + + // The background signal will not immediately suspend the timer queue. + scheduler_->OnRendererBackgrounded(); + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("T1"), std::string("T2"))); + + run_order.clear(); + PostTestTasks(&run_order, "T3"); + RunUntilIdle(); + EXPECT_THAT(run_order, testing::ElementsAre(std::string("T3"))); + + // Advance the time until after the scheduled timer queue suspension. + run_order.clear(); + clock_->Advance(suspend_timers_when_backgrounded_delay() + + base::TimeDelta::FromMilliseconds(10)); + RunUntilIdle(); + ASSERT_TRUE(run_order.empty()); + + // Timer tasks should be suspended until the foregrounded signal. + PostTestTasks(&run_order, "T4 T5"); + RunUntilIdle(); + EXPECT_TRUE(run_order.empty()); + + scheduler_->OnRendererForegrounded(); + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("T4"), std::string("T5"))); + + // Subsequent timer tasks should fire as usual. + run_order.clear(); + PostTestTasks(&run_order, "T6"); + RunUntilIdle(); + EXPECT_THAT(run_order, testing::ElementsAre(std::string("T6"))); +} + +TEST_F(RendererSchedulerImplTest, + ExpensiveLoadingTasksNotBlockedTillFirstBeginMainFrame) { + std::vector<std::string> run_order; + + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + SimulateExpensiveTasks(loading_task_runner_); + ForceTouchStartToBeExpectedSoon(); + PostTestTasks(&run_order, "L1 D1"); + RunUntilIdle(); + + EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); + EXPECT_FALSE(HaveSeenABeginMainframe()); + EXPECT_TRUE(LoadingTasksSeemExpensive()); + EXPECT_FALSE(TimerTasksSeemExpensive()); + EXPECT_TRUE(TouchStartExpectedSoon()); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("L1"), std::string("D1"))); + + // Emit a BeginMainFrame, and the loading task should get blocked. + DoMainFrame(); + run_order.clear(); + + PostTestTasks(&run_order, "L1 D1"); + RunUntilIdle(); + + EXPECT_EQ(RendererSchedulerImpl::UseCase::NONE, CurrentUseCase()); + EXPECT_TRUE(HaveSeenABeginMainframe()); + EXPECT_TRUE(LoadingTasksSeemExpensive()); + EXPECT_FALSE(TimerTasksSeemExpensive()); + EXPECT_TRUE(TouchStartExpectedSoon()); + EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1"))); + EXPECT_EQ(v8::PERFORMANCE_RESPONSE, RAILMode()); +} + +TEST_F(RendererSchedulerImplTest, + ExpensiveLoadingTasksNotBlockedIfNoTouchHandler) { + std::vector<std::string> run_order; + + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(false); + DoMainFrame(); + SimulateExpensiveTasks(loading_task_runner_); + ForceTouchStartToBeExpectedSoon(); + PostTestTasks(&run_order, "L1 D1"); + RunUntilIdle(); + + EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); + EXPECT_TRUE(HaveSeenABeginMainframe()); + EXPECT_TRUE(LoadingTasksSeemExpensive()); + EXPECT_FALSE(TimerTasksSeemExpensive()); + EXPECT_FALSE(TouchStartExpectedSoon()); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("L1"), std::string("D1"))); + EXPECT_EQ(v8::PERFORMANCE_ANIMATION, RAILMode()); +} + +TEST_F(RendererSchedulerImplTest, + ExpensiveTimerTaskBlocked_UseCase_NONE_PreviousCompositorGesture) { + std::vector<std::string> run_order; + + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + DoMainFrame(); + SimulateExpensiveTasks(timer_task_runner_); + ForceTouchStartToBeExpectedSoon(); + + PostTestTasks(&run_order, "T1 D1"); + RunUntilIdle(); + + EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); + EXPECT_TRUE(HaveSeenABeginMainframe()); + EXPECT_FALSE(LoadingTasksSeemExpensive()); + EXPECT_TRUE(TimerTasksSeemExpensive()); + EXPECT_TRUE(TouchStartExpectedSoon()); + EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1"))); + EXPECT_EQ(v8::PERFORMANCE_RESPONSE, RAILMode()); +} + +TEST_F(RendererSchedulerImplTest, + ExpensiveTimerTaskNotBlocked_UseCase_NONE_PreviousMainThreadGesture) { + std::vector<std::string> run_order; + + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + DoMainFrame(); + SimulateExpensiveTasks(timer_task_runner_); + + SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START, + blink::WebInputEvent::GestureScrollBegin); + EXPECT_EQ(UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, + ForceUpdatePolicyAndGetCurrentUseCase()); + + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchEnd), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + scheduler_->DidHandleInputEventOnMainThread( + FakeInputEvent(blink::WebInputEvent::TouchEnd)); + + clock_->Advance(priority_escalation_after_input_duration() * 2); + EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); + + PostTestTasks(&run_order, "T1 D1"); + RunUntilIdle(); + + EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); + EXPECT_TRUE(HaveSeenABeginMainframe()); + EXPECT_FALSE(LoadingTasksSeemExpensive()); + EXPECT_TRUE(TimerTasksSeemExpensive()); + EXPECT_TRUE(TouchStartExpectedSoon()); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("T1"), std::string("D1"))); + EXPECT_EQ(v8::PERFORMANCE_ANIMATION, RAILMode()); +} + +TEST_F(RendererSchedulerImplTest, + ExpensiveTimerTaskBlocked_UseCase_COMPOSITOR_GESTURE) { + std::vector<std::string> run_order; + + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + DoMainFrame(); + SimulateExpensiveTasks(timer_task_runner_); + ForceTouchStartToBeExpectedSoon(); + scheduler_->DidAnimateForInputOnCompositorThread(); + + PostTestTasks(&run_order, "T1 D1"); + RunUntilIdle(); + + EXPECT_EQ(UseCase::COMPOSITOR_GESTURE, + ForceUpdatePolicyAndGetCurrentUseCase()); + EXPECT_TRUE(HaveSeenABeginMainframe()); + EXPECT_FALSE(LoadingTasksSeemExpensive()); + EXPECT_TRUE(TimerTasksSeemExpensive()); + EXPECT_TRUE(TouchStartExpectedSoon()); + EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1"))); + EXPECT_EQ(v8::PERFORMANCE_RESPONSE, RAILMode()); +} + +TEST_F(RendererSchedulerImplTest, + ExpensiveTimerTaskNotBlockedIfDisallowed_UseCase_COMPOSITOR_GESTURE) { + std::vector<std::string> run_order; + + scheduler_->SetExpensiveTaskBlockingAllowed(false); + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + DoMainFrame(); + SimulateExpensiveTasks(timer_task_runner_); + ForceTouchStartToBeExpectedSoon(); + scheduler_->DidAnimateForInputOnCompositorThread(); + + PostTestTasks(&run_order, "T1 D1"); + RunUntilIdle(); + + EXPECT_EQ(UseCase::COMPOSITOR_GESTURE, + ForceUpdatePolicyAndGetCurrentUseCase()); + EXPECT_TRUE(HaveSeenABeginMainframe()); + EXPECT_FALSE(LoadingTasksSeemExpensive()); + EXPECT_TRUE(TimerTasksSeemExpensive()); + EXPECT_TRUE(TouchStartExpectedSoon()); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("T1"), std::string("D1"))); + EXPECT_EQ(v8::PERFORMANCE_RESPONSE, RAILMode()); +} + +TEST_F(RendererSchedulerImplTest, + ExpensiveTimerTaskBlocked_EvenIfBeginMainFrameNotExpectedSoon) { + std::vector<std::string> run_order; + + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + DoMainFrame(); + SimulateExpensiveTasks(timer_task_runner_); + ForceTouchStartToBeExpectedSoon(); + scheduler_->BeginFrameNotExpectedSoon(); + + PostTestTasks(&run_order, "T1 D1"); + RunUntilIdle(); + + EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); + EXPECT_TRUE(HaveSeenABeginMainframe()); + EXPECT_FALSE(LoadingTasksSeemExpensive()); + EXPECT_TRUE(TimerTasksSeemExpensive()); + EXPECT_TRUE(TouchStartExpectedSoon()); + EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1"))); + EXPECT_EQ(v8::PERFORMANCE_RESPONSE, RAILMode()); +} + +TEST_F(RendererSchedulerImplTest, + ExpensiveLoadingTasksBlockedIfChildFrameNavigationExpected) { + std::vector<std::string> run_order; + + DoMainFrame(); + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + SimulateExpensiveTasks(loading_task_runner_); + ForceTouchStartToBeExpectedSoon(); + scheduler_->AddPendingNavigation( + blink::WebScheduler::NavigatingFrameType::kChildFrame); + + PostTestTasks(&run_order, "L1 D1"); + RunUntilIdle(); + + // The expensive loading task gets blocked. + EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1"))); + EXPECT_EQ(v8::PERFORMANCE_RESPONSE, RAILMode()); +} + +TEST_F(RendererSchedulerImplTest, + ExpensiveLoadingTasksNotBlockedIfMainFrameNavigationExpected) { + std::vector<std::string> run_order; + + DoMainFrame(); + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + SimulateExpensiveTasks(loading_task_runner_); + ForceTouchStartToBeExpectedSoon(); + scheduler_->AddPendingNavigation( + blink::WebScheduler::NavigatingFrameType::kMainFrame); + + PostTestTasks(&run_order, "L1 D1"); + RunUntilIdle(); + + EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); + EXPECT_TRUE(HaveSeenABeginMainframe()); + EXPECT_TRUE(LoadingTasksSeemExpensive()); + EXPECT_FALSE(TimerTasksSeemExpensive()); + EXPECT_TRUE(TouchStartExpectedSoon()); + EXPECT_EQ(1, NavigationTaskExpectedCount()); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("L1"), std::string("D1"))); + + // After the nagigation has been cancelled, the expensive loading tasks should + // get blocked. + scheduler_->RemovePendingNavigation( + blink::WebScheduler::NavigatingFrameType::kMainFrame); + run_order.clear(); + + PostTestTasks(&run_order, "L1 D1"); + RunUntilIdle(); + + EXPECT_EQ(RendererSchedulerImpl::UseCase::NONE, CurrentUseCase()); + EXPECT_TRUE(HaveSeenABeginMainframe()); + EXPECT_TRUE(LoadingTasksSeemExpensive()); + EXPECT_FALSE(TimerTasksSeemExpensive()); + EXPECT_TRUE(TouchStartExpectedSoon()); + EXPECT_EQ(0, NavigationTaskExpectedCount()); + EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1"))); + EXPECT_EQ(v8::PERFORMANCE_RESPONSE, RAILMode()); +} + +TEST_F(RendererSchedulerImplTest, + ExpensiveLoadingTasksNotBlockedIfMainFrameNavigationExpected_Multiple) { + std::vector<std::string> run_order; + + DoMainFrame(); + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + SimulateExpensiveTasks(loading_task_runner_); + ForceTouchStartToBeExpectedSoon(); + scheduler_->AddPendingNavigation( + blink::WebScheduler::NavigatingFrameType::kMainFrame); + scheduler_->AddPendingNavigation( + blink::WebScheduler::NavigatingFrameType::kMainFrame); + + PostTestTasks(&run_order, "L1 D1"); + RunUntilIdle(); + + EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); + EXPECT_TRUE(HaveSeenABeginMainframe()); + EXPECT_TRUE(LoadingTasksSeemExpensive()); + EXPECT_FALSE(TimerTasksSeemExpensive()); + EXPECT_TRUE(TouchStartExpectedSoon()); + EXPECT_EQ(2, NavigationTaskExpectedCount()); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("L1"), std::string("D1"))); + + run_order.clear(); + scheduler_->RemovePendingNavigation( + blink::WebScheduler::NavigatingFrameType::kMainFrame); + // Navigation task expected ref count non-zero so expensive tasks still not + // blocked. + PostTestTasks(&run_order, "L1 D1"); + RunUntilIdle(); + + EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); + EXPECT_TRUE(HaveSeenABeginMainframe()); + EXPECT_TRUE(LoadingTasksSeemExpensive()); + EXPECT_FALSE(TimerTasksSeemExpensive()); + EXPECT_TRUE(TouchStartExpectedSoon()); + EXPECT_EQ(1, NavigationTaskExpectedCount()); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("L1"), std::string("D1"))); + + run_order.clear(); + scheduler_->RemovePendingNavigation( + blink::WebScheduler::NavigatingFrameType::kMainFrame); + // Navigation task expected ref count is now zero, the expensive loading tasks + // should get blocked. + PostTestTasks(&run_order, "L1 D1"); + RunUntilIdle(); + + EXPECT_EQ(RendererSchedulerImpl::UseCase::NONE, CurrentUseCase()); + EXPECT_TRUE(HaveSeenABeginMainframe()); + EXPECT_TRUE(LoadingTasksSeemExpensive()); + EXPECT_FALSE(TimerTasksSeemExpensive()); + EXPECT_TRUE(TouchStartExpectedSoon()); + EXPECT_EQ(0, NavigationTaskExpectedCount()); + EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1"))); + EXPECT_EQ(v8::PERFORMANCE_RESPONSE, RAILMode()); +} + +TEST_F(RendererSchedulerImplTest, + ExpensiveLoadingTasksNotBlockedDuringMainThreadGestures) { + std::vector<std::string> run_order; + + SimulateExpensiveTasks(loading_task_runner_); + + // Loading tasks should not be disabled during main thread user interactions. + PostTestTasks(&run_order, "C1 L1"); + + // Trigger main_thread_gesture UseCase + SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START, + blink::WebInputEvent::GestureScrollBegin); + RunUntilIdle(); + EXPECT_EQ(RendererSchedulerImpl::UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, + CurrentUseCase()); + + EXPECT_TRUE(LoadingTasksSeemExpensive()); + EXPECT_FALSE(TimerTasksSeemExpensive()); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("C1"), std::string("L1"))); + EXPECT_EQ(v8::PERFORMANCE_ANIMATION, RAILMode()); +} + +TEST_F(RendererSchedulerImplTest, ModeratelyExpensiveTimer_NotBlocked) { + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START, + blink::WebInputEvent::TouchMove); + RunUntilIdle(); + for (int i = 0; i < 20; i++) { + simulate_timer_task_ran_ = false; + + cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), + base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); + begin_frame_args.on_critical_path = false; + scheduler_->WillBeginFrame(begin_frame_args); + + compositor_task_runner_->PostTask( + FROM_HERE, base::Bind(&RendererSchedulerImplTest:: + SimulateMainThreadInputHandlingCompositorTask, + base::Unretained(this), + base::TimeDelta::FromMilliseconds(8))); + timer_task_runner_->PostTask( + FROM_HERE, base::Bind(&RendererSchedulerImplTest::SimulateTimerTask, + base::Unretained(this), + base::TimeDelta::FromMilliseconds(4))); + + RunUntilIdle(); + EXPECT_TRUE(simulate_timer_task_ran_) << " i = " << i; + EXPECT_EQ(RendererSchedulerImpl::UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, + CurrentUseCase()) + << " i = " << i; + EXPECT_FALSE(LoadingTasksSeemExpensive()) << " i = " << i; + EXPECT_FALSE(TimerTasksSeemExpensive()) << " i = " << i; + + base::TimeDelta time_till_next_frame = + EstimatedNextFrameBegin() - clock_->NowTicks(); + if (time_till_next_frame > base::TimeDelta()) + clock_->Advance(time_till_next_frame); + } +} + +TEST_F(RendererSchedulerImplTest, + FourtyMsTimer_NotBlocked_CompositorScrolling) { + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + RunUntilIdle(); + for (int i = 0; i < 20; i++) { + simulate_timer_task_ran_ = false; + + cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), + base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); + begin_frame_args.on_critical_path = false; + scheduler_->WillBeginFrame(begin_frame_args); + scheduler_->DidAnimateForInputOnCompositorThread(); + + compositor_task_runner_->PostTask( + FROM_HERE, + base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask, + base::Unretained(this), + base::TimeDelta::FromMilliseconds(8))); + timer_task_runner_->PostTask( + FROM_HERE, base::Bind(&RendererSchedulerImplTest::SimulateTimerTask, + base::Unretained(this), + base::TimeDelta::FromMilliseconds(40))); + + RunUntilIdle(); + EXPECT_TRUE(simulate_timer_task_ran_) << " i = " << i; + EXPECT_EQ(RendererSchedulerImpl::UseCase::COMPOSITOR_GESTURE, + CurrentUseCase()) + << " i = " << i; + EXPECT_FALSE(LoadingTasksSeemExpensive()) << " i = " << i; + EXPECT_FALSE(TimerTasksSeemExpensive()) << " i = " << i; + + base::TimeDelta time_till_next_frame = + EstimatedNextFrameBegin() - clock_->NowTicks(); + if (time_till_next_frame > base::TimeDelta()) + clock_->Advance(time_till_next_frame); + } +} + +TEST_F(RendererSchedulerImplTest, + ExpensiveTimer_NotBlocked_UseCase_MAIN_THREAD_CUSTOM_INPUT_HANDLING) { + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START, + blink::WebInputEvent::TouchMove); + RunUntilIdle(); + for (int i = 0; i < 20; i++) { + simulate_timer_task_ran_ = false; + + cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), + base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); + begin_frame_args.on_critical_path = false; + scheduler_->WillBeginFrame(begin_frame_args); + + compositor_task_runner_->PostTask( + FROM_HERE, base::Bind(&RendererSchedulerImplTest:: + SimulateMainThreadInputHandlingCompositorTask, + base::Unretained(this), + base::TimeDelta::FromMilliseconds(8))); + timer_task_runner_->PostTask( + FROM_HERE, base::Bind(&RendererSchedulerImplTest::SimulateTimerTask, + base::Unretained(this), + base::TimeDelta::FromMilliseconds(10))); + + RunUntilIdle(); + EXPECT_EQ(RendererSchedulerImpl::UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, + CurrentUseCase()) + << " i = " << i; + EXPECT_FALSE(LoadingTasksSeemExpensive()) << " i = " << i; + if (i == 0) { + EXPECT_FALSE(TimerTasksSeemExpensive()) << " i = " << i; + } else { + EXPECT_TRUE(TimerTasksSeemExpensive()) << " i = " << i; + } + EXPECT_TRUE(simulate_timer_task_ran_) << " i = " << i; + + base::TimeDelta time_till_next_frame = + EstimatedNextFrameBegin() - clock_->NowTicks(); + if (time_till_next_frame > base::TimeDelta()) + clock_->Advance(time_till_next_frame); + } +} + +TEST_F(RendererSchedulerImplTest, + EstimateLongestJankFreeTaskDuration_UseCase_NONE) { + EXPECT_EQ(UseCase::NONE, CurrentUseCase()); + EXPECT_EQ(rails_response_time(), + scheduler_->EstimateLongestJankFreeTaskDuration()); +} + +TEST_F(RendererSchedulerImplTest, + EstimateLongestJankFreeTaskDuration_UseCase_COMPOSITOR_GESTURE) { + SimulateCompositorGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START); + EXPECT_EQ(UseCase::COMPOSITOR_GESTURE, + ForceUpdatePolicyAndGetCurrentUseCase()); + EXPECT_EQ(rails_response_time(), + scheduler_->EstimateLongestJankFreeTaskDuration()); +} + +// TODO(alexclarke): Reenable once we've reinstaed the Loading UseCase. +TEST_F(RendererSchedulerImplTest, + DISABLED_EstimateLongestJankFreeTaskDuration_UseCase_) { + scheduler_->OnNavigationStarted(); + EXPECT_EQ(UseCase::LOADING, ForceUpdatePolicyAndGetCurrentUseCase()); + EXPECT_EQ(rails_response_time(), + scheduler_->EstimateLongestJankFreeTaskDuration()); +} + +TEST_F(RendererSchedulerImplTest, + EstimateLongestJankFreeTaskDuration_UseCase_MAIN_THREAD_GESTURE) { + SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START, + blink::WebInputEvent::GestureScrollUpdate); + cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), + base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); + begin_frame_args.on_critical_path = false; + scheduler_->WillBeginFrame(begin_frame_args); + + compositor_task_runner_->PostTask( + FROM_HERE, + base::Bind(&RendererSchedulerImplTest:: + SimulateMainThreadInputHandlingCompositorTask, + base::Unretained(this), base::TimeDelta::FromMilliseconds(5))); + + RunUntilIdle(); + EXPECT_EQ(UseCase::MAIN_THREAD_GESTURE, CurrentUseCase()); + + // 16ms frame - 5ms compositor work = 11ms for other stuff. + EXPECT_EQ(base::TimeDelta::FromMilliseconds(11), + scheduler_->EstimateLongestJankFreeTaskDuration()); +} + +TEST_F( + RendererSchedulerImplTest, + EstimateLongestJankFreeTaskDuration_UseCase_MAIN_THREAD_CUSTOM_INPUT_HANDLING) { + cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), + base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); + begin_frame_args.on_critical_path = false; + scheduler_->WillBeginFrame(begin_frame_args); + + compositor_task_runner_->PostTask( + FROM_HERE, + base::Bind(&RendererSchedulerImplTest:: + SimulateMainThreadInputHandlingCompositorTask, + base::Unretained(this), base::TimeDelta::FromMilliseconds(5))); + + RunUntilIdle(); + EXPECT_EQ(UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, CurrentUseCase()); + + // 16ms frame - 5ms compositor work = 11ms for other stuff. + EXPECT_EQ(base::TimeDelta::FromMilliseconds(11), + scheduler_->EstimateLongestJankFreeTaskDuration()); +} + +TEST_F(RendererSchedulerImplTest, + EstimateLongestJankFreeTaskDuration_UseCase_SYNCHRONIZED_GESTURE) { + SimulateCompositorGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START); + + cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), + base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); + begin_frame_args.on_critical_path = true; + scheduler_->WillBeginFrame(begin_frame_args); + + compositor_task_runner_->PostTask( + FROM_HERE, + base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask, + base::Unretained(this), base::TimeDelta::FromMilliseconds(5))); + + RunUntilIdle(); + EXPECT_EQ(UseCase::SYNCHRONIZED_GESTURE, CurrentUseCase()); + + // 16ms frame - 5ms compositor work = 11ms for other stuff. + EXPECT_EQ(base::TimeDelta::FromMilliseconds(11), + scheduler_->EstimateLongestJankFreeTaskDuration()); +} + +class WebViewSchedulerImplForTest : public WebViewSchedulerImpl { + public: + WebViewSchedulerImplForTest(RendererSchedulerImpl* scheduler) + : WebViewSchedulerImpl(nullptr, scheduler, false) {} + ~WebViewSchedulerImplForTest() override {} + + void ReportIntervention(const std::string& message) override { + interventions_.push_back(message); + } + + const std::vector<std::string>& interventions() const { + return interventions_; + } + + private: + std::vector<std::string> interventions_; + + DISALLOW_COPY_AND_ASSIGN(WebViewSchedulerImplForTest); +}; + +TEST_F(RendererSchedulerImplTest, BlockedTimerNotification) { + // Make sure we see one (and just one) console warning about an expensive + // timer being deferred. + WebViewSchedulerImplForTest web_view_scheduler(scheduler_.get()); + + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + scheduler_->SetExpensiveTaskBlockingAllowed(true); + DoMainFrame(); + SimulateExpensiveTasks(timer_task_runner_); + SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START); + ForceTouchStartToBeExpectedSoon(); + + std::vector<std::string> run_order; + PostTestTasks(&run_order, "T1 T2"); + RunUntilIdle(); + + EXPECT_EQ(0u, run_order.size()); + EXPECT_EQ(1u, web_view_scheduler.interventions().size()); + EXPECT_NE(std::string::npos, + web_view_scheduler.interventions()[0].find("crbug.com/574343")); +} + +TEST_F(RendererSchedulerImplTest, + BlockedTimerNotification_ExpensiveTaskBlockingNotAllowed) { + // Make sure we don't report warnings about blocked tasks when expensive task + // blocking is not allowed. + WebViewSchedulerImplForTest web_view_scheduler(scheduler_.get()); + + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + scheduler_->SetExpensiveTaskBlockingAllowed(false); + scheduler_->SuspendTimerQueue(); + DoMainFrame(); + SimulateExpensiveTasks(timer_task_runner_); + SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START); + ForceTouchStartToBeExpectedSoon(); + + std::vector<std::string> run_order; + PostTestTasks(&run_order, "T1 T2"); + RunUntilIdle(); + + EXPECT_EQ(0u, run_order.size()); + EXPECT_EQ(0u, web_view_scheduler.interventions().size()); +} + +TEST_F(RendererSchedulerImplTest, BlockedTimerNotification_TimersSuspended) { + // Make sure we don't report warnings about blocked tasks when timers are + // being blocked for other reasons. + WebViewSchedulerImplForTest web_view_scheduler(scheduler_.get()); + + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + scheduler_->SetExpensiveTaskBlockingAllowed(true); + scheduler_->SuspendTimerQueue(); + DoMainFrame(); + SimulateExpensiveTasks(timer_task_runner_); + SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START); + ForceTouchStartToBeExpectedSoon(); + + std::vector<std::string> run_order; + PostTestTasks(&run_order, "T1 T2"); + RunUntilIdle(); + + EXPECT_EQ(0u, run_order.size()); + EXPECT_EQ(0u, web_view_scheduler.interventions().size()); +} + +TEST_F(RendererSchedulerImplTest, BlockedTimerNotification_TOUCHSTART) { + // Make sure we don't report warnings about blocked tasks during TOUCHSTART. + WebViewSchedulerImplForTest web_view_scheduler(scheduler_.get()); + + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + DoMainFrame(); + SimulateExpensiveTasks(timer_task_runner_); + SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchStart), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + EXPECT_EQ(UseCase::TOUCHSTART, ForceUpdatePolicyAndGetCurrentUseCase()); + + std::vector<std::string> run_order; + PostTestTasks(&run_order, "T1 T2"); + RunUntilIdle(); + + EXPECT_EQ(0u, run_order.size()); + EXPECT_EQ(0u, web_view_scheduler.interventions().size()); +} + +TEST_F(RendererSchedulerImplTest, + BlockedTimerNotification_SYNCHRONIZED_GESTURE) { + // Make sure we only report warnings during a high blocking threshold. + WebViewSchedulerImplForTest web_view_scheduler(scheduler_.get()); + + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + DoMainFrame(); + SimulateExpensiveTasks(timer_task_runner_); + SimulateCompositorGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START); + + cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), + base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); + begin_frame_args.on_critical_path = true; + scheduler_->WillBeginFrame(begin_frame_args); + + EXPECT_EQ(UseCase::SYNCHRONIZED_GESTURE, + ForceUpdatePolicyAndGetCurrentUseCase()); + + std::vector<std::string> run_order; + PostTestTasks(&run_order, "T1 T2"); + RunUntilIdle(); + + EXPECT_EQ(0u, run_order.size()); + EXPECT_EQ(0u, web_view_scheduler.interventions().size()); +} + +namespace { +void SlowCountingTask(size_t* count, + base::SimpleTestTickClock* clock, + int task_duration, + scoped_refptr<base::SingleThreadTaskRunner> timer_queue) { + clock->Advance(base::TimeDelta::FromMilliseconds(task_duration)); + if (++(*count) < 500) { + timer_queue->PostTask(FROM_HERE, base::Bind(SlowCountingTask, count, clock, + task_duration, timer_queue)); + } +} +} + +TEST_F(RendererSchedulerImplTest, + SYNCHRONIZED_GESTURE_TimerTaskThrottling_task_expensive) { + SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START); + + base::TimeTicks first_throttled_run_time = + ThrottlingHelper::ThrottledRunTime(clock_->NowTicks()); + + size_t count = 0; + // With the compositor task taking 10ms, there is not enough time to run this + // 7ms timer task in the 16ms frame. + scheduler_->TimerTaskRunner()->PostTask( + FROM_HERE, base::Bind(SlowCountingTask, &count, clock_.get(), 7, + scheduler_->TimerTaskRunner())); + + for (int i = 0; i < 1000; i++) { + cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), + base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); + begin_frame_args.on_critical_path = true; + scheduler_->WillBeginFrame(begin_frame_args); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + + simulate_compositor_task_ran_ = false; + compositor_task_runner_->PostTask( + FROM_HERE, + base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask, + base::Unretained(this), + base::TimeDelta::FromMilliseconds(10))); + + mock_task_runner_->RunTasksWhile( + base::Bind(&RendererSchedulerImplTest::SimulatedCompositorTaskPending, + base::Unretained(this))); + EXPECT_EQ(UseCase::SYNCHRONIZED_GESTURE, CurrentUseCase()) << "i = " << i; + + // Before the policy is updated the queue will be enabled. Subsequently it + // will be disabled until the throttled queue is pumped. + bool expect_queue_enabled = + (i == 0) || (clock_->NowTicks() > first_throttled_run_time); + EXPECT_EQ(expect_queue_enabled, + scheduler_->TimerTaskRunner()->IsQueueEnabled()) + << "i = " << i; + } + + // Task is throttled but not completely blocked. + EXPECT_EQ(12u, count); +} + +TEST_F(RendererSchedulerImplTest, + SYNCHRONIZED_GESTURE_TimerTaskThrottling_TimersSuspended) { + SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START); + + base::TimeTicks first_throttled_run_time = + ThrottlingHelper::ThrottledRunTime(clock_->NowTicks()); + + size_t count = 0; + // With the compositor task taking 10ms, there is not enough time to run this + // 7ms timer task in the 16ms frame. + scheduler_->TimerTaskRunner()->PostTask( + FROM_HERE, base::Bind(SlowCountingTask, &count, clock_.get(), 7, + scheduler_->TimerTaskRunner())); + + bool suspended = false; + for (int i = 0; i < 1000; i++) { + cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), + base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); + begin_frame_args.on_critical_path = true; + scheduler_->WillBeginFrame(begin_frame_args); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + + simulate_compositor_task_ran_ = false; + compositor_task_runner_->PostTask( + FROM_HERE, + base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask, + base::Unretained(this), + base::TimeDelta::FromMilliseconds(10))); + + mock_task_runner_->RunTasksWhile( + base::Bind(&RendererSchedulerImplTest::SimulatedCompositorTaskPending, + base::Unretained(this))); + EXPECT_EQ(UseCase::SYNCHRONIZED_GESTURE, CurrentUseCase()) << "i = " << i; + + // Before the policy is updated the queue will be enabled. Subsequently it + // will be disabled until the throttled queue is pumped. + bool expect_queue_enabled = + (i == 0) || (clock_->NowTicks() > first_throttled_run_time); + if (suspended) + expect_queue_enabled = false; + EXPECT_EQ(expect_queue_enabled, + scheduler_->TimerTaskRunner()->IsQueueEnabled()) + << "i = " << i; + + // After we've run any expensive tasks suspend the queue. The throttling + // helper should /not/ re-enable this queue under any circumstances while + // timers are suspended. + if (count > 0 && !suspended) { + EXPECT_EQ(2u, count); + scheduler_->SuspendTimerQueue(); + suspended = true; + } + } + + // Make sure the timer queue stayed suspended! + EXPECT_EQ(2u, count); +} + +TEST_F(RendererSchedulerImplTest, + SYNCHRONIZED_GESTURE_TimerTaskThrottling_task_not_expensive) { + SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START); + + size_t count = 0; + // With the compositor task taking 10ms, there is enough time to run this 6ms + // timer task in the 16ms frame. + scheduler_->TimerTaskRunner()->PostTask( + FROM_HERE, base::Bind(SlowCountingTask, &count, clock_.get(), 6, + scheduler_->TimerTaskRunner())); + + for (int i = 0; i < 1000; i++) { + cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), + base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); + begin_frame_args.on_critical_path = true; + scheduler_->WillBeginFrame(begin_frame_args); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + + simulate_compositor_task_ran_ = false; + compositor_task_runner_->PostTask( + FROM_HERE, + base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask, + base::Unretained(this), + base::TimeDelta::FromMilliseconds(10))); + + mock_task_runner_->RunTasksWhile( + base::Bind(&RendererSchedulerImplTest::SimulatedCompositorTaskPending, + base::Unretained(this))); + EXPECT_EQ(UseCase::SYNCHRONIZED_GESTURE, CurrentUseCase()) << "i = " << i; + EXPECT_TRUE(scheduler_->TimerTaskRunner()->IsQueueEnabled()) << "i = " << i; + } + + // Task is not throttled. + EXPECT_EQ(500u, count); +} + +TEST_F(RendererSchedulerImplTest, + ExpensiveTimerTaskBlocked_SYNCHRONIZED_GESTURE_TouchStartExpected) { + SimulateExpensiveTasks(timer_task_runner_); + SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START); + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + ForceTouchStartToBeExpectedSoon(); + + // Bump us into SYNCHRONIZED_GESTURE. + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + + cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), + base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); + begin_frame_args.on_critical_path = true; + scheduler_->WillBeginFrame(begin_frame_args); + + EXPECT_EQ(UseCase::SYNCHRONIZED_GESTURE, + ForceUpdatePolicyAndGetCurrentUseCase()); + + EXPECT_TRUE(TimerTasksSeemExpensive()); + EXPECT_TRUE(TouchStartExpectedSoon()); + EXPECT_FALSE(scheduler_->TimerTaskRunner()->IsQueueEnabled()); +} + +TEST_F(RendererSchedulerImplTest, DenyLongIdleDuringTouchStart) { + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchStart), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + EXPECT_EQ(UseCase::TOUCHSTART, ForceUpdatePolicyAndGetCurrentUseCase()); + + // First check that long idle is denied during the TOUCHSTART use case. + IdleHelper::Delegate* idle_delegate = scheduler_.get(); + base::TimeTicks now; + base::TimeDelta next_time_to_check; + EXPECT_FALSE(idle_delegate->CanEnterLongIdlePeriod(now, &next_time_to_check)); + EXPECT_GE(next_time_to_check, base::TimeDelta()); + + // Check again at a time past the TOUCHSTART expiration. We should still get a + // non-negative delay to when to check again. + now += base::TimeDelta::FromMilliseconds(500); + EXPECT_FALSE(idle_delegate->CanEnterLongIdlePeriod(now, &next_time_to_check)); + EXPECT_GE(next_time_to_check, base::TimeDelta()); +} + +TEST_F(RendererSchedulerImplTest, TestCompositorPolicy_TouchStartDuringFling) { + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + scheduler_->DidAnimateForInputOnCompositorThread(); + // Note DidAnimateForInputOnCompositorThread does not by itself trigger a + // policy update. + EXPECT_EQ(RendererSchedulerImpl::UseCase::COMPOSITOR_GESTURE, + ForceUpdatePolicyAndGetCurrentUseCase()); + + // Make sure TouchStart causes a policy change. + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchStart), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + EXPECT_EQ(RendererSchedulerImpl::UseCase::TOUCHSTART, + ForceUpdatePolicyAndGetCurrentUseCase()); +} + +TEST_F(RendererSchedulerImplTest, SYNCHRONIZED_GESTURE_CompositingExpensive) { + SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START); + + // With the compositor task taking 20ms, there is not enough time to run + // other tasks in the same 16ms frame. To avoid starvation, compositing tasks + // should therefore not get prioritized. + std::vector<std::string> run_order; + for (int i = 0; i < 1000; i++) + PostTestTasks(&run_order, "T1"); + + for (int i = 0; i < 100; i++) { + cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), + base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); + begin_frame_args.on_critical_path = true; + scheduler_->WillBeginFrame(begin_frame_args); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + + simulate_compositor_task_ran_ = false; + compositor_task_runner_->PostTask( + FROM_HERE, + base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask, + base::Unretained(this), + base::TimeDelta::FromMilliseconds(20))); + + mock_task_runner_->RunTasksWhile( + base::Bind(&RendererSchedulerImplTest::SimulatedCompositorTaskPending, + base::Unretained(this))); + EXPECT_EQ(UseCase::SYNCHRONIZED_GESTURE, CurrentUseCase()) << "i = " << i; + } + + // Timer tasks should not have been starved by the expensive compositor + // tasks. + EXPECT_EQ(TaskQueue::NORMAL_PRIORITY, + scheduler_->CompositorTaskRunner()->GetQueuePriority()); + EXPECT_EQ(1000u, run_order.size()); +} + +TEST_F(RendererSchedulerImplTest, MAIN_THREAD_CUSTOM_INPUT_HANDLING) { + SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START, + blink::WebInputEvent::GestureScrollBegin); + + // With the compositor task taking 20ms, there is not enough time to run + // other tasks in the same 16ms frame. To avoid starvation, compositing tasks + // should therefore not get prioritized. + std::vector<std::string> run_order; + for (int i = 0; i < 1000; i++) + PostTestTasks(&run_order, "T1"); + + for (int i = 0; i < 100; i++) { + cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), + base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); + begin_frame_args.on_critical_path = true; + scheduler_->WillBeginFrame(begin_frame_args); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::TouchMove), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + + simulate_compositor_task_ran_ = false; + compositor_task_runner_->PostTask( + FROM_HERE, + base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask, + base::Unretained(this), + base::TimeDelta::FromMilliseconds(20))); + + mock_task_runner_->RunTasksWhile( + base::Bind(&RendererSchedulerImplTest::SimulatedCompositorTaskPending, + base::Unretained(this))); + EXPECT_EQ(UseCase::MAIN_THREAD_CUSTOM_INPUT_HANDLING, CurrentUseCase()) + << "i = " << i; + } + + // Timer tasks should not have been starved by the expensive compositor + // tasks. + EXPECT_EQ(TaskQueue::NORMAL_PRIORITY, + scheduler_->CompositorTaskRunner()->GetQueuePriority()); + EXPECT_EQ(1000u, run_order.size()); +} + +TEST_F(RendererSchedulerImplTest, MAIN_THREAD_GESTURE) { + SimulateMainThreadGestureStart(TouchEventPolicy::DONT_SEND_TOUCH_START, + blink::WebInputEvent::GestureScrollBegin); + + // With the compositor task taking 20ms, there is not enough time to run + // other tasks in the same 16ms frame. However because this is a main thread + // gesture instead of custom main thread input handling, we allow the timer + // tasks to be starved. + std::vector<std::string> run_order; + for (int i = 0; i < 1000; i++) + PostTestTasks(&run_order, "T1"); + + for (int i = 0; i < 100; i++) { + cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), + base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); + begin_frame_args.on_critical_path = true; + scheduler_->WillBeginFrame(begin_frame_args); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate), + RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); + + simulate_compositor_task_ran_ = false; + compositor_task_runner_->PostTask( + FROM_HERE, + base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask, + base::Unretained(this), + base::TimeDelta::FromMilliseconds(20))); + + mock_task_runner_->RunTasksWhile( + base::Bind(&RendererSchedulerImplTest::SimulatedCompositorTaskPending, + base::Unretained(this))); + EXPECT_EQ(UseCase::MAIN_THREAD_GESTURE, CurrentUseCase()) << "i = " << i; + } + + EXPECT_EQ(TaskQueue::HIGH_PRIORITY, + scheduler_->CompositorTaskRunner()->GetQueuePriority()); + EXPECT_EQ(279u, run_order.size()); +} + +class MockRAILModeObserver : public RendererScheduler::RAILModeObserver { + public: + MOCK_METHOD1(OnRAILModeChanged, void(v8::RAILMode rail_mode)); +}; + +TEST_F(RendererSchedulerImplTest, TestResponseRAILMode) { + MockRAILModeObserver observer; + scheduler_->SetRAILModeObserver(&observer); + EXPECT_CALL(observer, OnRAILModeChanged(v8::PERFORMANCE_RESPONSE)); + + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + ForceTouchStartToBeExpectedSoon(); + EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); + EXPECT_EQ(v8::PERFORMANCE_RESPONSE, RAILMode()); + scheduler_->SetRAILModeObserver(nullptr); +} + +TEST_F(RendererSchedulerImplTest, TestAnimateRAILMode) { + MockRAILModeObserver observer; + scheduler_->SetRAILModeObserver(&observer); + EXPECT_CALL(observer, OnRAILModeChanged(v8::PERFORMANCE_ANIMATION)).Times(0); + + EXPECT_FALSE(BeginFrameNotExpectedSoon()); + EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); + EXPECT_EQ(v8::PERFORMANCE_ANIMATION, RAILMode()); + scheduler_->SetRAILModeObserver(nullptr); +} + +TEST_F(RendererSchedulerImplTest, TestIdleRAILMode) { + MockRAILModeObserver observer; + scheduler_->SetRAILModeObserver(&observer); + EXPECT_CALL(observer, OnRAILModeChanged(v8::PERFORMANCE_ANIMATION)); + EXPECT_CALL(observer, OnRAILModeChanged(v8::PERFORMANCE_IDLE)); + + scheduler_->SetAllRenderWidgetsHidden(true); + EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); + EXPECT_EQ(v8::PERFORMANCE_IDLE, RAILMode()); + scheduler_->SetAllRenderWidgetsHidden(false); + EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); + EXPECT_EQ(v8::PERFORMANCE_ANIMATION, RAILMode()); + scheduler_->SetRAILModeObserver(nullptr); +} + +TEST_F(RendererSchedulerImplTest, UnthrottledTaskRunner) { + // Ensure neither suspension nor timer task throttling affects an unthrottled + // task runner. + SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START); + scoped_refptr<TaskQueue> unthrottled_task_runner = + scheduler_->NewUnthrottledTaskRunner("unthrottled_tq"); + + size_t timer_count = 0; + size_t unthrottled_count = 0; + scheduler_->TimerTaskRunner()->PostTask( + FROM_HERE, base::Bind(SlowCountingTask, &timer_count, clock_.get(), 7, + scheduler_->TimerTaskRunner())); + unthrottled_task_runner->PostTask( + FROM_HERE, base::Bind(SlowCountingTask, &unthrottled_count, clock_.get(), + 7, unthrottled_task_runner)); + scheduler_->SuspendTimerQueue(); + + for (int i = 0; i < 1000; i++) { + cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), + base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); + begin_frame_args.on_critical_path = true; + scheduler_->WillBeginFrame(begin_frame_args); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + + simulate_compositor_task_ran_ = false; + compositor_task_runner_->PostTask( + FROM_HERE, + base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask, + base::Unretained(this), + base::TimeDelta::FromMilliseconds(10))); + + mock_task_runner_->RunTasksWhile( + base::Bind(&RendererSchedulerImplTest::SimulatedCompositorTaskPending, + base::Unretained(this))); + EXPECT_EQ(UseCase::SYNCHRONIZED_GESTURE, CurrentUseCase()) << "i = " << i; + } + + EXPECT_EQ(0u, timer_count); + EXPECT_EQ(500u, unthrottled_count); +} + +TEST_F(RendererSchedulerImplTest, EnableVirtualTime) { + scheduler_->EnableVirtualTime(); + + scoped_refptr<TaskQueue> loading_tq = + scheduler_->NewLoadingTaskRunner("test"); + scoped_refptr<TaskQueue> timer_tq = scheduler_->NewTimerTaskRunner("test"); + scoped_refptr<TaskQueue> unthrottled_tq = + scheduler_->NewUnthrottledTaskRunner("test"); + + EXPECT_EQ(scheduler_->DefaultTaskRunner()->GetTimeDomain(), + scheduler_->GetVirtualTimeDomain()); + EXPECT_EQ(scheduler_->CompositorTaskRunner()->GetTimeDomain(), + scheduler_->GetVirtualTimeDomain()); + EXPECT_EQ(scheduler_->LoadingTaskRunner()->GetTimeDomain(), + scheduler_->GetVirtualTimeDomain()); + EXPECT_EQ(scheduler_->TimerTaskRunner()->GetTimeDomain(), + scheduler_->GetVirtualTimeDomain()); + + EXPECT_EQ(loading_tq->GetTimeDomain(), scheduler_->GetVirtualTimeDomain()); + EXPECT_EQ(timer_tq->GetTimeDomain(), scheduler_->GetVirtualTimeDomain()); + EXPECT_EQ(unthrottled_tq->GetTimeDomain(), + scheduler_->GetVirtualTimeDomain()); + + EXPECT_EQ(scheduler_->NewLoadingTaskRunner("test")->GetTimeDomain(), + scheduler_->GetVirtualTimeDomain()); + EXPECT_EQ(scheduler_->NewTimerTaskRunner("test")->GetTimeDomain(), + scheduler_->GetVirtualTimeDomain()); + EXPECT_EQ(scheduler_->NewUnthrottledTaskRunner("test")->GetTimeDomain(), + scheduler_->GetVirtualTimeDomain()); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_web_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_web_scheduler_impl.cc new file mode 100644 index 0000000..e97cac82 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_web_scheduler_impl.cc
@@ -0,0 +1,50 @@ +// 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 "platform/scheduler/renderer/renderer_web_scheduler_impl.h" + +#include <memory> + +#include "base/memory/ptr_util.h" +#include "public/platform/scheduler/base/task_queue.h" +#include "platform/scheduler/renderer/renderer_scheduler_impl.h" +#include "platform/scheduler/renderer/web_view_scheduler_impl.h" +#include "platform/RuntimeEnabledFeatures.h" + +namespace blink { +namespace scheduler { + +RendererWebSchedulerImpl::RendererWebSchedulerImpl( + RendererSchedulerImpl* renderer_scheduler) + : WebSchedulerImpl(renderer_scheduler, + renderer_scheduler->IdleTaskRunner(), + renderer_scheduler->LoadingTaskRunner(), + renderer_scheduler->TimerTaskRunner()), + renderer_scheduler_(renderer_scheduler) {} + +RendererWebSchedulerImpl::~RendererWebSchedulerImpl() {} + +void RendererWebSchedulerImpl::suspendTimerQueue() { + renderer_scheduler_->SuspendTimerQueue(); +} + +void RendererWebSchedulerImpl::resumeTimerQueue() { + renderer_scheduler_->ResumeTimerQueue(); +} + +std::unique_ptr<blink::WebViewScheduler> +RendererWebSchedulerImpl::createWebViewScheduler( + InterventionReporter* intervention_reporter) { + return base::WrapUnique( + new WebViewSchedulerImpl(intervention_reporter, renderer_scheduler_, + !blink::RuntimeEnabledFeatures:: + timerThrottlingForBackgroundTabsEnabled())); +} + +void RendererWebSchedulerImpl::onNavigationStarted() { + renderer_scheduler_->OnNavigationStarted(); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_web_scheduler_impl.h b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_web_scheduler_impl.h new file mode 100644 index 0000000..09113a3 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_web_scheduler_impl.h
@@ -0,0 +1,35 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_RENDERER_WEB_SCHEDULER_IMPL_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_RENDERER_WEB_SCHEDULER_IMPL_H_ + +#include "platform/scheduler/child/web_scheduler_impl.h" + +namespace blink { +namespace scheduler { + +class RendererSchedulerImpl; + +class BLINK_PLATFORM_EXPORT RendererWebSchedulerImpl : public WebSchedulerImpl { + public: + explicit RendererWebSchedulerImpl(RendererSchedulerImpl* renderer_scheduler); + + ~RendererWebSchedulerImpl() override; + + // WebScheduler implementation: + void suspendTimerQueue() override; + void resumeTimerQueue() override; + std::unique_ptr<WebViewScheduler> createWebViewScheduler( + InterventionReporter* intervention_reporter) override; + void onNavigationStarted() override; + + private: + RendererSchedulerImpl* renderer_scheduler_; // NOT OWNED +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_RENDERER_WEB_SCHEDULER_IMPL_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/task_cost_estimator.cc b/third_party/WebKit/Source/platform/scheduler/renderer/task_cost_estimator.cc new file mode 100644 index 0000000..1494839 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/task_cost_estimator.cc
@@ -0,0 +1,45 @@ +// 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 "platform/scheduler/renderer/task_cost_estimator.h" + +#include "base/time/default_tick_clock.h" + +namespace blink { +namespace scheduler { + +TaskCostEstimator::TaskCostEstimator(base::TickClock* time_source, + int sample_count, + double estimation_percentile) + : rolling_time_delta_history_(sample_count), + time_source_(time_source), + outstanding_task_count_(0), + estimation_percentile_(estimation_percentile) {} + +TaskCostEstimator::~TaskCostEstimator() {} + +void TaskCostEstimator::WillProcessTask(const base::PendingTask& pending_task) { + // Avoid measuring the duration in nested run loops. + if (++outstanding_task_count_ == 1) + task_start_time_ = time_source_->NowTicks(); +} + +void TaskCostEstimator::DidProcessTask(const base::PendingTask& pending_task) { + if (--outstanding_task_count_ == 0) { + base::TimeDelta duration = time_source_->NowTicks() - task_start_time_; + rolling_time_delta_history_.InsertSample(duration); + } +} + +base::TimeDelta TaskCostEstimator::expected_task_duration() const { + return rolling_time_delta_history_.Percentile(estimation_percentile_); +} + +void TaskCostEstimator::Clear() { + rolling_time_delta_history_.Clear(); + expected_task_duration_ = base::TimeDelta(); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/task_cost_estimator.h b/third_party/WebKit/Source/platform/scheduler/renderer/task_cost_estimator.h new file mode 100644 index 0000000..0b8298a --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/task_cost_estimator.h
@@ -0,0 +1,52 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_TASK_COST_ESTIMATOR_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_TASK_COST_ESTIMATOR_H_ + +#include "base/macros.h" +#include "base/message_loop/message_loop.h" +#include "base/time/time.h" +#include "cc/base/rolling_time_delta_history.h" +#include "public/platform/WebCommon.h" + +namespace base { +class TickClock; +} + +namespace blink { +namespace scheduler { + +// Estimates the cost of running tasks based on historical timing data. +class BLINK_PLATFORM_EXPORT TaskCostEstimator + : public base::MessageLoop::TaskObserver { + public: + TaskCostEstimator(base::TickClock* time_source, + int sample_count, + double estimation_percentile); + ~TaskCostEstimator() override; + + base::TimeDelta expected_task_duration() const; + + // TaskObserver implementation: + void WillProcessTask(const base::PendingTask& pending_task) override; + void DidProcessTask(const base::PendingTask& pending_task) override; + + void Clear(); + + private: + cc::RollingTimeDeltaHistory rolling_time_delta_history_; + base::TickClock* time_source_; // NOT OWNED + int outstanding_task_count_; + double estimation_percentile_; + base::TimeTicks task_start_time_; + base::TimeDelta expected_task_duration_; + + DISALLOW_COPY_AND_ASSIGN(TaskCostEstimator); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_TASK_COST_ESTIMATOR_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/task_cost_estimator_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/task_cost_estimator_unittest.cc new file mode 100644 index 0000000..478fc98d --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/task_cost_estimator_unittest.cc
@@ -0,0 +1,82 @@ +// 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 "platform/scheduler/renderer/task_cost_estimator.h" + +#include <memory> + +#include "base/test/simple_test_tick_clock.h" +#include "platform/scheduler/base/test_time_source.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace blink { +namespace scheduler { + +class TaskCostEstimatorTest : public testing::Test { + public: + TaskCostEstimatorTest() {} + ~TaskCostEstimatorTest() override {} + + void SetUp() override { + test_time_source_.reset(new TestTimeSource(&clock_)); + } + + base::SimpleTestTickClock clock_; + std::unique_ptr<TestTimeSource> test_time_source_; +}; + +class TaskCostEstimatorForTest : public TaskCostEstimator { + public: + TaskCostEstimatorForTest(TestTimeSource* test_time_source, + int sample_count, + double estimation_percentile) + : TaskCostEstimator(test_time_source, + sample_count, + estimation_percentile) {} +}; + +TEST_F(TaskCostEstimatorTest, BasicEstimation) { + TaskCostEstimatorForTest estimator(test_time_source_.get(), 1, 100); + base::PendingTask task(FROM_HERE, base::Closure()); + + estimator.WillProcessTask(task); + clock_.Advance(base::TimeDelta::FromMilliseconds(500)); + estimator.DidProcessTask(task); + + EXPECT_EQ(base::TimeDelta::FromMilliseconds(500), + estimator.expected_task_duration()); +} + +TEST_F(TaskCostEstimatorTest, Clear) { + TaskCostEstimatorForTest estimator(test_time_source_.get(), 1, 100); + base::PendingTask task(FROM_HERE, base::Closure()); + + estimator.WillProcessTask(task); + clock_.Advance(base::TimeDelta::FromMilliseconds(500)); + estimator.DidProcessTask(task); + + estimator.Clear(); + + EXPECT_EQ(base::TimeDelta(), estimator.expected_task_duration()); +} + +TEST_F(TaskCostEstimatorTest, NestedRunLoop) { + TaskCostEstimatorForTest estimator(test_time_source_.get(), 1, 100); + base::PendingTask task(FROM_HERE, base::Closure()); + + // Make sure we ignore the tasks inside the nested run loop. + estimator.WillProcessTask(task); + estimator.WillProcessTask(task); + clock_.Advance(base::TimeDelta::FromMilliseconds(500)); + estimator.DidProcessTask(task); + clock_.Advance(base::TimeDelta::FromMilliseconds(500)); + estimator.DidProcessTask(task); + + EXPECT_EQ(base::TimeDelta::FromMilliseconds(1000), + estimator.expected_task_duration()); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/throttled_time_domain.cc b/third_party/WebKit/Source/platform/scheduler/renderer/throttled_time_domain.cc new file mode 100644 index 0000000..d39bf3f --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/throttled_time_domain.cc
@@ -0,0 +1,41 @@ +// 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 "platform/scheduler/renderer/throttled_time_domain.h" + +namespace blink { +namespace scheduler { + +ThrottledTimeDomain::ThrottledTimeDomain(TimeDomain::Observer* observer, + const char* tracing_category) + : RealTimeDomain(observer, tracing_category) {} + +ThrottledTimeDomain::~ThrottledTimeDomain() {} + +const char* ThrottledTimeDomain::GetName() const { + return "ThrottledTimeDomain"; +} + +void ThrottledTimeDomain::RequestWakeup(base::TimeTicks now, + base::TimeDelta delay) { + // We assume the owner (i.e. ThrottlingHelper) will manage wakeups on our + // behalf. +} + +bool ThrottledTimeDomain::MaybeAdvanceTime() { + base::TimeTicks next_run_time; + if (!NextScheduledRunTime(&next_run_time)) + return false; + + base::TimeTicks now = Now(); + if (now >= next_run_time) + return true; // Causes DoWork to post a continuation. + + // Unlike RealTimeDomain::MaybeAdvanceTime we don't request a wake up here, we + // assume the owner (i.e. ThrottlingHelper) will manage wakeups on our behalf. + return false; +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/throttled_time_domain.h b/third_party/WebKit/Source/platform/scheduler/renderer/throttled_time_domain.h new file mode 100644 index 0000000..aa04ee9 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/throttled_time_domain.h
@@ -0,0 +1,36 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_THROTTLED_TIME_DOMAIN_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_THROTTLED_TIME_DOMAIN_H_ + +#include "base/macros.h" +#include "platform/scheduler/base/real_time_domain.h" + +namespace blink { +namespace scheduler { + +// A time domain for throttled tasks. behaves like an RealTimeDomain except it +// relies on the owner (ThrottlingHelper) to schedule wakeups. +class BLINK_PLATFORM_EXPORT ThrottledTimeDomain : public RealTimeDomain { + public: + ThrottledTimeDomain(TimeDomain::Observer* observer, + const char* tracing_category); + ~ThrottledTimeDomain() override; + + // TimeDomain implementation: + const char* GetName() const override; + void RequestWakeup(base::TimeTicks now, base::TimeDelta delay) override; + bool MaybeAdvanceTime() override; + + using TimeDomain::ClearExpiredWakeups; + + private: + DISALLOW_COPY_AND_ASSIGN(ThrottledTimeDomain); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_THROTTLED_TIME_DOMAIN_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/throttling_helper.cc b/third_party/WebKit/Source/platform/scheduler/renderer/throttling_helper.cc new file mode 100644 index 0000000..3e025e9d --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/throttling_helper.cc
@@ -0,0 +1,221 @@ +// 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 "platform/scheduler/renderer/throttling_helper.h" + +#include "base/logging.h" +#include "platform/scheduler/base/real_time_domain.h" +#include "platform/scheduler/child/scheduler_tqm_delegate.h" +#include "platform/scheduler/renderer/auto_advancing_virtual_time_domain.h" +#include "platform/scheduler/renderer/renderer_scheduler_impl.h" +#include "platform/scheduler/renderer/throttled_time_domain.h" +#include "platform/scheduler/renderer/web_frame_scheduler_impl.h" +#include "public/platform/WebFrameScheduler.h" + +namespace blink { +namespace scheduler { + +ThrottlingHelper::ThrottlingHelper(RendererSchedulerImpl* renderer_scheduler, + const char* tracing_category) + : task_runner_(renderer_scheduler->ControlTaskRunner()), + renderer_scheduler_(renderer_scheduler), + tick_clock_(renderer_scheduler->tick_clock()), + tracing_category_(tracing_category), + time_domain_(new ThrottledTimeDomain(this, tracing_category)), + virtual_time_(false), + weak_factory_(this) { + pump_throttled_tasks_closure_.Reset(base::Bind( + &ThrottlingHelper::PumpThrottledTasks, weak_factory_.GetWeakPtr())); + forward_immediate_work_closure_ = + base::Bind(&ThrottlingHelper::OnTimeDomainHasImmediateWork, + weak_factory_.GetWeakPtr()); + + renderer_scheduler_->RegisterTimeDomain(time_domain_.get()); +} + +ThrottlingHelper::~ThrottlingHelper() { + // It's possible for queues to be still throttled, so we need to tidy up + // before unregistering the time domain. + for (const TaskQueueMap::value_type& map_entry : throttled_queues_) { + TaskQueue* task_queue = map_entry.first; + task_queue->SetTimeDomain(renderer_scheduler_->real_time_domain()); + task_queue->SetPumpPolicy(TaskQueue::PumpPolicy::AUTO); + } + + renderer_scheduler_->UnregisterTimeDomain(time_domain_.get()); +} + +void ThrottlingHelper::SetQueueEnabled(TaskQueue* task_queue, bool enabled) { + TaskQueueMap::iterator find_it = throttled_queues_.find(task_queue); + + if (find_it == throttled_queues_.end()) { + task_queue->SetQueueEnabled(enabled); + return; + } + + find_it->second.enabled = enabled; + + // We don't enable the queue here because it's throttled and there might be + // tasks in it's work queue that would execute immediatly rather than after + // PumpThrottledTasks runs. + if (!enabled) + task_queue->SetQueueEnabled(false); +} + +void ThrottlingHelper::IncreaseThrottleRefCount(TaskQueue* task_queue) { + DCHECK_NE(task_queue, task_runner_.get()); + + if (virtual_time_) + return; + + std::pair<TaskQueueMap::iterator, bool> insert_result = + throttled_queues_.insert(std::make_pair( + task_queue, Metadata(1, task_queue->IsQueueEnabled()))); + + if (insert_result.second) { + // The insert was succesful so we need to throttle the queue. + task_queue->SetTimeDomain(time_domain_.get()); + task_queue->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL); + task_queue->SetQueueEnabled(false); + + if (!task_queue->IsEmpty()) { + if (task_queue->HasPendingImmediateWork()) { + OnTimeDomainHasImmediateWork(); + } else { + OnTimeDomainHasDelayedWork(); + } + } + } else { + // An entry already existed in the map so we need to increment the refcount. + insert_result.first->second.throttling_ref_count++; + } +} + +void ThrottlingHelper::DecreaseThrottleRefCount(TaskQueue* task_queue) { + if (virtual_time_) + return; + + TaskQueueMap::iterator iter = throttled_queues_.find(task_queue); + + if (iter != throttled_queues_.end() && + --iter->second.throttling_ref_count == 0) { + bool enabled = iter->second.enabled; + // The refcount has become zero, we need to unthrottle the queue. + throttled_queues_.erase(iter); + + task_queue->SetTimeDomain(renderer_scheduler_->real_time_domain()); + task_queue->SetPumpPolicy(TaskQueue::PumpPolicy::AUTO); + task_queue->SetQueueEnabled(enabled); + } +} + +void ThrottlingHelper::UnregisterTaskQueue(TaskQueue* task_queue) { + throttled_queues_.erase(task_queue); +} + +void ThrottlingHelper::OnTimeDomainHasImmediateWork() { + // Forward to the main thread if called from another thread. + if (!task_runner_->RunsTasksOnCurrentThread()) { + task_runner_->PostTask(FROM_HERE, forward_immediate_work_closure_); + return; + } + TRACE_EVENT0(tracing_category_, + "ThrottlingHelper::OnTimeDomainHasImmediateWork"); + base::TimeTicks now = tick_clock_->NowTicks(); + MaybeSchedulePumpThrottledTasksLocked(FROM_HERE, now, now); +} + +void ThrottlingHelper::OnTimeDomainHasDelayedWork() { + TRACE_EVENT0(tracing_category_, + "ThrottlingHelper::OnTimeDomainHasDelayedWork"); + base::TimeTicks next_scheduled_delayed_task; + bool has_delayed_task = + time_domain_->NextScheduledRunTime(&next_scheduled_delayed_task); + DCHECK(has_delayed_task); + base::TimeTicks now = tick_clock_->NowTicks(); + MaybeSchedulePumpThrottledTasksLocked(FROM_HERE, now, + next_scheduled_delayed_task); +} + +void ThrottlingHelper::PumpThrottledTasks() { + TRACE_EVENT0(tracing_category_, "ThrottlingHelper::PumpThrottledTasks"); + pending_pump_throttled_tasks_runtime_ = base::TimeTicks(); + + LazyNow lazy_low(tick_clock_); + for (const TaskQueueMap::value_type& map_entry : throttled_queues_) { + TaskQueue* task_queue = map_entry.first; + if (task_queue->IsEmpty()) + continue; + + task_queue->SetQueueEnabled(map_entry.second.enabled); + task_queue->PumpQueue(&lazy_low, false); + } + // Make sure NextScheduledRunTime gives us an up-to date result. + time_domain_->ClearExpiredWakeups(); + + base::TimeTicks next_scheduled_delayed_task; + // Maybe schedule a call to ThrottlingHelper::PumpThrottledTasks if there is + // a pending delayed task. NOTE posting a non-delayed task in the future will + // result in ThrottlingHelper::OnTimeDomainHasImmediateWork being called. + if (time_domain_->NextScheduledRunTime(&next_scheduled_delayed_task)) { + MaybeSchedulePumpThrottledTasksLocked(FROM_HERE, lazy_low.Now(), + next_scheduled_delayed_task); + } +} + +/* static */ +base::TimeTicks ThrottlingHelper::ThrottledRunTime( + base::TimeTicks unthrottled_runtime) { + const base::TimeDelta one_second = base::TimeDelta::FromSeconds(1); + return unthrottled_runtime + one_second - + ((unthrottled_runtime - base::TimeTicks()) % one_second); +} + +void ThrottlingHelper::MaybeSchedulePumpThrottledTasksLocked( + const tracked_objects::Location& from_here, + base::TimeTicks now, + base::TimeTicks unthrottled_runtime) { + if (virtual_time_) + return; + + base::TimeTicks throttled_runtime = + ThrottledRunTime(std::max(now, unthrottled_runtime)); + // If there is a pending call to PumpThrottledTasks and it's sooner than + // |unthrottled_runtime| then return. + if (!pending_pump_throttled_tasks_runtime_.is_null() && + throttled_runtime >= pending_pump_throttled_tasks_runtime_) { + return; + } + + pending_pump_throttled_tasks_runtime_ = throttled_runtime; + + pump_throttled_tasks_closure_.Cancel(); + + base::TimeDelta delay = pending_pump_throttled_tasks_runtime_ - now; + TRACE_EVENT1(tracing_category_, + "ThrottlingHelper::MaybeSchedulePumpThrottledTasksLocked", + "delay_till_next_pump_ms", delay.InMilliseconds()); + task_runner_->PostDelayedTask( + from_here, pump_throttled_tasks_closure_.callback(), delay); +} + +void ThrottlingHelper::EnableVirtualTime() { + virtual_time_ = true; + + pump_throttled_tasks_closure_.Cancel(); + + while (!throttled_queues_.empty()) { + TaskQueue* task_queue = throttled_queues_.begin()->first; + bool enabled = throttled_queues_.begin()->second.enabled; + + throttled_queues_.erase(throttled_queues_.begin()); + + task_queue->SetTimeDomain(renderer_scheduler_->GetVirtualTimeDomain()); + task_queue->SetPumpPolicy(TaskQueue::PumpPolicy::AUTO); + task_queue->SetQueueEnabled(enabled); + } +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/throttling_helper.h b/third_party/WebKit/Source/platform/scheduler/renderer/throttling_helper.h new file mode 100644 index 0000000..0f3a9932 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/throttling_helper.h
@@ -0,0 +1,105 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_THROTTLING_HELPER_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_THROTTLING_HELPER_H_ + +#include <set> + +#include "base/macros.h" +#include "platform/scheduler/base/cancelable_closure_holder.h" +#include "platform/scheduler/base/time_domain.h" +#include "public/platform/WebViewScheduler.h" + +namespace blink { +namespace scheduler { + +class RendererSchedulerImpl; +class ThrottledTimeDomain; +class WebFrameSchedulerImpl; + +class BLINK_PLATFORM_EXPORT ThrottlingHelper : public TimeDomain::Observer { + public: + ThrottlingHelper(RendererSchedulerImpl* renderer_scheduler, + const char* tracing_category); + + ~ThrottlingHelper() override; + + // TimeDomain::Observer implementation: + void OnTimeDomainHasImmediateWork() override; + void OnTimeDomainHasDelayedWork() override; + + // The purpose of this method is to make sure throttling doesn't conflict with + // enabling/disabling the queue for policy reasons. + // If |task_queue| is throttled then the ThrottlingHelper remembers the + // |enabled| setting. In addition if |enabled| is false then the queue is + // immediatly disabled. Otherwise if |task_queue| not throttled then + // TaskQueue::SetEnabled(enabled) is called. + void SetQueueEnabled(TaskQueue* task_queue, bool enabled); + + // Increments the throttled refcount and causes |task_queue| to be throttled + // if its not already throttled. + void IncreaseThrottleRefCount(TaskQueue* task_queue); + + // If the refcouint is non-zero it's decremented. If the throttled refcount + // becomes zero then |task_queue| is unthrottled. If the refcount was already + // zero this function does nothing. + void DecreaseThrottleRefCount(TaskQueue* task_queue); + + // Removes |task_queue| from |throttled_queues_|. + void UnregisterTaskQueue(TaskQueue* task_queue); + + // Tells the ThrottlingHelper we're using virtual time, which disables all + // throttling. + void EnableVirtualTime(); + + const ThrottledTimeDomain* time_domain() const { return time_domain_.get(); } + + static base::TimeTicks ThrottledRunTime(base::TimeTicks unthrottled_runtime); + + const scoped_refptr<TaskQueue>& task_runner() const { return task_runner_; } + + private: + struct Metadata { + Metadata() : throttling_ref_count(0), enabled(false) {} + + Metadata(size_t ref_count, bool is_enabled) + : throttling_ref_count(ref_count), enabled(is_enabled) {} + + size_t throttling_ref_count; + bool enabled; + }; + using TaskQueueMap = std::map<TaskQueue*, Metadata>; + + void PumpThrottledTasks(); + + // Note |unthrottled_runtime| might be in the past. When this happens we + // compute the delay to the next runtime based on now rather than + // unthrottled_runtime. + void MaybeSchedulePumpThrottledTasksLocked( + const tracked_objects::Location& from_here, + base::TimeTicks now, + base::TimeTicks unthrottled_runtime); + + TaskQueueMap throttled_queues_; + base::Closure forward_immediate_work_closure_; + scoped_refptr<TaskQueue> task_runner_; + RendererSchedulerImpl* renderer_scheduler_; // NOT OWNED + base::TickClock* tick_clock_; // NOT OWNED + const char* tracing_category_; // NOT OWNED + std::unique_ptr<ThrottledTimeDomain> time_domain_; + + CancelableClosureHolder pump_throttled_tasks_closure_; + base::TimeTicks pending_pump_throttled_tasks_runtime_; + bool virtual_time_; + + base::WeakPtrFactory<ThrottlingHelper> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(ThrottlingHelper); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_THROTTLING_HELPER_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/throttling_helper_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/throttling_helper_unittest.cc new file mode 100644 index 0000000..8aa24f5f --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/throttling_helper_unittest.cc
@@ -0,0 +1,480 @@ +// 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 "platform/scheduler/renderer/throttling_helper.h" + +#include <stddef.h> + +#include <memory> + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "base/test/simple_test_tick_clock.h" +#include "cc/test/ordered_simple_task_runner.h" +#include "platform/scheduler/base/test_time_source.h" +#include "platform/scheduler/child/scheduler_tqm_delegate_for_test.h" +#include "platform/scheduler/renderer/auto_advancing_virtual_time_domain.h" +#include "platform/scheduler/renderer/renderer_scheduler_impl.h" +#include "platform/scheduler/renderer/web_frame_scheduler_impl.h" +#include "platform/scheduler/renderer/web_view_scheduler_impl.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::ElementsAre; + +namespace blink { +namespace scheduler { + +namespace { +void CountingTask(size_t* count, scoped_refptr<TaskQueue> timer_queue) { + if (++(*count) < 10) { + timer_queue->PostTask(FROM_HERE, + base::Bind(&CountingTask, count, timer_queue)); + } +} +} + +class ThrottlingHelperTest : public testing::Test { + public: + ThrottlingHelperTest() {} + ~ThrottlingHelperTest() override {} + + void SetUp() override { + clock_.reset(new base::SimpleTestTickClock()); + clock_->Advance(base::TimeDelta::FromMicroseconds(5000)); + mock_task_runner_ = + make_scoped_refptr(new cc::OrderedSimpleTaskRunner(clock_.get(), true)); + delegate_ = SchedulerTqmDelegateForTest::Create( + mock_task_runner_, base::WrapUnique(new TestTimeSource(clock_.get()))); + scheduler_.reset(new RendererSchedulerImpl(delegate_)); + throttling_helper_ = scheduler_->throttling_helper(); + timer_queue_ = scheduler_->NewTimerTaskRunner("test_queue"); + } + + void TearDown() override { + scheduler_->Shutdown(); + scheduler_.reset(); + } + + void ExpectThrottled(scoped_refptr<TaskQueue> timer_queue) { + size_t count = 0; + timer_queue->PostTask(FROM_HERE, + base::Bind(&CountingTask, &count, timer_queue)); + + mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1)); + EXPECT_LT(count, 10u); + mock_task_runner_->RunUntilIdle(); + } + + void ExpectUnthrottled(scoped_refptr<TaskQueue> timer_queue) { + size_t count = 0; + timer_queue->PostTask(FROM_HERE, + base::Bind(&CountingTask, &count, timer_queue)); + + mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1)); + EXPECT_EQ(count, 10u); + mock_task_runner_->RunUntilIdle(); + } + + protected: + std::unique_ptr<base::SimpleTestTickClock> clock_; + scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_; + scoped_refptr<SchedulerTqmDelegate> delegate_; + std::unique_ptr<RendererSchedulerImpl> scheduler_; + scoped_refptr<TaskQueue> timer_queue_; + ThrottlingHelper* throttling_helper_; // NOT OWNED + + DISALLOW_COPY_AND_ASSIGN(ThrottlingHelperTest); +}; + +TEST_F(ThrottlingHelperTest, ThrottledRunTime) { + EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(1.0), + ThrottlingHelper::ThrottledRunTime( + base::TimeTicks() + base::TimeDelta::FromSecondsD(0.0))); + + EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(1.0), + ThrottlingHelper::ThrottledRunTime( + base::TimeTicks() + base::TimeDelta::FromSecondsD(0.1))); + + EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(1.0), + ThrottlingHelper::ThrottledRunTime( + base::TimeTicks() + base::TimeDelta::FromSecondsD(0.2))); + + EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(1.0), + ThrottlingHelper::ThrottledRunTime( + base::TimeTicks() + base::TimeDelta::FromSecondsD(0.5))); + + EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(1.0), + ThrottlingHelper::ThrottledRunTime( + base::TimeTicks() + base::TimeDelta::FromSecondsD(0.8))); + + EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(1.0), + ThrottlingHelper::ThrottledRunTime( + base::TimeTicks() + base::TimeDelta::FromSecondsD(0.9))); + + EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(2.0), + ThrottlingHelper::ThrottledRunTime( + base::TimeTicks() + base::TimeDelta::FromSecondsD(1.0))); + + EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(2.0), + ThrottlingHelper::ThrottledRunTime( + base::TimeTicks() + base::TimeDelta::FromSecondsD(1.1))); + + EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(9.0), + ThrottlingHelper::ThrottledRunTime( + base::TimeTicks() + base::TimeDelta::FromSecondsD(8.0))); + + EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSecondsD(9.0), + ThrottlingHelper::ThrottledRunTime( + base::TimeTicks() + base::TimeDelta::FromSecondsD(8.1))); +} + +namespace { +void TestTask(std::vector<base::TimeTicks>* run_times, + base::SimpleTestTickClock* clock) { + run_times->push_back(clock->NowTicks()); +} +} // namespace + +TEST_F(ThrottlingHelperTest, TimerAlignment) { + std::vector<base::TimeTicks> run_times; + timer_queue_->PostDelayedTask(FROM_HERE, + base::Bind(&TestTask, &run_times, clock_.get()), + base::TimeDelta::FromMilliseconds(200.0)); + + timer_queue_->PostDelayedTask(FROM_HERE, + base::Bind(&TestTask, &run_times, clock_.get()), + base::TimeDelta::FromMilliseconds(800.0)); + + timer_queue_->PostDelayedTask(FROM_HERE, + base::Bind(&TestTask, &run_times, clock_.get()), + base::TimeDelta::FromMilliseconds(1200.0)); + + timer_queue_->PostDelayedTask(FROM_HERE, + base::Bind(&TestTask, &run_times, clock_.get()), + base::TimeDelta::FromMilliseconds(8300.0)); + + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); + + mock_task_runner_->RunUntilIdle(); + + // Times are aligned to a multipple of 1000 milliseconds. + EXPECT_THAT( + run_times, + ElementsAre( + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1000.0), + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1000.0), + base::TimeTicks() + base::TimeDelta::FromMilliseconds(2000.0), + base::TimeTicks() + base::TimeDelta::FromMilliseconds(9000.0))); +} + +TEST_F(ThrottlingHelperTest, TimerAlignment_Unthrottled) { + std::vector<base::TimeTicks> run_times; + base::TimeTicks start_time = clock_->NowTicks(); + timer_queue_->PostDelayedTask(FROM_HERE, + base::Bind(&TestTask, &run_times, clock_.get()), + base::TimeDelta::FromMilliseconds(200.0)); + + timer_queue_->PostDelayedTask(FROM_HERE, + base::Bind(&TestTask, &run_times, clock_.get()), + base::TimeDelta::FromMilliseconds(800.0)); + + timer_queue_->PostDelayedTask(FROM_HERE, + base::Bind(&TestTask, &run_times, clock_.get()), + base::TimeDelta::FromMilliseconds(1200.0)); + + timer_queue_->PostDelayedTask(FROM_HERE, + base::Bind(&TestTask, &run_times, clock_.get()), + base::TimeDelta::FromMilliseconds(8300.0)); + + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); + throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get()); + + mock_task_runner_->RunUntilIdle(); + + // Times are not aligned. + EXPECT_THAT( + run_times, + ElementsAre(start_time + base::TimeDelta::FromMilliseconds(200.0), + start_time + base::TimeDelta::FromMilliseconds(800.0), + start_time + base::TimeDelta::FromMilliseconds(1200.0), + start_time + base::TimeDelta::FromMilliseconds(8300.0))); +} + +TEST_F(ThrottlingHelperTest, Refcount) { + ExpectUnthrottled(timer_queue_.get()); + + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); + ExpectThrottled(timer_queue_); + + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); + ExpectThrottled(timer_queue_); + + throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get()); + ExpectThrottled(timer_queue_); + + throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get()); + ExpectUnthrottled(timer_queue_); + + // Should be a NOP. + throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get()); + ExpectUnthrottled(timer_queue_); + + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); + ExpectThrottled(timer_queue_); +} + +TEST_F(ThrottlingHelperTest, + ThrotlingAnEmptyQueueDoesNotPostPumpThrottledTasksLocked) { + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); + + EXPECT_TRUE(throttling_helper_->task_runner()->IsEmpty()); +} + +TEST_F(ThrottlingHelperTest, WakeUpForNonDelayedTask) { + std::vector<base::TimeTicks> run_times; + + // Nothing is posted on timer_queue_ so PumpThrottledTasks will not tick. + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); + + // Posting a task should trigger the pump. + timer_queue_->PostTask(FROM_HERE, + base::Bind(&TestTask, &run_times, clock_.get())); + + mock_task_runner_->RunUntilIdle(); + EXPECT_THAT(run_times, + ElementsAre(base::TimeTicks() + + base::TimeDelta::FromMilliseconds(1000.0))); +} + +TEST_F(ThrottlingHelperTest, WakeUpForDelayedTask) { + std::vector<base::TimeTicks> run_times; + + // Nothing is posted on timer_queue_ so PumpThrottledTasks will not tick. + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); + + // Posting a task should trigger the pump. + timer_queue_->PostDelayedTask(FROM_HERE, + base::Bind(&TestTask, &run_times, clock_.get()), + base::TimeDelta::FromMilliseconds(1200.0)); + + mock_task_runner_->RunUntilIdle(); + EXPECT_THAT(run_times, + ElementsAre(base::TimeTicks() + + base::TimeDelta::FromMilliseconds(2000.0))); +} + +namespace { +bool MessageLoopTaskCounter(size_t* count) { + *count = *count + 1; + return true; +} + +void NopTask() {} + +} // namespace + +TEST_F(ThrottlingHelperTest, + SingleThrottledTaskPumpedAndRunWithNoExtraneousMessageLoopTasks) { + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); + + base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10)); + timer_queue_->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), delay); + + size_t task_count = 0; + mock_task_runner_->RunTasksWhile( + base::Bind(&MessageLoopTaskCounter, &task_count)); + + EXPECT_EQ(1u, task_count); +} + +TEST_F(ThrottlingHelperTest, + SingleFutureThrottledTaskPumpedAndRunWithNoExtraneousMessageLoopTasks) { + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); + + base::TimeDelta delay(base::TimeDelta::FromSecondsD(15.5)); + timer_queue_->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), delay); + + size_t task_count = 0; + mock_task_runner_->RunTasksWhile( + base::Bind(&MessageLoopTaskCounter, &task_count)); + + EXPECT_EQ(1u, task_count); +} + +TEST_F(ThrottlingHelperTest, + TwoFutureThrottledTaskPumpedAndRunWithNoExtraneousMessageLoopTasks) { + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); + std::vector<base::TimeTicks> run_times; + + base::TimeDelta delay(base::TimeDelta::FromSecondsD(15.5)); + timer_queue_->PostDelayedTask( + FROM_HERE, base::Bind(&TestTask, &run_times, clock_.get()), delay); + + base::TimeDelta delay2(base::TimeDelta::FromSecondsD(5.5)); + timer_queue_->PostDelayedTask( + FROM_HERE, base::Bind(&TestTask, &run_times, clock_.get()), delay2); + + size_t task_count = 0; + mock_task_runner_->RunTasksWhile( + base::Bind(&MessageLoopTaskCounter, &task_count)); + + EXPECT_EQ(2u, task_count); // There are two since the cancelled task runs in + // the same DoWork batch. + + EXPECT_THAT( + run_times, + ElementsAre(base::TimeTicks() + base::TimeDelta::FromSeconds(6), + base::TimeTicks() + base::TimeDelta::FromSeconds(16))); +} + +TEST_F(ThrottlingHelperTest, TaskDelayIsBasedOnRealTime) { + std::vector<base::TimeTicks> run_times; + + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); + + // Post an initial task that should run at the first aligned time period. + timer_queue_->PostDelayedTask(FROM_HERE, + base::Bind(&TestTask, &run_times, clock_.get()), + base::TimeDelta::FromMilliseconds(900.0)); + + mock_task_runner_->RunUntilIdle(); + + // Advance realtime. + clock_->Advance(base::TimeDelta::FromMilliseconds(250)); + + // Post a task that due to real time + delay must run in the third aligned + // time period. + timer_queue_->PostDelayedTask(FROM_HERE, + base::Bind(&TestTask, &run_times, clock_.get()), + base::TimeDelta::FromMilliseconds(900.0)); + + mock_task_runner_->RunUntilIdle(); + + EXPECT_THAT( + run_times, + ElementsAre( + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1000.0), + base::TimeTicks() + base::TimeDelta::FromMilliseconds(3000.0))); +} + +TEST_F(ThrottlingHelperTest, ThrottledTasksReportRealTime) { + EXPECT_EQ(timer_queue_->GetTimeDomain()->Now(), clock_->NowTicks()); + + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); + EXPECT_EQ(timer_queue_->GetTimeDomain()->Now(), clock_->NowTicks()); + + clock_->Advance(base::TimeDelta::FromMilliseconds(250)); + // Make sure the throttled time domain's Now() reports the same as the + // underlying clock. + EXPECT_EQ(timer_queue_->GetTimeDomain()->Now(), clock_->NowTicks()); +} + +TEST_F(ThrottlingHelperTest, TaskQueueDisabledTillPump) { + timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask)); + + EXPECT_TRUE(timer_queue_->IsQueueEnabled()); + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); + EXPECT_FALSE(timer_queue_->IsQueueEnabled()); + + mock_task_runner_->RunUntilIdle(); // Wait until the pump. + EXPECT_TRUE(timer_queue_->IsQueueEnabled()); +} + +TEST_F(ThrottlingHelperTest, TaskQueueUnthrottle_InitiallyEnabled) { + timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask)); + + timer_queue_->SetQueueEnabled(true); // NOP + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); + EXPECT_FALSE(timer_queue_->IsQueueEnabled()); + + throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get()); + EXPECT_TRUE(timer_queue_->IsQueueEnabled()); +} + +TEST_F(ThrottlingHelperTest, TaskQueueUnthrottle_InitiallyDisabled) { + timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask)); + + timer_queue_->SetQueueEnabled(false); + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); + EXPECT_FALSE(timer_queue_->IsQueueEnabled()); + + throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get()); + EXPECT_FALSE(timer_queue_->IsQueueEnabled()); +} + +TEST_F(ThrottlingHelperTest, SetQueueEnabled_Unthrottled) { + timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask)); + + throttling_helper_->SetQueueEnabled(timer_queue_.get(), false); + EXPECT_FALSE(timer_queue_->IsQueueEnabled()); + + throttling_helper_->SetQueueEnabled(timer_queue_.get(), true); + EXPECT_TRUE(timer_queue_->IsQueueEnabled()); +} + +TEST_F(ThrottlingHelperTest, SetQueueEnabled_DisabledWhileThrottled) { + timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask)); + + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); + EXPECT_FALSE(timer_queue_->IsQueueEnabled()); + + throttling_helper_->SetQueueEnabled(timer_queue_.get(), false); + throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get()); + EXPECT_FALSE(timer_queue_->IsQueueEnabled()); +} + +TEST_F(ThrottlingHelperTest, TaskQueueDisabledTillPump_ThenManuallyDisabled) { + timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask)); + + EXPECT_TRUE(timer_queue_->IsQueueEnabled()); + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); + EXPECT_FALSE(timer_queue_->IsQueueEnabled()); + + mock_task_runner_->RunUntilIdle(); // Wait until the pump. + EXPECT_TRUE(timer_queue_->IsQueueEnabled()); + + throttling_helper_->SetQueueEnabled(timer_queue_.get(), false); + EXPECT_FALSE(timer_queue_->IsQueueEnabled()); +} + +TEST_F(ThrottlingHelperTest, DoubleIncrementDoubleDecrement) { + timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask)); + + EXPECT_TRUE(timer_queue_->IsQueueEnabled()); + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); + EXPECT_FALSE(timer_queue_->IsQueueEnabled()); + throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get()); + throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get()); + EXPECT_TRUE(timer_queue_->IsQueueEnabled()); +} + +TEST_F(ThrottlingHelperTest, EnableVirtualTimeThenIncrement) { + timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask)); + + scheduler_->EnableVirtualTime(); + EXPECT_EQ(timer_queue_->GetTimeDomain(), scheduler_->GetVirtualTimeDomain()); + + EXPECT_TRUE(timer_queue_->IsQueueEnabled()); + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); + EXPECT_TRUE(timer_queue_->IsQueueEnabled()); + EXPECT_EQ(timer_queue_->GetTimeDomain(), scheduler_->GetVirtualTimeDomain()); +} + +TEST_F(ThrottlingHelperTest, IncrementThenEnableVirtualTime) { + timer_queue_->PostTask(FROM_HERE, base::Bind(&NopTask)); + + EXPECT_TRUE(timer_queue_->IsQueueEnabled()); + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); + EXPECT_FALSE(timer_queue_->IsQueueEnabled()); + + scheduler_->EnableVirtualTime(); + EXPECT_TRUE(timer_queue_->IsQueueEnabled()); + EXPECT_EQ(timer_queue_->GetTimeDomain(), scheduler_->GetVirtualTimeDomain()); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/user_model.cc b/third_party/WebKit/Source/platform/scheduler/renderer/user_model.cc new file mode 100644 index 0000000..a288c1b8 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/user_model.cc
@@ -0,0 +1,224 @@ +// 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 "platform/scheduler/renderer/user_model.h" + +#include "base/metrics/histogram_macros.h" + +namespace blink { +namespace scheduler { + +namespace { +// This enum is used to back a histogram, and should therefore be treated as +// append-only. +enum GesturePredictionResult { + GESTURE_OCCURED_WAS_PREDICTED = 0, + GESTURE_OCCURED_BUT_NOT_PREDICTED = 1, + GESTURE_PREDICTED_BUT_DID_NOT_OCCUR = 2, + GESTURE_PREDICTION_RESULT_COUNT = 3 +}; + +void RecordGesturePrediction(GesturePredictionResult result) { + UMA_HISTOGRAM_ENUMERATION( + "RendererScheduler.UserModel.GesturePredictedCorrectly", result, + GESTURE_PREDICTION_RESULT_COUNT); +} + +} // namespace + +UserModel::UserModel() + : pending_input_event_count_(0), + is_gesture_active_(false), + is_gesture_expected_(false) {} +UserModel::~UserModel() {} + +void UserModel::DidStartProcessingInputEvent(blink::WebInputEvent::Type type, + const base::TimeTicks now) { + last_input_signal_time_ = now; + if (type == blink::WebInputEvent::TouchStart || + type == blink::WebInputEvent::GestureScrollBegin || + type == blink::WebInputEvent::GesturePinchBegin) { + // Only update stats once per gesture. + if (!is_gesture_active_) { + last_gesture_start_time_ = now; + + RecordGesturePrediction(is_gesture_expected_ + ? GESTURE_OCCURED_WAS_PREDICTED + : GESTURE_OCCURED_BUT_NOT_PREDICTED); + + if (!last_reset_time_.is_null()) { + base::TimeDelta time_since_reset = now - last_reset_time_; + UMA_HISTOGRAM_MEDIUM_TIMES( + "RendererScheduler.UserModel.GestureStartTimeSinceModelReset", + time_since_reset); + } + + // If there has been a previous gesture, record a UMA metric for the time + // interval between then and now. + if (!last_continuous_gesture_time_.is_null()) { + base::TimeDelta time_since_last_gesture = + now - last_continuous_gesture_time_; + UMA_HISTOGRAM_MEDIUM_TIMES( + "RendererScheduler.UserModel.TimeBetweenGestures", + time_since_last_gesture); + } + } + + is_gesture_active_ = true; + } + + // We need to track continuous gestures seperatly for scroll detection + // because taps should not be confused with scrolls. + if (type == blink::WebInputEvent::GestureScrollBegin || + type == blink::WebInputEvent::GestureScrollEnd || + type == blink::WebInputEvent::GestureScrollUpdate || + type == blink::WebInputEvent::GestureFlingStart || + type == blink::WebInputEvent::GestureFlingCancel || + type == blink::WebInputEvent::GesturePinchBegin || + type == blink::WebInputEvent::GesturePinchEnd || + type == blink::WebInputEvent::GesturePinchUpdate) { + last_continuous_gesture_time_ = now; + } + + // If the gesture has ended, clear |is_gesture_active_| and record a UMA + // metric that tracks its duration. + if (type == blink::WebInputEvent::GestureScrollEnd || + type == blink::WebInputEvent::GesturePinchEnd || + type == blink::WebInputEvent::GestureFlingStart || + type == blink::WebInputEvent::TouchEnd) { + // Only update stats once per gesture. + if (is_gesture_active_) { + base::TimeDelta duration = now - last_gesture_start_time_; + UMA_HISTOGRAM_TIMES("RendererScheduler.UserModel.GestureDuration", + duration); + } + is_gesture_active_ = false; + } + + TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), + "is_gesture_active", is_gesture_active_); + + pending_input_event_count_++; +} + +void UserModel::DidFinishProcessingInputEvent(const base::TimeTicks now) { + last_input_signal_time_ = now; + if (pending_input_event_count_ > 0) + pending_input_event_count_--; +} + +base::TimeDelta UserModel::TimeLeftInUserGesture(base::TimeTicks now) const { + base::TimeDelta escalated_priority_duration = + base::TimeDelta::FromMilliseconds(kGestureEstimationLimitMillis); + + // If the input event is still pending, go into input prioritized policy and + // check again later. + if (pending_input_event_count_ > 0) + return escalated_priority_duration; + if (last_input_signal_time_.is_null() || + last_input_signal_time_ + escalated_priority_duration < now) { + return base::TimeDelta(); + } + return last_input_signal_time_ + escalated_priority_duration - now; +} + +bool UserModel::IsGestureExpectedSoon( + const base::TimeTicks now, + base::TimeDelta* prediction_valid_duration) { + bool was_gesture_expected = is_gesture_expected_; + is_gesture_expected_ = + IsGestureExpectedSoonImpl(now, prediction_valid_duration); + + // Track when we start expecting a gesture so we can work out later if a + // gesture actually happened. + if (!was_gesture_expected && is_gesture_expected_) + last_gesture_expected_start_time_ = now; + + if (was_gesture_expected && !is_gesture_expected_ && + last_gesture_expected_start_time_ > last_gesture_start_time_) { + RecordGesturePrediction(GESTURE_PREDICTED_BUT_DID_NOT_OCCUR); + } + return is_gesture_expected_; +} + +bool UserModel::IsGestureExpectedSoonImpl( + const base::TimeTicks now, + base::TimeDelta* prediction_valid_duration) const { + if (is_gesture_active_) { + if (IsGestureExpectedToContinue(now, prediction_valid_duration)) { + return false; + } else { + // If a gesture is not expected to continue then we expect a subsequent + // gesture soon. + *prediction_valid_duration = + base::TimeDelta::FromMilliseconds(kExpectSubsequentGestureMillis); + return true; + } + } else { + // If we've have a finished a gesture then a subsequent gesture is deemed + // likely. + base::TimeDelta expect_subsequent_gesture_for = + base::TimeDelta::FromMilliseconds(kExpectSubsequentGestureMillis); + if (last_continuous_gesture_time_.is_null() || + last_continuous_gesture_time_ + expect_subsequent_gesture_for <= now) { + return false; + } + *prediction_valid_duration = + last_continuous_gesture_time_ + expect_subsequent_gesture_for - now; + return true; + } +} + +bool UserModel::IsGestureExpectedToContinue( + const base::TimeTicks now, + base::TimeDelta* prediction_valid_duration) const { + if (!is_gesture_active_) + return false; + + base::TimeDelta median_gesture_duration = + base::TimeDelta::FromMilliseconds(kMedianGestureDurationMillis); + base::TimeTicks expected_gesture_end_time = + last_gesture_start_time_ + median_gesture_duration; + + if (expected_gesture_end_time > now) { + *prediction_valid_duration = expected_gesture_end_time - now; + return true; + } + return false; +} + +void UserModel::Reset(base::TimeTicks now) { + last_input_signal_time_ = base::TimeTicks(); + last_gesture_start_time_ = base::TimeTicks(); + last_continuous_gesture_time_ = base::TimeTicks(); + last_gesture_expected_start_time_ = base::TimeTicks(); + last_reset_time_ = now; + is_gesture_active_ = false; + is_gesture_expected_ = false; +} + +void UserModel::AsValueInto(base::trace_event::TracedValue* state) const { + state->BeginDictionary("user_model"); + state->SetInteger("pending_input_event_count", pending_input_event_count_); + state->SetDouble( + "last_input_signal_time", + (last_input_signal_time_ - base::TimeTicks()).InMillisecondsF()); + state->SetDouble( + "last_gesture_start_time", + (last_gesture_start_time_ - base::TimeTicks()).InMillisecondsF()); + state->SetDouble( + "last_continuous_gesture_time", + (last_continuous_gesture_time_ - base::TimeTicks()).InMillisecondsF()); + state->SetDouble("last_gesture_expected_start_time", + (last_gesture_expected_start_time_ - base::TimeTicks()) + .InMillisecondsF()); + state->SetDouble("last_reset_time", + (last_reset_time_ - base::TimeTicks()).InMillisecondsF()); + state->SetBoolean("is_gesture_expected", is_gesture_expected_); + state->SetBoolean("is_gesture_active", is_gesture_active_); + state->EndDictionary(); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/user_model.h b/third_party/WebKit/Source/platform/scheduler/renderer/user_model.h new file mode 100644 index 0000000..c0b5d2e --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/user_model.h
@@ -0,0 +1,86 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_USER_MODEL_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_USER_MODEL_H_ + +#include "base/macros.h" +#include "base/trace_event/trace_event.h" +#include "base/trace_event/trace_event_argument.h" +#include "public/platform/scheduler/renderer/renderer_scheduler.h" +#include "public/platform/WebCommon.h" +#include "public/platform/WebInputEvent.h" + +namespace blink { +namespace scheduler { + +class BLINK_PLATFORM_EXPORT UserModel { + public: + UserModel(); + ~UserModel(); + + // Tells us that the system started processing an input event. Must be paired + // with a call to DidFinishProcessingInputEvent. + void DidStartProcessingInputEvent(WebInputEvent::Type type, + const base::TimeTicks now); + + // Tells us that the system finished processing an input event. + void DidFinishProcessingInputEvent(const base::TimeTicks now); + + // Returns the estimated amount of time left in the current user gesture, to a + // maximum of |kGestureEstimationLimitMillis|. After that time has elapased + // this function should be called again. + base::TimeDelta TimeLeftInUserGesture(base::TimeTicks now) const; + + // Tries to guess if a user gesture is expected soon. Currently this is + // very simple, but one day I hope to do something more sophisticated here. + // The prediction may change after |prediction_valid_duration| has elapsed. + bool IsGestureExpectedSoon(const base::TimeTicks now, + base::TimeDelta* prediction_valid_duration); + + // Returns true if a gesture has been in progress for less than the median + // gesture duration. The prediction may change after + // |prediction_valid_duration| has elapsed. + bool IsGestureExpectedToContinue( + const base::TimeTicks now, + base::TimeDelta* prediction_valid_duration) const; + + void AsValueInto(base::trace_event::TracedValue* state) const; + + // The time we should stay in a priority-escalated mode after an input event. + static const int kGestureEstimationLimitMillis = 100; + + // This is based on two weeks of Android usage data. + static const int kMedianGestureDurationMillis = 300; + + // We consider further gesture start events to be likely if the user has + // interacted with the device in the past two seconds. + // Based on Android usage data, 2000ms between gestures is the 75th percentile + // with 700ms being the 50th. + static const int kExpectSubsequentGestureMillis = 2000; + + // Clears input signals. + void Reset(base::TimeTicks now); + + private: + bool IsGestureExpectedSoonImpl( + const base::TimeTicks now, + base::TimeDelta* prediction_valid_duration) const; + + int pending_input_event_count_; + base::TimeTicks last_input_signal_time_; + base::TimeTicks last_gesture_start_time_; + base::TimeTicks last_continuous_gesture_time_; // Doesn't include Taps. + base::TimeTicks last_gesture_expected_start_time_; + base::TimeTicks last_reset_time_; + bool is_gesture_active_; // This typically means the user's finger is down. + bool is_gesture_expected_; + + DISALLOW_COPY_AND_ASSIGN(UserModel); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_USER_MODEL_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/user_model_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/user_model_unittest.cc new file mode 100644 index 0000000..695a19d --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/user_model_unittest.cc
@@ -0,0 +1,256 @@ +// 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 "platform/scheduler/renderer/user_model.h" + +#include "base/test/simple_test_tick_clock.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace blink { +namespace scheduler { + +class UserModelTest : public testing::Test { + public: + UserModelTest() {} + ~UserModelTest() override {} + + void SetUp() override { + clock_.reset(new base::SimpleTestTickClock()); + clock_->Advance(base::TimeDelta::FromMicroseconds(5000)); + + user_model_.reset(new UserModel()); + } + + protected: + static base::TimeDelta priority_escalation_after_input_duration() { + return base::TimeDelta::FromMilliseconds( + UserModel::kGestureEstimationLimitMillis); + } + + static base::TimeDelta subsequent_input_expected_after_input_duration() { + return base::TimeDelta::FromMilliseconds( + UserModel::kExpectSubsequentGestureMillis); + } + + std::unique_ptr<base::SimpleTestTickClock> clock_; + std::unique_ptr<UserModel> user_model_; +}; + +TEST_F(UserModelTest, TimeLeftInUserGesture_NoInput) { + EXPECT_EQ(base::TimeDelta(), + user_model_->TimeLeftInUserGesture(clock_->NowTicks())); +} + +TEST_F(UserModelTest, TimeLeftInUserGesture_ImmediatelyAfterInput) { + user_model_->DidStartProcessingInputEvent( + blink::WebInputEvent::Type::TouchStart, clock_->NowTicks()); + user_model_->DidFinishProcessingInputEvent(clock_->NowTicks()); + EXPECT_EQ(priority_escalation_after_input_duration(), + user_model_->TimeLeftInUserGesture(clock_->NowTicks())); +} + +TEST_F(UserModelTest, TimeLeftInUserGesture_ShortlyAfterInput) { + user_model_->DidStartProcessingInputEvent( + blink::WebInputEvent::Type::TouchStart, clock_->NowTicks()); + user_model_->DidFinishProcessingInputEvent(clock_->NowTicks()); + base::TimeDelta delta(base::TimeDelta::FromMilliseconds(10)); + clock_->Advance(delta); + EXPECT_EQ(priority_escalation_after_input_duration() - delta, + user_model_->TimeLeftInUserGesture(clock_->NowTicks())); +} + +TEST_F(UserModelTest, TimeLeftInUserGesture_LongAfterInput) { + user_model_->DidStartProcessingInputEvent( + blink::WebInputEvent::Type::TouchStart, clock_->NowTicks()); + user_model_->DidFinishProcessingInputEvent(clock_->NowTicks()); + clock_->Advance(priority_escalation_after_input_duration() * 2); + EXPECT_EQ(base::TimeDelta(), + user_model_->TimeLeftInUserGesture(clock_->NowTicks())); +} + +TEST_F(UserModelTest, DidFinishProcessingInputEvent_Delayed) { + user_model_->DidStartProcessingInputEvent( + blink::WebInputEvent::Type::TouchStart, clock_->NowTicks()); + clock_->Advance(priority_escalation_after_input_duration() * 10); + + EXPECT_EQ(priority_escalation_after_input_duration(), + user_model_->TimeLeftInUserGesture(clock_->NowTicks())); + + user_model_->DidFinishProcessingInputEvent(clock_->NowTicks()); + base::TimeDelta delta(base::TimeDelta::FromMilliseconds(10)); + clock_->Advance(delta); + + EXPECT_EQ(priority_escalation_after_input_duration() - delta, + user_model_->TimeLeftInUserGesture(clock_->NowTicks())); +} + +TEST_F(UserModelTest, GestureExpectedSoon_NoRecentInput) { + base::TimeDelta prediction_valid_duration; + EXPECT_FALSE(user_model_->IsGestureExpectedSoon(clock_->NowTicks(), + &prediction_valid_duration)); + EXPECT_EQ(base::TimeDelta(), prediction_valid_duration); +} + +TEST_F(UserModelTest, GestureExpectedSoon_ShortlyAfter_GestureScrollBegin) { + user_model_->DidStartProcessingInputEvent( + blink::WebInputEvent::Type::GestureScrollBegin, clock_->NowTicks()); + user_model_->DidFinishProcessingInputEvent(clock_->NowTicks()); + + base::TimeDelta delta(base::TimeDelta::FromMilliseconds(10)); + clock_->Advance(delta); + + base::TimeDelta prediction_valid_duration; + EXPECT_FALSE(user_model_->IsGestureExpectedSoon(clock_->NowTicks(), + &prediction_valid_duration)); + EXPECT_EQ(base::TimeDelta::FromMilliseconds( + UserModel::kMedianGestureDurationMillis) - + delta, + prediction_valid_duration); +} + +TEST_F(UserModelTest, GestureExpectedSoon_LongAfter_GestureScrollBegin) { + user_model_->DidStartProcessingInputEvent( + blink::WebInputEvent::Type::GestureScrollBegin, clock_->NowTicks()); + user_model_->DidFinishProcessingInputEvent(clock_->NowTicks()); + + base::TimeDelta delta(base::TimeDelta::FromMilliseconds( + UserModel::kMedianGestureDurationMillis * 2)); + clock_->Advance(delta); + + base::TimeDelta prediction_valid_duration; + EXPECT_TRUE(user_model_->IsGestureExpectedSoon(clock_->NowTicks(), + &prediction_valid_duration)); + EXPECT_EQ(base::TimeDelta::FromMilliseconds( + UserModel::kExpectSubsequentGestureMillis), + prediction_valid_duration); +} + +TEST_F(UserModelTest, GestureExpectedSoon_ImmediatelyAfter_GestureScrollEnd) { + user_model_->DidStartProcessingInputEvent( + blink::WebInputEvent::Type::GestureScrollEnd, clock_->NowTicks()); + user_model_->DidFinishProcessingInputEvent(clock_->NowTicks()); + + base::TimeDelta prediction_valid_duration; + EXPECT_TRUE(user_model_->IsGestureExpectedSoon(clock_->NowTicks(), + &prediction_valid_duration)); + EXPECT_EQ(subsequent_input_expected_after_input_duration(), + prediction_valid_duration); +} + +TEST_F(UserModelTest, GestureExpectedSoon_ShortlyAfter_GestureScrollEnd) { + user_model_->DidStartProcessingInputEvent( + blink::WebInputEvent::Type::GestureScrollEnd, clock_->NowTicks()); + user_model_->DidFinishProcessingInputEvent(clock_->NowTicks()); + + base::TimeDelta delta(base::TimeDelta::FromMilliseconds(10)); + clock_->Advance(delta); + + base::TimeDelta prediction_valid_duration; + EXPECT_TRUE(user_model_->IsGestureExpectedSoon(clock_->NowTicks(), + &prediction_valid_duration)); + EXPECT_EQ(subsequent_input_expected_after_input_duration() - delta, + prediction_valid_duration); +} + +TEST_F(UserModelTest, GestureExpectedSoon_LongAfter_GestureScrollEnd) { + user_model_->DidStartProcessingInputEvent( + blink::WebInputEvent::Type::GestureScrollEnd, clock_->NowTicks()); + user_model_->DidFinishProcessingInputEvent(clock_->NowTicks()); + clock_->Advance(subsequent_input_expected_after_input_duration() * 2); + + base::TimeDelta prediction_valid_duration; + EXPECT_FALSE(user_model_->IsGestureExpectedSoon(clock_->NowTicks(), + &prediction_valid_duration)); + EXPECT_EQ(base::TimeDelta(), prediction_valid_duration); +} + +TEST_F(UserModelTest, GestureExpectedSoon_ShortlyAfter_GesturePinchEnd) { + user_model_->DidStartProcessingInputEvent( + blink::WebInputEvent::Type::GesturePinchEnd, clock_->NowTicks()); + user_model_->DidFinishProcessingInputEvent(clock_->NowTicks()); + + base::TimeDelta delta(base::TimeDelta::FromMilliseconds(10)); + clock_->Advance(delta); + + base::TimeDelta prediction_valid_duration; + EXPECT_TRUE(user_model_->IsGestureExpectedSoon(clock_->NowTicks(), + &prediction_valid_duration)); + EXPECT_EQ(subsequent_input_expected_after_input_duration() - delta, + prediction_valid_duration); +} + +TEST_F(UserModelTest, GestureExpectedSoon_ShortlyAfterInput_GestureTap) { + user_model_->DidStartProcessingInputEvent( + blink::WebInputEvent::Type::GestureTap, clock_->NowTicks()); + user_model_->DidFinishProcessingInputEvent(clock_->NowTicks()); + + base::TimeDelta delta(base::TimeDelta::FromMilliseconds(10)); + clock_->Advance(delta); + + base::TimeDelta prediction_valid_duration; + EXPECT_FALSE(user_model_->IsGestureExpectedSoon(clock_->NowTicks(), + &prediction_valid_duration)); + EXPECT_EQ(base::TimeDelta(), prediction_valid_duration); +} + +TEST_F(UserModelTest, IsGestureExpectedToContinue_NoGesture) { + base::TimeDelta prediction_valid_duration; + EXPECT_FALSE(user_model_->IsGestureExpectedToContinue( + clock_->NowTicks(), &prediction_valid_duration)); + EXPECT_EQ(base::TimeDelta(), prediction_valid_duration); +} + +TEST_F(UserModelTest, IsGestureExpectedToContinue_GestureJustStarted) { + user_model_->DidStartProcessingInputEvent( + blink::WebInputEvent::Type::GestureScrollBegin, clock_->NowTicks()); + base::TimeDelta prediction_valid_duration; + EXPECT_TRUE(user_model_->IsGestureExpectedToContinue( + clock_->NowTicks(), &prediction_valid_duration)); + EXPECT_EQ(base::TimeDelta::FromMilliseconds( + UserModel::kMedianGestureDurationMillis), + prediction_valid_duration); +} + +TEST_F(UserModelTest, IsGestureExpectedToContinue_GestureJustEnded) { + user_model_->DidStartProcessingInputEvent( + blink::WebInputEvent::Type::GestureScrollEnd, clock_->NowTicks()); + base::TimeDelta prediction_valid_duration; + EXPECT_FALSE(user_model_->IsGestureExpectedToContinue( + clock_->NowTicks(), &prediction_valid_duration)); + EXPECT_EQ(base::TimeDelta(), prediction_valid_duration); +} + +TEST_F(UserModelTest, IsGestureExpectedToContinue_ShortlyAfterGestureStarted) { + user_model_->DidStartProcessingInputEvent( + blink::WebInputEvent::Type::GestureScrollBegin, clock_->NowTicks()); + + base::TimeDelta delta(base::TimeDelta::FromMilliseconds(10)); + clock_->Advance(delta); + + base::TimeDelta prediction_valid_duration; + EXPECT_TRUE(user_model_->IsGestureExpectedToContinue( + clock_->NowTicks(), &prediction_valid_duration)); + EXPECT_EQ(base::TimeDelta::FromMilliseconds( + UserModel::kMedianGestureDurationMillis) - + delta, + prediction_valid_duration); +} + +TEST_F(UserModelTest, IsGestureExpectedToContinue_LongAfterGestureStarted) { + user_model_->DidStartProcessingInputEvent( + blink::WebInputEvent::Type::GestureScrollBegin, clock_->NowTicks()); + + base::TimeDelta delta(base::TimeDelta::FromMilliseconds( + UserModel::kMedianGestureDurationMillis * 2)); + clock_->Advance(delta); + + base::TimeDelta prediction_valid_duration; + EXPECT_FALSE(user_model_->IsGestureExpectedToContinue( + clock_->NowTicks(), &prediction_valid_duration)); + EXPECT_EQ(base::TimeDelta(), prediction_valid_duration); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.cc new file mode 100644 index 0000000..76b2579e --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.cc
@@ -0,0 +1,139 @@ +// 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 "platform/scheduler/renderer/web_frame_scheduler_impl.h" + +#include "base/trace_event/blame_context.h" +#include "platform/scheduler/base/real_time_domain.h" +#include "platform/scheduler/base/virtual_time_domain.h" +#include "platform/scheduler/child/web_task_runner_impl.h" +#include "platform/scheduler/renderer/auto_advancing_virtual_time_domain.h" +#include "platform/scheduler/renderer/renderer_scheduler_impl.h" +#include "platform/scheduler/renderer/web_view_scheduler_impl.h" +#include "public/platform/BlameContext.h" +#include "public/platform/WebString.h" + +namespace blink { +namespace scheduler { + +WebFrameSchedulerImpl::WebFrameSchedulerImpl( + RendererSchedulerImpl* renderer_scheduler, + WebViewSchedulerImpl* parent_web_view_scheduler, + base::trace_event::BlameContext* blame_context) + : renderer_scheduler_(renderer_scheduler), + parent_web_view_scheduler_(parent_web_view_scheduler), + blame_context_(blame_context), + frame_visible_(true), + page_visible_(true) {} + +WebFrameSchedulerImpl::~WebFrameSchedulerImpl() { + if (loading_task_queue_) { + loading_task_queue_->UnregisterTaskQueue(); + loading_task_queue_->SetBlameContext(nullptr); + } + + if (timer_task_queue_) { + timer_task_queue_->UnregisterTaskQueue(); + timer_task_queue_->SetBlameContext(nullptr); + } + + if (unthrottled_task_queue_) { + unthrottled_task_queue_->UnregisterTaskQueue(); + unthrottled_task_queue_->SetBlameContext(nullptr); + } + + if (parent_web_view_scheduler_) + parent_web_view_scheduler_->Unregister(this); +} + +void WebFrameSchedulerImpl::DetachFromWebViewScheduler() { + parent_web_view_scheduler_ = nullptr; +} + +void WebFrameSchedulerImpl::setFrameVisible(bool frame_visible) { + frame_visible_ = frame_visible; + // TODO(alexclarke): Do something with this flag. +} + +blink::WebTaskRunner* WebFrameSchedulerImpl::loadingTaskRunner() { + DCHECK(parent_web_view_scheduler_); + if (!loading_web_task_runner_) { + loading_task_queue_ = + renderer_scheduler_->NewLoadingTaskRunner("frame_loading_tq"); + loading_task_queue_->SetBlameContext(blame_context_); + loading_web_task_runner_.reset(new WebTaskRunnerImpl(loading_task_queue_)); + } + return loading_web_task_runner_.get(); +} + +blink::WebTaskRunner* WebFrameSchedulerImpl::timerTaskRunner() { + DCHECK(parent_web_view_scheduler_); + if (!timer_web_task_runner_) { + timer_task_queue_ = + renderer_scheduler_->NewTimerTaskRunner("frame_timer_tq"); + timer_task_queue_->SetBlameContext(blame_context_); + if (!page_visible_) { + renderer_scheduler_->throttling_helper()->IncreaseThrottleRefCount( + timer_task_queue_.get()); + } + timer_web_task_runner_.reset(new WebTaskRunnerImpl(timer_task_queue_)); + } + return timer_web_task_runner_.get(); +} + +blink::WebTaskRunner* WebFrameSchedulerImpl::unthrottledTaskRunner() { + DCHECK(parent_web_view_scheduler_); + if (!unthrottled_web_task_runner_) { + unthrottled_task_queue_ = + renderer_scheduler_->NewUnthrottledTaskRunner("frame_unthrottled_tq"); + unthrottled_task_queue_->SetBlameContext(blame_context_); + unthrottled_web_task_runner_.reset( + new WebTaskRunnerImpl(unthrottled_task_queue_)); + } + return unthrottled_web_task_runner_.get(); +} + +blink::WebViewScheduler* WebFrameSchedulerImpl::webViewScheduler() { + return parent_web_view_scheduler_; +} + +void WebFrameSchedulerImpl::didStartLoading(unsigned long identifier) { + if (parent_web_view_scheduler_) + parent_web_view_scheduler_->DidStartLoading(identifier); +} + +void WebFrameSchedulerImpl::didStopLoading(unsigned long identifier) { + if (parent_web_view_scheduler_) + parent_web_view_scheduler_->DidStopLoading(identifier); +} + +void WebFrameSchedulerImpl::setDocumentParsingInBackground( + bool background_parser_active) { + if (background_parser_active) + parent_web_view_scheduler_->IncrementBackgroundParserCount(); + else + parent_web_view_scheduler_->DecrementBackgroundParserCount(); +} + +void WebFrameSchedulerImpl::setPageVisible(bool page_visible) { + DCHECK(parent_web_view_scheduler_); + if (page_visible_ == page_visible) + return; + + page_visible_ = page_visible; + + if (!timer_web_task_runner_) + return; + + if (page_visible_) { + renderer_scheduler_->throttling_helper()->DecreaseThrottleRefCount( + timer_task_queue_.get()); + } else { + renderer_scheduler_->throttling_helper()->IncreaseThrottleRefCount( + timer_task_queue_.get()); + } +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.h b/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.h new file mode 100644 index 0000000..e18896d --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.h
@@ -0,0 +1,77 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_WEB_FRAME_SCHEDULER_IMPL_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_WEB_FRAME_SCHEDULER_IMPL_H_ + +#include <memory> + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/trace_event/trace_event.h" +#include "public/platform/scheduler/base/task_queue.h" +#include "public/platform/WebCommon.h" +#include "public/platform/WebFrameScheduler.h" + +namespace base { +namespace trace_event { +class BlameContext; +} // namespace trace_event +class SingleThreadTaskRunner; +} // namespace base + +namespace blink { +namespace scheduler { + +class AutoAdvancingVirtualTimeDomain; +class RendererSchedulerImpl; +class TaskQueue; +class WebTaskRunnerImpl; +class WebViewSchedulerImpl; + +class BLINK_PLATFORM_EXPORT WebFrameSchedulerImpl : public WebFrameScheduler { + public: + WebFrameSchedulerImpl(RendererSchedulerImpl* renderer_scheduler, + WebViewSchedulerImpl* parent_web_view_scheduler, + base::trace_event::BlameContext* blame_context); + + ~WebFrameSchedulerImpl() override; + + // WebFrameScheduler implementation: + void setFrameVisible(bool frame_visible) override; + void setPageVisible(bool page_visible) override; + WebTaskRunner* loadingTaskRunner() override; + WebTaskRunner* timerTaskRunner() override; + WebTaskRunner* unthrottledTaskRunner() override; + WebViewScheduler* webViewScheduler() override; + void didStartLoading(unsigned long identifier) override; + void didStopLoading(unsigned long identifier) override; + void setDocumentParsingInBackground(bool background_parser_active) override; + + private: + friend class WebViewSchedulerImpl; + + void DetachFromWebViewScheduler(); + void ApplyPolicyToTimerQueue(); + + scoped_refptr<TaskQueue> loading_task_queue_; + scoped_refptr<TaskQueue> timer_task_queue_; + scoped_refptr<TaskQueue> unthrottled_task_queue_; + std::unique_ptr<WebTaskRunnerImpl> loading_web_task_runner_; + std::unique_ptr<WebTaskRunnerImpl> timer_web_task_runner_; + std::unique_ptr<WebTaskRunnerImpl> unthrottled_web_task_runner_; + RendererSchedulerImpl* renderer_scheduler_; // NOT OWNED + WebViewSchedulerImpl* parent_web_view_scheduler_; // NOT OWNED + base::trace_event::BlameContext* blame_context_; // NOT OWNED + TaskQueue::PumpPolicy virtual_time_pump_policy_; + bool frame_visible_; + bool page_visible_; + + DISALLOW_COPY_AND_ASSIGN(WebFrameSchedulerImpl); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_WEB_FRAME_SCHEDULER_IMPL_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl.cc new file mode 100644 index 0000000..0dff1a2d --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl.cc
@@ -0,0 +1,158 @@ +// 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 "platform/scheduler/renderer/web_view_scheduler_impl.h" + +#include "base/logging.h" +#include "platform/scheduler/base/virtual_time_domain.h" +#include "platform/scheduler/child/scheduler_tqm_delegate.h" +#include "platform/scheduler/renderer/auto_advancing_virtual_time_domain.h" +#include "platform/scheduler/renderer/renderer_scheduler_impl.h" +#include "platform/scheduler/renderer/web_frame_scheduler_impl.h" +#include "public/platform/WebFrameScheduler.h" + +namespace blink { +namespace scheduler { + +WebViewSchedulerImpl::WebViewSchedulerImpl( + WebScheduler::InterventionReporter* intervention_reporter, + RendererSchedulerImpl* renderer_scheduler, + bool disable_background_timer_throttling) + : intervention_reporter_(intervention_reporter), + renderer_scheduler_(renderer_scheduler), + virtual_time_policy_(VirtualTimePolicy::ADVANCE), + background_parser_count_(0), + page_visible_(true), + disable_background_timer_throttling_(disable_background_timer_throttling), + allow_virtual_time_to_advance_(true), + have_seen_loading_task_(false), + virtual_time_(false) { + renderer_scheduler->AddWebViewScheduler(this); +} + +WebViewSchedulerImpl::~WebViewSchedulerImpl() { + // TODO(alexclarke): Find out why we can't rely on the web view outliving the + // frame. + for (WebFrameSchedulerImpl* frame_scheduler : frame_schedulers_) { + frame_scheduler->DetachFromWebViewScheduler(); + } + renderer_scheduler_->RemoveWebViewScheduler(this); +} + +void WebViewSchedulerImpl::setPageVisible(bool page_visible) { + if (disable_background_timer_throttling_ || page_visible_ == page_visible) + return; + + page_visible_ = page_visible; + + for (WebFrameSchedulerImpl* frame_scheduler : frame_schedulers_) { + frame_scheduler->setPageVisible(page_visible_); + } +} + +std::unique_ptr<WebFrameSchedulerImpl> +WebViewSchedulerImpl::createWebFrameSchedulerImpl( + base::trace_event::BlameContext* blame_context) { + std::unique_ptr<WebFrameSchedulerImpl> frame_scheduler( + new WebFrameSchedulerImpl(renderer_scheduler_, this, blame_context)); + frame_scheduler->setPageVisible(page_visible_); + frame_schedulers_.insert(frame_scheduler.get()); + return frame_scheduler; +} + +std::unique_ptr<blink::WebFrameScheduler> +WebViewSchedulerImpl::createFrameScheduler(blink::BlameContext* blame_context) { + return createWebFrameSchedulerImpl(blame_context); +} + +void WebViewSchedulerImpl::Unregister(WebFrameSchedulerImpl* frame_scheduler) { + DCHECK(frame_schedulers_.find(frame_scheduler) != frame_schedulers_.end()); + frame_schedulers_.erase(frame_scheduler); +} + +void WebViewSchedulerImpl::ReportIntervention(const std::string& message) { + intervention_reporter_->ReportIntervention(WebString::fromUTF8(message)); +} + +void WebViewSchedulerImpl::enableVirtualTime() { + if (virtual_time_) + return; + + virtual_time_ = true; + renderer_scheduler_->GetVirtualTimeDomain()->SetCanAdvanceVirtualTime( + allow_virtual_time_to_advance_); + + renderer_scheduler_->EnableVirtualTime(); +} + +void WebViewSchedulerImpl::setAllowVirtualTimeToAdvance( + bool allow_virtual_time_to_advance) { + allow_virtual_time_to_advance_ = allow_virtual_time_to_advance; + + if (!virtual_time_) + return; + + renderer_scheduler_->GetVirtualTimeDomain()->SetCanAdvanceVirtualTime( + allow_virtual_time_to_advance); +} + +bool WebViewSchedulerImpl::virtualTimeAllowedToAdvance() const { + return allow_virtual_time_to_advance_; +} + +void WebViewSchedulerImpl::DidStartLoading(unsigned long identifier) { + pending_loads_.insert(identifier); + have_seen_loading_task_ = true; + ApplyVirtualTimePolicy(); +} + +void WebViewSchedulerImpl::DidStopLoading(unsigned long identifier) { + pending_loads_.erase(identifier); + ApplyVirtualTimePolicy(); +} + +void WebViewSchedulerImpl::IncrementBackgroundParserCount() { + background_parser_count_++; + ApplyVirtualTimePolicy(); +} + +void WebViewSchedulerImpl::DecrementBackgroundParserCount() { + background_parser_count_--; + DCHECK_GE(background_parser_count_, 0); + ApplyVirtualTimePolicy(); +} + +void WebViewSchedulerImpl::setVirtualTimePolicy(VirtualTimePolicy policy) { + virtual_time_policy_ = policy; + + switch (virtual_time_policy_) { + case VirtualTimePolicy::ADVANCE: + setAllowVirtualTimeToAdvance(true); + break; + + case VirtualTimePolicy::PAUSE: + setAllowVirtualTimeToAdvance(false); + break; + + case VirtualTimePolicy::DETERMINISTIC_LOADING: + ApplyVirtualTimePolicy(); + break; + } +} + +void WebViewSchedulerImpl::ApplyVirtualTimePolicy() { + if (virtual_time_policy_ != VirtualTimePolicy::DETERMINISTIC_LOADING) { + return; + } + + // We pause virtual time until we've seen a loading task posted, because + // otherwise we could advance virtual time arbitarially far before the + // first load arrives. + setAllowVirtualTimeToAdvance(pending_loads_.size() == 0 && + background_parser_count_ == 0 && + have_seen_loading_task_); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl.h b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl.h new file mode 100644 index 0000000..09fe175 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl.h
@@ -0,0 +1,82 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_WEB_VIEW_SCHEDULER_IMPL_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_WEB_VIEW_SCHEDULER_IMPL_H_ + +#include <memory> +#include <set> +#include <string> + +#include "base/macros.h" +#include "public/platform/scheduler/base/task_queue.h" +#include "public/platform/WebCommon.h" +#include "public/platform/WebScheduler.h" +#include "public/platform/WebViewScheduler.h" + +namespace base { +namespace trace_event { +class BlameContext; +} // namespace trace_event +class SingleThreadTaskRunner; +} // namespace base + +namespace blink { +namespace scheduler { + +class RendererSchedulerImpl; +class WebFrameSchedulerImpl; + +class BLINK_PLATFORM_EXPORT WebViewSchedulerImpl : public WebViewScheduler { + public: + WebViewSchedulerImpl( + WebScheduler::InterventionReporter* intervention_reporter, + RendererSchedulerImpl* renderer_scheduler, + bool disable_background_timer_throttling); + + ~WebViewSchedulerImpl() override; + + // WebViewScheduler implementation: + void setPageVisible(bool page_visible) override; + std::unique_ptr<WebFrameScheduler> createFrameScheduler( + BlameContext* blame_context) override; + void enableVirtualTime() override; + bool virtualTimeAllowedToAdvance() const override; + void setVirtualTimePolicy(VirtualTimePolicy virtual_time_policy) override; + + // Virtual for testing. + virtual void ReportIntervention(const std::string& message); + + std::unique_ptr<WebFrameSchedulerImpl> createWebFrameSchedulerImpl( + base::trace_event::BlameContext* blame_context); + + void DidStartLoading(unsigned long identifier); + void DidStopLoading(unsigned long identifier); + void IncrementBackgroundParserCount(); + void DecrementBackgroundParserCount(); + void Unregister(WebFrameSchedulerImpl* frame_scheduler); + + private: + void setAllowVirtualTimeToAdvance(bool allow_virtual_time_to_advance); + void ApplyVirtualTimePolicy(); + + std::set<WebFrameSchedulerImpl*> frame_schedulers_; + std::set<unsigned long> pending_loads_; + WebScheduler::InterventionReporter* intervention_reporter_; // Not owned. + RendererSchedulerImpl* renderer_scheduler_; + VirtualTimePolicy virtual_time_policy_; + int background_parser_count_; + bool page_visible_; + bool disable_background_timer_throttling_; + bool allow_virtual_time_to_advance_; + bool have_seen_loading_task_; + bool virtual_time_; + + DISALLOW_COPY_AND_ASSIGN(WebViewSchedulerImpl); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_WEB_VIEW_SCHEDULER_IMPL_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl_unittest.cc new file mode 100644 index 0000000..4ddb4d5 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl_unittest.cc
@@ -0,0 +1,590 @@ +// 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 "platform/scheduler/renderer/web_view_scheduler_impl.h" + +#include <memory> + +#include "base/callback.h" +#include "base/memory/ptr_util.h" +#include "base/test/simple_test_tick_clock.h" +#include "cc/test/ordered_simple_task_runner.h" +#include "platform/scheduler/base/test_time_source.h" +#include "platform/scheduler/child/scheduler_tqm_delegate_for_test.h" +#include "platform/scheduler/renderer/renderer_scheduler_impl.h" +#include "platform/scheduler/renderer/web_frame_scheduler_impl.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "public/platform/WebTaskRunner.h" +#include "public/platform/WebTraceLocation.h" + +using testing::ElementsAre; +using VirtualTimePolicy = blink::WebViewScheduler::VirtualTimePolicy; + +namespace blink { +namespace scheduler { + +class WebViewSchedulerImplTest : public testing::Test { + public: + WebViewSchedulerImplTest() {} + ~WebViewSchedulerImplTest() override {} + + void SetUp() override { + clock_.reset(new base::SimpleTestTickClock()); + clock_->Advance(base::TimeDelta::FromMicroseconds(5000)); + mock_task_runner_ = + make_scoped_refptr(new cc::OrderedSimpleTaskRunner(clock_.get(), true)); + delegate_ = SchedulerTqmDelegateForTest::Create( + mock_task_runner_, base::WrapUnique(new TestTimeSource(clock_.get()))); + scheduler_.reset(new RendererSchedulerImpl(delegate_)); + web_view_scheduler_.reset(new WebViewSchedulerImpl( + nullptr, scheduler_.get(), DisableBackgroundTimerThrottling())); + web_frame_scheduler_ = + web_view_scheduler_->createWebFrameSchedulerImpl(nullptr); + } + + void TearDown() override { + web_frame_scheduler_.reset(); + web_view_scheduler_.reset(); + scheduler_->Shutdown(); + scheduler_.reset(); + } + + virtual bool DisableBackgroundTimerThrottling() const { return false; } + + std::unique_ptr<base::SimpleTestTickClock> clock_; + scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_; + scoped_refptr<SchedulerTqmDelegate> delegate_; + std::unique_ptr<RendererSchedulerImpl> scheduler_; + std::unique_ptr<WebViewSchedulerImpl> web_view_scheduler_; + std::unique_ptr<WebFrameSchedulerImpl> web_frame_scheduler_; +}; + +TEST_F(WebViewSchedulerImplTest, TestDestructionOfFrameSchedulersBefore) { + std::unique_ptr<blink::WebFrameScheduler> frame1( + web_view_scheduler_->createFrameScheduler(nullptr)); + std::unique_ptr<blink::WebFrameScheduler> frame2( + web_view_scheduler_->createFrameScheduler(nullptr)); +} + +TEST_F(WebViewSchedulerImplTest, TestDestructionOfFrameSchedulersAfter) { + std::unique_ptr<blink::WebFrameScheduler> frame1( + web_view_scheduler_->createFrameScheduler(nullptr)); + std::unique_ptr<blink::WebFrameScheduler> frame2( + web_view_scheduler_->createFrameScheduler(nullptr)); + web_view_scheduler_.reset(); +} + +namespace { +class RepeatingTask : public blink::WebTaskRunner::Task { + public: + RepeatingTask(blink::WebTaskRunner* web_task_runner, int* run_count) + : web_task_runner_(web_task_runner), run_count_(run_count) {} + + ~RepeatingTask() override {} + + void run() override { + (*run_count_)++; + web_task_runner_->postDelayedTask( + BLINK_FROM_HERE, new RepeatingTask(web_task_runner_, run_count_), 1.0); + } + + private: + blink::WebTaskRunner* web_task_runner_; // NOT OWNED + int* run_count_; // NOT OWNED +}; +} // namespace + +TEST_F(WebViewSchedulerImplTest, RepeatingTimer_PageInForeground) { + web_view_scheduler_->setPageVisible(true); + + int run_count = 0; + web_frame_scheduler_->timerTaskRunner()->postDelayedTask( + BLINK_FROM_HERE, + new RepeatingTask(web_frame_scheduler_->timerTaskRunner(), &run_count), + 1.0); + + mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1)); + EXPECT_EQ(1000, run_count); +} + +TEST_F(WebViewSchedulerImplTest, RepeatingTimer_PageInBackground) { + web_view_scheduler_->setPageVisible(false); + + int run_count = 0; + web_frame_scheduler_->timerTaskRunner()->postDelayedTask( + BLINK_FROM_HERE, + new RepeatingTask(web_frame_scheduler_->timerTaskRunner(), &run_count), + 1.0); + + mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1)); + EXPECT_EQ(1, run_count); +} + +TEST_F(WebViewSchedulerImplTest, RepeatingLoadingTask_PageInBackground) { + web_view_scheduler_->setPageVisible(false); + + int run_count = 0; + web_frame_scheduler_->loadingTaskRunner()->postDelayedTask( + BLINK_FROM_HERE, + new RepeatingTask(web_frame_scheduler_->loadingTaskRunner(), &run_count), + 1.0); + + mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1)); + EXPECT_EQ(1000, run_count); // Loading tasks should not be throttled +} + +TEST_F(WebViewSchedulerImplTest, RepeatingTimers_OneBackgroundOneForeground) { + std::unique_ptr<WebViewSchedulerImpl> web_view_scheduler2( + new WebViewSchedulerImpl(nullptr, scheduler_.get(), false)); + std::unique_ptr<WebFrameSchedulerImpl> web_frame_scheduler2 = + web_view_scheduler2->createWebFrameSchedulerImpl(nullptr); + + web_view_scheduler_->setPageVisible(true); + web_view_scheduler2->setPageVisible(false); + + int run_count1 = 0; + int run_count2 = 0; + web_frame_scheduler_->timerTaskRunner()->postDelayedTask( + BLINK_FROM_HERE, + new RepeatingTask(web_frame_scheduler_->timerTaskRunner(), &run_count1), + 1.0); + web_frame_scheduler2->timerTaskRunner()->postDelayedTask( + BLINK_FROM_HERE, + new RepeatingTask(web_frame_scheduler2->timerTaskRunner(), &run_count2), + 1.0); + + mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1)); + EXPECT_EQ(1000, run_count1); + EXPECT_EQ(1, run_count2); +} + +namespace { +class VirtualTimeRecorderTask : public blink::WebTaskRunner::Task { + public: + VirtualTimeRecorderTask(base::SimpleTestTickClock* clock, + blink::WebTaskRunner* web_task_runner, + std::vector<base::TimeTicks>* out_real_times, + std::vector<size_t>* out_virtual_times_ms) + : clock_(clock), + web_task_runner_(web_task_runner), + out_real_times_(out_real_times), + out_virtual_times_ms_(out_virtual_times_ms) {} + + ~VirtualTimeRecorderTask() override {} + + void run() override { + out_real_times_->push_back(clock_->NowTicks()); + out_virtual_times_ms_->push_back( + web_task_runner_->monotonicallyIncreasingVirtualTimeSeconds() * 1000.0); + } + + private: + base::SimpleTestTickClock* clock_; // NOT OWNED + blink::WebTaskRunner* web_task_runner_; // NOT OWNED + std::vector<base::TimeTicks>* out_real_times_; // NOT OWNED + std::vector<size_t>* out_virtual_times_ms_; // NOT OWNED +}; +} + +TEST_F(WebViewSchedulerImplTest, VirtualTime_TimerFastForwarding) { + std::vector<base::TimeTicks> real_times; + std::vector<size_t> virtual_times_ms; + base::TimeTicks initial_real_time = scheduler_->tick_clock()->NowTicks(); + size_t initial_virtual_time_ms = + web_frame_scheduler_->timerTaskRunner() + ->monotonicallyIncreasingVirtualTimeSeconds() * + 1000.0; + + web_view_scheduler_->enableVirtualTime(); + + web_frame_scheduler_->timerTaskRunner()->postDelayedTask( + BLINK_FROM_HERE, + new VirtualTimeRecorderTask(clock_.get(), + web_frame_scheduler_->timerTaskRunner(), + &real_times, &virtual_times_ms), + 2.0); + + web_frame_scheduler_->timerTaskRunner()->postDelayedTask( + BLINK_FROM_HERE, + new VirtualTimeRecorderTask(clock_.get(), + web_frame_scheduler_->timerTaskRunner(), + &real_times, &virtual_times_ms), + 20.0); + + web_frame_scheduler_->timerTaskRunner()->postDelayedTask( + BLINK_FROM_HERE, + new VirtualTimeRecorderTask(clock_.get(), + web_frame_scheduler_->timerTaskRunner(), + &real_times, &virtual_times_ms), + 200.0); + + mock_task_runner_->RunUntilIdle(); + + EXPECT_THAT(real_times, ElementsAre(initial_real_time, initial_real_time, + initial_real_time)); + EXPECT_THAT(virtual_times_ms, ElementsAre(initial_virtual_time_ms + 2, + initial_virtual_time_ms + 20, + initial_virtual_time_ms + 200)); +} + +TEST_F(WebViewSchedulerImplTest, VirtualTime_LoadingTaskFastForwarding) { + std::vector<base::TimeTicks> real_times; + std::vector<size_t> virtual_times_ms; + base::TimeTicks initial_real_time = scheduler_->tick_clock()->NowTicks(); + size_t initial_virtual_time_ms = + web_frame_scheduler_->timerTaskRunner() + ->monotonicallyIncreasingVirtualTimeSeconds() * + 1000.0; + + web_view_scheduler_->enableVirtualTime(); + + web_frame_scheduler_->loadingTaskRunner()->postDelayedTask( + BLINK_FROM_HERE, + new VirtualTimeRecorderTask(clock_.get(), + web_frame_scheduler_->loadingTaskRunner(), + &real_times, &virtual_times_ms), + 2.0); + + web_frame_scheduler_->loadingTaskRunner()->postDelayedTask( + BLINK_FROM_HERE, + new VirtualTimeRecorderTask(clock_.get(), + web_frame_scheduler_->loadingTaskRunner(), + &real_times, &virtual_times_ms), + 20.0); + + web_frame_scheduler_->loadingTaskRunner()->postDelayedTask( + BLINK_FROM_HERE, + new VirtualTimeRecorderTask(clock_.get(), + web_frame_scheduler_->loadingTaskRunner(), + &real_times, &virtual_times_ms), + 200.0); + + mock_task_runner_->RunUntilIdle(); + + EXPECT_THAT(real_times, ElementsAre(initial_real_time, initial_real_time, + initial_real_time)); + EXPECT_THAT(virtual_times_ms, ElementsAre(initial_virtual_time_ms + 2, + initial_virtual_time_ms + 20, + initial_virtual_time_ms + 200)); +} + +TEST_F(WebViewSchedulerImplTest, + RepeatingTimer_PageInBackground_MeansNothingForVirtualTime) { + web_view_scheduler_->enableVirtualTime(); + web_view_scheduler_->setPageVisible(false); + base::TimeTicks initial_real_time = scheduler_->tick_clock()->NowTicks(); + + int run_count = 0; + web_frame_scheduler_->timerTaskRunner()->postDelayedTask( + BLINK_FROM_HERE, + new RepeatingTask(web_frame_scheduler_->timerTaskRunner(), &run_count), + 1.0); + + mock_task_runner_->RunTasksWhile(mock_task_runner_->TaskRunCountBelow(2000)); + // Virtual time means page visibility is ignored. + EXPECT_EQ(1999, run_count); + + // The global tick clock has not moved, yet we ran a large number of "delayed" + // tasks despite calling setPageVisible(false). + EXPECT_EQ(initial_real_time, scheduler_->tick_clock()->NowTicks()); +} + +namespace { +class RunOrderTask : public blink::WebTaskRunner::Task { + public: + RunOrderTask(int index, std::vector<int>* out_run_order) + : index_(index), out_run_order_(out_run_order) {} + + ~RunOrderTask() override {} + + void run() override { out_run_order_->push_back(index_); } + + private: + int index_; + std::vector<int>* out_run_order_; // NOT OWNED +}; + +class DelayedRunOrderTask : public blink::WebTaskRunner::Task { + public: + DelayedRunOrderTask(int index, + blink::WebTaskRunner* task_runner, + std::vector<int>* out_run_order) + : index_(index), + task_runner_(task_runner), + out_run_order_(out_run_order) {} + + ~DelayedRunOrderTask() override {} + + void run() override { + out_run_order_->push_back(index_); + task_runner_->postTask(BLINK_FROM_HERE, + new RunOrderTask(index_ + 1, out_run_order_)); + } + + private: + int index_; + blink::WebTaskRunner* task_runner_; // NOT OWNED + std::vector<int>* out_run_order_; // NOT OWNED +}; +} + +TEST_F(WebViewSchedulerImplTest, VirtualTime_NotAllowedToAdvance) { + std::vector<int> run_order; + + web_view_scheduler_->setVirtualTimePolicy(VirtualTimePolicy::PAUSE); + web_view_scheduler_->enableVirtualTime(); + + web_frame_scheduler_->timerTaskRunner()->postTask( + BLINK_FROM_HERE, new RunOrderTask(0, &run_order)); + + web_frame_scheduler_->timerTaskRunner()->postDelayedTask( + BLINK_FROM_HERE, + new DelayedRunOrderTask(1, web_frame_scheduler_->timerTaskRunner(), + &run_order), + 2.0); + + web_frame_scheduler_->timerTaskRunner()->postDelayedTask( + BLINK_FROM_HERE, + new DelayedRunOrderTask(3, web_frame_scheduler_->timerTaskRunner(), + &run_order), + 4.0); + + mock_task_runner_->RunUntilIdle(); + + // Immediate tasks are allowed to run even if delayed tasks are not. + EXPECT_THAT(run_order, ElementsAre(0)); +} + +TEST_F(WebViewSchedulerImplTest, VirtualTime_AllowedToAdvance) { + std::vector<int> run_order; + + web_view_scheduler_->setVirtualTimePolicy(VirtualTimePolicy::ADVANCE); + web_view_scheduler_->enableVirtualTime(); + + web_frame_scheduler_->timerTaskRunner()->postTask( + BLINK_FROM_HERE, new RunOrderTask(0, &run_order)); + + web_frame_scheduler_->timerTaskRunner()->postDelayedTask( + BLINK_FROM_HERE, + new DelayedRunOrderTask(1, web_frame_scheduler_->timerTaskRunner(), + &run_order), + 2.0); + + web_frame_scheduler_->timerTaskRunner()->postDelayedTask( + BLINK_FROM_HERE, + new DelayedRunOrderTask(3, web_frame_scheduler_->timerTaskRunner(), + &run_order), + 4.0); + + mock_task_runner_->RunUntilIdle(); + + EXPECT_THAT(run_order, ElementsAre(0, 1, 2, 3, 4)); +} + +class WebViewSchedulerImplTestWithDisabledBackgroundTimerThrottling + : public WebViewSchedulerImplTest { + public: + WebViewSchedulerImplTestWithDisabledBackgroundTimerThrottling() {} + ~WebViewSchedulerImplTestWithDisabledBackgroundTimerThrottling() override {} + + bool DisableBackgroundTimerThrottling() const override { return true; } +}; + +TEST_F(WebViewSchedulerImplTestWithDisabledBackgroundTimerThrottling, + RepeatingTimer_PageInBackground) { + web_view_scheduler_->setPageVisible(false); + + int run_count = 0; + web_frame_scheduler_->timerTaskRunner()->postDelayedTask( + BLINK_FROM_HERE, + new RepeatingTask(web_frame_scheduler_->timerTaskRunner(), &run_count), + 1.0); + + mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1)); + EXPECT_EQ(1000, run_count); +} + +TEST_F(WebViewSchedulerImplTest, VirtualTimeSettings_NewWebFrameScheduler) { + std::vector<int> run_order; + + web_view_scheduler_->setVirtualTimePolicy(VirtualTimePolicy::PAUSE); + web_view_scheduler_->enableVirtualTime(); + + std::unique_ptr<WebFrameSchedulerImpl> web_frame_scheduler = + web_view_scheduler_->createWebFrameSchedulerImpl(nullptr); + + web_frame_scheduler->timerTaskRunner()->postDelayedTask( + BLINK_FROM_HERE, new RunOrderTask(1, &run_order), 0.1); + + mock_task_runner_->RunUntilIdle(); + EXPECT_TRUE(run_order.empty()); + + web_view_scheduler_->setVirtualTimePolicy(VirtualTimePolicy::ADVANCE); + mock_task_runner_->RunUntilIdle(); + + EXPECT_THAT(run_order, ElementsAre(1)); +} + +namespace { +class DeleteWebFrameSchedulerTask : public blink::WebTaskRunner::Task { + public: + explicit DeleteWebFrameSchedulerTask(WebViewSchedulerImpl* web_view_scheduler) + : web_frame_scheduler_( + web_view_scheduler->createWebFrameSchedulerImpl(nullptr)) {} + + ~DeleteWebFrameSchedulerTask() override {} + + void run() override { web_frame_scheduler_.reset(); } + + WebFrameSchedulerImpl* web_frame_scheduler() const { + return web_frame_scheduler_.get(); + } + + private: + std::unique_ptr<WebFrameSchedulerImpl> web_frame_scheduler_; +}; + +class DeleteWebViewSchedulerTask : public blink::WebTaskRunner::Task { + public: + explicit DeleteWebViewSchedulerTask(WebViewSchedulerImpl* web_view_scheduler) + : web_view_scheduler_(web_view_scheduler) {} + + ~DeleteWebViewSchedulerTask() override {} + + void run() override { web_view_scheduler_.reset(); } + + private: + std::unique_ptr<WebViewSchedulerImpl> web_view_scheduler_; +}; +} // namespace + +TEST_F(WebViewSchedulerImplTest, DeleteWebFrameSchedulers_InTask) { + for (int i = 0; i < 10; i++) { + DeleteWebFrameSchedulerTask* task = + new DeleteWebFrameSchedulerTask(web_view_scheduler_.get()); + task->web_frame_scheduler()->timerTaskRunner()->postDelayedTask( + BLINK_FROM_HERE, task, 1.0); + } + mock_task_runner_->RunUntilIdle(); +} + +TEST_F(WebViewSchedulerImplTest, DeleteWebViewScheduler_InTask) { + web_frame_scheduler_->timerTaskRunner()->postTask( + BLINK_FROM_HERE, + new DeleteWebViewSchedulerTask(web_view_scheduler_.release())); + mock_task_runner_->RunUntilIdle(); +} + +TEST_F(WebViewSchedulerImplTest, DeleteThrottledQueue_InTask) { + web_view_scheduler_->setPageVisible(false); + + DeleteWebFrameSchedulerTask* delete_frame_task = + new DeleteWebFrameSchedulerTask(web_view_scheduler_.get()); + blink::WebTaskRunner* timer_task_runner = + delete_frame_task->web_frame_scheduler()->timerTaskRunner(); + + int run_count = 0; + timer_task_runner->postDelayedTask( + BLINK_FROM_HERE, new RepeatingTask(timer_task_runner, &run_count), 1.0); + + // Note this will run at time t = 10s since we start at time t = 5000us, and + // it will prevent further tasks from running (i.e. the RepeatingTask) by + // deleting the WebFrameScheduler. + timer_task_runner->postDelayedTask(BLINK_FROM_HERE, delete_frame_task, + 9990.0); + + mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(100)); + EXPECT_EQ(10, run_count); +} + +TEST_F(WebViewSchedulerImplTest, VirtualTimePolicy_DETERMINISTIC_LOADING) { + web_view_scheduler_->setVirtualTimePolicy( + VirtualTimePolicy::DETERMINISTIC_LOADING); + // Initially virtual time is not allowed to advance until we have seen at + // least one load. + EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); + + web_view_scheduler_->DidStartLoading(1u); + EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); + + web_view_scheduler_->DidStartLoading(2u); + EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); + + web_view_scheduler_->DidStopLoading(2u); + EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); + + web_view_scheduler_->DidStartLoading(3u); + EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); + + web_view_scheduler_->DidStopLoading(1u); + EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); + + web_view_scheduler_->DidStopLoading(3u); + EXPECT_TRUE(web_view_scheduler_->virtualTimeAllowedToAdvance()); + + web_view_scheduler_->DidStartLoading(4u); + EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); + + web_view_scheduler_->DidStopLoading(4u); + EXPECT_TRUE(web_view_scheduler_->virtualTimeAllowedToAdvance()); +} + +TEST_F(WebViewSchedulerImplTest, RedundantDidStopLoadingCallsAreHarmless) { + web_view_scheduler_->setVirtualTimePolicy( + VirtualTimePolicy::DETERMINISTIC_LOADING); + + web_view_scheduler_->DidStartLoading(1u); + EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); + + web_view_scheduler_->DidStopLoading(1u); + EXPECT_TRUE(web_view_scheduler_->virtualTimeAllowedToAdvance()); + + web_view_scheduler_->DidStopLoading(1u); + EXPECT_TRUE(web_view_scheduler_->virtualTimeAllowedToAdvance()); + + web_view_scheduler_->DidStopLoading(1u); + EXPECT_TRUE(web_view_scheduler_->virtualTimeAllowedToAdvance()); + + web_view_scheduler_->DidStartLoading(2u); + EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); + + web_view_scheduler_->DidStopLoading(2u); + EXPECT_TRUE(web_view_scheduler_->virtualTimeAllowedToAdvance()); +} + +TEST_F(WebViewSchedulerImplTest, BackgroundParser_DETERMINISTIC_LOADING) { + web_view_scheduler_->setVirtualTimePolicy( + VirtualTimePolicy::DETERMINISTIC_LOADING); + // Initially virtual time is not allowed to advance until we have seen at + // least one load. + EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); + + web_view_scheduler_->IncrementBackgroundParserCount(); + EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); + + web_view_scheduler_->DidStartLoading(1u); + EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); + + web_view_scheduler_->DidStopLoading(1u); + EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); + + web_view_scheduler_->IncrementBackgroundParserCount(); + EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); + + web_view_scheduler_->DecrementBackgroundParserCount(); + EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); + + web_view_scheduler_->DecrementBackgroundParserCount(); + EXPECT_TRUE(web_view_scheduler_->virtualTimeAllowedToAdvance()); + + web_view_scheduler_->IncrementBackgroundParserCount(); + EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance()); + + web_view_scheduler_->DecrementBackgroundParserCount(); + EXPECT_TRUE(web_view_scheduler_->virtualTimeAllowedToAdvance()); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.cc b/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.cc new file mode 100644 index 0000000..13acf169 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.cc
@@ -0,0 +1,60 @@ +// 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 "platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.h" + +#include "public/platform/scheduler/base/task_queue.h" +#include "platform/scheduler/child/web_task_runner_impl.h" +#include "platform/scheduler/renderer/renderer_scheduler_impl.h" +#include "platform/scheduler/renderer/renderer_web_scheduler_impl.h" +#include "public/platform/WebTraceLocation.h" + +namespace blink { +namespace scheduler { + +WebThreadImplForRendererScheduler::WebThreadImplForRendererScheduler( + RendererSchedulerImpl* scheduler) + : web_scheduler_(new RendererWebSchedulerImpl(scheduler)), + task_runner_(scheduler->DefaultTaskRunner()), + idle_task_runner_(scheduler->IdleTaskRunner()), + scheduler_(scheduler), + thread_id_(base::PlatformThread::CurrentId()), + web_task_runner_(new WebTaskRunnerImpl(scheduler->DefaultTaskRunner())) {} + +WebThreadImplForRendererScheduler::~WebThreadImplForRendererScheduler() {} + +blink::PlatformThreadId WebThreadImplForRendererScheduler::threadId() const { + return thread_id_; +} + +blink::WebScheduler* WebThreadImplForRendererScheduler::scheduler() const { + return web_scheduler_.get(); +} + +base::SingleThreadTaskRunner* WebThreadImplForRendererScheduler::GetTaskRunner() + const { + return task_runner_.get(); +} + +SingleThreadIdleTaskRunner* +WebThreadImplForRendererScheduler::GetIdleTaskRunner() const { + return idle_task_runner_.get(); +} + +blink::WebTaskRunner* WebThreadImplForRendererScheduler::getWebTaskRunner() { + return web_task_runner_.get(); +} + +void WebThreadImplForRendererScheduler::AddTaskObserverInternal( + base::MessageLoop::TaskObserver* observer) { + scheduler_->AddTaskObserver(observer); +} + +void WebThreadImplForRendererScheduler::RemoveTaskObserverInternal( + base::MessageLoop::TaskObserver* observer) { + scheduler_->RemoveTaskObserver(observer); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.h b/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.h new file mode 100644 index 0000000..b7785fa6 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.h
@@ -0,0 +1,53 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_WEBTHREAD_IMPL_FOR_RENDERER_SCHEDULER_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_WEBTHREAD_IMPL_FOR_RENDERER_SCHEDULER_H_ + +#include "base/containers/scoped_ptr_hash_map.h" +#include "public/platform/scheduler/child/webthread_base.h" + +namespace blink { +class WebScheduler; +}; + +namespace blink { +namespace scheduler { +class RendererSchedulerImpl; +class WebSchedulerImpl; +class WebTaskRunnerImpl; + +class BLINK_PLATFORM_EXPORT WebThreadImplForRendererScheduler + : public WebThreadBase { + public: + explicit WebThreadImplForRendererScheduler(RendererSchedulerImpl* scheduler); + ~WebThreadImplForRendererScheduler() override; + + // WebThread implementation. + WebScheduler* scheduler() const override; + PlatformThreadId threadId() const override; + WebTaskRunner* getWebTaskRunner() override; + + // WebThreadBase implementation. + base::SingleThreadTaskRunner* GetTaskRunner() const override; + SingleThreadIdleTaskRunner* GetIdleTaskRunner() const override; + + private: + void AddTaskObserverInternal( + base::MessageLoop::TaskObserver* observer) override; + void RemoveTaskObserverInternal( + base::MessageLoop::TaskObserver* observer) override; + + std::unique_ptr<WebSchedulerImpl> web_scheduler_; + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_; + RendererSchedulerImpl* scheduler_; // Not owned. + PlatformThreadId thread_id_; + std::unique_ptr<WebTaskRunnerImpl> web_task_runner_; +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_WEBTHREAD_IMPL_FOR_RENDERER_SCHEDULER_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler_unittest.cc new file mode 100644 index 0000000..50e8c7a --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler_unittest.cc
@@ -0,0 +1,215 @@ +// 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 "platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.h" + +#include <stddef.h> + +#include "base/location.h" +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "base/run_loop.h" +#include "base/single_thread_task_runner.h" +#include "base/test/simple_test_tick_clock.h" +#include "platform/scheduler/base/test_time_source.h" +#include "platform/scheduler/child/scheduler_tqm_delegate_impl.h" +#include "platform/scheduler/renderer/renderer_scheduler_impl.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "public/platform/WebTaskRunner.h" +#include "public/platform/WebTraceLocation.h" + +namespace blink { +namespace scheduler { +namespace { + +const int kWorkBatchSize = 2; + +class MockTask : public blink::WebTaskRunner::Task { + public: + MOCK_METHOD0(run, void()); +}; + +class MockTaskObserver : public blink::WebThread::TaskObserver { + public: + MOCK_METHOD0(willProcessTask, void()); + MOCK_METHOD0(didProcessTask, void()); +}; +} // namespace + +class WebThreadImplForRendererSchedulerTest : public testing::Test { + public: + WebThreadImplForRendererSchedulerTest() {} + + void SetUp() override { + clock_.reset(new base::SimpleTestTickClock()); + clock_->Advance(base::TimeDelta::FromMicroseconds(5000)); + scheduler_.reset(new RendererSchedulerImpl(SchedulerTqmDelegateImpl::Create( + &message_loop_, base::WrapUnique(new TestTimeSource(clock_.get()))))); + default_task_runner_ = scheduler_->DefaultTaskRunner(); + thread_ = scheduler_->CreateMainThread(); + } + + ~WebThreadImplForRendererSchedulerTest() override {} + + void SetWorkBatchSizeForTesting(size_t work_batch_size) { + scheduler_->GetSchedulerHelperForTesting()->SetWorkBatchSizeForTesting( + work_batch_size); + } + + void TearDown() override { scheduler_->Shutdown(); } + + protected: + base::MessageLoop message_loop_; + std::unique_ptr<base::SimpleTestTickClock> clock_; + std::unique_ptr<RendererSchedulerImpl> scheduler_; + scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_; + std::unique_ptr<blink::WebThread> thread_; + + DISALLOW_COPY_AND_ASSIGN(WebThreadImplForRendererSchedulerTest); +}; + +TEST_F(WebThreadImplForRendererSchedulerTest, TestTaskObserver) { + MockTaskObserver observer; + thread_->addTaskObserver(&observer); + std::unique_ptr<MockTask> task(new MockTask()); + + { + testing::InSequence sequence; + EXPECT_CALL(observer, willProcessTask()); + EXPECT_CALL(*task, run()); + EXPECT_CALL(observer, didProcessTask()); + } + + thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(), + task.release()); + base::RunLoop().RunUntilIdle(); + thread_->removeTaskObserver(&observer); +} + +TEST_F(WebThreadImplForRendererSchedulerTest, TestWorkBatchWithOneTask) { + MockTaskObserver observer; + thread_->addTaskObserver(&observer); + std::unique_ptr<MockTask> task(new MockTask()); + + SetWorkBatchSizeForTesting(kWorkBatchSize); + { + testing::InSequence sequence; + EXPECT_CALL(observer, willProcessTask()); + EXPECT_CALL(*task, run()); + EXPECT_CALL(observer, didProcessTask()); + } + + thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(), + task.release()); + base::RunLoop().RunUntilIdle(); + thread_->removeTaskObserver(&observer); +} + +TEST_F(WebThreadImplForRendererSchedulerTest, TestWorkBatchWithTwoTasks) { + MockTaskObserver observer; + thread_->addTaskObserver(&observer); + std::unique_ptr<MockTask> task1(new MockTask()); + std::unique_ptr<MockTask> task2(new MockTask()); + + SetWorkBatchSizeForTesting(kWorkBatchSize); + { + testing::InSequence sequence; + EXPECT_CALL(observer, willProcessTask()); + EXPECT_CALL(*task1, run()); + EXPECT_CALL(observer, didProcessTask()); + + EXPECT_CALL(observer, willProcessTask()); + EXPECT_CALL(*task2, run()); + EXPECT_CALL(observer, didProcessTask()); + } + + thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(), + task1.release()); + thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(), + task2.release()); + base::RunLoop().RunUntilIdle(); + thread_->removeTaskObserver(&observer); +} + +TEST_F(WebThreadImplForRendererSchedulerTest, TestWorkBatchWithThreeTasks) { + MockTaskObserver observer; + thread_->addTaskObserver(&observer); + std::unique_ptr<MockTask> task1(new MockTask()); + std::unique_ptr<MockTask> task2(new MockTask()); + std::unique_ptr<MockTask> task3(new MockTask()); + + SetWorkBatchSizeForTesting(kWorkBatchSize); + { + testing::InSequence sequence; + EXPECT_CALL(observer, willProcessTask()); + EXPECT_CALL(*task1, run()); + EXPECT_CALL(observer, didProcessTask()); + + EXPECT_CALL(observer, willProcessTask()); + EXPECT_CALL(*task2, run()); + EXPECT_CALL(observer, didProcessTask()); + + EXPECT_CALL(observer, willProcessTask()); + EXPECT_CALL(*task3, run()); + EXPECT_CALL(observer, didProcessTask()); + } + + thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(), + task1.release()); + thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(), + task2.release()); + thread_->getWebTaskRunner()->postTask(blink::WebTraceLocation(), + task3.release()); + base::RunLoop().RunUntilIdle(); + thread_->removeTaskObserver(&observer); +} + +class ExitRunLoopTask : public blink::WebTaskRunner::Task { + public: + ExitRunLoopTask(base::RunLoop* run_loop) : run_loop_(run_loop) {} + + void run() override { run_loop_->Quit(); } + + private: + base::RunLoop* run_loop_; +}; + +void EnterRunLoop(base::MessageLoop* message_loop, blink::WebThread* thread) { + // Note: WebThreads do not support nested run loops, which is why we use a + // run loop directly. + base::RunLoop run_loop; + thread->getWebTaskRunner()->postTask(blink::WebTraceLocation(), + new ExitRunLoopTask(&run_loop)); + message_loop->SetNestableTasksAllowed(true); + run_loop.Run(); +} + +TEST_F(WebThreadImplForRendererSchedulerTest, TestNestedRunLoop) { + MockTaskObserver observer; + thread_->addTaskObserver(&observer); + + { + testing::InSequence sequence; + + // One callback for EnterRunLoop. + EXPECT_CALL(observer, willProcessTask()); + + // A pair for ExitRunLoopTask. + EXPECT_CALL(observer, willProcessTask()); + EXPECT_CALL(observer, didProcessTask()); + + // A final callback for EnterRunLoop. + EXPECT_CALL(observer, didProcessTask()); + } + + message_loop_.task_runner()->PostTask( + FROM_HERE, base::Bind(&EnterRunLoop, base::Unretained(&message_loop_), + base::Unretained(thread_.get()))); + base::RunLoop().RunUntilIdle(); + thread_->removeTaskObserver(&observer); +} + +} // namespace scheduler +} // namespace blink
diff --git a/components/scheduler/test/DEPS b/third_party/WebKit/Source/platform/scheduler/test/DEPS similarity index 100% rename from components/scheduler/test/DEPS rename to third_party/WebKit/Source/platform/scheduler/test/DEPS
diff --git a/third_party/WebKit/Source/platform/scheduler/test/fake_renderer_scheduler.cc b/third_party/WebKit/Source/platform/scheduler/test/fake_renderer_scheduler.cc new file mode 100644 index 0000000..b146c3a --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/test/fake_renderer_scheduler.cc
@@ -0,0 +1,123 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "public/platform/scheduler/test/fake_renderer_scheduler.h" + +#include "public/platform/WebThread.h" + +namespace blink { +namespace scheduler { + +FakeRendererScheduler::FakeRendererScheduler() {} + +FakeRendererScheduler::~FakeRendererScheduler() {} + +std::unique_ptr<blink::WebThread> FakeRendererScheduler::CreateMainThread() { + return nullptr; +} + +scoped_refptr<TaskQueue> FakeRendererScheduler::DefaultTaskRunner() { + return nullptr; +} + +scoped_refptr<TaskQueue> FakeRendererScheduler::CompositorTaskRunner() { + return nullptr; +} + +scoped_refptr<TaskQueue> FakeRendererScheduler::LoadingTaskRunner() { + return nullptr; +} + +scoped_refptr<SingleThreadIdleTaskRunner> +FakeRendererScheduler::IdleTaskRunner() { + return nullptr; +} + +scoped_refptr<TaskQueue> FakeRendererScheduler::TimerTaskRunner() { + return nullptr; +} + +scoped_refptr<TaskQueue> FakeRendererScheduler::NewLoadingTaskRunner( + const char* name) { + return nullptr; +} + +scoped_refptr<TaskQueue> FakeRendererScheduler::NewTimerTaskRunner( + const char* name) { + return nullptr; +} + +scoped_refptr<TaskQueue> FakeRendererScheduler::NewUnthrottledTaskRunner( + const char* name) { + return nullptr; +} + +std::unique_ptr<RenderWidgetSchedulingState> +FakeRendererScheduler::NewRenderWidgetSchedulingState() { + return nullptr; +} + +void FakeRendererScheduler::WillBeginFrame(const cc::BeginFrameArgs& args) {} + +void FakeRendererScheduler::BeginFrameNotExpectedSoon() {} + +void FakeRendererScheduler::DidCommitFrameToCompositor() {} + +void FakeRendererScheduler::DidHandleInputEventOnCompositorThread( + const blink::WebInputEvent& web_input_event, + InputEventState event_state) {} + +void FakeRendererScheduler::DidHandleInputEventOnMainThread( + const blink::WebInputEvent& web_input_event) {} + +void FakeRendererScheduler::DidAnimateForInputOnCompositorThread() {} + +bool FakeRendererScheduler::IsHighPriorityWorkAnticipated() { + return false; +} + +void FakeRendererScheduler::OnRendererBackgrounded() {} + +void FakeRendererScheduler::OnRendererForegrounded() {} + +void FakeRendererScheduler::SuspendRenderer() {} + +void FakeRendererScheduler::AddPendingNavigation( + blink::WebScheduler::NavigatingFrameType type) {} + +void FakeRendererScheduler::RemovePendingNavigation( + blink::WebScheduler::NavigatingFrameType type) {} + +void FakeRendererScheduler::OnNavigationStarted() {} + +bool FakeRendererScheduler::ShouldYieldForHighPriorityWork() { + return false; +} + +bool FakeRendererScheduler::CanExceedIdleDeadlineIfRequired() const { + return false; +} + +void FakeRendererScheduler::AddTaskObserver( + base::MessageLoop::TaskObserver* task_observer) {} + +void FakeRendererScheduler::RemoveTaskObserver( + base::MessageLoop::TaskObserver* task_observer) {} + +void FakeRendererScheduler::Shutdown() {} + +void FakeRendererScheduler::SuspendTimerQueue() {} + +void FakeRendererScheduler::ResumeTimerQueue() {} + +void FakeRendererScheduler::SetTimerQueueSuspensionWhenBackgroundedEnabled( + bool enabled) {} + +void FakeRendererScheduler::SetTopLevelBlameContext( + base::trace_event::BlameContext* blame_context) {} + +void FakeRendererScheduler::SetRAILModeObserver(RAILModeObserver* observer) {} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.cc b/third_party/WebKit/Source/platform/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.cc new file mode 100644 index 0000000..35e7468 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.cc
@@ -0,0 +1,97 @@ +// 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 "platform/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.h" + +#include <utility> + +#include "base/memory/ptr_util.h" +#include "base/time/default_tick_clock.h" + +namespace blink { +namespace scheduler { + +// static +scoped_refptr<LazySchedulerMessageLoopDelegateForTests> +LazySchedulerMessageLoopDelegateForTests::Create() { + return make_scoped_refptr(new LazySchedulerMessageLoopDelegateForTests()); +} + +LazySchedulerMessageLoopDelegateForTests:: + LazySchedulerMessageLoopDelegateForTests() + : message_loop_(base::MessageLoop::current()), + thread_id_(base::PlatformThread::CurrentId()), + time_source_(base::WrapUnique(new base::DefaultTickClock())) { + if (message_loop_) + original_task_runner_ = message_loop_->task_runner(); +} + +LazySchedulerMessageLoopDelegateForTests:: + ~LazySchedulerMessageLoopDelegateForTests() { + RestoreDefaultTaskRunner(); +} + +base::MessageLoop* LazySchedulerMessageLoopDelegateForTests::EnsureMessageLoop() + const { + if (message_loop_) + return message_loop_; + DCHECK(RunsTasksOnCurrentThread()); + message_loop_ = base::MessageLoop::current(); + DCHECK(message_loop_); + original_task_runner_ = message_loop_->task_runner(); + if (pending_task_runner_) + message_loop_->SetTaskRunner(std::move(pending_task_runner_)); + return message_loop_; +} + +void LazySchedulerMessageLoopDelegateForTests::SetDefaultTaskRunner( + scoped_refptr<base::SingleThreadTaskRunner> task_runner) { + if (!HasMessageLoop()) { + pending_task_runner_ = std::move(task_runner); + return; + } + message_loop_->SetTaskRunner(std::move(task_runner)); +} + +void LazySchedulerMessageLoopDelegateForTests::RestoreDefaultTaskRunner() { + if (HasMessageLoop() && base::MessageLoop::current() == message_loop_) + message_loop_->SetTaskRunner(original_task_runner_); +} + +bool LazySchedulerMessageLoopDelegateForTests::HasMessageLoop() const { + return message_loop_ != nullptr; +} + +bool LazySchedulerMessageLoopDelegateForTests::PostDelayedTask( + const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) { + EnsureMessageLoop(); + return original_task_runner_->PostDelayedTask(from_here, task, delay); +} + +bool LazySchedulerMessageLoopDelegateForTests::PostNonNestableDelayedTask( + const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) { + EnsureMessageLoop(); + return original_task_runner_->PostNonNestableDelayedTask(from_here, task, + delay); +} + +bool LazySchedulerMessageLoopDelegateForTests::RunsTasksOnCurrentThread() + const { + return thread_id_ == base::PlatformThread::CurrentId(); +} + +bool LazySchedulerMessageLoopDelegateForTests::IsNested() const { + return EnsureMessageLoop()->IsNested(); +} + +base::TimeTicks LazySchedulerMessageLoopDelegateForTests::NowTicks() { + return time_source_->NowTicks(); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.h b/third_party/WebKit/Source/platform/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.h new file mode 100644 index 0000000..bd802a9 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.h
@@ -0,0 +1,64 @@ +// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_TEST_LAZY_SCHEDULER_MESSAGE_LOOP_DELEGATE_FOR_TESTS_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_TEST_LAZY_SCHEDULER_MESSAGE_LOOP_DELEGATE_FOR_TESTS_H_ + +#include <memory> + +#include "base/macros.h" +#include "base/message_loop/message_loop.h" +#include "base/time/tick_clock.h" +#include "platform/scheduler/child/scheduler_tqm_delegate.h" + +namespace blink { +namespace scheduler { + +// This class connects the scheduler to a MessageLoop, but unlike +// SchedulerMessageLoopDelegate it allows the message loop to be created lazily +// after the scheduler has been brought up. This is needed in testing scenarios +// where Blink is initialized before a MessageLoop has been created. +// +// TODO(skyostil): Fix the relevant test suites and remove this class +// (crbug.com/495659). +class LazySchedulerMessageLoopDelegateForTests : public SchedulerTqmDelegate { + public: + static scoped_refptr<LazySchedulerMessageLoopDelegateForTests> Create(); + + // SchedulerTqmDelegate implementation + void SetDefaultTaskRunner( + scoped_refptr<base::SingleThreadTaskRunner> task_runner) override; + void RestoreDefaultTaskRunner() override; + bool PostDelayedTask(const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) override; + bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) override; + bool RunsTasksOnCurrentThread() const override; + bool IsNested() const override; + base::TimeTicks NowTicks() override; + + private: + LazySchedulerMessageLoopDelegateForTests(); + ~LazySchedulerMessageLoopDelegateForTests() override; + + bool HasMessageLoop() const; + base::MessageLoop* EnsureMessageLoop() const; + + mutable base::MessageLoop* message_loop_; + base::PlatformThreadId thread_id_; + + // A task runner which hasn't yet been overridden in the message loop. + mutable scoped_refptr<base::SingleThreadTaskRunner> pending_task_runner_; + mutable scoped_refptr<base::SingleThreadTaskRunner> original_task_runner_; + std::unique_ptr<base::TickClock> time_source_; + + DISALLOW_COPY_AND_ASSIGN(LazySchedulerMessageLoopDelegateForTests); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_TEST_LAZY_SCHEDULER_MESSAGE_LOOP_DELEGATE_FOR_TESTS_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/test/renderer_scheduler_test_support.cc b/third_party/WebKit/Source/platform/scheduler/test/renderer_scheduler_test_support.cc new file mode 100644 index 0000000..75d6c95 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/test/renderer_scheduler_test_support.cc
@@ -0,0 +1,26 @@ +// 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 "public/platform/scheduler/test/renderer_scheduler_test_support.h" + +#include "platform/scheduler/renderer/renderer_scheduler_impl.h" +#include "platform/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.h" + +namespace blink { +namespace scheduler { + +std::unique_ptr<RendererScheduler> CreateRendererSchedulerForTests() { + return base::WrapUnique(new scheduler::RendererSchedulerImpl( + scheduler::LazySchedulerMessageLoopDelegateForTests::Create())); +} + +void RunIdleTasksForTesting(RendererScheduler* scheduler, + const base::Closure& callback) { + RendererSchedulerImpl* scheduler_impl = + static_cast<RendererSchedulerImpl*>(scheduler); + scheduler_impl->RunIdleTasksForTesting(callback); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/utility/webthread_impl_for_utility_thread.cc b/third_party/WebKit/Source/platform/scheduler/utility/webthread_impl_for_utility_thread.cc new file mode 100644 index 0000000..3309dc0 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/utility/webthread_impl_for_utility_thread.cc
@@ -0,0 +1,39 @@ +// 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 "public/platform/scheduler/utility/webthread_impl_for_utility_thread.h" + +#include "base/threading/thread_task_runner_handle.h" + +namespace blink { +namespace scheduler { + +WebThreadImplForUtilityThread::WebThreadImplForUtilityThread() + : task_runner_(base::ThreadTaskRunnerHandle::Get()), + thread_id_(base::PlatformThread::CurrentId()) {} + +WebThreadImplForUtilityThread::~WebThreadImplForUtilityThread() {} + +blink::WebScheduler* WebThreadImplForUtilityThread::scheduler() const { + NOTIMPLEMENTED(); + return nullptr; +} + +blink::PlatformThreadId WebThreadImplForUtilityThread::threadId() const { + return thread_id_; +} + +base::SingleThreadTaskRunner* WebThreadImplForUtilityThread::GetTaskRunner() + const { + return task_runner_.get(); +} + +scheduler::SingleThreadIdleTaskRunner* +WebThreadImplForUtilityThread::GetIdleTaskRunner() const { + NOTIMPLEMENTED(); + return nullptr; +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp index 528f9e3..51300ee 100644 --- a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp +++ b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp
@@ -107,6 +107,12 @@ return 0.0; } + base::SingleThreadTaskRunner* taskRunner() override + { + NOTREACHED(); + return nullptr; + } + private: Deque<std::unique_ptr<WebTaskRunner::Task>>* m_tasks; // NOT OWNED };
diff --git a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.h b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.h index bc5b15b..2aecf10 100644 --- a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.h +++ b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.h
@@ -67,7 +67,7 @@ void postIdleTask(const WebTraceLocation&, WebThread::IdleTask*) override { } void postNonNestableIdleTask(const WebTraceLocation&, WebThread::IdleTask*) override { } void postIdleTaskAfterWakeup(const WebTraceLocation&, WebThread::IdleTask*) override { } - std::unique_ptr<WebViewScheduler> createWebViewScheduler(blink::WebView*) override { return nullptr; } + std::unique_ptr<WebViewScheduler> createWebViewScheduler(InterventionReporter*) override { return nullptr; } void suspendTimerQueue() override { } void resumeTimerQueue() override { } void addPendingNavigation(WebScheduler::NavigatingFrameType) override { }
diff --git a/third_party/WebKit/Source/platform/text/CompressibleString.cpp b/third_party/WebKit/Source/platform/text/CompressibleString.cpp deleted file mode 100644 index 3b7f6c3..0000000 --- a/third_party/WebKit/Source/platform/text/CompressibleString.cpp +++ /dev/null
@@ -1,129 +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 "platform/text/CompressibleString.h" - -#include "platform/Histogram.h" -#include "wtf/Assertions.h" -#include "wtf/WTFThreadData.h" -#include "wtf/text/WTFString.h" - -namespace blink { - -class CompressibleStringTable { - WTF_MAKE_NONCOPYABLE(CompressibleStringTable); -public: - static CompressibleStringTable* create(WTFThreadData& data) - { - data.m_compressibleStringTable = new CompressibleStringTable; - data.m_compressibleStringTableDestructor = CompressibleStringTable::destroy; - return data.m_compressibleStringTable; - } - - void add(CompressibleStringImpl* string) - { - ASSERT(!m_table.contains(string)); - m_table.add(string); - } - - bool contains(CompressibleStringImpl* string) const - { - return m_table.contains(string); - } - - void remove(CompressibleStringImpl* string) - { - ASSERT(m_table.contains(string)); - m_table.remove(string); - } - - void compressAll() - { - HashSet<CompressibleStringImpl*>::iterator end = m_table.end(); - for (HashSet<CompressibleStringImpl*>::iterator iter = m_table.begin(); iter != end; ++iter) { - CompressibleStringImpl* string = *iter; - if (!string->isCompressed()) - string->compressString(); - } - } - -private: - CompressibleStringTable() { } - - static void destroy(CompressibleStringTable* table) - { - delete table; - } - - HashSet<CompressibleStringImpl*> m_table; -}; - -static inline CompressibleStringTable& compressibleStringTable() -{ - WTFThreadData& data = wtfThreadData(); - CompressibleStringTable* table = data.compressibleStringTable(); - if (UNLIKELY(!table)) - table = CompressibleStringTable::create(data); - return *table; -} - -static const unsigned CompressibleStringImplSizeThrehold = 100000; - -void CompressibleStringImpl::compressAll() -{ - compressibleStringTable().compressAll(); -} - -CompressibleStringImpl::CompressibleStringImpl(PassRefPtr<StringImpl> impl) - : m_string(impl) - , m_isCompressed(false) -{ - if (originalContentSizeInBytes() > CompressibleStringImplSizeThrehold) - compressibleStringTable().add(this); -} - -CompressibleStringImpl::~CompressibleStringImpl() -{ - if (originalContentSizeInBytes() > CompressibleStringImplSizeThrehold) - compressibleStringTable().remove(this); -} - -enum CompressibleStringCountType { - StringWasCompressedInBackgroundTab, - StringWasDecompressed, - CompressibleStringCountTypeMax = StringWasDecompressed, -}; - -static void recordCompressibleStringCount(CompressibleStringCountType type) -{ - DEFINE_THREAD_SAFE_STATIC_LOCAL(EnumerationHistogram, sringTypeHistogram, new EnumerationHistogram("Memory.CompressibleStringCount", CompressibleStringCountTypeMax + 1)); - sringTypeHistogram.count(type); -} - -// compressString does nothing but collect UMA so far. -// TODO(hajimehoshi): Implement this. -void CompressibleStringImpl::compressString() -{ - recordCompressibleStringCount(StringWasCompressedInBackgroundTab); - ASSERT(!isCompressed()); - m_isCompressed = true; -} - -// decompressString does nothing but collect UMA so far. -// TODO(hajimehoshi): Implement this. -void CompressibleStringImpl::decompressString() -{ - // TODO(hajimehoshi): We wanted to tell whether decompressing in a - // background tab or a foreground tab, but this was impossible. For example, - // one renderer process of a new tab page is used for multiple tabs. - // Another example is that reloading a page will re-use the process with a - // new Page object and updating a static variable along with reloading will - // be complex. See also crbug/581266. We will revisit when the situation - // changes. - recordCompressibleStringCount(StringWasDecompressed); - ASSERT(isCompressed()); - m_isCompressed = false; -} - -} // namespace blink
diff --git a/third_party/WebKit/Source/platform/text/CompressibleString.h b/third_party/WebKit/Source/platform/text/CompressibleString.h deleted file mode 100644 index 0ab99cf6..0000000 --- a/third_party/WebKit/Source/platform/text/CompressibleString.h +++ /dev/null
@@ -1,120 +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 CompressibleString_h -#define CompressibleString_h - -#include "platform/PlatformExport.h" -#include "wtf/RefCounted.h" -#include "wtf/text/Unicode.h" -#include "wtf/text/WTFString.h" - -namespace blink { - -// TODO(hajimehoshi): Now these classes are in platform/text to use UMA. Move -// them to wtf/text. - -class PLATFORM_EXPORT CompressibleStringImpl final : public RefCounted<CompressibleStringImpl> { - WTF_MAKE_NONCOPYABLE(CompressibleStringImpl); -public: - static void compressAll(); - - CompressibleStringImpl() - : m_string() - , m_isCompressed(false) - { - } - - explicit CompressibleStringImpl(PassRefPtr<StringImpl>); - ~CompressibleStringImpl(); - - bool isEmpty() const { return originalLength() == 0; } - - bool isCompressed() const { return m_isCompressed; } - unsigned originalLength() const { return m_string.length(); } - bool is8Bit() const { return m_string.is8Bit(); } - - unsigned originalContentSizeInBytes() const - { - if (is8Bit()) - return originalLength() * sizeof(LChar); - return originalLength() * sizeof(UChar); - } - - // TODO(hajimehoshi): Update this once we implement compression. - unsigned currentSizeInBytes() const - { - return originalContentSizeInBytes(); - } - - const String& toString() - { - if (UNLIKELY(isCompressed())) - decompressString(); - return m_string; - } - - const LChar* characters8() - { - return toString().characters8(); - } - - const UChar* characters16() - { - return toString().characters16(); - } - - void compressString(); - void decompressString(); - -private: - String m_string; - bool m_isCompressed; -}; - -class PLATFORM_EXPORT CompressibleString final { -public: - CompressibleString() - : m_impl(nullptr) - { - } - - CompressibleString(const CompressibleString& rhs) - : m_impl(rhs.m_impl) - { - } - - explicit CompressibleString(PassRefPtr<StringImpl> impl) - : m_impl(impl ? adoptRef(new CompressibleStringImpl(impl)) : nullptr) - { - } - - bool isNull() const { return !m_impl; } - bool isEmpty() const { return isNull() || m_impl->isEmpty(); } - unsigned length() const { return m_impl ? m_impl->originalLength() : 0; } - - unsigned currentSizeInBytes() const { return m_impl ? m_impl->currentSizeInBytes() : 0; } - - bool isCompressed() const { return m_impl ? m_impl->isCompressed() : false; } - bool is8Bit() const { return m_impl ? m_impl->is8Bit() : false; } - - const String& toString() const { return m_impl ? m_impl->toString() : emptyString(); } - const LChar* characters8() const { return m_impl ? m_impl->characters8() : nullptr; } - const UChar* characters16() const { return m_impl ? m_impl->characters16() : nullptr; } - - CompressibleStringImpl* impl() const { return m_impl.get(); } - -private: - void compressString() const { m_impl->compressString(); } - void decompressString() const { m_impl->decompressString(); } - - mutable RefPtr<CompressibleStringImpl> m_impl; -}; - -} // namespace blink - -using blink::CompressibleString; -using blink::CompressibleStringImpl; - -#endif
diff --git a/third_party/WebKit/Source/platform/text/LocaleToScriptMapping.cpp b/third_party/WebKit/Source/platform/text/LocaleToScriptMapping.cpp index ae2f92c6..075ac33 100644 --- a/third_party/WebKit/Source/platform/text/LocaleToScriptMapping.cpp +++ b/third_party/WebKit/Source/platform/text/LocaleToScriptMapping.cpp
@@ -43,12 +43,11 @@ using SubtagScriptMap = HashMap<String, UScriptCode, CaseFoldingHash>; -static SubtagScriptMap createSubtagScriptMap(const SubtagScript list[], size_t size) +static void createSubtagScriptMap(SubtagScriptMap& map, const SubtagScript list[], size_t size) { - SubtagScriptMap map; + map.reserveCapacityForSize(size); for (size_t i = 0; i < size; ++i) map.set(list[i].subtag, list[i].script); - return map; } UScriptCode scriptNameToCode(const String& scriptName) @@ -165,8 +164,9 @@ { "zxxx", USCRIPT_UNWRITTEN_LANGUAGES }, { "zzzz", USCRIPT_UNKNOWN } }; - DEFINE_STATIC_LOCAL(SubtagScriptMap, scriptNameCodeMap, - (createSubtagScriptMap(scriptNameCodeList, WTF_ARRAY_LENGTH(scriptNameCodeList)))); + DEFINE_STATIC_LOCAL(SubtagScriptMap, scriptNameCodeMap, ()); + if (scriptNameCodeMap.isEmpty()) + createSubtagScriptMap(scriptNameCodeMap, scriptNameCodeList, WTF_ARRAY_LENGTH(scriptNameCodeList)); const auto& it = scriptNameCodeMap.find(scriptName); if (it != scriptNameCodeMap.end()) @@ -453,8 +453,9 @@ { "zh-mo", USCRIPT_TRADITIONAL_HAN }, { "zh-tw", USCRIPT_TRADITIONAL_HAN }, }; - DEFINE_STATIC_LOCAL(SubtagScriptMap, localeScriptMap, - (createSubtagScriptMap(localeScriptList, WTF_ARRAY_LENGTH(localeScriptList)))); + DEFINE_STATIC_LOCAL(SubtagScriptMap, localeScriptMap, ()); + if (localeScriptMap.isEmpty()) + createSubtagScriptMap(localeScriptMap, localeScriptList, WTF_ARRAY_LENGTH(localeScriptList)); // BCP 47 uses '-' as the delimiter but ICU uses '_'. // https://tools.ietf.org/html/bcp47 @@ -487,8 +488,9 @@ { "mo", USCRIPT_TRADITIONAL_HAN }, { "tw", USCRIPT_TRADITIONAL_HAN }, }; - DEFINE_STATIC_LOCAL(SubtagScriptMap, regionScriptMap, - (createSubtagScriptMap(regionScriptList, WTF_ARRAY_LENGTH(regionScriptList)))); + DEFINE_STATIC_LOCAL(SubtagScriptMap, regionScriptMap, ()); + if (regionScriptMap.isEmpty()) + createSubtagScriptMap(regionScriptMap, regionScriptList, WTF_ARRAY_LENGTH(regionScriptList)); const auto& it = regionScriptMap.find(region); return it != regionScriptMap.end() ? it->value : USCRIPT_COMMON;
diff --git a/third_party/WebKit/Source/platform/text/TextCheckerClient.h b/third_party/WebKit/Source/platform/text/TextCheckerClient.h index bb9761a..ce4f32bd 100644 --- a/third_party/WebKit/Source/platform/text/TextCheckerClient.h +++ b/third_party/WebKit/Source/platform/text/TextCheckerClient.h
@@ -44,6 +44,7 @@ virtual void checkSpellingOfString(const String&, int* misspellingLocation, int* misspellingLength) = 0; virtual void checkGrammarOfString(const String&, Vector<GrammarDetail>&, int* badGrammarLocation, int* badGrammarLength) = 0; virtual void requestCheckingOfString(TextCheckingRequest*) = 0; + virtual void cancelAllPendingRequests() = 0; }; } // namespace blink
diff --git a/third_party/WebKit/Source/platform/text/TextChecking.h b/third_party/WebKit/Source/platform/text/TextChecking.h index f05b87d..0cda166 100644 --- a/third_party/WebKit/Source/platform/text/TextChecking.h +++ b/third_party/WebKit/Source/platform/text/TextChecking.h
@@ -39,14 +39,6 @@ namespace blink { -enum TextCheckingType { - TextCheckingTypeNone = 0, - TextCheckingTypeSpelling = 1 << 1, - TextCheckingTypeGrammar = 1 << 2, -}; - -typedef unsigned TextCheckingTypeMask; - enum TextCheckingProcessType { TextCheckingProcessBatch, TextCheckingProcessIncremental @@ -78,13 +70,11 @@ public: TextCheckingRequestData() : m_sequence(unrequestedTextCheckingSequence) - , m_mask(TextCheckingTypeNone) , m_processType(TextCheckingProcessIncremental) { } - TextCheckingRequestData(int sequence, const String& text, TextCheckingTypeMask mask, TextCheckingProcessType processType, const Vector<uint32_t>& markers, const Vector<unsigned>& offsets) + TextCheckingRequestData(int sequence, const String& text, TextCheckingProcessType processType, const Vector<uint32_t>& markers, const Vector<unsigned>& offsets) : m_sequence(sequence) , m_text(text) - , m_mask(mask) , m_processType(processType) , m_markers(markers) , m_offsets(offsets) @@ -92,8 +82,6 @@ int sequence() const { return m_sequence; } String text() const { return m_text; } - TextCheckingTypeMask mask() const { return m_mask; } - bool maskContains(TextCheckingType type) const { return m_mask & type; } TextCheckingProcessType processType() const { return m_processType; } const Vector<uint32_t>& markers() const { return m_markers; } const Vector<unsigned>& offsets() const { return m_offsets; } @@ -101,7 +89,6 @@ private: int m_sequence; String m_text; - TextCheckingTypeMask m_mask; TextCheckingProcessType m_processType; Vector<uint32_t> m_markers; Vector<unsigned> m_offsets;
diff --git a/third_party/WebKit/Source/platform/v8_inspector/DebuggerScript.js b/third_party/WebKit/Source/platform/v8_inspector/DebuggerScript.js index cd9a2bd..b6e09968 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/DebuggerScript.js +++ b/third_party/WebKit/Source/platform/v8_inspector/DebuggerScript.js
@@ -229,9 +229,7 @@ */ DebuggerScript.setBreakpoint = function(execState, info) { - var positionAlignment = info.interstatementLocation ? Debug.BreakPositionAlignment.BreakPosition : Debug.BreakPositionAlignment.Statement; - var breakId = Debug.setScriptBreakPointById(info.sourceID, info.lineNumber, info.columnNumber, info.condition, undefined, positionAlignment); - + var breakId = Debug.setScriptBreakPointById(info.sourceID, info.lineNumber, info.columnNumber, info.condition, undefined, Debug.BreakPositionAlignment.Statement); var locations = Debug.findBreakPointActualLocations(breakId); if (!locations.length) return undefined;
diff --git a/third_party/WebKit/Source/platform/v8_inspector/InjectedScriptSource.js b/third_party/WebKit/Source/platform/v8_inspector/InjectedScriptSource.js index 1c972b3..7e8b2cb4 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/InjectedScriptSource.js +++ b/third_party/WebKit/Source/platform/v8_inspector/InjectedScriptSource.js
@@ -60,7 +60,7 @@ */ function toString(obj) { - // We don't use String(obj) because String16 could be overridden. + // We don't use String(obj) because String could be overridden. // Also the ("" + obj) expression may throw. try { return "" + obj; @@ -171,7 +171,8 @@ { for (var interfaceName in domAttributesWithObservableSideEffectOnGet) { var interfaceFunction = inspectedGlobalObject[interfaceName]; - var isInstance = typeof interfaceFunction === "function" && object instanceof interfaceFunction; + // instanceof call looks safe after typeof check. + var isInstance = typeof interfaceFunction === "function" && /* suppressBlacklist */ object instanceof interfaceFunction; if (isInstance) return attribute in domAttributesWithObservableSideEffectOnGet[interfaceName]; } @@ -198,18 +199,17 @@ } /** - * @type {!Map<string, string>} + * @type {!Object<string, string>} * @const */ -InjectedScript.closureTypes = new Map([ - ["local", "Local"], - ["closure", "Closure"], - ["catch", "Catch"], - ["block", "Block"], - ["script", "Script"], - ["with", "With Block"], - ["global", "Global"] -]); +InjectedScript.closureTypes = { __proto__: null }; +InjectedScript.closureTypes["local"] = "Local"; +InjectedScript.closureTypes["closure"] = "Closure"; +InjectedScript.closureTypes["catch"] = "Catch"; +InjectedScript.closureTypes["block"] = "Block"; +InjectedScript.closureTypes["script"] = "Script"; +InjectedScript.closureTypes["with"] = "With Block"; +InjectedScript.closureTypes["global"] = "Global"; InjectedScript.prototype = { /** @@ -369,6 +369,21 @@ /** * @param {!Object} object + * @return {?Object} + */ + _objectPrototype: function(object) + { + if (InjectedScriptHost.subtype(object) === "proxy") + return null; + try { + return Object.getPrototypeOf(object); + } catch (e) { + return null; + } + }, + + /** + * @param {!Object} object * @param {boolean=} ownProperties * @param {boolean=} accessorPropertiesOnly * @param {?Array.<string>=} propertyNamesOnly @@ -439,7 +454,7 @@ if (propertyNamesOnly) { for (var i = 0; i < propertyNamesOnly.length; ++i) { var name = propertyNamesOnly[i]; - for (var o = object; this._isDefined(o); o = InjectedScriptHost.prototype(o)) { + for (var o = object; this._isDefined(o); o = this._objectPrototype(o)) { if (InjectedScriptHost.objectHasOwnProperty(o, name)) { for (var descriptor of process(o, [name])) yield descriptor; @@ -467,7 +482,7 @@ } catch (e) { } - for (var o = object; this._isDefined(o); o = InjectedScriptHost.prototype(o)) { + for (var o = object; this._isDefined(o); o = this._objectPrototype(o)) { if (InjectedScriptHost.subtype(o) === "proxy") continue; if (skipGetOwnPropertyNames && o === object) { @@ -486,7 +501,7 @@ yield descriptor; } if (ownProperties) { - var proto = InjectedScriptHost.prototype(o); + var proto = this._objectPrototype(o); if (proto && !accessorPropertiesOnly) yield { name: "__proto__", value: proto, writable: true, configurable: true, enumerable: false, isOwn: true, __proto__: null }; break; @@ -622,7 +637,8 @@ if (isSymbol(obj)) { try { - return obj.toString() || "Symbol"; + // It isn't safe, because Symbol.prototype.toString can be overriden. + return /* suppressBlacklist */ obj.toString() || "Symbol"; } catch (e) { return "Symbol"; } @@ -653,7 +669,7 @@ return "Scopes[" + obj.length + "]"; if (subtype === "internal#scope") - return (InjectedScript.closureTypes.get(obj.type) || "Unknown") + (obj.name ? " (" + obj.name + ")" : ""); + return (InjectedScript.closureTypes[obj.type] || "Unknown") + (obj.name ? " (" + obj.name + ")" : ""); return className; }, @@ -778,7 +794,8 @@ */ function logError(error) { - Promise.resolve().then(inspectedGlobalObject.console.error.bind(inspectedGlobalObject.console, "Custom Formatter Failed: " + error.message)); + // We use user code to generate custom output for object, we can use user code for reporting error too. + Promise.resolve().then(/* suppressBlacklist */ inspectedGlobalObject.console.error.bind(inspectedGlobalObject.console, "Custom Formatter Failed: " + error.message)); } /**
diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8Compat.h b/third_party/WebKit/Source/platform/v8_inspector/V8Compat.h index 0f5b12c..d623da1a 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/V8Compat.h +++ b/third_party/WebKit/Source/platform/v8_inspector/V8Compat.h
@@ -22,7 +22,11 @@ }; } // namespace v8 - +#define V8_FUNCTION_NEW_REMOVE_PROTOTYPE(context, callback, data, length) \ + v8::Function::New((context), (callback), (data), (length)) +#else +#define V8_FUNCTION_NEW_REMOVE_PROTOTYPE(context, callback, data, length) \ + v8::Function::New((context), (callback), (data), (length), v8::ConstructorBehavior::kThrow) #endif // V8_MAJOR_VERSION < 5 || (V8_MAJOR_VERSION == 5 && V8_MINOR_VERSION < 1) #endif // V8Compat_h
diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8Console.cpp b/third_party/WebKit/Source/platform/v8_inspector/V8Console.cpp index 55d0c4f..1bd738a8 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/V8Console.cpp +++ b/third_party/WebKit/Source/platform/v8_inspector/V8Console.cpp
@@ -271,13 +271,13 @@ { v8::Local<v8::String> funcName = toV8StringInternalized(context->GetIsolate(), name); v8::Local<v8::Function> func; - if (!v8::Function::New(context, callback, console, 0, v8::ConstructorBehavior::kThrow).ToLocal(&func)) + if (!V8_FUNCTION_NEW_REMOVE_PROTOTYPE(context, callback, console, 0).ToLocal(&func)) return; func->SetName(funcName); if (description) { v8::Local<v8::String> returnValue = toV8String(context->GetIsolate(), description); v8::Local<v8::Function> toStringFunction; - if (v8::Function::New(context, returnDataCallback, returnValue, 0, v8::ConstructorBehavior::kThrow).ToLocal(&toStringFunction)) + if (V8_FUNCTION_NEW_REMOVE_PROTOTYPE(context, returnDataCallback, returnValue, 0).ToLocal(&toStringFunction)) func->Set(toV8StringInternalized(context->GetIsolate(), "toString"), toStringFunction); } if (!console->Set(context, funcName, func).FromMaybe(false)) @@ -690,7 +690,7 @@ DCHECK(success); if (hasMemoryAttribute) - console->SetAccessorProperty(toV8StringInternalized(isolate, "memory"), v8::Function::New(context, V8Console::memoryGetterCallback, console, 0, v8::ConstructorBehavior::kThrow).ToLocalChecked(), v8::Function::New(context, V8Console::memorySetterCallback, v8::Local<v8::Value>(), 0, v8::ConstructorBehavior::kThrow).ToLocalChecked(), static_cast<v8::PropertyAttribute>(v8::None), v8::DEFAULT); + console->SetAccessorProperty(toV8StringInternalized(isolate, "memory"), V8_FUNCTION_NEW_REMOVE_PROTOTYPE(context, V8Console::memoryGetterCallback, console, 0).ToLocalChecked(), V8_FUNCTION_NEW_REMOVE_PROTOTYPE(context, V8Console::memorySetterCallback, v8::Local<v8::Value>(), 0).ToLocalChecked(), static_cast<v8::PropertyAttribute>(v8::None), v8::DEFAULT); console->SetPrivate(context, inspectedContextPrivateKey(isolate), v8::External::New(isolate, inspectedContext)); return console;
diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8Debugger.cpp b/third_party/WebKit/Source/platform/v8_inspector/V8Debugger.cpp index f580af4..f5898b4a 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/V8Debugger.cpp +++ b/third_party/WebKit/Source/platform/v8_inspector/V8Debugger.cpp
@@ -48,6 +48,7 @@ , m_enableCount(0) , m_breakpointsActivated(true) , m_runningNestedMessageLoop(false) + , m_ignoreScriptParsedEventsCounter(0) , m_maxAsyncCallStackDepth(0) { } @@ -137,7 +138,7 @@ } } -String16 V8Debugger::setBreakpoint(const String16& sourceID, const ScriptBreakpoint& scriptBreakpoint, int* actualLineNumber, int* actualColumnNumber, bool interstatementLocation) +String16 V8Debugger::setBreakpoint(const String16& sourceID, const ScriptBreakpoint& scriptBreakpoint, int* actualLineNumber, int* actualColumnNumber) { v8::HandleScope scope(m_isolate); v8::Context::Scope contextScope(debuggerContext()); @@ -146,7 +147,6 @@ info->Set(toV8StringInternalized(m_isolate, "sourceID"), toV8String(m_isolate, sourceID)); info->Set(toV8StringInternalized(m_isolate, "lineNumber"), v8::Integer::New(m_isolate, scriptBreakpoint.lineNumber)); info->Set(toV8StringInternalized(m_isolate, "columnNumber"), v8::Integer::New(m_isolate, scriptBreakpoint.columnNumber)); - info->Set(toV8StringInternalized(m_isolate, "interstatementLocation"), v8Boolean(interstatementLocation, m_isolate)); info->Set(toV8StringInternalized(m_isolate, "condition"), toV8String(m_isolate, scriptBreakpoint.condition)); v8::Local<v8::Function> setBreakpointFunction = v8::Local<v8::Function>::Cast(m_debuggerScript.Get(m_isolate)->Get(toV8StringInternalized(m_isolate, "setBreakpoint"))); @@ -249,7 +249,7 @@ v8::HandleScope scope(m_isolate); v8::Local<v8::Function> breakFunction; - if (!v8::Function::New(m_isolate->GetCurrentContext(), &V8Debugger::breakProgramCallback, v8::External::New(m_isolate, this), 0, v8::ConstructorBehavior::kThrow).ToLocal(&breakFunction)) + if (!V8_FUNCTION_NEW_REMOVE_PROTOTYPE(m_isolate->GetCurrentContext(), &V8Debugger::breakProgramCallback, v8::External::New(m_isolate, this), 0).ToLocal(&breakFunction)) return; v8::Debug::Call(debuggerContext(), breakFunction).ToLocalChecked(); } @@ -504,7 +504,7 @@ V8DebuggerAgentImpl* agent = m_inspector->enabledDebuggerAgentForGroup(getGroupId(eventContext)); if (agent) { v8::HandleScope scope(m_isolate); - if (event == v8::AfterCompile || event == v8::CompileError) { + if (m_ignoreScriptParsedEventsCounter == 0 && (event == v8::AfterCompile || event == v8::CompileError)) { v8::Context::Scope contextScope(debuggerContext()); v8::Local<v8::Value> argv[] = { eventDetails.GetEventData() }; v8::Local<v8::Value> value = callDebuggerMethod("getAfterCompileScript", 1, argv).ToLocalChecked(); @@ -806,6 +806,17 @@ m_currentTasks.clear(); } +void V8Debugger::muteScriptParsedEvents() +{ + ++m_ignoreScriptParsedEventsCounter; +} + +void V8Debugger::unmuteScriptParsedEvents() +{ + --m_ignoreScriptParsedEventsCounter; + DCHECK_GE(m_ignoreScriptParsedEventsCounter, 0); +} + std::unique_ptr<V8StackTraceImpl> V8Debugger::captureStackTrace(bool fullStack) { if (!m_isolate->InContext())
diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8Debugger.h b/third_party/WebKit/Source/platform/v8_inspector/V8Debugger.h index c7ce2b3..b3bf651 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/V8Debugger.h +++ b/third_party/WebKit/Source/platform/v8_inspector/V8Debugger.h
@@ -36,7 +36,7 @@ bool enabled() const; - String16 setBreakpoint(const String16& sourceID, const ScriptBreakpoint&, int* actualLineNumber, int* actualColumnNumber, bool interstatementLocation); + String16 setBreakpoint(const String16& sourceID, const ScriptBreakpoint&, int* actualLineNumber, int* actualColumnNumber); void removeBreakpoint(const String16& breakpointId); void setBreakpointsActivated(bool); bool breakpointsActivated() const { return m_breakpointsActivated; } @@ -85,6 +85,9 @@ void asyncTaskFinished(void* task); void allAsyncTasksCanceled(); + void muteScriptParsedEvents(); + void unmuteScriptParsedEvents(); + private: void compileDebuggerScript(); v8::MaybeLocal<v8::Value> callDebuggerMethod(const char* functionName, int argc, v8::Local<v8::Value> argv[]); @@ -112,6 +115,7 @@ v8::Local<v8::Object> m_executionState; v8::Local<v8::Context> m_pausedContext; bool m_runningNestedMessageLoop; + int m_ignoreScriptParsedEventsCounter; using AsyncTaskToStackTrace = protocol::HashMap<void*, std::unique_ptr<V8StackTraceImpl>>; AsyncTaskToStackTrace m_asyncTaskStacks;
diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.cpp b/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.cpp index 584c0164..c97eaeb17 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.cpp +++ b/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.cpp
@@ -376,9 +376,7 @@ m_breakpointIdToDebuggerBreakpointIds.erase(breakpointId); } -void V8DebuggerAgentImpl::continueToLocation(ErrorString* errorString, - std::unique_ptr<protocol::Debugger::Location> location, - const protocol::Maybe<bool>& interstateLocationOpt) +void V8DebuggerAgentImpl::continueToLocation(ErrorString* errorString, std::unique_ptr<protocol::Debugger::Location> location) { if (!checkEnabled(errorString)) return; @@ -395,7 +393,7 @@ return; ScriptBreakpoint breakpoint(lineNumber, columnNumber, ""); - m_continueToLocationBreakpointId = m_debugger->setBreakpoint(scriptId, breakpoint, &lineNumber, &columnNumber, interstateLocationOpt.fromMaybe(false)); + m_continueToLocationBreakpointId = m_debugger->setBreakpoint(scriptId, breakpoint, &lineNumber, &columnNumber); resume(errorString); } @@ -502,7 +500,7 @@ int actualLineNumber; int actualColumnNumber; - String16 debuggerBreakpointId = m_debugger->setBreakpoint(scriptId, breakpoint, &actualLineNumber, &actualColumnNumber, false); + String16 debuggerBreakpointId = m_debugger->setBreakpoint(scriptId, breakpoint, &actualLineNumber, &actualColumnNumber); if (debuggerBreakpointId.isEmpty()) return nullptr;
diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.h b/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.h index e777f3b..317911ad 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.h +++ b/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.h
@@ -71,8 +71,7 @@ std::unique_ptr<protocol::Debugger::Location>* actualLocation) override; void removeBreakpoint(ErrorString*, const String16& breakpointId) override; void continueToLocation(ErrorString*, - std::unique_ptr<protocol::Debugger::Location>, - const Maybe<bool>& interstateLocationOpt) override; + std::unique_ptr<protocol::Debugger::Location>) override; void getBacktrace(ErrorString*, std::unique_ptr<protocol::Array<protocol::Debugger::CallFrame>>*, Maybe<protocol::Runtime::StackTrace>*) override;
diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8InjectedScriptHost.cpp b/third_party/WebKit/Source/platform/v8_inspector/V8InjectedScriptHost.cpp index 2eb34fb..6f9a2a05c 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/V8InjectedScriptHost.cpp +++ b/third_party/WebKit/Source/platform/v8_inspector/V8InjectedScriptHost.cpp
@@ -21,7 +21,7 @@ { v8::Local<v8::String> funcName = toV8StringInternalized(context->GetIsolate(), name); v8::Local<v8::Function> func; - if (!v8::Function::New(context, callback, external, 0, v8::ConstructorBehavior::kThrow).ToLocal(&func)) + if (!V8_FUNCTION_NEW_REMOVE_PROTOTYPE(context, callback, external, 0).ToLocal(&func)) return; func->SetName(funcName); if (!obj->Set(context, funcName, func).FromMaybe(false)) @@ -51,7 +51,6 @@ setFunctionProperty(context, injectedScriptHost, "objectHasOwnProperty", V8InjectedScriptHost::objectHasOwnPropertyCallback, debuggerExternal); setFunctionProperty(context, injectedScriptHost, "bind", V8InjectedScriptHost::bindCallback, debuggerExternal); setFunctionProperty(context, injectedScriptHost, "proxyTargetValue", V8InjectedScriptHost::proxyTargetValueCallback, debuggerExternal); - setFunctionProperty(context, injectedScriptHost, "prototype", V8InjectedScriptHost::prototypeCallback, debuggerExternal); return injectedScriptHost; } @@ -184,10 +183,4 @@ info.GetReturnValue().Set(target); } -void V8InjectedScriptHost::prototypeCallback(const v8::FunctionCallbackInfo<v8::Value>& info) -{ - DCHECK(info.Length() > 0 && info[0]->IsObject()); - info.GetReturnValue().Set(info[0].As<v8::Object>()->GetPrototype()); -} - } // namespace blink
diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8InjectedScriptHost.h b/third_party/WebKit/Source/platform/v8_inspector/V8InjectedScriptHost.h index 0a3282a..496b5a77 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/V8InjectedScriptHost.h +++ b/third_party/WebKit/Source/platform/v8_inspector/V8InjectedScriptHost.h
@@ -29,7 +29,6 @@ static void objectHasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>&); static void bindCallback(const v8::FunctionCallbackInfo<v8::Value>&); static void proxyTargetValueCallback(const v8::FunctionCallbackInfo<v8::Value>&); - static void prototypeCallback(const v8::FunctionCallbackInfo<v8::Value>&); }; } // namespace blink
diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8RuntimeAgentImpl.cpp b/third_party/WebKit/Source/platform/v8_inspector/V8RuntimeAgentImpl.cpp index cf2c2ba..79d8cc9c 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/V8RuntimeAgentImpl.cpp +++ b/third_party/WebKit/Source/platform/v8_inspector/V8RuntimeAgentImpl.cpp
@@ -35,8 +35,10 @@ #include "platform/v8_inspector/InjectedScript.h" #include "platform/v8_inspector/InspectedContext.h" #include "platform/v8_inspector/RemoteObjectId.h" +#include "platform/v8_inspector/V8Compat.h" #include "platform/v8_inspector/V8ConsoleMessage.h" #include "platform/v8_inspector/V8Debugger.h" +#include "platform/v8_inspector/V8DebuggerAgentImpl.h" #include "platform/v8_inspector/V8InspectorImpl.h" #include "platform/v8_inspector/V8InspectorSessionImpl.h" #include "platform/v8_inspector/V8StackTraceImpl.h" @@ -80,12 +82,12 @@ ProtocolPromiseHandler<Callback>* handler = new ProtocolPromiseHandler(inspector, contextGroupId, executionContextId, objectGroup, returnByValue, generatePreview, std::move(callback)); v8::Local<v8::Value> wrapper = handler->m_wrapper.Get(inspector->isolate()); - v8::Local<v8::Function> thenCallbackFunction = v8::Function::New(context, thenCallback, wrapper, 0, v8::ConstructorBehavior::kThrow).ToLocalChecked(); + v8::Local<v8::Function> thenCallbackFunction = V8_FUNCTION_NEW_REMOVE_PROTOTYPE(context, thenCallback, wrapper, 0).ToLocalChecked(); if (promise->Then(context, thenCallbackFunction).IsEmpty()) { rawCallback->sendFailure("Internal error"); return; } - v8::Local<v8::Function> catchCallbackFunction = v8::Function::New(context, catchCallback, wrapper, 0, v8::ConstructorBehavior::kThrow).ToLocalChecked(); + v8::Local<v8::Function> catchCallbackFunction = V8_FUNCTION_NEW_REMOVE_PROTOTYPE(context, catchCallback, wrapper, 0).ToLocalChecked(); if (promise->Catch(context, catchCallbackFunction).IsEmpty()) { rawCallback->sendFailure("Internal error"); return; @@ -503,7 +505,11 @@ if (!scope.initialize()) return; + if (!persistScript) + m_inspector->debugger()->muteScriptParsedEvents(); v8::Local<v8::Script> script = m_inspector->compileScript(scope.context(), toV8String(m_inspector->isolate(), expression), sourceURL, false); + if (!persistScript) + m_inspector->debugger()->unmuteScriptParsedEvents(); if (script.IsEmpty()) { v8::Local<v8::Message> message = scope.tryCatch().Message(); if (!message.IsEmpty())
diff --git a/third_party/WebKit/Source/platform/v8_inspector/injected_script_externs.js b/third_party/WebKit/Source/platform/v8_inspector/injected_script_externs.js index 3d8b3d1..03455614 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/injected_script_externs.js +++ b/third_party/WebKit/Source/platform/v8_inspector/injected_script_externs.js
@@ -58,12 +58,6 @@ */ InjectedScriptHostClass.prototype.proxyTargetValue = function(object) {} -/** - * @param {!Object} object - * @return {Object|undefined} - */ -InjectedScriptHostClass.prototype.prototype = function(object) {} - /** @type {!InjectedScriptHostClass} */ var InjectedScriptHost; /** @type {!Window} */
diff --git a/third_party/WebKit/Source/platform/v8_inspector/js_protocol.json b/third_party/WebKit/Source/platform/v8_inspector/js_protocol.json index 3213398..620d49c8 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/js_protocol.json +++ b/third_party/WebKit/Source/platform/v8_inspector/js_protocol.json
@@ -30,17 +30,17 @@ { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "map", "set", "iterator", "generator", "error", "proxy", "promise", "typedarray"], "description": "Object subtype hint. Specified for <code>object</code> type values only." }, { "name": "className", "type": "string", "optional": true, "description": "Object class (constructor) name. Specified for <code>object</code> type values only." }, { "name": "value", "type": "any", "optional": true, "description": "Remote object value in case of primitive values or JSON values (if it was requested)." }, - { "name": "unserializableValue", "$ref": "UnserializableValue", "optional": true, "hidden": true, "description": "Primitive value which can not be JSON-stringified does not have <code>value</code>, but gets this property." }, + { "name": "unserializableValue", "$ref": "UnserializableValue", "optional": true, "experimental": true, "description": "Primitive value which can not be JSON-stringified does not have <code>value</code>, but gets this property." }, { "name": "description", "type": "string", "optional": true, "description": "String representation of the object." }, { "name": "objectId", "$ref": "RemoteObjectId", "optional": true, "description": "Unique object identifier (for non-primitive values)." }, - { "name": "preview", "$ref": "ObjectPreview", "optional": true, "description": "Preview containing abbreviated property values. Specified for <code>object</code> type values only.", "hidden": true }, - { "name": "customPreview", "$ref": "CustomPreview", "optional": true, "hidden": true} + { "name": "preview", "$ref": "ObjectPreview", "optional": true, "description": "Preview containing abbreviated property values. Specified for <code>object</code> type values only.", "experimental": true }, + { "name": "customPreview", "$ref": "CustomPreview", "optional": true, "experimental": true} ] }, { "id": "CustomPreview", "type": "object", - "hidden": true, + "experimental": true, "properties": [ { "name": "header", "type": "string"}, { "name": "hasBody", "type": "boolean"}, @@ -52,7 +52,7 @@ { "id": "ObjectPreview", "type": "object", - "hidden": true, + "experimental": true, "description": "Object containing abbreviated remote object value.", "properties": [ { "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean", "symbol"], "description": "Object type." }, @@ -66,7 +66,7 @@ { "id": "PropertyPreview", "type": "object", - "hidden": true, + "experimental": true, "properties": [ { "name": "name", "type": "string", "description": "Property name." }, { "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean", "symbol", "accessor"], "description": "Object type. Accessor means that the property itself is an accessor property." }, @@ -78,7 +78,7 @@ { "id": "EntryPreview", "type": "object", - "hidden": true, + "experimental": true, "properties": [ { "name": "key", "$ref": "ObjectPreview", "optional": true, "description": "Preview of the key. Specified for map-like collection entries." }, { "name": "value", "$ref": "ObjectPreview", "description": "Preview of the value." } @@ -97,8 +97,8 @@ { "name": "configurable", "type": "boolean", "description": "True if the type of this property descriptor may be changed and if the property may be deleted from the corresponding object." }, { "name": "enumerable", "type": "boolean", "description": "True if this property shows up during enumeration of the properties on the corresponding object." }, { "name": "wasThrown", "type": "boolean", "optional": true, "description": "True if the result was thrown during the evaluation." }, - { "name": "isOwn", "optional": true, "type": "boolean", "description": "True if the property is owned for the object.", "hidden": true }, - { "name": "symbol", "$ref": "RemoteObject", "optional": true, "description": "Property symbol object, if the property is of the <code>symbol</code> type.", "hidden": true } + { "name": "isOwn", "optional": true, "type": "boolean", "description": "True if the property is owned for the object.", "experimental": true }, + { "name": "symbol", "$ref": "RemoteObject", "optional": true, "description": "Property symbol object, if the property is of the <code>symbol</code> type.", "experimental": true } ] }, { @@ -109,7 +109,7 @@ { "name": "name", "type": "string", "description": "Conventional property name." }, { "name": "value", "$ref": "RemoteObject", "optional": true, "description": "The value associated with the property." } ], - "hidden": true + "experimental": true }, { "id": "CallArgument", @@ -117,7 +117,7 @@ "description": "Represents function call argument. Either remote object id <code>objectId</code>, primitive <code>value</code>, unserializable primitive value or neither of (for undefined) them should be specified.", "properties": [ { "name": "value", "type": "any", "optional": true, "description": "Primitive value." }, - { "name": "unserializableValue", "$ref": "UnserializableValue", "optional": true, "hidden": true, "description": "Primitive value which can not be JSON-stringified." }, + { "name": "unserializableValue", "$ref": "UnserializableValue", "optional": true, "experimental": true, "description": "Primitive value which can not be JSON-stringified." }, { "name": "objectId", "$ref": "RemoteObjectId", "optional": true, "description": "Remote object handle." } ] }, @@ -132,15 +132,15 @@ "description": "Description of an isolated world.", "properties": [ { "name": "id", "$ref": "ExecutionContextId", "description": "Unique id of the execution context. It can be used to specify in which execution context script evaluation should be performed." }, - { "name": "origin", "type": "string", "description": "Execution context origin.", "hidden": true }, - { "name": "name", "type": "string", "description": "Human readable name describing given context.", "hidden": true }, - { "name": "auxData", "type": "object", "optional": true, "description": "Embedder-specific auxiliary data.", "hidden": true } + { "name": "origin", "type": "string", "description": "Execution context origin.", "experimental": true }, + { "name": "name", "type": "string", "description": "Human readable name describing given context.", "experimental": true }, + { "name": "auxData", "type": "object", "optional": true, "description": "Embedder-specific auxiliary data.", "experimental": true } ] }, { "id": "ExceptionDetails", "type": "object", - "hidden": true, + "experimental": true, "description": "Detailed information about exception (or error) that was thrown during script compilation or execution.", "properties": [ { "name": "text", "type": "string", "description": "Exception text." }, @@ -155,7 +155,7 @@ "id": "Timestamp", "type": "number", "description": "Number of milliseconds since epoch.", - "hidden": true + "experimental": true }, { "id": "CallFrame", @@ -177,7 +177,7 @@ "properties": [ { "name": "description", "type": "string", "optional": true, "description": "String label of this stack trace. For async traces this may be a name of the function that initiated the async call." }, { "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "JavaScript function name." }, - { "name": "parent", "$ref": "StackTrace", "optional": true, "hidden": true, "description": "Asynchronous JavaScript stack trace that preceded this stack, if available." } + { "name": "parent", "$ref": "StackTrace", "optional": true, "experimental": true, "description": "Asynchronous JavaScript stack trace that preceded this stack, if available." } ] } ], @@ -188,24 +188,24 @@ "parameters": [ { "name": "expression", "type": "string", "description": "Expression to evaluate." }, { "name": "objectGroup", "type": "string", "optional": true, "description": "Symbolic group name that can be used to release multiple objects." }, - { "name": "includeCommandLineAPI", "type": "boolean", "optional": true, "description": "Determines whether Command Line API should be available during the evaluation.", "hidden": true }, - { "name": "doNotPauseOnExceptionsAndMuteConsole", "type": "boolean", "optional": true, "description": "Specifies whether evaluation should stop on exceptions and mute console. Overrides setPauseOnException state.", "hidden": true }, + { "name": "includeCommandLineAPI", "type": "boolean", "optional": true, "description": "Determines whether Command Line API should be available during the evaluation.", "experimental": true }, + { "name": "doNotPauseOnExceptionsAndMuteConsole", "type": "boolean", "optional": true, "description": "Specifies whether evaluation should stop on exceptions and mute console. Overrides setPauseOnException state.", "experimental": true }, { "name": "contextId", "$ref": "ExecutionContextId", "optional": true, "description": "Specifies in which execution context to perform evaluation. If the parameter is omitted the evaluation will be performed in the context of the inspected page." }, { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object that should be sent by value." }, - { "name": "generatePreview", "type": "boolean", "optional": true, "hidden": true, "description": "Whether preview should be generated for the result." }, - { "name": "userGesture", "type": "boolean", "optional": true, "hidden": true, "description": "Whether execution should be treated as initiated by user in the UI." }, - { "name": "awaitPromise", "type": "boolean", "optional":true, "hidden": true, "description": "Whether execution should wait for promise to be resolved. If the result of evaluation is not a Promise, it's considered to be an error." } + { "name": "generatePreview", "type": "boolean", "optional": true, "experimental": true, "description": "Whether preview should be generated for the result." }, + { "name": "userGesture", "type": "boolean", "optional": true, "experimental": true, "description": "Whether execution should be treated as initiated by user in the UI." }, + { "name": "awaitPromise", "type": "boolean", "optional":true, "experimental": true, "description": "Whether execution should wait for promise to be resolved. If the result of evaluation is not a Promise, it's considered to be an error." } ], "returns": [ { "name": "result", "$ref": "RemoteObject", "description": "Evaluation result." }, { "name": "wasThrown", "type": "boolean", "optional": true, "description": "True if the result was thrown during the evaluation." }, - { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "hidden": true, "description": "Exception details."} + { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "experimental": true, "description": "Exception details."} ], "description": "Evaluates expression on global object." }, { "name": "awaitPromise", - "hidden": true, + "experimental": true, "async": true, "parameters": [ { "name": "promiseObjectId", "$ref": "RemoteObjectId", "description": "Identifier of the promise." }, @@ -226,16 +226,16 @@ { "name": "objectId", "$ref": "RemoteObjectId", "description": "Identifier of the object to call function on." }, { "name": "functionDeclaration", "type": "string", "description": "Declaration of the function to call." }, { "name": "arguments", "type": "array", "items": { "$ref": "CallArgument", "description": "Call argument." }, "optional": true, "description": "Call arguments. All call arguments must belong to the same JavaScript world as the target object." }, - { "name": "doNotPauseOnExceptionsAndMuteConsole", "type": "boolean", "optional": true, "description": "Specifies whether function call should stop on exceptions and mute console. Overrides setPauseOnException state.", "hidden": true }, + { "name": "doNotPauseOnExceptionsAndMuteConsole", "type": "boolean", "optional": true, "description": "Specifies whether function call should stop on exceptions and mute console. Overrides setPauseOnException state.", "experimental": true }, { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object which should be sent by value." }, - { "name": "generatePreview", "type": "boolean", "optional": true, "hidden": true, "description": "Whether preview should be generated for the result." }, - { "name": "userGesture", "type": "boolean", "optional": true, "hidden": true, "description": "Whether execution should be treated as initiated by user in the UI." }, - { "name": "awaitPromise", "type": "boolean", "optional":true, "hidden": true, "description": "Whether execution should wait for promise to be resolved. If the result of evaluation is not a Promise, it's considered to be an error." } + { "name": "generatePreview", "type": "boolean", "optional": true, "experimental": true, "description": "Whether preview should be generated for the result." }, + { "name": "userGesture", "type": "boolean", "optional": true, "experimental": true, "description": "Whether execution should be treated as initiated by user in the UI." }, + { "name": "awaitPromise", "type": "boolean", "optional":true, "experimental": true, "description": "Whether execution should wait for promise to be resolved. If the result of evaluation is not a Promise, it's considered to be an error." } ], "returns": [ { "name": "result", "$ref": "RemoteObject", "description": "Call result." }, { "name": "wasThrown", "type": "boolean", "optional": true, "description": "True if the result was thrown during the evaluation." }, - { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "hidden": true, "description": "Exception details."} + { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "experimental": true, "description": "Exception details."} ], "description": "Calls function with given declaration on the given object. Object group of the result is inherited from the target object." }, @@ -244,13 +244,13 @@ "parameters": [ { "name": "objectId", "$ref": "RemoteObjectId", "description": "Identifier of the object to return properties for." }, { "name": "ownProperties", "optional": true, "type": "boolean", "description": "If true, returns properties belonging only to the element itself, not to its prototype chain." }, - { "name": "accessorPropertiesOnly", "optional": true, "type": "boolean", "description": "If true, returns accessor properties (with getter/setter) only; internal properties are not returned either.", "hidden": true }, - { "name": "generatePreview", "type": "boolean", "optional": true, "hidden": true, "description": "Whether preview should be generated for the results." } + { "name": "accessorPropertiesOnly", "optional": true, "type": "boolean", "description": "If true, returns accessor properties (with getter/setter) only; internal properties are not returned either.", "experimental": true }, + { "name": "generatePreview", "type": "boolean", "optional": true, "experimental": true, "description": "Whether preview should be generated for the results." } ], "returns": [ { "name": "result", "type": "array", "items": { "$ref": "PropertyDescriptor" }, "description": "Object properties." }, - { "name": "internalProperties", "optional": true, "type": "array", "items": { "$ref": "InternalPropertyDescriptor" }, "description": "Internal object properties (only of the element itself).", "hidden": true }, - { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "hidden": true, "description": "Exception details."} + { "name": "internalProperties", "optional": true, "type": "array", "items": { "$ref": "InternalPropertyDescriptor" }, "description": "Internal object properties (only of the element itself).", "experimental": true }, + { "name": "exceptionDetails", "$ref": "ExceptionDetails", "optional": true, "experimental": true, "description": "Exception details."} ], "description": "Returns properties of a given object. Object group of the result is inherited from the target object." }, @@ -270,7 +270,7 @@ }, { "name": "run", - "hidden": true, + "experimental": true, "description": "Tells inspected instance(worker or page) that it can run in case it was started paused." }, { @@ -279,12 +279,12 @@ }, { "name": "disable", - "hidden": true, + "experimental": true, "description": "Disables reporting of execution contexts creation." }, { "name": "discardConsoleEntries", - "hidden": true, + "experimental": true, "description": "Discards collected exceptions and console API calls." }, { @@ -295,11 +295,11 @@ "type": "boolean" } ], - "hidden": true + "experimental": true }, { "name": "compileScript", - "hidden": true, + "experimental": true, "parameters": [ { "name": "expression", "type": "string", "description": "Expression to compile." }, { "name": "sourceURL", "type": "string", "description": "Source url to be set for the script." }, @@ -314,7 +314,7 @@ }, { "name": "runScript", - "hidden": true, + "experimental": true, "async": true, "parameters": [ { "name": "scriptId", "$ref": "ScriptId", "description": "Id of the script to run." }, @@ -363,7 +363,7 @@ { "name": "exception", "$ref": "RemoteObject", "optional": true, "description": "Exception object." }, { "name": "executionContextId", "$ref": "ExecutionContextId", "optional": true, "description": "Identifier of the context where exception happened." } ], - "hidden": true + "experimental": true }, { "name": "exceptionRevoked", @@ -372,7 +372,7 @@ { "name": "message", "type": "string", "description": "Message describing why exception was revoked." }, { "name": "exceptionId", "type": "integer", "description": "The id of revoked exception, as reported in <code>exceptionUnhandled</code>." } ], - "hidden": true + "experimental": true }, { "name": "consoleAPICalled", @@ -384,7 +384,7 @@ { "name": "timestamp", "$ref": "Timestamp", "description": "Call timestamp." }, { "name": "stackTrace", "$ref": "StackTrace", "optional": true, "description": "Stack trace captured when the call was made." } ], - "hidden": true + "experimental": true }, { "name": "inspectRequested", @@ -392,7 +392,7 @@ { "name": "object", "$ref": "RemoteObject" }, { "name": "hints", "type": "object" } ], - "hidden": true + "experimental": true } ] }, @@ -423,7 +423,7 @@ }, { "id": "ScriptPosition", - "hidden": true, + "experimental": true, "type": "object", "properties": [ { "name": "lineNumber", "type": "integer" }, @@ -437,11 +437,11 @@ "properties": [ { "name": "callFrameId", "$ref": "CallFrameId", "description": "Call frame identifier. This identifier is only valid while the virtual machine is paused." }, { "name": "functionName", "type": "string", "description": "Name of the JavaScript function called on this call frame." }, - { "name": "functionLocation", "$ref": "Location", "optional": true, "hidden": true, "description": "Location in the source code." }, + { "name": "functionLocation", "$ref": "Location", "optional": true, "experimental": true, "description": "Location in the source code." }, { "name": "location", "$ref": "Location", "description": "Location in the source code." }, { "name": "scopeChain", "type": "array", "items": { "$ref": "Scope" }, "description": "Scope chain for this call frame." }, { "name": "this", "$ref": "Runtime.RemoteObject", "description": "<code>this</code> object for this call frame." }, - { "name": "returnValue", "$ref": "Runtime.RemoteObject", "optional": true, "hidden": true, "description": "The value being returned, if the function is at return point." } + { "name": "returnValue", "$ref": "Runtime.RemoteObject", "optional": true, "experimental": true, "description": "The value being returned, if the function is at return point." } ], "description": "JavaScript call frame. Array of call frames form the call stack." }, @@ -451,9 +451,9 @@ "properties": [ { "name": "type", "type": "string", "enum": ["global", "local", "with", "closure", "catch", "block", "script"], "description": "Scope type." }, { "name": "object", "$ref": "Runtime.RemoteObject", "description": "Object representing the scope. For <code>global</code> and <code>with</code> scopes it represents the actual object; for the rest of the scopes, it is artificial transient object enumerating scope variables as its properties." }, - { "name": "name", "type": "string", "optional": true, "hidden": true }, - { "name": "startLocation", "$ref": "Location", "optional": true, "hidden": true, "description": "Location in the source code where scope starts" }, - { "name": "endLocation", "$ref": "Location", "optional": true, "hidden": true, "description": "Location in the source code where scope ends" } + { "name": "name", "type": "string", "optional": true, "experimental": true }, + { "name": "startLocation", "$ref": "Location", "optional": true, "experimental": true, "description": "Location in the source code where scope starts" }, + { "name": "endLocation", "$ref": "Location", "optional": true, "experimental": true, "description": "Location in the source code where scope ends" } ], "description": "Scope description." }, @@ -466,7 +466,7 @@ { "name": "lineNumber", "type": "number", "description": "Line number in resource content." }, { "name": "lineContent", "type": "string", "description": "Line with match content." } ], - "hidden": true + "experimental": true } ], "commands": [ @@ -487,7 +487,7 @@ }, { "name": "setSkipAllPauses", - "hidden": true, + "experimental": true, "parameters": [ { "name": "skipped", "type": "boolean", "description": "New value for skip pauses state." } ], @@ -530,8 +530,7 @@ { "name": "continueToLocation", "parameters": [ - { "name": "location", "$ref": "Location", "description": "Location to continue to." }, - { "name": "interstatementLocation", "type": "boolean", "optional": true, "hidden": true, "description": "Allows breakpoints at the intemediate positions inside statements." } + { "name": "location", "$ref": "Location", "description": "Location to continue to." } ], "description": "Continues execution until specific location is reached." }, @@ -580,12 +579,12 @@ "parameters": [ { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Id of the script to edit." }, { "name": "scriptSource", "type": "string", "description": "New content of the script." }, - { "name": "preview", "type": "boolean", "optional": true, "description": " If true the change will not actually be applied. Preview mode may be used to get result description without actually modifying the code.", "hidden": true } + { "name": "preview", "type": "boolean", "optional": true, "description": " If true the change will not actually be applied. Preview mode may be used to get result description without actually modifying the code.", "experimental": true } ], "returns": [ { "name": "callFrames", "type": "array", "optional": true, "items": { "$ref": "CallFrame" }, "description": "New stack trace in case editing has happened while VM was stopped." }, - { "name": "stackChanged", "type": "boolean", "optional": true, "description": "Whether current call stack was modified after applying the changes.", "hidden": true }, - { "name": "asyncStackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "Async stack trace, if any.", "hidden": true }, + { "name": "stackChanged", "type": "boolean", "optional": true, "description": "Whether current call stack was modified after applying the changes.", "experimental": true }, + { "name": "asyncStackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "Async stack trace, if any.", "experimental": true }, { "name": "compileError", "optional": true, "$ref": "Runtime.ExceptionDetails", "description": "Error data if any." } ], "description": "Edits JavaScript source live." @@ -599,7 +598,7 @@ { "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "New stack trace." }, { "name": "asyncStackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "Async stack trace, if any." } ], - "hidden": true, + "experimental": true, "description": "Restarts particular call frame from the beginning." }, { @@ -625,15 +624,15 @@ { "name": "callFrameId", "$ref": "CallFrameId", "description": "Call frame identifier to evaluate on." }, { "name": "expression", "type": "string", "description": "Expression to evaluate." }, { "name": "objectGroup", "type": "string", "optional": true, "description": "String object group name to put result into (allows rapid releasing resulting object handles using <code>releaseObjectGroup</code>)." }, - { "name": "includeCommandLineAPI", "type": "boolean", "optional": true, "description": "Specifies whether command line API should be available to the evaluated expression, defaults to false.", "hidden": true }, - { "name": "doNotPauseOnExceptionsAndMuteConsole", "type": "boolean", "optional": true, "description": "Specifies whether evaluation should stop on exceptions and mute console. Overrides setPauseOnException state.", "hidden": true }, + { "name": "includeCommandLineAPI", "type": "boolean", "optional": true, "description": "Specifies whether command line API should be available to the evaluated expression, defaults to false.", "experimental": true }, + { "name": "doNotPauseOnExceptionsAndMuteConsole", "type": "boolean", "optional": true, "description": "Specifies whether evaluation should stop on exceptions and mute console. Overrides setPauseOnException state.", "experimental": true }, { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object that should be sent by value." }, - { "name": "generatePreview", "type": "boolean", "optional": true, "hidden": true, "description": "Whether preview should be generated for the result." } + { "name": "generatePreview", "type": "boolean", "optional": true, "experimental": true, "description": "Whether preview should be generated for the result." } ], "returns": [ { "name": "result", "$ref": "Runtime.RemoteObject", "description": "Object wrapper for the evaluation result." }, { "name": "wasThrown", "type": "boolean", "optional": true, "description": "True if the result was thrown during the evaluation." }, - { "name": "exceptionDetails", "$ref": "Runtime.ExceptionDetails", "optional": true, "hidden": true, "description": "Exception details."} + { "name": "exceptionDetails", "$ref": "Runtime.ExceptionDetails", "optional": true, "experimental": true, "description": "Exception details."} ], "description": "Evaluates expression on a given call frame." }, @@ -645,7 +644,7 @@ { "name": "newValue", "$ref": "Runtime.CallArgument", "description": "New variable value." }, { "name": "callFrameId", "$ref": "CallFrameId", "description": "Id of callframe that holds variable." } ], - "hidden": true, + "experimental": true, "description": "Changes value of variable in a callframe. Object-based scopes are not supported and must be mutated manually." }, { @@ -654,7 +653,7 @@ { "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "Call stack the virtual machine stopped on." }, { "name": "asyncStackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "Async stack trace, if any." } ], - "hidden": true, + "experimental": true, "description": "Returns call stack including variables changed since VM was paused. VM must be paused." }, { @@ -662,7 +661,7 @@ "parameters": [ { "name": "maxDepth", "type": "integer", "description": "Maximum depth of async call stacks. Setting to <code>0</code> will effectively disable collecting async call stacks (default)." } ], - "hidden": true, + "experimental": true, "description": "Enables or disables async call stacks tracking." }, { @@ -670,7 +669,7 @@ "parameters": [ { "name": "patterns", "type": "array", "items": { "type": "string" }, "description": "Array of regexps that will be used to check script url for blackbox state." } ], - "hidden": true, + "experimental": true, "description": "Replace previous blackbox patterns with passed ones. Forces backend to skip stepping/pausing in scripts with url matching one of the patterns. VM will try to leave blackboxed script by performing 'step in' several times, finally resorting to 'step out' if unsuccessful." }, { @@ -679,7 +678,7 @@ { "name": "scriptId", "$ref": "Runtime.ScriptId", "description": "Id of the script." }, { "name": "positions", "type": "array", "items": { "$ref": "ScriptPosition" } } ], - "hidden": true, + "experimental": true, "description": "Makes backend skip steps in the script in blackboxed ranges. VM will try leave blacklisted scripts by performing 'step in' several times, finally resorting to 'step out' if unsuccessful. Positions array contains positions where blackbox state is changed. First interval isn't blackboxed. Array should be sorted." } ], @@ -693,14 +692,14 @@ { "name": "startColumn", "type": "integer", "description": "Column offset of the script within the resource with given URL." }, { "name": "endLine", "type": "integer", "description": "Last line of the script." }, { "name": "endColumn", "type": "integer", "description": "Length of the last line of the script." }, - { "name": "executionContextId", "$ref": "Runtime.ExecutionContextId", "description": "Specifies script creation context.", "hidden": true }, - { "name": "hash", "type": "string", "hidden": true, "description": "Content hash of the script."}, - { "name": "executionContextAuxData", "type": "object", "optional": true, "description": "Embedder-specific auxiliary data.", "hidden": true }, - { "name": "isInternalScript", "type": "boolean", "optional": true, "description": "Determines whether this script is an internal script.", "hidden": true }, - { "name": "isLiveEdit", "type": "boolean", "optional": true, "description": "True, if this script is generated as a result of the live edit operation.", "hidden": true }, + { "name": "executionContextId", "$ref": "Runtime.ExecutionContextId", "description": "Specifies script creation context.", "experimental": true }, + { "name": "hash", "type": "string", "experimental": true, "description": "Content hash of the script."}, + { "name": "executionContextAuxData", "type": "object", "optional": true, "description": "Embedder-specific auxiliary data.", "experimental": true }, + { "name": "isInternalScript", "type": "boolean", "optional": true, "description": "Determines whether this script is an internal script.", "experimental": true }, + { "name": "isLiveEdit", "type": "boolean", "optional": true, "description": "True, if this script is generated as a result of the live edit operation.", "experimental": true }, { "name": "sourceMapURL", "type": "string", "optional": true, "description": "URL of source map associated with script (if any)." }, - { "name": "hasSourceURL", "type": "boolean", "optional": true, "description": "True, if this script has sourceURL.", "hidden": true }, - { "name": "deprecatedCommentWasUsed", "type": "boolean", "optional": true, "hidden": true, "description": "True, if '//@ sourceURL' or '//@ sourceMappingURL' was used."} + { "name": "hasSourceURL", "type": "boolean", "optional": true, "description": "True, if this script has sourceURL.", "experimental": true }, + { "name": "deprecatedCommentWasUsed", "type": "boolean", "optional": true, "experimental": true, "description": "True, if '//@ sourceURL' or '//@ sourceMappingURL' was used."} ], "description": "Fired when virtual machine parses script. This event is also fired for all known and uncollected scripts upon enabling debugger." }, @@ -713,13 +712,13 @@ { "name": "startColumn", "type": "integer", "description": "Column offset of the script within the resource with given URL." }, { "name": "endLine", "type": "integer", "description": "Last line of the script." }, { "name": "endColumn", "type": "integer", "description": "Length of the last line of the script." }, - { "name": "executionContextId", "$ref": "Runtime.ExecutionContextId", "description": "Specifies script creation context.", "hidden": true }, - { "name": "hash", "type": "string", "hidden": true, "description": "Content hash of the script."}, - { "name": "executionContextAuxData", "type": "object", "optional": true, "description": "Embedder-specific auxiliary data.", "hidden": true }, - { "name": "isInternalScript", "type": "boolean", "optional": true, "description": "Determines whether this script is an internal script.", "hidden": true }, + { "name": "executionContextId", "$ref": "Runtime.ExecutionContextId", "description": "Specifies script creation context.", "experimental": true }, + { "name": "hash", "type": "string", "experimental": true, "description": "Content hash of the script."}, + { "name": "executionContextAuxData", "type": "object", "optional": true, "description": "Embedder-specific auxiliary data.", "experimental": true }, + { "name": "isInternalScript", "type": "boolean", "optional": true, "description": "Determines whether this script is an internal script.", "experimental": true }, { "name": "sourceMapURL", "type": "string", "optional": true, "description": "URL of source map associated with script (if any)." }, - { "name": "hasSourceURL", "type": "boolean", "optional": true, "description": "True, if this script has sourceURL.", "hidden": true }, - { "name": "deprecatedCommentWasUsed", "type": "boolean", "optional": true, "hidden": true, "description": "True, if '//@ sourceURL' or '//@ sourceMappingURL' was used."} + { "name": "hasSourceURL", "type": "boolean", "optional": true, "description": "True, if this script has sourceURL.", "experimental": true }, + { "name": "deprecatedCommentWasUsed", "type": "boolean", "optional": true, "experimental": true, "description": "True, if '//@ sourceURL' or '//@ sourceMappingURL' was used."} ], "description": "Fired when virtual machine fails to parse the script." }, @@ -737,8 +736,8 @@ { "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "Call stack the virtual machine stopped on." }, { "name": "reason", "type": "string", "enum": [ "XHR", "DOM", "EventListener", "exception", "assert", "debugCommand", "promiseRejection", "other" ], "description": "Pause reason.", "exported": true }, { "name": "data", "type": "object", "optional": true, "description": "Object containing break-specific auxiliary properties." }, - { "name": "hitBreakpoints", "type": "array", "optional": true, "items": { "type": "string" }, "description": "Hit breakpoints IDs", "hidden": true }, - { "name": "asyncStackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "Async stack trace, if any.", "hidden": true } + { "name": "hitBreakpoints", "type": "array", "optional": true, "items": { "type": "string" }, "description": "Hit breakpoints IDs", "experimental": true }, + { "name": "asyncStackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "Async stack trace, if any.", "experimental": true } ], "description": "Fired when the virtual machine stopped on breakpoint or exception or any other stop criteria." }, @@ -794,7 +793,7 @@ "name": "messageRepeatCountUpdated", "parameters": [ { "name": "count", "type": "integer", "description": "New repeat count value." }, - { "name": "timestamp", "$ref": "Runtime.Timestamp", "description": "Timestamp of most recent message in batch.", "hidden": true } + { "name": "timestamp", "$ref": "Runtime.Timestamp", "description": "Timestamp of most recent message in batch.", "experimental": true } ], "description": "Not issued.", "deprecated": true @@ -809,7 +808,7 @@ { "domain": "Profiler", "dependencies": ["Runtime", "Debugger"], - "hidden": true, + "experimental": true, "types": [ { "id": "CPUProfileNode", @@ -894,7 +893,7 @@ { "domain": "HeapProfiler", "dependencies": ["Runtime"], - "hidden": true, + "experimental": true, "types": [ { "id": "HeapSnapshotObjectId",
diff --git a/third_party/WebKit/Source/platform/v8_inspector/public/SimpleInspector.cpp b/third_party/WebKit/Source/platform/v8_inspector/public/SimpleInspector.cpp deleted file mode 100644 index 7653fd6..0000000 --- a/third_party/WebKit/Source/platform/v8_inspector/public/SimpleInspector.cpp +++ /dev/null
@@ -1,52 +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 "platform/v8_inspector/public/SimpleInspector.h" - -#include "platform/inspector_protocol/DispatcherBase.h" -#include "platform/v8_inspector/public/V8Inspector.h" -#include "platform/v8_inspector/public/V8InspectorSession.h" - -namespace blink { - -SimpleInspector::SimpleInspector(v8::Isolate* isolate, v8::Local<v8::Context> context) - : m_context(context) -{ - m_inspector = V8Inspector::create(isolate, this); - m_inspector->contextCreated(V8ContextInfo(context, 1, "NodeJS Main Context")); -} - -SimpleInspector::~SimpleInspector() -{ - disconnectFrontend(); -} - -void SimpleInspector::connectFrontend(protocol::FrontendChannel* channel) -{ - m_session = m_inspector->connect(1, channel, nullptr); -} - -void SimpleInspector::disconnectFrontend() -{ - m_session.reset(); -} - -void SimpleInspector::dispatchMessageFromFrontend(const String16& message) -{ - if (m_session) - m_session->dispatchProtocolMessage(message); -} - -v8::Local<v8::Context> SimpleInspector::ensureDefaultContextInGroup(int contextGroupId) -{ - return m_context; -} - -void SimpleInspector::notifyContextDestroyed() -{ - m_inspector->contextDestroyed(m_context); -} - -} // namespace blink
diff --git a/third_party/WebKit/Source/platform/v8_inspector/public/SimpleInspector.h b/third_party/WebKit/Source/platform/v8_inspector/public/SimpleInspector.h deleted file mode 100644 index fc5426b..0000000 --- a/third_party/WebKit/Source/platform/v8_inspector/public/SimpleInspector.h +++ /dev/null
@@ -1,45 +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 SimpleInspector_h -#define SimpleInspector_h - -#include "platform/inspector_protocol/Platform.h" -#include "platform/v8_inspector/public/V8InspectorClient.h" - -#include <v8.h> - -namespace blink { - -namespace protocol { -class Dispatcher; -class Frontend; -class FrontendChannel; -} - -class V8Inspector; -class V8InspectorSession; - -class SimpleInspector : public V8InspectorClient { -public: - SimpleInspector(v8::Isolate*, v8::Local<v8::Context>); - ~SimpleInspector() override; - - // Transport interface. - void connectFrontend(protocol::FrontendChannel*); - void disconnectFrontend(); - void dispatchMessageFromFrontend(const String16& message); - void notifyContextDestroyed(); - -private: - v8::Local<v8::Context> ensureDefaultContextInGroup(int contextGroupId) override; - - std::unique_ptr<V8Inspector> m_inspector; - std::unique_ptr<V8InspectorSession> m_session; - v8::Local<v8::Context> m_context; -}; - -} - -#endif // SimpleInspector_h
diff --git a/third_party/WebKit/Source/platform/v8_inspector/v8_inspector.gyp b/third_party/WebKit/Source/platform/v8_inspector/v8_inspector.gyp index e848ad5..ebfc91a 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/v8_inspector.gyp +++ b/third_party/WebKit/Source/platform/v8_inspector/v8_inspector.gyp
@@ -237,8 +237,6 @@ 'public/V8Inspector.h', 'public/V8InspectorClient.h', 'public/V8HeapProfilerAgent.h', - 'public/SimpleInspector.cpp', - 'public/SimpleInspector.h', 'public/V8InspectorSession.h', 'public/V8StackTrace.h',
diff --git a/third_party/WebKit/Source/web/AssertMatchingEnums.cpp b/third_party/WebKit/Source/web/AssertMatchingEnums.cpp index f746f7bb..771cf063 100644 --- a/third_party/WebKit/Source/web/AssertMatchingEnums.cpp +++ b/third_party/WebKit/Source/web/AssertMatchingEnums.cpp
@@ -37,6 +37,9 @@ #include "core/editing/SelectionType.h" #include "core/editing/TextAffinity.h" #include "core/editing/markers/DocumentMarker.h" +#if OS(MACOSX) +#include "core/events/WheelEvent.h" +#endif #include "core/fileapi/FileError.h" #include "core/frame/Frame.h" #include "core/frame/FrameTypes.h" @@ -126,7 +129,6 @@ #include "public/web/WebSettings.h" #include "public/web/WebSpeechRecognizerClient.h" #include "public/web/WebTextCheckingResult.h" -#include "public/web/WebTextCheckingType.h" #include "public/web/WebTextDecorationType.h" #include "public/web/WebTouchAction.h" #include "public/web/WebView.h" @@ -507,6 +509,24 @@ STATIC_ASSERT_ENUM(WebMouseEvent::ButtonMiddle, MiddleButton); STATIC_ASSERT_ENUM(WebMouseEvent::ButtonRight, RightButton); +#if OS(MACOSX) +STATIC_ASSERT_ENUM(WebMouseWheelEvent::PhaseNone, PlatformWheelEventPhaseNone); +STATIC_ASSERT_ENUM(WebMouseWheelEvent::PhaseBegan, PlatformWheelEventPhaseBegan); +STATIC_ASSERT_ENUM(WebMouseWheelEvent::PhaseStationary, PlatformWheelEventPhaseStationary); +STATIC_ASSERT_ENUM(WebMouseWheelEvent::PhaseChanged, PlatformWheelEventPhaseChanged); +STATIC_ASSERT_ENUM(WebMouseWheelEvent::PhaseEnded, PlatformWheelEventPhaseEnded); +STATIC_ASSERT_ENUM(WebMouseWheelEvent::PhaseCancelled, PlatformWheelEventPhaseCancelled); +STATIC_ASSERT_ENUM(WebMouseWheelEvent::PhaseMayBegin, PlatformWheelEventPhaseMayBegin); + +STATIC_ASSERT_ENUM(WebMouseWheelEvent::PhaseNone, WheelEventPhaseNone); +STATIC_ASSERT_ENUM(WebMouseWheelEvent::PhaseBegan, WheelEventPhaseBegan); +STATIC_ASSERT_ENUM(WebMouseWheelEvent::PhaseStationary, WheelEventPhaseStationary); +STATIC_ASSERT_ENUM(WebMouseWheelEvent::PhaseChanged, WheelEventPhaseChanged); +STATIC_ASSERT_ENUM(WebMouseWheelEvent::PhaseEnded, WheelEventPhaseEnded); +STATIC_ASSERT_ENUM(WebMouseWheelEvent::PhaseCancelled, WheelEventPhaseCancelled); +STATIC_ASSERT_ENUM(WebMouseWheelEvent::PhaseMayBegin, WheelEventPhaseMayBegin); +#endif + STATIC_ASSERT_ENUM(WebScrollbar::Horizontal, HorizontalScrollbar); STATIC_ASSERT_ENUM(WebScrollbar::Vertical, VerticalScrollbar); @@ -588,14 +608,6 @@ STATIC_ASSERT_ENUM(WebFileErrorTypeMismatch, FileError::kTypeMismatchErr); STATIC_ASSERT_ENUM(WebFileErrorPathExists, FileError::kPathExistsErr); -STATIC_ASSERT_ENUM(WebTextCheckingTypeSpelling, TextCheckingTypeSpelling); -STATIC_ASSERT_ENUM(WebTextCheckingTypeGrammar, TextCheckingTypeGrammar); - -// TODO(rouslan): Remove these comparisons between text-checking and text-decoration enum values after removing the -// deprecated constructor WebTextCheckingResult(WebTextCheckingType). -STATIC_ASSERT_ENUM(WebTextCheckingTypeSpelling, TextDecorationTypeSpelling); -STATIC_ASSERT_ENUM(WebTextCheckingTypeGrammar, TextDecorationTypeGrammar); - STATIC_ASSERT_ENUM(WebTextDecorationTypeSpelling, TextDecorationTypeSpelling); STATIC_ASSERT_ENUM(WebTextDecorationTypeGrammar, TextDecorationTypeGrammar); STATIC_ASSERT_ENUM(WebTextDecorationTypeInvisibleSpellcheck, TextDecorationTypeInvisibleSpellcheck);
diff --git a/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp b/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp index 1f10cdc..af5a8d2 100644 --- a/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp +++ b/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp
@@ -1030,4 +1030,9 @@ return WebLocalFrameImpl::fromFrame(m_webFrame->frame()->localFrameRoot())->devToolsAgentImpl(); } +KURL FrameLoaderClientImpl::overrideFlashEmbedWithHTML(const KURL& url) +{ + return m_webFrame->client()->overrideFlashEmbedWithHTML(WebURL(url)); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/web/FrameLoaderClientImpl.h b/third_party/WebKit/Source/web/FrameLoaderClientImpl.h index d72f15d..86d726f 100644 --- a/third_party/WebKit/Source/web/FrameLoaderClientImpl.h +++ b/third_party/WebKit/Source/web/FrameLoaderClientImpl.h
@@ -184,6 +184,8 @@ WebEffectiveConnectionType getEffectiveConnectionType() override; + KURL overrideFlashEmbedWithHTML(const KURL&) override; + private: explicit FrameLoaderClientImpl(WebLocalFrameImpl*);
diff --git a/third_party/WebKit/Source/web/LinkHighlightImpl.cpp b/third_party/WebKit/Source/web/LinkHighlightImpl.cpp index ac13837b..041f80e 100644 --- a/third_party/WebKit/Source/web/LinkHighlightImpl.cpp +++ b/third_party/WebKit/Source/web/LinkHighlightImpl.cpp
@@ -313,13 +313,13 @@ const auto& timingFunction = *CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseType::EASE); - curve->addCubicBezierKeyframe(CompositorFloatKeyframe(0, startOpacity), timingFunction); + curve->addKeyframe(CompositorFloatKeyframe(0, startOpacity), timingFunction); // Make sure we have displayed for at least minPreFadeDuration before starting to fade out. float extraDurationRequired = std::max(0.f, minPreFadeDuration - static_cast<float>(monotonicallyIncreasingTime() - m_startTime)); if (extraDurationRequired) - curve->addCubicBezierKeyframe(CompositorFloatKeyframe(extraDurationRequired, startOpacity), timingFunction); + curve->addKeyframe(CompositorFloatKeyframe(extraDurationRequired, startOpacity), timingFunction); // For layout tests we don't fade out. - curve->addCubicBezierKeyframe(CompositorFloatKeyframe(fadeDuration + extraDurationRequired, layoutTestMode() ? startOpacity : 0), timingFunction); + curve->addKeyframe(CompositorFloatKeyframe(fadeDuration + extraDurationRequired, layoutTestMode() ? startOpacity : 0), timingFunction); std::unique_ptr<CompositorAnimation> animation = CompositorAnimation::create(*curve, CompositorTargetProperty::OPACITY, 0, 0);
diff --git a/third_party/WebKit/Source/web/PopupMenuImpl.cpp b/third_party/WebKit/Source/web/PopupMenuImpl.cpp index 7ee847eb08..5a2d476 100644 --- a/third_party/WebKit/Source/web/PopupMenuImpl.cpp +++ b/third_party/WebKit/Source/web/PopupMenuImpl.cpp
@@ -294,7 +294,7 @@ // TODO(tkent): We generate unnecessary "style: {\n},\n" even if no // additional style. PagePopupClient::addString("style: {\n", data); - if (style->visibility() == HIDDEN) + if (style->visibility() == EVisibility::Hidden) addProperty("visibility", String("hidden"), data); if (style->display() == NONE) addProperty("display", String("none"), data);
diff --git a/third_party/WebKit/Source/web/SpellCheckerClientImpl.cpp b/third_party/WebKit/Source/web/SpellCheckerClientImpl.cpp index 3dbc908..7f61bdb 100644 --- a/third_party/WebKit/Source/web/SpellCheckerClientImpl.cpp +++ b/third_party/WebKit/Source/web/SpellCheckerClientImpl.cpp
@@ -147,39 +147,20 @@ m_webView->spellCheckClient()->requestCheckingOfText(text, markers, markerOffsets, new WebTextCheckingCompletionImpl(request)); } +void SpellCheckerClientImpl::cancelAllPendingRequests() +{ + if (!m_webView->spellCheckClient()) + return; + m_webView->spellCheckClient()->cancelAllPendingRequests(); +} + void SpellCheckerClientImpl::checkGrammarOfString(const String& text, WTF::Vector<GrammarDetail>& details, int* badGrammarLocation, int* badGrammarLength) { if (badGrammarLocation) *badGrammarLocation = -1; if (badGrammarLength) *badGrammarLength = 0; - - if (!m_webView->spellCheckClient()) - return; - WebVector<WebTextCheckingResult> webResults; - m_webView->spellCheckClient()->checkTextOfParagraph(text, WebTextCheckingTypeGrammar, &webResults); - if (!webResults.size()) - return; - - // Convert a list of WebTextCheckingResults to a list of GrammarDetails. If - // the converted vector of GrammarDetails has grammar errors, we set - // badGrammarLocation and badGrammarLength to tell WebKit that the input - // text has grammar errors. - for (size_t i = 0; i < webResults.size(); ++i) { - if (webResults[i].decoration == WebTextDecorationTypeGrammar) { - GrammarDetail detail; - detail.location = webResults[i].location; - detail.length = webResults[i].length; - detail.userDescription = webResults[i].replacement; - details.append(detail); - } - } - if (!details.size()) - return; - if (badGrammarLocation) - *badGrammarLocation = 0; - if (badGrammarLength) - *badGrammarLength = text.length(); + return; } void SpellCheckerClientImpl::updateSpellingUIWithMisspelledWord(const String& misspelledWord)
diff --git a/third_party/WebKit/Source/web/SpellCheckerClientImpl.h b/third_party/WebKit/Source/web/SpellCheckerClientImpl.h index 307635e..0ba0147 100644 --- a/third_party/WebKit/Source/web/SpellCheckerClientImpl.h +++ b/third_party/WebKit/Source/web/SpellCheckerClientImpl.h
@@ -54,6 +54,7 @@ void showSpellingUI(bool show) override; bool spellingUIIsShowing() override; void requestCheckingOfString(TextCheckingRequest*) override; + void cancelAllPendingRequests() override; TextCheckerClient& textChecker() override { return *this; }
diff --git a/third_party/WebKit/Source/web/WebFrameContentDumper.cpp b/third_party/WebKit/Source/web/WebFrameContentDumper.cpp index 2a3f9244..e441269 100644 --- a/third_party/WebKit/Source/web/WebFrameContentDumper.cpp +++ b/third_party/WebKit/Source/web/WebFrameContentDumper.cpp
@@ -62,7 +62,7 @@ LayoutPart* ownerLayoutObject = curLocalChild->ownerLayoutObject(); if (contentLayoutItem.isNull() || !contentLayoutItem.size().width() || !contentLayoutItem.size().height() || (contentLayoutItem.location().x() + contentLayoutItem.size().width() <= 0) || (contentLayoutItem.location().y() + contentLayoutItem.size().height() <= 0) - || (ownerLayoutObject && ownerLayoutObject->style() && ownerLayoutObject->style()->visibility() != VISIBLE)) { + || (ownerLayoutObject && ownerLayoutObject->style() && ownerLayoutObject->style()->visibility() != EVisibility::Visible)) { continue; }
diff --git a/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp b/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp index 495350b..0001976 100644 --- a/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp +++ b/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp
@@ -132,7 +132,6 @@ { visitor->trace(m_localRoot); visitor->trace(m_mouseCaptureNode); - visitor->trace(m_mutator); } // WebWidget ------------------------------------------------------------------ @@ -899,10 +898,9 @@ void WebFrameWidgetImpl::applyReplacementRange(int start, int length) { if (LocalFrame* frame = focusedLocalFrameInWidget()) { - WebLocalFrameImpl* webLocalFrame = WebLocalFrameImpl::fromFrame(frame); - WebRange webrange = WebRange::fromDocumentRange(webLocalFrame, start, length); - if (!webrange.isNull()) - webLocalFrame->selectRange(webrange); + // TODO(dglazkov): Going from LocalFrame to WebLocalFrameImpl seems + // silly. What is going on here? + WebLocalFrameImpl::fromFrame(frame)->selectRange(WebRange(start, length)); } }
diff --git a/third_party/WebKit/Source/web/WebFrameWidgetImpl.h b/third_party/WebKit/Source/web/WebFrameWidgetImpl.h index f3070d8..5760b09 100644 --- a/third_party/WebKit/Source/web/WebFrameWidgetImpl.h +++ b/third_party/WebKit/Source/web/WebFrameWidgetImpl.h
@@ -230,7 +230,7 @@ // This is owned by the LayerTreeHostImpl, and should only be used on the // compositor thread. The LayerTreeHostImpl is indirectly owned by this // class so this pointer should be valid until this class is destructed. - Member<CompositorMutatorImpl> m_mutator; + CrossThreadPersistent<CompositorMutatorImpl> m_mutator; WebLayerTreeView* m_layerTreeView; WebLayer* m_rootLayer;
diff --git a/third_party/WebKit/Source/web/WebInputEventConversion.cpp b/third_party/WebKit/Source/web/WebInputEventConversion.cpp index 9f2171f..d8879e6d 100644 --- a/third_party/WebKit/Source/web/WebInputEventConversion.cpp +++ b/third_party/WebKit/Source/web/WebInputEventConversion.cpp
@@ -236,8 +236,6 @@ #if OS(MACOSX) m_phase = static_cast<PlatformWheelEventPhase>(e.phase); m_momentumPhase = static_cast<PlatformWheelEventPhase>(e.momentumPhase); - m_canRubberbandLeft = e.canRubberbandLeft; - m_canRubberbandRight = e.canRubberbandRight; #endif } @@ -641,6 +639,10 @@ railsMode = static_cast<RailsMode>(event.getRailsMode()); hasPreciseScrollingDeltas = event.hasPreciseScrollingDeltas(); dispatchType = event.cancelable() ? WebInputEvent::Blocking : WebInputEvent::EventNonBlocking; +#if OS(MACOSX) + phase = static_cast<Phase>(event.phase()); + momentumPhase = static_cast<Phase>(event.momentumPhase()); +#endif } WebKeyboardEventBuilder::WebKeyboardEventBuilder(const KeyboardEvent& event)
diff --git a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp index e466d918..fc1a846 100644 --- a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp +++ b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
@@ -654,7 +654,7 @@ bool WebLocalFrameImpl::hasVisibleContent() const { if (LayoutPart* layoutObject = frame()->ownerLayoutObject()) { - if (layoutObject->style()->visibility() != VISIBLE) + if (layoutObject->style()->visibility() != EVisibility::Visible) return false; } @@ -1158,10 +1158,35 @@ void WebLocalFrameImpl::selectRange(const WebRange& webRange) { TRACE_EVENT0("blink", "WebLocalFrameImpl::selectRange"); - if (Range* range = static_cast<Range*>(webRange)) + + // TODO(dglazkov): The use of updateStyleAndLayoutIgnorePendingStylesheets needs to be audited. + // see http://crbug.com/590369 for more details. + frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets(); + + DocumentLifecycle::DisallowTransitionScope(frame()->document()->lifecycle()); + + // TODO(dglazkov): Use EphemeralRange here. + // See http://crbug.com/636216 for more details. + if (Range* range = webRange.createRange(frame())) frame()->selection().setSelectedRange(range, VP_DEFAULT_AFFINITY, SelectionDirectionalMode::NonDirectional, NotUserTriggered); } +WebString WebLocalFrameImpl::rangeAsText(const WebRange& webRange) +{ + // TODO(dglazkov): The use of updateStyleAndLayoutIgnorePendingStylesheets needs to be audited. + // see http://crbug.com/590369 for more details. + frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets(); + + DocumentLifecycle::DisallowTransitionScope(frame()->document()->lifecycle()); + + // TODO(dglazkov): Use EphemeralRange here. + // See http://crbug.com/636216 for more details. + if (Range* range = webRange.createRange(frame())) + return range->text(); + + return WebString(); +} + void WebLocalFrameImpl::moveRangeSelectionExtent(const WebPoint& point) { TRACE_EVENT0("blink", "WebLocalFrameImpl::moveRangeSelectionExtent");
diff --git a/third_party/WebKit/Source/web/WebLocalFrameImpl.h b/third_party/WebKit/Source/web/WebLocalFrameImpl.h index c927858..a74e511 100644 --- a/third_party/WebKit/Source/web/WebLocalFrameImpl.h +++ b/third_party/WebKit/Source/web/WebLocalFrameImpl.h
@@ -161,6 +161,7 @@ bool selectWordAroundCaret() override; void selectRange(const WebPoint& base, const WebPoint& extent) override; void selectRange(const WebRange&) override; + WebString rangeAsText(const WebRange&) override; void moveRangeSelectionExtent(const WebPoint&) override; void moveRangeSelection(const WebPoint& base, const WebPoint& extent, WebFrame::TextGranularity = CharacterGranularity) override; void moveCaretSelection(const WebPoint&) override;
diff --git a/third_party/WebKit/Source/web/WebRange.cpp b/third_party/WebKit/Source/web/WebRange.cpp index 49cd2fa9..b659375b 100644 --- a/third_party/WebKit/Source/web/WebRange.cpp +++ b/third_party/WebKit/Source/web/WebRange.cpp
@@ -30,71 +30,36 @@ #include "public/web/WebRange.h" -#include "bindings/core/v8/ExceptionState.h" -#include "bindings/core/v8/ExceptionStatePlaceholder.h" #include "core/dom/Document.h" -#include "core/dom/Element.h" #include "core/dom/Range.h" -#include "core/dom/shadow/ShadowRoot.h" #include "core/editing/FrameSelection.h" #include "core/editing/PlainTextRange.h" -#include "core/frame/FrameView.h" #include "core/frame/LocalFrame.h" -#include "public/platform/WebString.h" -#include "public/web/WebExceptionCode.h" -#include "public/web/WebNode.h" -#include "web/WebLocalFrameImpl.h" -#include "wtf/PassRefPtr.h" namespace blink { -void WebRange::reset() +WebRange::WebRange(int start, int length) + : m_start(start) + , m_end(start + length) { - m_private.reset(); + DCHECK(start != -1 && length != 0) << "These values are reserved to indicate that the range is null"; } -void WebRange::assign(const WebRange& other) +WebRange::WebRange(Range* range) { - m_private = other.m_private; + if (!range) + return; + + m_start = range->startOffset(); + m_end = range->endOffset(); } -int WebRange::startOffset() const +Range* WebRange::createRange(LocalFrame* frame) const { - return m_private->startOffset(); -} + Element* selectionRoot = frame->selection().rootEditableElement(); + ContainerNode* scope = selectionRoot ? selectionRoot : frame->document()->documentElement(); -int WebRange::endOffset() const -{ - return m_private->endOffset(); -} - -WebString WebRange::toPlainText() const -{ - return m_private->text(); -} - -// static -WebRange WebRange::fromDocumentRange(WebLocalFrame* frame, int start, int length) -{ - LocalFrame* webFrame = toWebLocalFrameImpl(frame)->frame(); - Element* selectionRoot = webFrame->selection().rootEditableElement(); - ContainerNode* scope = selectionRoot ? selectionRoot : webFrame->document()->documentElement(); - - // TODO(dglazkov): The use of updateStyleAndLayoutIgnorePendingStylesheets needs to be audited. - // see http://crbug.com/590369 for more details. - scope->document().updateStyleAndLayoutIgnorePendingStylesheets(); - - return createRange(PlainTextRange(start, start + length).createRange(*scope)); -} - -WebRange::WebRange(Range*range) - : m_private(range) -{ -} - -WebRange::operator Range*() const -{ - return m_private.get(); + return blink::createRange(PlainTextRange(m_start, m_end).createRange(*scope)); } } // namespace blink
diff --git a/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp b/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp index cde74e7..41545bba 100644 --- a/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp +++ b/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp
@@ -355,6 +355,11 @@ RuntimeEnabledFeatures::setAutoplayMutedVideosEnabled(enable); } +void WebRuntimeFeatures::enableTimerThrottlingForBackgroundTabs(bool enable) +{ + RuntimeEnabledFeatures::setTimerThrottlingForBackgroundTabsEnabled(enable); +} + void WebRuntimeFeatures::enableSendBeaconThrowForBlobWithNonSimpleType(bool enable) { RuntimeEnabledFeatures::setSendBeaconThrowForBlobWithNonSimpleTypeEnabled(enable);
diff --git a/third_party/WebKit/Source/web/WebSurroundingText.cpp b/third_party/WebKit/Source/web/WebSurroundingText.cpp index 1584e7c..cdd758e 100644 --- a/third_party/WebKit/Source/web/WebSurroundingText.cpp +++ b/third_party/WebKit/Source/web/WebSurroundingText.cpp
@@ -28,11 +28,13 @@ #include "core/dom/Node.h" #include "core/dom/Range.h" #include "core/dom/Text.h" +#include "core/editing/FrameSelection.h" #include "core/editing/SurroundingText.h" #include "core/editing/VisiblePosition.h" #include "core/layout/LayoutObject.h" #include "public/platform/WebPoint.h" #include "public/web/WebHitTestResult.h" +#include "web/WebLocalFrameImpl.h" namespace blink { @@ -53,9 +55,10 @@ m_private.reset(new SurroundingText(createVisiblePosition(node->layoutObject()->positionForPoint(static_cast<IntPoint>(nodePoint))).deepEquivalent().parentAnchoredEquivalent(), maxLength)); } -void WebSurroundingText::initialize(const WebRange& webRange, size_t maxLength) +void WebSurroundingText::initializeFromCurrentSelection(WebLocalFrame* frame, size_t maxLength) { - if (Range* range = static_cast<Range*>(webRange)) + LocalFrame* webFrame = toWebLocalFrameImpl(frame)->frame(); + if (Range* range = createRange(webFrame->selection().selection().toNormalizedEphemeralRange())) m_private.reset(new SurroundingText(*range, maxLength)); }
diff --git a/third_party/WebKit/Source/web/WebViewImpl.cpp b/third_party/WebKit/Source/web/WebViewImpl.cpp index 2718077..d462654 100644 --- a/third_party/WebKit/Source/web/WebViewImpl.cpp +++ b/third_party/WebKit/Source/web/WebViewImpl.cpp
@@ -137,6 +137,7 @@ #include "public/web/WebAXObject.h" #include "public/web/WebActiveWheelFlingParameters.h" #include "public/web/WebAutofillClient.h" +#include "public/web/WebConsoleMessage.h" #include "public/web/WebElement.h" #include "public/web/WebFrame.h" #include "public/web/WebFrameClient.h" @@ -1053,6 +1054,14 @@ page()->acceptLanguagesChanged(); } +void WebViewImpl::ReportIntervention(const WebString& message) +{ + if (!mainFrame()) + return; + WebConsoleMessage consoleMessage(WebConsoleMessage::LevelWarning, message); + mainFrame()->addMessageToConsole(consoleMessage); +} + WebInputEventResult WebViewImpl::handleKeyEvent(const WebKeyboardEvent& event) { DCHECK((event.type == WebInputEvent::RawKeyDown) @@ -2851,11 +2860,8 @@ void WebViewImpl::applyReplacementRange(int start, int length) { - if (WebLocalFrame* frame = focusedFrame()) { - WebRange webrange = WebRange::fromDocumentRange(frame, start, length); - if (!webrange.isNull()) - frame->selectRange(webrange); - } + if (WebLocalFrame* frame = focusedFrame()) + frame->selectRange(WebRange(start, length)); } // WebView --------------------------------------------------------------------
diff --git a/third_party/WebKit/Source/web/WebViewImpl.h b/third_party/WebKit/Source/web/WebViewImpl.h index f7f745c..c953b41 100644 --- a/third_party/WebKit/Source/web/WebViewImpl.h +++ b/third_party/WebKit/Source/web/WebViewImpl.h
@@ -46,6 +46,7 @@ #include "public/platform/WebLayer.h" #include "public/platform/WebPoint.h" #include "public/platform/WebRect.h" +#include "public/platform/WebScheduler.h" #include "public/platform/WebSize.h" #include "public/platform/WebString.h" #include "public/platform/WebVector.h" @@ -99,7 +100,8 @@ class WEB_EXPORT WebViewImpl final : WTF_NON_EXPORTED_BASE(public WebView) , public RefCounted<WebViewImpl> , WTF_NON_EXPORTED_BASE(public WebGestureCurveTarget) - , public PageWidgetEventHandler { + , public PageWidgetEventHandler + , public WebScheduler::InterventionReporter { public: static WebViewImpl* create(WebViewClient*, WebPageVisibilityState); static HashSet<WebViewImpl*>& allInstances(); @@ -282,6 +284,9 @@ void setShowScrollBottleneckRects(bool) override; void acceptLanguagesChanged() override; + // WebScheduler::InterventionReporter implementation: + void ReportIntervention(const WebString& message) override; + void didUpdateFullScreenSize(); float defaultMinimumPageScaleFactor() const;
diff --git a/third_party/WebKit/Source/web/tests/MHTMLTest.cpp b/third_party/WebKit/Source/web/tests/MHTMLTest.cpp index cada31a96..57d252c 100644 --- a/third_party/WebKit/Source/web/tests/MHTMLTest.cpp +++ b/third_party/WebKit/Source/web/tests/MHTMLTest.cpp
@@ -28,6 +28,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "bindings/core/v8/ScriptController.h" #include "core/dom/Document.h" #include "core/frame/LocalFrame.h" #include "core/frame/Location.h" @@ -104,7 +105,7 @@ void registerMockedURLLoad(const std::string& url, const WebString& fileName) { - URLTestHelpers::registerMockedURLLoad(toKURL(url), fileName, WebString::fromUTF8("mhtml/"), WebString::fromUTF8("text/html")); + URLTestHelpers::registerMockedURLLoad(toKURL(url), fileName, WebString::fromUTF8("mhtml/"), WebString::fromUTF8("multipart/related")); } void loadURLInTopFrame(const WebURL& url) @@ -243,12 +244,36 @@ KURL fileURL = toKURL("file://foo"); KURL specialSchemeURL = toKURL("fooscheme://bar"); - // MHTMLArchives can be initialized from any local scheme, but never a remote scheme. - EXPECT_EQ(nullptr, MHTMLArchive::create(httpURL, data.get())); + // MHTMLArchives can only be initialized from local schemes and http/https schemes. + EXPECT_NE(nullptr, MHTMLArchive::create(httpURL, data.get())); EXPECT_NE(nullptr, MHTMLArchive::create(fileURL, data.get())); EXPECT_EQ(nullptr, MHTMLArchive::create(specialSchemeURL, data.get())); SchemeRegistry::registerURLSchemeAsLocal("fooscheme"); EXPECT_NE(nullptr, MHTMLArchive::create(specialSchemeURL, data.get())); } +// Checks that full sandboxing protection has been turned on. +TEST_F(MHTMLTest, EnforceSandboxFlags) +{ + const char kURL[] = "http://www.example.com"; + + // Register the mocked frame and load it. + registerMockedURLLoad(kURL, WebString::fromUTF8("simple_test.mht")); + loadURLInTopFrame(toKURL(kURL)); + ASSERT_TRUE(page()); + LocalFrame* frame = toLocalFrame(page()->mainFrame()); + ASSERT_TRUE(frame); + Document* document = frame->document(); + ASSERT_TRUE(document); + + // Full sandboxing should be turned on. + EXPECT_TRUE(document->isSandboxed(SandboxAll)); + + // MHTML document should be loaded into unique origin. + EXPECT_TRUE(document->getSecurityOrigin()->isUnique()); + // Script execution should be disabled. + EXPECT_FALSE(frame->script().canExecuteScripts(NotAboutToExecuteScript)); +} + + } // namespace blink
diff --git a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp index a881cd8..c2a759fa 100644 --- a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp +++ b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
@@ -5151,7 +5151,7 @@ const int allTextBeginOffset = 0; const int allTextLength = 11; - frame->selectRange(WebRange::fromDocumentRange(frame, allTextBeginOffset, allTextLength)); + frame->selectRange(WebRange(allTextBeginOffset, allTextLength)); EphemeralRange selectionRange = frame->frame()->selection().selection().toNormalizedEphemeralRange(); EXPECT_EQ(1, spellcheck.numberOfTimesChecked()); @@ -5185,7 +5185,7 @@ const int allTextBeginOffset = 0; const int allTextLength = 11; - frame->selectRange(WebRange::fromDocumentRange(frame, allTextBeginOffset, allTextLength)); + frame->selectRange(WebRange(allTextBeginOffset, allTextLength)); EphemeralRange selectionRange = frame->frame()->selection().selection().toNormalizedEphemeralRange(); EXPECT_EQ(0U, document->markers().markersInRange(selectionRange, DocumentMarker::Spelling).size()); @@ -5266,6 +5266,14 @@ m_completion = completion; } + void cancelAllPendingRequests() override + { + if (!m_completion) + return; + m_completion->didCancelCheckingText(); + m_completion = nullptr; + } + void kickNoResults() { kick(-1, -1, WebTextDecorationTypeSpelling);
diff --git a/third_party/WebKit/Source/web/tests/WebInputEventConversionTest.cpp b/third_party/WebKit/Source/web/tests/WebInputEventConversionTest.cpp index 3cefc5787..1dad51b 100644 --- a/third_party/WebKit/Source/web/tests/WebInputEventConversionTest.cpp +++ b/third_party/WebKit/Source/web/tests/WebInputEventConversionTest.cpp
@@ -909,7 +909,11 @@ WheelEvent* event = WheelEvent::create(FloatPoint(1, 3), FloatPoint(5, 10), WheelEvent::kDomDeltaPage, document->domWindow(), IntPoint(2, 6), IntPoint(10, 30), PlatformEvent::CtrlKey, 0, 0, -1 /* null plugin id */, - true /* hasPreciseScrollingDeltas */, Event::RailsModeHorizontal, true /*cancelable*/); + true /* hasPreciseScrollingDeltas */, Event::RailsModeHorizontal, true /*cancelable*/ +#if OS(MACOSX) + , WheelEventPhaseBegan, WheelEventPhaseChanged +#endif + ); WebMouseWheelEventBuilder webMouseWheel(toLocalFrame(webViewImpl->page()->mainFrame())->view(), document->layoutViewItem(), *event); EXPECT_EQ(1, webMouseWheel.wheelTicksX); EXPECT_EQ(3, webMouseWheel.wheelTicksY); @@ -924,12 +928,20 @@ EXPECT_EQ(WebInputEvent::RailsModeHorizontal, webMouseWheel.railsMode); EXPECT_TRUE(webMouseWheel.hasPreciseScrollingDeltas); EXPECT_EQ(WebInputEvent::Blocking, webMouseWheel.dispatchType); +#if OS(MACOSX) + EXPECT_EQ(WebMouseWheelEvent::PhaseBegan, webMouseWheel.phase); + EXPECT_EQ(WebMouseWheelEvent::PhaseChanged, webMouseWheel.momentumPhase); +#endif } { WheelEvent* event = WheelEvent::create(FloatPoint(1, 3), FloatPoint(5, 10), WheelEvent::kDomDeltaPage, document->domWindow(), IntPoint(2, 6), IntPoint(10, 30), - PlatformEvent::CtrlKey, 0, 0, -1 /* null plugin id */, true /* hasPreciseScrollingDeltas */, Event::RailsModeHorizontal, false); + PlatformEvent::CtrlKey, 0, 0, -1 /* null plugin id */, true /* hasPreciseScrollingDeltas */, Event::RailsModeHorizontal, false +#if OS(MACOSX) + , WheelEventPhaseNone, WheelEventPhaseNone +#endif + ); WebMouseWheelEventBuilder webMouseWheel(toLocalFrame(webViewImpl->page()->mainFrame())->view(), document->layoutViewItem(), *event); EXPECT_EQ(WebInputEvent::EventNonBlocking, webMouseWheel.dispatchType); } @@ -960,6 +972,8 @@ webMouseWheelEvent.modifiers = WebInputEvent::ControlKey; webMouseWheelEvent.hasPreciseScrollingDeltas = true; webMouseWheelEvent.railsMode = WebInputEvent::RailsModeHorizontal; + webMouseWheelEvent.phase = WebMouseWheelEvent::PhaseBegan; + webMouseWheelEvent.momentumPhase = WebMouseWheelEvent::PhaseChanged; PlatformWheelEventBuilder platformWheelBuilder(view, webMouseWheelEvent); EXPECT_EQ(0, platformWheelBuilder.position().x()); @@ -969,6 +983,10 @@ EXPECT_EQ(PlatformEvent::CtrlKey, platformWheelBuilder.getModifiers()); EXPECT_TRUE(platformWheelBuilder.hasPreciseScrollingDeltas()); EXPECT_EQ(platformWheelBuilder.getRailsMode(), PlatformEvent::RailsModeHorizontal); +#if OS(MACOSX) + EXPECT_EQ(PlatformWheelEventPhaseBegan, platformWheelBuilder.phase()); + EXPECT_EQ(PlatformWheelEventPhaseChanged, platformWheelBuilder.momentumPhase()); +#endif } { @@ -981,6 +999,8 @@ webMouseWheelEvent.modifiers = WebInputEvent::ShiftKey; webMouseWheelEvent.hasPreciseScrollingDeltas = false; webMouseWheelEvent.railsMode = WebInputEvent::RailsModeFree; + webMouseWheelEvent.phase = WebMouseWheelEvent::PhaseNone; + webMouseWheelEvent.momentumPhase = WebMouseWheelEvent::PhaseNone; PlatformWheelEventBuilder platformWheelBuilder(view, webMouseWheelEvent); EXPECT_EQ(5, platformWheelBuilder.position().x()); @@ -990,6 +1010,10 @@ EXPECT_EQ(PlatformEvent::ShiftKey, platformWheelBuilder.getModifiers()); EXPECT_FALSE(platformWheelBuilder.hasPreciseScrollingDeltas()); EXPECT_EQ(platformWheelBuilder.getRailsMode(), PlatformEvent::RailsModeFree); +#if OS(MACOSX) + EXPECT_EQ(PlatformWheelEventPhaseNone, platformWheelBuilder.phase()); + EXPECT_EQ(PlatformWheelEventPhaseNone, platformWheelBuilder.momentumPhase()); +#endif } { @@ -1002,6 +1026,8 @@ webMouseWheelEvent.modifiers = WebInputEvent::AltKey; webMouseWheelEvent.hasPreciseScrollingDeltas = true; webMouseWheelEvent.railsMode = WebInputEvent::RailsModeVertical; + webMouseWheelEvent.phase = WebMouseWheelEvent::PhaseNone; + webMouseWheelEvent.momentumPhase = WebMouseWheelEvent::PhaseNone; PlatformWheelEventBuilder platformWheelBuilder(view, webMouseWheelEvent); EXPECT_EQ(5, platformWheelBuilder.position().x()); @@ -1011,12 +1037,16 @@ EXPECT_EQ(PlatformEvent::AltKey, platformWheelBuilder.getModifiers()); EXPECT_TRUE(platformWheelBuilder.hasPreciseScrollingDeltas()); EXPECT_EQ(platformWheelBuilder.getRailsMode(), PlatformEvent::RailsModeVertical); +#if OS(MACOSX) + EXPECT_EQ(PlatformWheelEventPhaseNone, platformWheelBuilder.phase()); + EXPECT_EQ(PlatformWheelEventPhaseNone, platformWheelBuilder.momentumPhase()); +#endif } } TEST(WebInputEventConversionTest, PlatformGestureEventBuilder) { - const std::string baseURL("http://www.test8.com/"); + const std::string baseURL("http://www.test9.com/"); const std::string fileName("fixed_layout.html"); URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(baseURL.c_str()), WebString::fromUTF8("fixed_layout.html"));
diff --git a/third_party/WebKit/Source/wtf/WTFThreadData.cpp b/third_party/WebKit/Source/wtf/WTFThreadData.cpp index 2c3c6c48..548cc76 100644 --- a/third_party/WebKit/Source/wtf/WTFThreadData.cpp +++ b/third_party/WebKit/Source/wtf/WTFThreadData.cpp
@@ -35,16 +35,12 @@ WTFThreadData::WTFThreadData() : m_atomicStringTable(new AtomicStringTable) - , m_compressibleStringTable(nullptr) - , m_compressibleStringTableDestructor(nullptr) , m_cachedConverterICU(new ICUConverterWrapper) { } WTFThreadData::~WTFThreadData() { - if (m_compressibleStringTableDestructor) - m_compressibleStringTableDestructor(m_compressibleStringTable); } } // namespace WTF
diff --git a/third_party/WebKit/Source/wtf/WTFThreadData.h b/third_party/WebKit/Source/wtf/WTFThreadData.h index e1fff54..672f1aaa 100644 --- a/third_party/WebKit/Source/wtf/WTFThreadData.h +++ b/third_party/WebKit/Source/wtf/WTFThreadData.h
@@ -36,16 +36,6 @@ #include "wtf/text/StringHash.h" #include <memory> -namespace blink { - -// TODO(hajimehoshi): CompressibleStringTable should be moved from blink to WTF -// namespace. Fix this forward declaration when we do this. -class CompressibleStringTable; - -typedef void (*CompressibleStringTableDestructor)(CompressibleStringTable*); - -} - namespace WTF { class AtomicStringTable; @@ -63,22 +53,14 @@ return *m_atomicStringTable; } - blink::CompressibleStringTable* compressibleStringTable() - { - return m_compressibleStringTable; - } - ICUConverterWrapper& cachedConverterICU() { return *m_cachedConverterICU; } private: std::unique_ptr<AtomicStringTable> m_atomicStringTable; - blink::CompressibleStringTable* m_compressibleStringTable; - blink::CompressibleStringTableDestructor m_compressibleStringTableDestructor; std::unique_ptr<ICUConverterWrapper> m_cachedConverterICU; static ThreadSpecific<WTFThreadData>* staticData; friend WTFThreadData& wtfThreadData(); - friend class blink::CompressibleStringTable; }; inline WTFThreadData& wtfThreadData()
diff --git a/third_party/WebKit/Source/wtf/text/AtomicString.h b/third_party/WebKit/Source/wtf/text/AtomicString.h index 2dc75a7..67b7dc2 100644 --- a/third_party/WebKit/Source/wtf/text/AtomicString.h +++ b/third_party/WebKit/Source/wtf/text/AtomicString.h
@@ -86,10 +86,24 @@ size_t find(const StringView& value, unsigned start = 0, TextCaseSensitivity caseSensitivity = TextCaseSensitive) const { return m_string.find(value, start, caseSensitivity); } + // Unicode aware case insensitive string matching. + size_t findIgnoringCase(const StringView& value, unsigned start = 0) const + { return m_string.findIgnoringCase(value, start); } + + // ASCII case insensitive string matching. + size_t findIgnoringASCIICase(const StringView& value, unsigned start = 0) const + { return m_string.findIgnoringASCIICase(value, start); } + bool contains(char c) const { return find(c) != kNotFound; } bool contains(const StringView& value, TextCaseSensitivity caseSensitivity = TextCaseSensitive) const { return find(value, 0, caseSensitivity) != kNotFound; } + // Find the last instance of a single character or string. + size_t reverseFind(UChar c, unsigned start = UINT_MAX) const + { return m_string.reverseFind(c, start); } + size_t reverseFind(const StringView& value, unsigned start = UINT_MAX) const + { return m_string.reverseFind(value, start); } + bool startsWith(const StringView& prefix, TextCaseSensitivity caseSensitivity = TextCaseSensitive) const { return m_string.startsWith(prefix, caseSensitivity); } bool startsWith(UChar character) const
diff --git a/third_party/WebKit/Source/wtf/text/StringImpl.cpp b/third_party/WebKit/Source/wtf/text/StringImpl.cpp index e05c031..850f986 100644 --- a/third_party/WebKit/Source/wtf/text/StringImpl.cpp +++ b/third_party/WebKit/Source/wtf/text/StringImpl.cpp
@@ -1317,7 +1317,7 @@ } template <typename SearchCharacterType, typename MatchCharacterType> -ALWAYS_INLINE static size_t reverseFindInner(const SearchCharacterType* searchCharacters, const MatchCharacterType* matchCharacters, unsigned index, unsigned length, unsigned matchLength) +ALWAYS_INLINE static size_t reverseFindInternal(const SearchCharacterType* searchCharacters, const MatchCharacterType* matchCharacters, unsigned index, unsigned length, unsigned matchLength) { // Optimization: keep a running hash of the strings, // only call equal if the hashes match. @@ -1343,12 +1343,12 @@ return delta; } -size_t StringImpl::reverseFind(StringImpl* matchString, unsigned index) +size_t StringImpl::reverseFind(const StringView& matchString, unsigned index) { - // Check for null or empty string to match against - if (!matchString) + if (UNLIKELY(matchString.isNull())) return kNotFound; - unsigned matchLength = matchString->length(); + + unsigned matchLength = matchString.length(); unsigned ourLength = length(); if (!matchLength) return min(index, ourLength); @@ -1356,8 +1356,8 @@ // Optimization 1: fast case for strings of length 1. if (matchLength == 1) { if (is8Bit()) - return WTF::reverseFind(characters8(), ourLength, (*matchString)[0], index); - return WTF::reverseFind(characters16(), ourLength, (*matchString)[0], index); + return WTF::reverseFind(characters8(), ourLength, matchString[0], index); + return WTF::reverseFind(characters16(), ourLength, matchString[0], index); } // Check index & matchLength are in range. @@ -1365,15 +1365,13 @@ return kNotFound; if (is8Bit()) { - if (matchString->is8Bit()) - return reverseFindInner(characters8(), matchString->characters8(), index, ourLength, matchLength); - return reverseFindInner(characters8(), matchString->characters16(), index, ourLength, matchLength); + if (matchString.is8Bit()) + return reverseFindInternal(characters8(), matchString.characters8(), index, ourLength, matchLength); + return reverseFindInternal(characters8(), matchString.characters16(), index, ourLength, matchLength); } - - if (matchString->is8Bit()) - return reverseFindInner(characters16(), matchString->characters8(), index, ourLength, matchLength); - - return reverseFindInner(characters16(), matchString->characters16(), index, ourLength, matchLength); + if (matchString.is8Bit()) + return reverseFindInternal(characters16(), matchString.characters8(), index, ourLength, matchLength); + return reverseFindInternal(characters16(), matchString.characters16(), index, ourLength, matchLength); } bool StringImpl::startsWith(UChar character) const
diff --git a/third_party/WebKit/Source/wtf/text/StringImpl.h b/third_party/WebKit/Source/wtf/text/StringImpl.h index 1311c0d..30736e2 100644 --- a/third_party/WebKit/Source/wtf/text/StringImpl.h +++ b/third_party/WebKit/Source/wtf/text/StringImpl.h
@@ -378,7 +378,7 @@ size_t findIgnoringASCIICase(const StringView&, unsigned index = 0); size_t reverseFind(UChar, unsigned index = UINT_MAX); - size_t reverseFind(StringImpl*, unsigned index = UINT_MAX); + size_t reverseFind(const StringView&, unsigned index = UINT_MAX); bool startsWith(UChar) const; bool startsWith(const StringView&) const; @@ -716,5 +716,6 @@ using WTF::equal; using WTF::equalNonNull; using WTF::lengthOfNullTerminatedString; +using WTF::reverseFind; #endif
diff --git a/third_party/WebKit/Source/wtf/text/WTFString.h b/third_party/WebKit/Source/wtf/text/WTFString.h index 2595365..b5aa5a9e 100644 --- a/third_party/WebKit/Source/wtf/text/WTFString.h +++ b/third_party/WebKit/Source/wtf/text/WTFString.h
@@ -182,6 +182,14 @@ size_t find(const StringView& value, unsigned start = 0, TextCaseSensitivity caseSensitivity = TextCaseSensitive) const { return m_impl ? DISPATCH_CASE_OP(caseSensitivity, m_impl->find, (value, start)) : kNotFound; } + // Unicode aware case insensitive string matching. + size_t findIgnoringCase(const StringView& value, unsigned start = 0) const + { return m_impl ? m_impl->findIgnoringCase(value, start) : kNotFound; } + + // ASCII case insensitive string matching. + size_t findIgnoringASCIICase(const StringView& value, unsigned start = 0) const + { return m_impl ? m_impl->findIgnoringASCIICase(value, start) : kNotFound; } + bool contains(char c) const { return find(c) != kNotFound; } bool contains(const StringView& value, TextCaseSensitivity caseSensitivity = TextCaseSensitive) const { return find(value, 0, caseSensitivity) != kNotFound; } @@ -189,18 +197,8 @@ // Find the last instance of a single character or string. size_t reverseFind(UChar c, unsigned start = UINT_MAX) const { return m_impl ? m_impl->reverseFind(c, start) : kNotFound; } - size_t reverseFind(const String& str, unsigned start = UINT_MAX) const - { return m_impl ? m_impl->reverseFind(str.impl(), start) : kNotFound; } - - // Case insensitive string matching. - size_t findIgnoringCase(const LChar* str, unsigned start = 0) const - { return m_impl ? m_impl->findIgnoringCase(str, start) : kNotFound; } - size_t findIgnoringCase(const String& str, unsigned start = 0) const - { return m_impl ? m_impl->findIgnoringCase(str.impl(), start) : kNotFound; } - - // ASCII case insensitive string matching. - size_t findIgnoringASCIICase(const String& str, unsigned start = 0) const - { return m_impl ? m_impl->findIgnoringASCIICase(str.impl(), start) : kNotFound; } + size_t reverseFind(const StringView& value, unsigned start = UINT_MAX) const + { return m_impl ? m_impl->reverseFind(value, start) : kNotFound; } unsigned copyTo(UChar* buffer, unsigned pos, unsigned maxLength) const; @@ -603,7 +601,6 @@ using WTF::find; using WTF::isAllSpecialCharacters; using WTF::isSpaceOrNewline; -using WTF::reverseFind; #include "wtf/text/AtomicString.h" #endif // WTFString_h
diff --git a/third_party/WebKit/Tools/Scripts/update-w3c-test-expectations b/third_party/WebKit/Tools/Scripts/update-w3c-test-expectations index f36c8a2..c872fd0 100755 --- a/third_party/WebKit/Tools/Scripts/update-w3c-test-expectations +++ b/third_party/WebKit/Tools/Scripts/update-w3c-test-expectations
@@ -13,6 +13,4 @@ host = host.Host() host.initialize_scm() port = host.port_factory.get() - return_code = main(host, port) - -sys.exit(return_code) + sys.exit(main(host, port))
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/config/builders.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/config/builders.py index 30594dec..661a5ae 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/common/config/builders.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/config/builders.py
@@ -82,7 +82,7 @@ }, "linux_trusty_blink_rel": { "port_name": "linux-precise", - "specifiers": ['Precise', 'Release'], + "specifiers": ['Trusty', 'Release'], "is_try_builder": True, }, "mac10.9_blink_rel": { @@ -92,7 +92,7 @@ }, "mac10.10_blink_rel": { "port_name": "mac-mac10.10", - "specifiers": ['Mac10.', 'Release'], + "specifiers": ['Mac10.10', 'Release'], "is_try_builder": True, }, "mac10.11_blink_rel": {
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/config/urls.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/config/urls.py deleted file mode 100644 index 7c9b19c5..0000000 --- a/third_party/WebKit/Tools/Scripts/webkitpy/common/config/urls.py +++ /dev/null
@@ -1,31 +0,0 @@ -# Copyright (c) 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. - -# FIXME: this could be moved over to perftestsrunner (the one place where it's used). -def view_source_url(local_path): - return "https://src.chromium.org/viewvc/blink/trunk/%s" % local_path
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/sheriff_calendar.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/net/sheriff_calendar.py deleted file mode 100644 index bb60fca8..0000000 --- a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/sheriff_calendar.py +++ /dev/null
@@ -1,59 +0,0 @@ -# Copyright 2014 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import re -import urllib2 - -# This is based on code from: -# https://chromium.googlesource.com/chromium/tools/build/+/master/scripts/tools/blink_roller/auto_roll.py -# Ideally we should share code between these. - -# FIXME: This probably belongs in config.py? -BLINK_SHERIFF_URL = ( - 'http://build.chromium.org/p/chromium.webkit/sheriff_webkit.js') - - -# Does not support unicode or special characters. -VALID_EMAIL_REGEXP = re.compile(r'^[A-Za-z0-9\.&\'\+-/=_]+@[A-Za-z0-9\.-]+$') - - -def _complete_email(name): - """If the name does not include '@', append '@chromium.org'.""" - if '@' not in name: - return name + '@chromium.org' - return name - - -def _names_from_sheriff_js(sheriff_js): - match = re.match(r'document.write\(\'(.*)\'\)', sheriff_js) - emails_string = match.group(1) - # Detect 'none (channel is sheriff)' text and ignore it. - if 'channel is sheriff' in emails_string.lower(): - return [] - return map(str.strip, emails_string.split(',')) - - -def _email_is_valid(email): - """Determines whether the given email address is valid.""" - return VALID_EMAIL_REGEXP.match(email) is not None - - -def _filter_emails(emails): - """Returns the given list with any invalid email addresses removed.""" - rv = [] - for email in emails: - if _email_is_valid(email): - rv.append(email) - else: - print 'WARNING: Not including %s (invalid email address)' % email - return rv - - -def _emails_from_url(sheriff_url): - sheriff_js = urllib2.urlopen(sheriff_url).read() - return map(_complete_email, _names_from_sheriff_js(sheriff_js)) - - -def current_gardener_emails(): - return _emails_from_url(BLINK_SHERIFF_URL)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/sheriff_calendar_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/net/sheriff_calendar_unittest.py deleted file mode 100644 index 56b3788..0000000 --- a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/sheriff_calendar_unittest.py +++ /dev/null
@@ -1,57 +0,0 @@ -# Copyright 2014 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# This is based on code from: -# https://chromium.googlesource.com/chromium/tools/build/+/master/scripts/tools/blink_roller/auto_roll_test.py -# Ideally we should share code between these. - - -from webkitpy.common.system.outputcapture import OutputCaptureTestCaseBase -from webkitpy.common.net import sheriff_calendar as calendar - - -class SheriffCalendarTest(OutputCaptureTestCaseBase): - - def test_complete_email(self): - expected_emails = ['foo@chromium.org', 'bar@google.com', 'baz@chromium.org'] - names = ['foo', 'bar@google.com', 'baz'] - self.assertEqual(map(calendar._complete_email, names), expected_emails) - - def test_emails(self): - expected_emails = ['foo@bar.com', 'baz@baz.com'] - calendar._emails_from_url = lambda urls: expected_emails - self.assertEqual(calendar.current_gardener_emails(), expected_emails) - - def _assert_parse(self, js_string, expected_emails): - self.assertEqual(calendar._names_from_sheriff_js(js_string), expected_emails) - - def test_names_from_sheriff_js(self): - self._assert_parse('document.write(\'none (channel is sheriff)\')', []) - self._assert_parse('document.write(\'foo, bar\')', ['foo', 'bar']) - - def test_email_regexp(self): - self.assertTrue(calendar._email_is_valid('somebody@example.com')) - self.assertTrue(calendar._email_is_valid('somebody@example.domain.com')) - self.assertTrue(calendar._email_is_valid('somebody@example-domain.com')) - self.assertTrue(calendar._email_is_valid('some.body@example.com')) - self.assertTrue(calendar._email_is_valid('some_body@example.com')) - self.assertTrue(calendar._email_is_valid('some+body@example.com')) - self.assertTrue(calendar._email_is_valid('some+body@com')) - self.assertTrue(calendar._email_is_valid('some/body@example.com')) - # These are valid according to the standard, but not supported here. - self.assertFalse(calendar._email_is_valid('some~body@example.com')) - self.assertFalse(calendar._email_is_valid('some!body@example.com')) - self.assertFalse(calendar._email_is_valid('some?body@example.com')) - self.assertFalse(calendar._email_is_valid('some" "body@example.com')) - self.assertFalse(calendar._email_is_valid('"{somebody}"@example.com')) - # Bogus emails, not valid according to the standard. - self.assertFalse(calendar._email_is_valid('rm -rf /#@example.com')) - self.assertFalse(calendar._email_is_valid('some body@example.com')) - self.assertFalse(calendar._email_is_valid('[some body]@example.com')) - - def test_filter_emails(self): - input_emails = ['foo@bar.com', 'baz@baz.com', 'bogus email @ !!!'] - expected_emails = ['foo@bar.com', 'baz@baz.com'] - self.assertEquals(calendar._filter_emails(input_emails), expected_emails) - self.assertStdout('WARNING: Not including bogus email @ !!! (invalid email address)\n')
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_configuration_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_configuration_unittest.py index 859d6e5..c2733641 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_configuration_unittest.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_configuration_unittest.py
@@ -28,7 +28,7 @@ import unittest -from webkitpy.layout_tests.models.test_configuration import * +from webkitpy.layout_tests.models.test_configuration import SpecifierSorter, TestConfiguration, TestConfigurationConverter def make_mock_all_test_configurations_set():
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations_unittest.py index 2286c39d..e3493e03f 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations_unittest.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations_unittest.py
@@ -31,9 +31,12 @@ from webkitpy.common.host_mock import MockHost from webkitpy.common.system.outputcapture import OutputCapture - -from webkitpy.layout_tests.models.test_configuration import * -from webkitpy.layout_tests.models.test_expectations import * +from webkitpy.layout_tests.models.test_configuration import TestConfiguration, TestConfigurationConverter +from webkitpy.layout_tests.models.test_expectations import ( + TestExpectationLine, TestExpectations, ParseError, TestExpectationParser, + PASS, FAIL, TEXT, IMAGE, IMAGE_PLUS_TEXT, AUDIO, + TIMEOUT, CRASH, LEAK, SKIP, WONTFIX, NEEDS_REBASELINE, MISSING +) class Base(unittest.TestCase):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_failures_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_failures_unittest.py index 0310e3b..0e207df 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_failures_unittest.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_failures_unittest.py
@@ -28,7 +28,10 @@ import unittest -from webkitpy.layout_tests.models.test_failures import * +from webkitpy.layout_tests.models.test_failures import ( + ALL_FAILURE_CLASSES, determine_result_type, + FailureCrash, FailureTimeout, TestFailure +) class TestFailuresTest(unittest.TestCase):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/performance_tests/perftestsrunner.py b/third_party/WebKit/Tools/Scripts/webkitpy/performance_tests/perftestsrunner.py index eb2a84f..0db4fd9 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/performance_tests/perftestsrunner.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/performance_tests/perftestsrunner.py
@@ -37,7 +37,6 @@ from webkitpy.common import find_files from webkitpy.common.checkout.scm.detection import SCMDetector -from webkitpy.common.config.urls import view_source_url from webkitpy.common.host import Host from webkitpy.common.net.file_uploader import FileUploader from webkitpy.performance_tests.perftest import PerfTestFactory @@ -290,7 +289,8 @@ path = test.test_name_without_file_extension().split('/') for i in range(0, len(path)): is_last_token = i + 1 == len(path) - url = view_source_url('PerformanceTests/' + (test.test_name() if is_last_token else '/'.join(path[0:i + 1]))) + url = self.view_source_url( + 'PerformanceTests/' + (test.test_name() if is_last_token else '/'.join(path[0:i + 1]))) tests.setdefault(path[i], {'url': url}) current_test = tests[path[i]] if is_last_token: @@ -304,6 +304,10 @@ return contents @staticmethod + def view_source_url(path_from_blink): + return 'https://chromium.googlesource.com/chromium/src/+/master/third_party/WebKit/%s' % path_from_blink + + @staticmethod def _datetime_in_ES5_compatible_iso_format(datetime): return datetime.strftime('%Y-%m-%dT%H:%M:%S.%f')
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/performance_tests/perftestsrunner_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/performance_tests/perftestsrunner_unittest.py index 2047e2b..68c2e24 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/performance_tests/perftestsrunner_unittest.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/performance_tests/perftestsrunner_unittest.py
@@ -272,8 +272,11 @@ """ - results = {'url': 'https://src.chromium.org/viewvc/blink/trunk/PerformanceTests/Bindings/event-target-wrapper.html', - 'metrics': {'Time': {'current': [[1486.0, 1471.0, 1510.0, 1505.0, 1478.0, 1490.0]] * 4}}} + results = { + 'url': ('https://chromium.googlesource.com/chromium/src/+/master/third_party/WebKit' + '/PerformanceTests/Bindings/event-target-wrapper.html'), + 'metrics': {'Time': {'current': [[1486.0, 1471.0, 1510.0, 1505.0, 1478.0, 1490.0]] * 4}} + } class SomeParserTestData: @@ -526,9 +529,11 @@ return logs _event_target_wrapper_and_inspector_results = { - "Bindings": - {"url": "https://src.chromium.org/viewvc/blink/trunk/PerformanceTests/Bindings", - "tests": {"event-target-wrapper": EventTargetWrapperTestData.results}}} + "Bindings": { + "url": "https://chromium.googlesource.com/chromium/src/+/master/third_party/WebKit/PerformanceTests/Bindings", + "tests": {"event-target-wrapper": EventTargetWrapperTestData.results} + } + } def test_run_with_json_output(self): runner, port = self.create_runner_and_setup_results_template(args=['--output-json-path=/mock-checkout/output.json', @@ -735,11 +740,13 @@ self.assertEqual(output['tests'].keys(), ['Bindings']) self.assertEqual(sorted(output['tests']['Bindings'].keys()), ['tests', 'url']) self.assertEqual(output['tests']['Bindings']['url'], - 'https://src.chromium.org/viewvc/blink/trunk/PerformanceTests/Bindings') + 'https://chromium.googlesource.com/chromium/src/+/master/third_party/WebKit/PerformanceTests/Bindings') self.assertEqual(output['tests']['Bindings']['tests'].keys(), ['event-target-wrapper']) self.assertEqual(output['tests']['Bindings']['tests']['event-target-wrapper'], { - 'url': 'https://src.chromium.org/viewvc/blink/trunk/PerformanceTests/Bindings/event-target-wrapper.html', - 'metrics': {'Time': {'current': [[1486.0, 1471.0, 1510.0, 1505.0, 1478.0, 1490.0]] * 4}}}) + 'url': ('https://chromium.googlesource.com/chromium/src/+/master/third_party/WebKit' + '/PerformanceTests/Bindings/event-target-wrapper.html'), + 'metrics': {'Time': {'current': [[1486.0, 1471.0, 1510.0, 1505.0, 1478.0, 1490.0]] * 4}} + }) def test_run_with_repeat(self): self.maxDiff = None
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/pylintrc b/third_party/WebKit/Tools/Scripts/webkitpy/pylintrc index a33d3e0f..cda0612b 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/pylintrc +++ b/third_party/WebKit/Tools/Scripts/webkitpy/pylintrc
@@ -26,8 +26,6 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# FIXME: remove this whitespace diff. -# [MASTER] # Specify a configuration file. @@ -74,12 +72,13 @@ wildcard-import, fixme, global-statement, + no-self-use, [REPORTS] # Set the output format. Available formats are text, parseable, colorized, msvs -# (visual studio) and html +# (visual studio) and html. output-format=text # Put messages in a separate file for each module / package specified on the @@ -87,8 +86,7 @@ # written in a file name "pylint_global.[txt|html]". files-output=no -# Tells whether to display a full report or only the messages -# CHANGED: +# Tells whether to display a full report or only the messages. reports=no # Python expression which should return a note less than 10 (10 is the highest @@ -160,30 +158,28 @@ # Maximum number of characters on a single line. max-line-length=132 -# Maximum number of lines in a module +# Maximum number of lines in a module. max-module-lines=4000 -# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 -# tab). -# CHANGED: +# String used as indentation unit. indent-string=' ' [BASIC] -# Required attributes for module, separated by a comma +# Required attributes for module, separated by a comma. required-attributes= -# List of builtins function names that should not be used, separated by a comma +# List of builtins function names that should not be used, separated by a comma. bad-functions=apply -# Regular expression which should only match correct module names +# Regular expression which should only match correct module names. module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+)|([a-z-][a-z0-9-]*))$ -# Regular expression which should only match correct module level names +# Regular expression which should only match correct module level names. const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ -# Regular expression which should only match correct class names +# Regular expression which should only match correct class names. class-rgx=[A-Z_][a-zA-Z0-9]+$ # Regular expression which should only match correct function names @@ -192,49 +188,49 @@ # Regular expression which should only match correct method names method-rgx=[a-z_][a-z0-9_]{2,60}$ -# Regular expression which should only match correct instance attribute names +# Regular expression which should only match correct instance attribute names. attr-rgx=[a-z_][a-z0-9_]{1,30}$ -# Regular expression which should only match correct argument names +# Regular expression which should only match correct argument names. argument-rgx=[a-z_][a-z0-9_]{1,30}$ -# Regular expression which should only match correct variable names +# Regular expression which should only match correct variable names. variable-rgx=[a-z_][a-z0-9_]{1,30}$ -# Regular expression which should only match correct list comprehension / -# generator expression variable names +# Regular expression which should only match correct list comprehension or +# generator expression variable names. inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ -# Good variable names which should always be accepted, separated by a comma +# Good variable names which should always be accepted, separated by a comma. good-names=i,j,k,ex,Run,_,_log -# Bad variable names which should always be refused, separated by a comma +# Bad variable names which should always be refused, separated by a comma. bad-names=foo,bar,baz,toto,tutu,tata # Regular expression which should only match functions or classes name which do -# not require a docstring +# not require a docstring. no-docstring-rgx=__.*__ [DESIGN] -# Maximum number of arguments for function / method +# Maximum number of arguments for function / method. max-args=5 # Argument names that match this expression will be ignored. Default to name -# with leading underscore +# with leading underscore. ignored-argument-names=_.* -# Maximum number of locals for function / method body +# Maximum number of locals for function / method body. max-locals=15 -# Maximum number of return / yield for function / method body +# Maximum number of return / yield for function / method body. max-returns=6 -# Maximum number of branch for function / method body +# Maximum number of branch for function / method body. max-branchs=12 -# Maximum number of statements in function / method body +# Maximum number of statements in function / method body. max-statements=50 # Maximum number of parents for a class (see R0901). @@ -265,24 +261,24 @@ [IMPORTS] -# Deprecated modules which should not be used, separated by a comma +# Deprecated modules which should not be used, separated by a comma. deprecated-modules=regsub,string,TERMIOS,Bastion,rexec # Create a graph of every (i.e. internal and external) dependencies in the -# given file (report RP0402 must not be disabled) +# given file (report RP0402 must not be disabled). import-graph= # Create a graph of external dependencies in the given file (report RP0402 must -# not be disabled) +# not be disabled). ext-import-graph= # Create a graph of internal dependencies in the given file (report RP0402 must -# not be disabled) +# not be disabled). int-import-graph= [EXCEPTIONS] # Exceptions that will emit a warning when being caught. Defaults to -# "Exception" +# "Exception". overgeneral-exceptions=Exception
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/queries_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/queries_unittest.py index 1d6efd5..6d88cc1c 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/queries_unittest.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/queries_unittest.py
@@ -31,8 +31,7 @@ import unittest from webkitpy.common.system.outputcapture import OutputCapture -from webkitpy.tool.commands.queries import PrintBaselines -from webkitpy.tool.commands.queries import PrintExpectations +from webkitpy.tool.commands.queries import PrintBaselines, PrintExpectations from webkitpy.tool.mock_tool import MockWebKitPatch
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl.py new file mode 100644 index 0000000..ab839fc --- /dev/null +++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl.py
@@ -0,0 +1,125 @@ +# 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. + +"""A command to fetch new baselines from try jobs for a Rietveld issue. + +This command interacts with the Rietveld API to get information about try jobs +with layout test results. +""" + +import logging +import optparse + +from webkitpy.common.checkout.scm.git import Git +from webkitpy.common.net.rietveld import latest_try_jobs +from webkitpy.common.net.web import Web +from webkitpy.layout_tests.models.test_expectations import BASELINE_SUFFIX_LIST +from webkitpy.tool.commands.rebaseline import AbstractParallelRebaselineCommand +from webkitpy.tool.commands.rebaseline import Build + + +_log = logging.getLogger(__name__) + + +class RebaselineCL(AbstractParallelRebaselineCommand): + name = "rebaseline-cl" + help_text = "Fetches new baselines for one CL, from layout test runs on try bots." + show_in_main_help = True + + def __init__(self): + super(RebaselineCL, self).__init__(options=[ + optparse.make_option( + '--issue', type='int', default=None, + help='Rietveld issue number; if none given, this will be obtained via `git cl issue`.'), + optparse.make_option( + '--dry-run', action='store_true', default=False, + help='Dry run mode; list actions that would be performed but do not do anything.'), + self.no_optimize_option, + self.results_directory_option, + ]) + self.web = Web() + + def execute(self, options, args, tool): + issue_number = self._get_issue_number(options) + if not issue_number: + return + if args: + test_prefix_list = {} + try_jobs = latest_try_jobs(issue_number, self._try_bots(), self.web) + builds = [Build(j.builder_name, j.build_number) for j in try_jobs] + for test in args: + test_prefix_list[test] = {b: BASELINE_SUFFIX_LIST for b in builds} + else: + test_prefix_list = self._test_prefix_list(issue_number) + self._log_test_prefix_list(test_prefix_list) + + if options.dry_run: + return + self._rebaseline(options, test_prefix_list) + + def _get_issue_number(self, options): + """Gets the Rietveld CL number from either |options| or from the current local branch.""" + if options.issue: + return options.issue + issue_number = self.git().get_issue_number() + _log.debug('Issue number for current branch: %s', issue_number) + if not issue_number.isdigit(): + _log.error('No issue number given and no issue for current branch.') + return None + return int(issue_number) + + def git(self): + """Returns a Git instance; can be overridden for tests.""" + # Pass in a current working directory inside of the repo so + # that this command can be called from outside of the repo. + return Git(cwd=self._tool.filesystem.dirname(self._tool.path())) + + def _test_prefix_list(self, issue_number): + """Returns a collection of test, builder and file extensions to get new baselines for.""" + builds_to_tests = self._builds_to_tests(issue_number) + result = {} + for build, tests in builds_to_tests.iteritems(): + for test in tests: + if test not in result: + result[test] = {} + result[test][build] = BASELINE_SUFFIX_LIST + return result + + def _builds_to_tests(self, issue_number): + """Fetches a list of try bots, and for each, fetches tests with new baselines.""" + _log.debug('Getting results for Rietveld issue %d.', issue_number) + try_jobs = latest_try_jobs(issue_number, self._try_bots(), self.web) + if not try_jobs: + _log.debug('No try job results for builders in: %r.', self._try_bots()) + builds_to_tests = {} + for job in try_jobs: + test_results = self._unexpected_mismatch_results(job) + build = Build(job.builder_name, job.build_number) + builds_to_tests[build] = sorted(r.test_name() for r in test_results) + return builds_to_tests + + def _try_bots(self): + """Retuns a collection of try bot builders to fetch results for.""" + return self._tool.builders.all_try_builder_names() + + def _unexpected_mismatch_results(self, try_job): + """Fetches a list of LayoutTestResult objects for unexpected results with new baselines.""" + buildbot = self._tool.buildbot + results_url = buildbot.results_url(try_job.builder_name, try_job.build_number) + layout_test_results = buildbot.fetch_layout_test_results(results_url) + if layout_test_results is None: + _log.warning('Failed to request layout test results from "%s".', results_url) + return [] + return layout_test_results.unexpected_mismatch_results() + + @staticmethod + def _log_test_prefix_list(test_prefix_list): + """Logs the tests to download new baselines for.""" + if not test_prefix_list: + _log.info('No tests to rebaseline.') + return + _log.info('Tests to rebaseline:') + for test, builds in test_prefix_list.iteritems(): + builds_str = ', '.join(sorted('%s (%s)' % (b.builder_name, b.build_number) for b in builds)) + _log.info(' %s: %s', test, builds_str)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl_unittest.py new file mode 100644 index 0000000..88e4494 --- /dev/null +++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl_unittest.py
@@ -0,0 +1,134 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import optparse +import json + +from webkitpy.common.checkout.scm.scm_mock import MockSCM +from webkitpy.common.net.buildbot import Build +from webkitpy.common.net.web_mock import MockWeb +from webkitpy.common.system.outputcapture import OutputCapture +from webkitpy.layout_tests.builder_list import BuilderList +from webkitpy.tool.commands.rebaseline_cl import RebaselineCL +from webkitpy.tool.commands.rebaseline_unittest import BaseTestCase + + +class RebaselineCLTest(BaseTestCase): + command_constructor = RebaselineCL + + def setUp(self): + super(RebaselineCLTest, self).setUp() + self.command.web = MockWeb(urls={ + 'https://codereview.chromium.org/api/11112222': json.dumps({ + 'patchsets': [1, 2], + }), + 'https://codereview.chromium.org/api/11112222/2': json.dumps({ + 'try_job_results': [ + { + 'builder': 'MOCK Try Win', + 'buildnumber': 5000, + }, + { + 'builder': 'MOCK Mac Try', + 'buildnumber': 4000, + }, + ], + }), + }) + self.tool.builders = BuilderList({ + "MOCK Try Win": { + "port_name": "test-win-win7", + "specifiers": ["Win7", "Release"], + "is_try_builder": True, + }, + "MOCK Try Mac": { + "port_name": "test-mac-mac10.10", + "specifiers": ["Mac10.10", "Release"], + "is_try_builder": True, + }, + }) + self.git = MockSCM() + self.git.get_issue_number = lambda: 'None' + self.command.git = lambda: self.git + + @staticmethod + def command_options(**kwargs): + options = { + 'issue': None, + 'dry_run': False, + 'optimize': True, + 'verbose': False, + 'results_directory': None, + } + options.update(kwargs) + return optparse.Values(dict(**options)) + + def test_execute_with_issue_number_given(self): + oc = OutputCapture() + try: + oc.capture_output() + self.command.execute(self.command_options(issue=11112222), [], self.tool) + finally: + _, _, logs = oc.restore_output() + self.assertMultiLineEqual( + logs, + ('Tests to rebaseline:\n' + ' svg/dynamic-updates/SVGFEDropShadowElement-dom-stdDeviation-attr.html: MOCK Try Win (5000)\n' + ' fast/dom/prototype-inheritance.html: MOCK Try Win (5000)\n' + ' fast/dom/prototype-taco.html: MOCK Try Win (5000)\n' + 'Rebaselining fast/dom/prototype-inheritance.html\n' + 'Rebaselining fast/dom/prototype-taco.html\n' + 'Rebaselining svg/dynamic-updates/SVGFEDropShadowElement-dom-stdDeviation-attr.html\n')) + + def test_execute_with_no_issue_number(self): + oc = OutputCapture() + try: + oc.capture_output() + self.command.execute(self.command_options(), [], self.tool) + finally: + _, _, logs = oc.restore_output() + self.assertEqual(logs, 'No issue number given and no issue for current branch.\n') + + def test_execute_with_issue_number_from_branch(self): + self.git.get_issue_number = lambda: '11112222' + oc = OutputCapture() + try: + oc.capture_output() + self.command.execute(self.command_options(), [], self.tool) + finally: + _, _, logs = oc.restore_output() + self.assertMultiLineEqual( + logs, + ('Tests to rebaseline:\n' + ' svg/dynamic-updates/SVGFEDropShadowElement-dom-stdDeviation-attr.html: MOCK Try Win (5000)\n' + ' fast/dom/prototype-inheritance.html: MOCK Try Win (5000)\n' + ' fast/dom/prototype-taco.html: MOCK Try Win (5000)\n' + 'Rebaselining fast/dom/prototype-inheritance.html\n' + 'Rebaselining fast/dom/prototype-taco.html\n' + 'Rebaselining svg/dynamic-updates/SVGFEDropShadowElement-dom-stdDeviation-attr.html\n')) + + def test_rebaseline_calls(self): + """Tests the list of commands that are invoked when rebaseline is called.""" + # First write test contents to the mock filesystem so that + # fast/dom/prototype-taco.html is considered a real test to rebaseline. + # TODO(qyearsley): Change this to avoid accessing protected methods. + # pylint: disable=protected-access + port = self.tool.port_factory.get('test-win-win7') + self._write( + port._filesystem.join(port.layout_tests_dir(), 'fast/dom/prototype-taco.html'), + 'test contents') + + self.command._rebaseline( + self.command_options(issue=11112222), + {"fast/dom/prototype-taco.html": {Build("MOCK Try Win", 5000): ["txt", "png"]}}) + + self.assertEqual( + self.tool.executive.calls, + [ + [['python', 'echo', 'copy-existing-baselines-internal', '--suffixes', 'txt', + '--builder', 'MOCK Try Win', '--test', 'fast/dom/prototype-taco.html', '--build-number', '5000']], + [['python', 'echo', 'rebaseline-test-internal', '--suffixes', 'txt', + '--builder', 'MOCK Try Win', '--test', 'fast/dom/prototype-taco.html', '--build-number', '5000']], + [['python', 'echo', 'optimize-baselines', '--no-modify-scm', '--suffixes', 'txt', 'fast/dom/prototype-taco.html']] + ])
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_from_try_jobs.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_from_try_jobs.py deleted file mode 100644 index 242f9a2..0000000 --- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_from_try_jobs.py +++ /dev/null
@@ -1,125 +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. - -"""A command to fetch new baselines from try jobs for a Rietveld issue. - -This command interacts with the Rietveld API to get information about try jobs -with layout test results. -""" - -import logging -import optparse - -from webkitpy.common.checkout.scm.git import Git -from webkitpy.common.net.rietveld import latest_try_jobs -from webkitpy.common.net.web import Web -from webkitpy.layout_tests.models.test_expectations import BASELINE_SUFFIX_LIST -from webkitpy.tool.commands.rebaseline import AbstractParallelRebaselineCommand -from webkitpy.tool.commands.rebaseline import Build - - -_log = logging.getLogger(__name__) - - -class RebaselineFromTryJobs(AbstractParallelRebaselineCommand): - name = "rebaseline-from-try-jobs" - help_text = "Fetches new baselines from layout test runs on try bots." - show_in_main_help = True - - def __init__(self): - super(RebaselineFromTryJobs, self).__init__(options=[ - optparse.make_option( - '--issue', type='int', default=None, - help='Rietveld issue number; if none given, this will be obtained via `git cl issue`.'), - optparse.make_option( - '--dry-run', action='store_true', default=False, - help='Dry run mode; list actions that would be performed but do not do anything.'), - self.no_optimize_option, - self.results_directory_option, - ]) - self.web = Web() - - def execute(self, options, args, tool): - issue_number = self._get_issue_number(options) - if not issue_number: - return - if args: - test_prefix_list = {} - try_jobs = latest_try_jobs(issue_number, self._try_bots(), self.web) - builds = [Build(j.builder_name, j.build_number) for j in try_jobs] - for t in args: - test_prefix_list[t] = {b: BASELINE_SUFFIX_LIST for b in builds} - else: - test_prefix_list = self._test_prefix_list(issue_number) - self._log_test_prefix_list(test_prefix_list) - - if options.dry_run: - return - self._rebaseline(options, test_prefix_list) - - def _get_issue_number(self, options): - """Gets the Rietveld CL number from either |options| or from the current local branch.""" - if options.issue: - return options.issue - issue_number = self.git().get_issue_number() - _log.debug('Issue number for current branch: %s', issue_number) - if not issue_number.isdigit(): - _log.error('No issue number given and no issue for current branch.') - return None - return int(issue_number) - - def git(self): - """Returns a Git instance; can be overridden for tests.""" - # Pass in a current working directory inside of the repo so - # that this command can be called from outside of the repo. - return Git(cwd=self._tool.filesystem.dirname(self._tool.path())) - - def _test_prefix_list(self, issue_number): - """Returns a collection of test, builder and file extensions to get new baselines for.""" - builds_to_tests = self._builds_to_tests(issue_number) - result = {} - for build, tests in builds_to_tests.iteritems(): - for test in tests: - if test not in result: - result[test] = {} - result[test][build] = BASELINE_SUFFIX_LIST - return result - - def _builds_to_tests(self, issue_number): - """Fetches a list of try bots, and for each, fetches tests with new baselines.""" - _log.debug('Getting results for Rietveld issue %d.', issue_number) - try_jobs = latest_try_jobs(issue_number, self._try_bots(), self.web) - if not try_jobs: - _log.debug('No try job results for builders in: %r.', self._try_bots()) - builds_to_tests = {} - for job in try_jobs: - test_results = self._unexpected_mismatch_results(job) - build = Build(job.builder_name, job.build_number) - builds_to_tests[build] = sorted(r.test_name() for r in test_results) - return builds_to_tests - - def _try_bots(self): - """Retuns a collection of try bot builders to fetch results for.""" - return self._tool.builders.all_try_builder_names() - - def _unexpected_mismatch_results(self, try_job): - """Fetches a list of LayoutTestResult objects for unexpected results with new baselines.""" - buildbot = self._tool.buildbot - results_url = buildbot.results_url(try_job.builder_name, try_job.build_number) - layout_test_results = buildbot.fetch_layout_test_results(results_url) - if layout_test_results is None: - _log.warning('Failed to request layout test results from "%s".', results_url) - return [] - return layout_test_results.unexpected_mismatch_results() - - @staticmethod - def _log_test_prefix_list(test_prefix_list): - """Logs the tests to download new baselines for.""" - if not test_prefix_list: - _log.info('No tests to rebaseline.') - return - _log.info('Tests to rebaseline:') - for test, builds in test_prefix_list.iteritems(): - builds_str = ', '.join(sorted('%s (%s)' % (b.builder_name, b.build_number) for b in builds)) - _log.info(' %s: %s', test, builds_str)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_from_try_jobs_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_from_try_jobs_unittest.py deleted file mode 100644 index 4c2ec2c..0000000 --- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_from_try_jobs_unittest.py +++ /dev/null
@@ -1,134 +0,0 @@ -# Copyright 2016 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import optparse -import json - -from webkitpy.common.checkout.scm.scm_mock import MockSCM -from webkitpy.common.net.buildbot import Build -from webkitpy.common.net.web_mock import MockWeb -from webkitpy.common.system.outputcapture import OutputCapture -from webkitpy.layout_tests.builder_list import BuilderList -from webkitpy.tool.commands.rebaseline_from_try_jobs import RebaselineFromTryJobs -from webkitpy.tool.commands.rebaseline_unittest import BaseTestCase - - -class RebaselineFromTryJobsTest(BaseTestCase): - command_constructor = RebaselineFromTryJobs - - def setUp(self): - super(RebaselineFromTryJobsTest, self).setUp() - self.command.web = MockWeb(urls={ - 'https://codereview.chromium.org/api/11112222': json.dumps({ - 'patchsets': [1, 2], - }), - 'https://codereview.chromium.org/api/11112222/2': json.dumps({ - 'try_job_results': [ - { - 'builder': 'MOCK Try Win', - 'buildnumber': 5000, - }, - { - 'builder': 'MOCK Mac Try', - 'buildnumber': 4000, - }, - ], - }), - }) - self.tool.builders = BuilderList({ - "MOCK Try Win": { - "port_name": "test-win-win7", - "specifiers": ["Win7", "Release"], - "is_try_builder": True, - }, - "MOCK Try Mac": { - "port_name": "test-mac-mac10.10", - "specifiers": ["Mac10.10", "Release"], - "is_try_builder": True, - }, - }) - self.git = MockSCM() - self.git.get_issue_number = lambda: 'None' - self.command.git = lambda: self.git - - @staticmethod - def command_options(**kwargs): - options = { - 'issue': None, - 'dry_run': False, - 'optimize': True, - 'verbose': False, - 'results_directory': None, - } - options.update(kwargs) - return optparse.Values(dict(**options)) - - def test_execute_with_issue_number_given(self): - oc = OutputCapture() - try: - oc.capture_output() - self.command.execute(self.command_options(issue=11112222), [], self.tool) - finally: - _, _, logs = oc.restore_output() - self.assertMultiLineEqual( - logs, - ('Tests to rebaseline:\n' - ' svg/dynamic-updates/SVGFEDropShadowElement-dom-stdDeviation-attr.html: MOCK Try Win (5000)\n' - ' fast/dom/prototype-inheritance.html: MOCK Try Win (5000)\n' - ' fast/dom/prototype-taco.html: MOCK Try Win (5000)\n' - 'Rebaselining fast/dom/prototype-inheritance.html\n' - 'Rebaselining fast/dom/prototype-taco.html\n' - 'Rebaselining svg/dynamic-updates/SVGFEDropShadowElement-dom-stdDeviation-attr.html\n')) - - def test_execute_with_no_issue_number(self): - oc = OutputCapture() - try: - oc.capture_output() - self.command.execute(self.command_options(), [], self.tool) - finally: - _, _, logs = oc.restore_output() - self.assertEqual(logs, 'No issue number given and no issue for current branch.\n') - - def test_execute_with_issue_number_from_branch(self): - self.git.get_issue_number = lambda: '11112222' - oc = OutputCapture() - try: - oc.capture_output() - self.command.execute(self.command_options(), [], self.tool) - finally: - _, _, logs = oc.restore_output() - self.assertMultiLineEqual( - logs, - ('Tests to rebaseline:\n' - ' svg/dynamic-updates/SVGFEDropShadowElement-dom-stdDeviation-attr.html: MOCK Try Win (5000)\n' - ' fast/dom/prototype-inheritance.html: MOCK Try Win (5000)\n' - ' fast/dom/prototype-taco.html: MOCK Try Win (5000)\n' - 'Rebaselining fast/dom/prototype-inheritance.html\n' - 'Rebaselining fast/dom/prototype-taco.html\n' - 'Rebaselining svg/dynamic-updates/SVGFEDropShadowElement-dom-stdDeviation-attr.html\n')) - - def test_rebaseline_calls(self): - """Tests the list of commands that are invoked when rebaseline is called.""" - # First write test contents to the mock filesystem so that - # fast/dom/prototype-taco.html is considered a real test to rebaseline. - # TODO(qyearsley): Change this to avoid accessing protected methods. - # pylint: disable=protected-access - port = self.tool.port_factory.get('test-win-win7') - self._write( - port._filesystem.join(port.layout_tests_dir(), 'fast/dom/prototype-taco.html'), - 'test contents') - - self.command._rebaseline( - self.command_options(issue=11112222), - {"fast/dom/prototype-taco.html": {Build("MOCK Try Win", 5000): ["txt", "png"]}}) - - self.assertEqual( - self.tool.executive.calls, - [ - [['python', 'echo', 'copy-existing-baselines-internal', '--suffixes', 'txt', - '--builder', 'MOCK Try Win', '--test', 'fast/dom/prototype-taco.html', '--build-number', '5000']], - [['python', 'echo', 'rebaseline-test-internal', '--suffixes', 'txt', - '--builder', 'MOCK Try Win', '--test', 'fast/dom/prototype-taco.html', '--build-number', '5000']], - [['python', 'echo', 'optimize-baselines', '--no-modify-scm', '--suffixes', 'txt', 'fast/dom/prototype-taco.html']] - ])
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py index 5e83405..3ef19f5 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py
@@ -7,17 +7,13 @@ from webkitpy.common.net.buildbot import Build from webkitpy.common.net.layouttestresults import LayoutTestResults -from webkitpy.common.net.rietveld import Build -from webkitpy.common.system.executive_mock import MockExecutive -from webkitpy.common.system.executive_mock import MockExecutive2 +from webkitpy.common.system.executive_mock import MockExecutive, MockExecutive2 from webkitpy.common.system.outputcapture import OutputCapture from webkitpy.layout_tests.builder_list import BuilderList -from webkitpy.tool.commands.rebaseline import AbstractParallelRebaselineCommand -from webkitpy.tool.commands.rebaseline import CopyExistingBaselinesInternal -from webkitpy.tool.commands.rebaseline import Rebaseline -from webkitpy.tool.commands.rebaseline import RebaselineExpectations -from webkitpy.tool.commands.rebaseline import RebaselineJson -from webkitpy.tool.commands.rebaseline import RebaselineTest +from webkitpy.tool.commands.rebaseline import ( + AbstractParallelRebaselineCommand, CopyExistingBaselinesInternal, + Rebaseline, RebaselineExpectations, RebaselineJson, RebaselineTest +) from webkitpy.tool.mock_tool import MockWebKitPatch
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/webkit_patch.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/webkit_patch.py index da5a85b..ded0ac1c 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/webkit_patch.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/webkit_patch.py
@@ -57,7 +57,7 @@ from webkitpy.tool.commands.rebaseline import RebaselineExpectations from webkitpy.tool.commands.rebaseline import RebaselineJson from webkitpy.tool.commands.rebaseline import RebaselineTest -from webkitpy.tool.commands.rebaseline_from_try_jobs import RebaselineFromTryJobs +from webkitpy.tool.commands.rebaseline_cl import RebaselineCL from webkitpy.tool.commands.rebaseline_server import RebaselineServer @@ -90,8 +90,8 @@ PrintBaselines(), PrintExpectations(), Rebaseline(), + RebaselineCL(), RebaselineExpectations(), - RebaselineFromTryJobs(), RebaselineJson(), RebaselineServer(), RebaselineTest(),
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/deps_updater.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/deps_updater.py index 19b448f..0d600f2 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/deps_updater.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/deps_updater.py
@@ -64,8 +64,8 @@ else: raise AssertionError("Unsupported target %s" % self.target) - self.commit_changes_if_needed(chromium_commitish, import_commitish) - if self.auto_update: + has_changes = self.commit_changes_if_needed(chromium_commitish, import_commitish) + if self.auto_update and has_changes: try_bots = self.host.builders.all_try_builder_names() data_file_path = self.finder.path_from_webkit_base('Tools', 'Scripts', 'webkitpy', 'w3c', 'directory_owners.json') with open(data_file_path) as data_file: @@ -84,7 +84,7 @@ self.write_test_expectations() else: self.print_('No Failures, committing patch.') - self.run(['git', 'cl', 'land', '-f']) + self.run(['git', 'cl', 'land', '-f', '--auth-refresh-token-json', self.auth_refresh_token_json]) return 0 def parse_args(self, argv): @@ -199,8 +199,10 @@ self.run(['git', 'commit', '-a', '-F', path_to_commit_msg]) self.remove(path_to_commit_msg) self.print_('## Done: changes imported and committed.') + return True else: self.print_('## Done: no changes to import.') + return False def is_manual_test(self, fs, dirname, basename): """Returns True if the file should be removed because it's a manual test. @@ -340,9 +342,10 @@ self.print_('## Adding test expectations lines to LayoutTests/TestExpectations.') script_path = self.path_from_webkit_base('Tools', 'Scripts', 'update-w3c-test-expectations') self.run([self.host.executable, script_path]) - message = '\'Modified TestExpectations for newly imported tests.\'' + message = '\'Modifies TestExpectations and/or downloads new baselines for tests\'' self.check_run(['git', 'commit', '-a', '-m', message]) - self.check_run(['git', 'cl', 'upload', '-m', message]) + self.check_run(['git', 'cl', 'upload', '-m', message, + '--auth-refresh-token-json', self.auth_refresh_token_json]) def has_failing_results(self): while True: @@ -357,7 +360,11 @@ return False def generate_upload_command(self, email_list): - command = ['git', 'cl', 'upload', '-f', '-m', 'W3C auto test importer'] + message = """W3C auto test importer + +TBR=qyearsley@chromium.org""" + + command = ['git', 'cl', 'upload', '-f', '-m', message] command += ['--cc=' + email for email in email_list] if self.auth_refresh_token_json: command += ['--auth-refresh-token-json', self.auth_refresh_token_json]
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/update_w3c_test_expectations.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/update_w3c_test_expectations.py index 4a8641df..14d9dfd6 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/update_w3c_test_expectations.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/update_w3c_test_expectations.py
@@ -28,9 +28,11 @@ if not try_jobs: print 'No Try Job information was collected.' return 1 + for job in try_jobs: platform_results = expectations_line_adder.get_failing_results_dict(BuildBot(), job.builder_name, job.build_number) test_expectations = expectations_line_adder.merge_dicts(test_expectations, platform_results) + for test_name, platform_result in test_expectations.iteritems(): test_expectations[test_name] = expectations_line_adder.merge_same_valued_keys(platform_result) test_expectations = expectations_line_adder.get_expected_txt_files(test_expectations) @@ -146,10 +148,12 @@ merged_dict[current_key] = dictionary[current_key] keys.remove(current_key) break + for next_item in keys[1:]: if dictionary[current_key] == dictionary[next_item]: found_match = True matching_value_keys.update([current_key, next_item]) + if next_item == keys[-1]: if found_match: merged_dict[tuple(matching_value_keys)] = dictionary[current_key]
diff --git a/third_party/WebKit/public/blink_headers.gypi b/third_party/WebKit/public/blink_headers.gypi index 708b52a..1b8f902 100644 --- a/third_party/WebKit/public/blink_headers.gypi +++ b/third_party/WebKit/public/blink_headers.gypi
@@ -312,6 +312,18 @@ "platform/modules/websockets/WebSocketHandleClient.h", "platform/modules/websockets/WebSocketHandshakeRequestInfo.h", "platform/modules/websockets/WebSocketHandshakeResponseInfo.h", + "platform/scheduler/base/task_queue.h", + "platform/scheduler/child/child_scheduler.h", + "platform/scheduler/child/compositor_worker_scheduler.h", + "platform/scheduler/child/single_thread_idle_task_runner.h", + "platform/scheduler/child/webthread_base.h", + "platform/scheduler/child/webthread_impl_for_worker_scheduler.h", + "platform/scheduler/child/worker_scheduler.h", + "platform/scheduler/renderer/render_widget_scheduling_state.h", + "platform/scheduler/renderer/renderer_scheduler.h", + "platform/scheduler/test/fake_renderer_scheduler.h", + "platform/scheduler/test/renderer_scheduler_test_support.h", + "platform/scheduler/utility/webthread_impl_for_utility_thread.h", "web/WebAXEnums.h", "web/WebAXObject.h", "web/WebActiveWheelFlingParameters.h", @@ -451,7 +463,6 @@ "web/WebTestingSupport.h", "web/WebTextCheckingCompletion.h", "web/WebTextCheckingResult.h", - "web/WebTextCheckingType.h", "web/WebTextDecorationType.h", "web/WebTextDirection.h", "web/WebTextInputInfo.h",
diff --git a/third_party/WebKit/public/platform/WebDisplayItemList.h b/third_party/WebKit/public/platform/WebDisplayItemList.h index 91659e0..2342edbe 100644 --- a/third_party/WebKit/public/platform/WebDisplayItemList.h +++ b/third_party/WebKit/public/platform/WebDisplayItemList.h
@@ -39,26 +39,26 @@ virtual void appendDrawingItem(const WebRect& visualRect, sk_sp<const SkPicture>) { } - virtual void appendClipItem(const WebRect& visualRect, const WebRect& clipRect, const WebVector<SkRRect>& roundedClipRects) { } - virtual void appendEndClipItem(const WebRect& visualRect) { } - virtual void appendClipPathItem(const WebRect& visualRect, const SkPath&, SkRegion::Op, bool antialias) { } - virtual void appendEndClipPathItem(const WebRect& visualRect) { } - virtual void appendFloatClipItem(const WebRect& visualRect, const WebFloatRect& clipRect) { } - virtual void appendEndFloatClipItem(const WebRect& visualRect) { } - virtual void appendTransformItem(const WebRect& visualRect, const SkMatrix44&) { } - virtual void appendEndTransformItem(const WebRect& visualRect) { } - virtual void appendCompositingItem(const WebRect& visualRect, float opacity, + virtual void appendClipItem(const WebRect& clipRect, const WebVector<SkRRect>& roundedClipRects) { } + virtual void appendEndClipItem() { } + virtual void appendClipPathItem(const SkPath&, SkRegion::Op, bool antialias) { } + virtual void appendEndClipPathItem() { } + virtual void appendFloatClipItem(const WebFloatRect& clipRect) { } + virtual void appendEndFloatClipItem() { } + virtual void appendTransformItem(const SkMatrix44&) { } + virtual void appendEndTransformItem() { } + virtual void appendCompositingItem(float opacity, SkXfermode::Mode, SkRect* bounds, SkColorFilter*) { } - virtual void appendEndCompositingItem(const WebRect& visualRect) { } + virtual void appendEndCompositingItem() { } // TODO(loyso): This should use CompositorFilterOperation. crbug.com/584551 - virtual void appendFilterItem(const WebRect& visualRect, const cc::FilterOperations&, const WebFloatRect& bounds) { } - virtual void appendEndFilterItem(const WebRect& visualRect) { } + virtual void appendFilterItem(const cc::FilterOperations&, const WebFloatRect& bounds) { } + virtual void appendEndFilterItem() { } // Scroll containers are identified by an opaque pointer. using ScrollContainerId = const void*; - virtual void appendScrollItem(const WebRect& visualRect, const WebSize& scrollOffset, ScrollContainerId) { } - virtual void appendEndScrollItem(const WebRect& visualRect) { } + virtual void appendScrollItem(const WebSize& scrollOffset, ScrollContainerId) { } + virtual void appendEndScrollItem() { } virtual void setIsSuitableForGpuRasterization(bool isSuitable) { } };
diff --git a/third_party/WebKit/public/platform/WebInputEvent.h b/third_party/WebKit/public/platform/WebInputEvent.h index 83f5613e..c7ccbf8f 100644 --- a/third_party/WebKit/public/platform/WebInputEvent.h +++ b/third_party/WebKit/public/platform/WebInputEvent.h
@@ -420,23 +420,6 @@ Phase phase; Phase momentumPhase; - // Rubberbanding is an OSX visual effect. When a user scrolls the content - // area with a track pad, and the content area is already at its limit in - // the direction being scrolled, the entire content area is allowed to - // scroll slightly off screen, revealing a grey background. When the user - // lets go, the content area snaps back into place. Blink is responsible - // for this rubberbanding effect, but the embedder may wish to disable - // rubber banding in the left or right direction, if the scroll should have - // an alternate effect. The common case is that a scroll in the left or - // right directions causes a back or forwards navigation, respectively. - // - // These flags prevent rubber banding from starting in a given direction, - // but have no effect on an ongoing rubber banding. A rubber banding that - // started in the vertical direction is allowed to continue in the right - // direction, even if canRubberbandRight is 0. - bool canRubberbandLeft; - bool canRubberbandRight; - bool scrollByPage; bool hasPreciseScrollingDeltas; @@ -457,8 +440,6 @@ , resendingPluginId(-1) , phase(PhaseNone) , momentumPhase(PhaseNone) - , canRubberbandLeft(true) - , canRubberbandRight(true) , scrollByPage(false) , hasPreciseScrollingDeltas(false) , railsMode(RailsModeFree)
diff --git a/third_party/WebKit/public/platform/WebScheduler.h b/third_party/WebKit/public/platform/WebScheduler.h index 3fb63c5..1e04777 100644 --- a/third_party/WebKit/public/platform/WebScheduler.h +++ b/third_party/WebKit/public/platform/WebScheduler.h
@@ -6,6 +6,7 @@ #define WebScheduler_h #include "WebCommon.h" +#include "WebString.h" #include "public/platform/WebTaskRunner.h" #include "public/platform/WebThread.h" #include "public/platform/WebTraceLocation.h" @@ -19,8 +20,18 @@ // This class is used to submit tasks and pass other information from Blink to // the platform's scheduler. +// TODO(skyostil): Replace this class with RendererScheduler. class BLINK_PLATFORM_EXPORT WebScheduler { public: + class BLINK_PLATFORM_EXPORT InterventionReporter { + public: + virtual ~InterventionReporter() {} + + // The scheduler has performed an intervention, described by |message|, + // which should be reported to the developer. + virtual void ReportIntervention(const WebString& message) = 0; + }; + virtual ~WebScheduler() { } // Called to prevent any more pending tasks from running. Must be called on @@ -69,7 +80,7 @@ // Creates a new WebViewScheduler for a given WebView. Must be called from // the associated WebThread. - virtual std::unique_ptr<WebViewScheduler> createWebViewScheduler(blink::WebView*) = 0; + virtual std::unique_ptr<WebViewScheduler> createWebViewScheduler(InterventionReporter*) = 0; // Suspends the timer queue and increments the timer queue suspension count. // May only be called from the main thread.
diff --git a/third_party/WebKit/public/platform/WebTaskRunner.h b/third_party/WebKit/public/platform/WebTaskRunner.h index 3f4c35c..6e2bbd8e 100644 --- a/third_party/WebKit/public/platform/WebTaskRunner.h +++ b/third_party/WebKit/public/platform/WebTaskRunner.h
@@ -13,8 +13,14 @@ #include "wtf/Functional.h" #endif +namespace base { +class SingleThreadTaskRunner; +} + namespace blink { +using SingleThreadTaskRunner = base::SingleThreadTaskRunner; + // The blink representation of a chromium SingleThreadTaskRunner. class BLINK_PLATFORM_EXPORT WebTaskRunner { public: @@ -59,6 +65,9 @@ // real time domain. virtual double monotonicallyIncreasingVirtualTimeSeconds() const = 0; + // Returns the underlying task runner object. + virtual SingleThreadTaskRunner* taskRunner() = 0; + #ifdef INSIDE_BLINK // Helpers for posting bound functions as tasks.
diff --git a/third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerCache.h b/third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerCache.h index f52005d0..09f1efc 100644 --- a/third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerCache.h +++ b/third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerCache.h
@@ -59,7 +59,7 @@ // calling onSuccess or onFailure. virtual void dispatchMatch(CacheMatchCallbacks*, const WebServiceWorkerRequest&, const QueryParams&) = 0; virtual void dispatchMatchAll(CacheWithResponsesCallbacks*, const WebServiceWorkerRequest&, const QueryParams&) = 0; - virtual void dispatchKeys(CacheWithRequestsCallbacks*, const WebServiceWorkerRequest*, const QueryParams&) = 0; + virtual void dispatchKeys(CacheWithRequestsCallbacks*, const WebServiceWorkerRequest&, const QueryParams&) = 0; virtual void dispatchBatch(CacheBatchCallbacks*, const WebVector<BatchOperation>&) = 0; };
diff --git a/third_party/WebKit/public/platform/scheduler/.clang-format b/third_party/WebKit/public/platform/scheduler/.clang-format new file mode 100644 index 0000000..6fdf1dc --- /dev/null +++ b/third_party/WebKit/public/platform/scheduler/.clang-format
@@ -0,0 +1,8 @@ +# Defines the Chromium style for automatic reformatting. +# http://clang.llvm.org/docs/ClangFormatStyleOptions.html +BasedOnStyle: Chromium +# This defaults to 'Auto'. Explicitly set it for a while, so that +# 'vector<vector<int> >' in existing files gets formatted to +# 'vector<vector<int>>'. ('Auto' means that clang-format will only use +# 'int>>' if the file already contains at least one such instance.) +Standard: Cpp11
diff --git a/third_party/WebKit/public/platform/scheduler/DEPS b/third_party/WebKit/public/platform/scheduler/DEPS new file mode 100644 index 0000000..9f0e0127 --- /dev/null +++ b/third_party/WebKit/public/platform/scheduler/DEPS
@@ -0,0 +1,12 @@ +include_rules = [ + "+base/bind.h", + "+base/callback.h", + "+base/macros.h", + "+base/memory/ptr_util.h", + "+base/memory/ref_counted.h", + "+base/message_loop/message_loop.h", + "+base/single_thread_task_runner.h", + "+base/threading/thread.h", + "+base/time/time.h", + "+v8/include/v8.h", +]
diff --git a/components/scheduler/OWNERS b/third_party/WebKit/public/platform/scheduler/OWNERS similarity index 100% copy from components/scheduler/OWNERS copy to third_party/WebKit/public/platform/scheduler/OWNERS
diff --git a/third_party/WebKit/public/platform/scheduler/base/task_queue.h b/third_party/WebKit/public/platform/scheduler/base/task_queue.h new file mode 100644 index 0000000..9dc47a3 --- /dev/null +++ b/third_party/WebKit/public/platform/scheduler/base/task_queue.h
@@ -0,0 +1,218 @@ +// 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 THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_H_ +#define THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_H_ + +#include "base/macros.h" +#include "base/message_loop/message_loop.h" +#include "base/single_thread_task_runner.h" +#include "base/trace_event/trace_event.h" +#include "public/platform/WebCommon.h" + +namespace base { +namespace trace_event { +class BlameContext; +} +} + +namespace blink { +namespace scheduler { +class LazyNow; +class TimeDomain; + +class BLINK_PLATFORM_EXPORT TaskQueue : public base::SingleThreadTaskRunner { + public: + TaskQueue() {} + + // Unregisters the task queue after which no tasks posted to it will run and + // the TaskQueueManager's reference to it will be released soon. + virtual void UnregisterTaskQueue() = 0; + + enum QueuePriority { + // Queues with control priority will run before any other queue, and will + // explicitly starve other queues. Typically this should only be used for + // private queues which perform control operations. + CONTROL_PRIORITY, + // Queues with high priority will be selected preferentially over normal or + // best effort queues. The selector will ensure that high priority queues + // cannot completely starve normal priority queues. + HIGH_PRIORITY, + // Queues with normal priority are the default. + NORMAL_PRIORITY, + // Queues with best effort priority will only be run if all other queues are + // empty. They can be starved by the other queues. + BEST_EFFORT_PRIORITY, + // Must be the last entry. + QUEUE_PRIORITY_COUNT, + FIRST_QUEUE_PRIORITY = CONTROL_PRIORITY, + }; + + // Keep TaskQueue::PumpPolicyToString in sync with this enum. + enum class PumpPolicy { + // Tasks posted to an incoming queue with an AUTO pump policy will be + // automatically scheduled for execution or transferred to the work queue + // automatically. + AUTO, + // Tasks posted to an incoming queue with an AFTER_WAKEUP pump policy + // will be scheduled for execution or transferred to the work queue + // automatically but only after another queue has executed a task. + AFTER_WAKEUP, + // Tasks posted to an incoming queue with a MANUAL will not be + // automatically scheduled for execution or transferred to the work queue. + // Instead, the selector should call PumpQueue() when necessary to bring + // in new tasks for execution. + MANUAL, + // Must be last entry. + PUMP_POLICY_COUNT, + FIRST_PUMP_POLICY = AUTO, + }; + + // Keep TaskQueue::WakeupPolicyToString in sync with this enum. + enum class WakeupPolicy { + // Tasks run on a queue with CAN_WAKE_OTHER_QUEUES wakeup policy can + // cause queues with the AFTER_WAKEUP PumpPolicy to be woken up. + CAN_WAKE_OTHER_QUEUES, + // Tasks run on a queue with DONT_WAKE_OTHER_QUEUES won't cause queues + // with the AFTER_WAKEUP PumpPolicy to be woken up. + DONT_WAKE_OTHER_QUEUES, + // Must be last entry. + WAKEUP_POLICY_COUNT, + FIRST_WAKEUP_POLICY = CAN_WAKE_OTHER_QUEUES, + }; + + // Options for constructing a TaskQueue. Once set the |name|, + // |should_monitor_quiescence| and |wakeup_policy| are immutable. The + // |pump_policy| can be mutated with |SetPumpPolicy()|. + struct Spec { + // Note |name| must have application lifetime. + explicit Spec(const char* name) + : name(name), + should_monitor_quiescence(false), + pump_policy(TaskQueue::PumpPolicy::AUTO), + wakeup_policy(TaskQueue::WakeupPolicy::CAN_WAKE_OTHER_QUEUES), + time_domain(nullptr), + should_notify_observers(true), + should_report_when_execution_blocked(false) {} + + Spec SetShouldMonitorQuiescence(bool should_monitor) { + should_monitor_quiescence = should_monitor; + return *this; + } + + Spec SetPumpPolicy(PumpPolicy policy) { + pump_policy = policy; + return *this; + } + + Spec SetWakeupPolicy(WakeupPolicy policy) { + wakeup_policy = policy; + return *this; + } + + Spec SetShouldNotifyObservers(bool run_observers) { + should_notify_observers = run_observers; + return *this; + } + + Spec SetTimeDomain(TimeDomain* domain) { + time_domain = domain; + return *this; + } + + // See TaskQueueManager::Observer::OnTriedToExecuteBlockedTask. + Spec SetShouldReportWhenExecutionBlocked(bool should_report) { + should_report_when_execution_blocked = should_report; + return *this; + } + + const char* name; + bool should_monitor_quiescence; + TaskQueue::PumpPolicy pump_policy; + TaskQueue::WakeupPolicy wakeup_policy; + TimeDomain* time_domain; + bool should_notify_observers; + bool should_report_when_execution_blocked; + }; + + // Enable or disable task execution for this queue. NOTE this must be called + // on the thread this TaskQueue was created by. + virtual void SetQueueEnabled(bool enabled) = 0; + + // NOTE this must be called on the thread this TaskQueue was created by. + virtual bool IsQueueEnabled() const = 0; + + // Returns true if the queue is completely empty. + virtual bool IsEmpty() const = 0; + + // Returns true if the queue has work that's ready to execute now, or if it + // would have if the queue was pumped. NOTE this must be called on the thread + // this TaskQueue was created by. + virtual bool HasPendingImmediateWork() const = 0; + + // Returns true if tasks can't run now but could if the queue was pumped. + virtual bool NeedsPumping() const = 0; + + // Can be called on any thread. + virtual const char* GetName() const = 0; + + // Set the priority of the queue to |priority|. NOTE this must be called on + // the thread this TaskQueue was created by. + virtual void SetQueuePriority(QueuePriority priority) = 0; + + // Returns the current queue priority. + virtual QueuePriority GetQueuePriority() const = 0; + + // Set the pumping policy of the queue to |pump_policy|. NOTE this must be + // called on the thread this TaskQueue was created by. + virtual void SetPumpPolicy(PumpPolicy pump_policy) = 0; + + // Returns the current PumpPolicy. NOTE this must be called on the thread this + // TaskQueue was created by. + virtual PumpPolicy GetPumpPolicy() const = 0; + + // Reloads new tasks from the incoming queue into the work queue, regardless + // of whether the work queue is empty or not. After this, the function ensures + // that the tasks in the work queue, if any, are scheduled for execution. + // + // This function only needs to be called if automatic pumping is disabled. + // By default automatic pumping is enabled for all queues. NOTE this must be + // called on the thread this TaskQueue was created by. + // + // The |may_post_dowork| parameter controls whether or not PumpQueue calls + // TaskQueueManager::MaybeScheduleImmediateWork. + // TODO(alexclarke): Add a base::RunLoop observer so we can get rid of + // |may_post_dowork|. + virtual void PumpQueue(LazyNow* lazy_now, bool may_post_dowork) = 0; + + // These functions can only be called on the same thread that the task queue + // manager executes its tasks on. + virtual void AddTaskObserver( + base::MessageLoop::TaskObserver* task_observer) = 0; + virtual void RemoveTaskObserver( + base::MessageLoop::TaskObserver* task_observer) = 0; + + // Set the blame context which is entered and left while executing tasks from + // this task queue. |blame_context| must be null or outlive this task queue. + // Must be called on the thread this TaskQueue was created by. + virtual void SetBlameContext( + base::trace_event::BlameContext* blame_context) = 0; + + // Removes the task queue from the previous TimeDomain and adds it to + // |domain|. This is a moderately expensive operation. + virtual void SetTimeDomain(TimeDomain* domain) = 0; + + // Returns the queue's current TimeDomain. Can be called from any thread. + virtual TimeDomain* GetTimeDomain() const = 0; + + protected: + ~TaskQueue() override {} + + DISALLOW_COPY_AND_ASSIGN(TaskQueue); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_H_
diff --git a/third_party/WebKit/public/platform/scheduler/child/child_scheduler.h b/third_party/WebKit/public/platform/scheduler/child/child_scheduler.h new file mode 100644 index 0000000..c49ce28 --- /dev/null +++ b/third_party/WebKit/public/platform/scheduler/child/child_scheduler.h
@@ -0,0 +1,72 @@ +// 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 THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_CHILD_CHILD_SCHEDULER_H_ +#define THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_CHILD_CHILD_SCHEDULER_H_ + +#include "base/macros.h" +#include "base/message_loop/message_loop.h" +#include "public/platform/scheduler/base/task_queue.h" +#include "public/platform/scheduler/child/single_thread_idle_task_runner.h" +#include "public/platform/WebCommon.h" + +namespace base { +class MessageLoop; +} + +namespace blink { +namespace scheduler { +class TaskQueue; + +class BLINK_PLATFORM_EXPORT ChildScheduler { + public: + virtual ~ChildScheduler() {} + + // Returns the default task runner. + virtual scoped_refptr<TaskQueue> DefaultTaskRunner() = 0; + + // Returns the idle task runner. Tasks posted to this runner may be reordered + // relative to other task types and may be starved for an arbitrarily long + // time if no idle time is available. + virtual scoped_refptr<SingleThreadIdleTaskRunner> IdleTaskRunner() = 0; + + // Returns true if there is high priority work pending on the main thread + // and the caller should yield to let the scheduler service that work. Note + // that this is a stricter condition than |IsHighPriorityWorkAnticipated|, + // restricted to the case where real work is pending. + // Must be called from the thread this scheduler was created on. + virtual bool ShouldYieldForHighPriorityWork() = 0; + + // Returns true if a currently running idle task could exceed its deadline + // without impacting user experience too much. This should only be used if + // there is a task which cannot be pre-empted and is likely to take longer + // than the largest expected idle task deadline. It should NOT be polled to + // check whether more work can be performed on the current idle task after + // its deadline has expired - post a new idle task for the continuation of the + // work in this case. + // Must be called from the thread this scheduler was created on. + virtual bool CanExceedIdleDeadlineIfRequired() const = 0; + + // Adds or removes a task observer from the scheduler. The observer will be + // notified before and after every executed task. These functions can only be + // called on the thread this scheduler was created on. + virtual void AddTaskObserver( + base::MessageLoop::TaskObserver* task_observer) = 0; + virtual void RemoveTaskObserver( + base::MessageLoop::TaskObserver* task_observer) = 0; + + // Shuts down the scheduler by dropping any remaining pending work in the work + // queues. After this call any work posted to the task runners will be + // silently dropped. + virtual void Shutdown() = 0; + + protected: + ChildScheduler() {} + DISALLOW_COPY_AND_ASSIGN(ChildScheduler); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_CHILD_CHILD_SCHEDULER_H_
diff --git a/third_party/WebKit/public/platform/scheduler/child/compositor_worker_scheduler.h b/third_party/WebKit/public/platform/scheduler/child/compositor_worker_scheduler.h new file mode 100644 index 0000000..2a17690 --- /dev/null +++ b/third_party/WebKit/public/platform/scheduler/child/compositor_worker_scheduler.h
@@ -0,0 +1,55 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_CHILD_COMPOSITOR_WORKER_SCHEDULER_H_ +#define THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_CHILD_COMPOSITOR_WORKER_SCHEDULER_H_ + +#include "base/macros.h" +#include "public/platform/scheduler/child/single_thread_idle_task_runner.h" +#include "public/platform/scheduler/child/worker_scheduler.h" +#include "public/platform/WebCommon.h" + +namespace base { +class Thread; +} + +namespace blink { +namespace scheduler { + +class BLINK_PLATFORM_EXPORT CompositorWorkerScheduler + : public WorkerScheduler, + public SingleThreadIdleTaskRunner::Delegate { + public: + explicit CompositorWorkerScheduler(base::Thread* thread); + ~CompositorWorkerScheduler() override; + + // WorkerScheduler: + void Init() override; + + // ChildScheduler: + scoped_refptr<TaskQueue> DefaultTaskRunner() override; + scoped_refptr<scheduler::SingleThreadIdleTaskRunner> IdleTaskRunner() + override; + bool ShouldYieldForHighPriorityWork() override; + bool CanExceedIdleDeadlineIfRequired() const override; + void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer) override; + void RemoveTaskObserver( + base::MessageLoop::TaskObserver* task_observer) override; + void Shutdown() override; + + // SingleThreadIdleTaskRunner::Delegate: + void OnIdleTaskPosted() override; + base::TimeTicks WillProcessIdleTask() override; + void DidProcessIdleTask() override; + + private: + base::Thread* thread_; + + DISALLOW_COPY_AND_ASSIGN(CompositorWorkerScheduler); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_CHILD_COMPOSITOR_WORKER_SCHEDULER_H_
diff --git a/third_party/WebKit/public/platform/scheduler/child/single_thread_idle_task_runner.h b/third_party/WebKit/public/platform/scheduler/child/single_thread_idle_task_runner.h new file mode 100644 index 0000000..f795e5a5 --- /dev/null +++ b/third_party/WebKit/public/platform/scheduler/child/single_thread_idle_task_runner.h
@@ -0,0 +1,101 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_CHILD_SINGLE_THREAD_IDLE_TASK_RUNNER_H_ +#define THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_CHILD_SINGLE_THREAD_IDLE_TASK_RUNNER_H_ + +#include "base/bind.h" +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/single_thread_task_runner.h" +#include "base/time/time.h" +#include "base/trace_event/trace_event.h" +#include "public/platform/WebCommon.h" + +namespace base { +namespace trace_event { +class BlameContext; +} +} + +namespace blink { +namespace scheduler { + +// A SingleThreadIdleTaskRunner is a task runner for running idle tasks. Idle +// tasks have an unbound argument which is bound to a deadline +// (in base::TimeTicks) when they are run. The idle task is expected to +// complete by this deadline. +class SingleThreadIdleTaskRunner + : public base::RefCountedThreadSafe<SingleThreadIdleTaskRunner> { + public: + typedef base::Callback<void(base::TimeTicks)> IdleTask; + + // Used to request idle task deadlines and signal posting of idle tasks. + class BLINK_PLATFORM_EXPORT Delegate { + public: + Delegate(); + virtual ~Delegate(); + + // Signals that an idle task has been posted. This will be called on the + // posting thread, which may not be the same thread as the + // SingleThreadIdleTaskRunner runs on. + virtual void OnIdleTaskPosted() = 0; + + // Signals that a new idle task is about to be run and returns the deadline + // for this idle task. + virtual base::TimeTicks WillProcessIdleTask() = 0; + + // Signals that an idle task has finished being run. + virtual void DidProcessIdleTask() = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(Delegate); + }; + + // NOTE Category strings must have application lifetime (statics or + // literals). They may not include " chars. + SingleThreadIdleTaskRunner( + scoped_refptr<base::SingleThreadTaskRunner> idle_priority_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> after_wakeup_task_runner, + Delegate* Delegate, + const char* tracing_category); + + virtual void PostIdleTask(const tracked_objects::Location& from_here, + const IdleTask& idle_task); + + virtual void PostNonNestableIdleTask( + const tracked_objects::Location& from_here, + const IdleTask& idle_task); + + virtual void PostIdleTaskAfterWakeup( + const tracked_objects::Location& from_here, + const IdleTask& idle_task); + + bool RunsTasksOnCurrentThread() const; + + void SetBlameContext(base::trace_event::BlameContext* blame_context); + + protected: + virtual ~SingleThreadIdleTaskRunner(); + + private: + friend class base::RefCountedThreadSafe<SingleThreadIdleTaskRunner>; + + void RunTask(IdleTask idle_task); + + scoped_refptr<base::SingleThreadTaskRunner> idle_priority_task_runner_; + scoped_refptr<base::SingleThreadTaskRunner> after_wakeup_task_runner_; + Delegate* delegate_; // NOT OWNED + const char* tracing_category_; + base::trace_event::BlameContext* blame_context_; // Not owned. + base::WeakPtr<SingleThreadIdleTaskRunner> weak_scheduler_ptr_; + base::WeakPtrFactory<SingleThreadIdleTaskRunner> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(SingleThreadIdleTaskRunner); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_CHILD_SINGLE_THREAD_IDLE_TASK_RUNNER_H_
diff --git a/third_party/WebKit/public/platform/scheduler/child/webthread_base.h b/third_party/WebKit/public/platform/scheduler/child/webthread_base.h new file mode 100644 index 0000000..6bfddec --- /dev/null +++ b/third_party/WebKit/public/platform/scheduler/child/webthread_base.h
@@ -0,0 +1,66 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_CHILD_WEBTHREAD_BASE_H_ +#define THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_CHILD_WEBTHREAD_BASE_H_ + +#include <map> +#include <memory> + +#include "base/threading/thread.h" +#include "public/platform/WebCommon.h" +#include "public/platform/WebThread.h" +#include "public/platform/WebTraceLocation.h" + +namespace blink { +namespace scheduler { +class SingleThreadIdleTaskRunner; + +class BLINK_PLATFORM_EXPORT WebThreadBase : public WebThread { + public: + ~WebThreadBase() override; + + // WebThread implementation. + bool isCurrentThread() const override; + PlatformThreadId threadId() const override = 0; + + virtual void postIdleTask(const WebTraceLocation& location, + IdleTask* idle_task); + virtual void postIdleTaskAfterWakeup(const WebTraceLocation& location, + IdleTask* idle_task); + + void addTaskObserver(TaskObserver* observer) override; + void removeTaskObserver(TaskObserver* observer) override; + + // Returns the base::Bind-compatible task runner for posting tasks to this + // thread. Can be called from any thread. + virtual base::SingleThreadTaskRunner* GetTaskRunner() const = 0; + + // Returns the base::Bind-compatible task runner for posting idle tasks to + // this thread. Can be called from any thread. + virtual scheduler::SingleThreadIdleTaskRunner* GetIdleTaskRunner() const = 0; + + protected: + class TaskObserverAdapter; + + WebThreadBase(); + + virtual void AddTaskObserverInternal( + base::MessageLoop::TaskObserver* observer); + virtual void RemoveTaskObserverInternal( + base::MessageLoop::TaskObserver* observer); + + static void RunWebThreadIdleTask( + std::unique_ptr<WebThread::IdleTask> idle_task, + base::TimeTicks deadline); + + private: + typedef std::map<TaskObserver*, TaskObserverAdapter*> TaskObserverMap; + TaskObserverMap task_observer_map_; +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_CHILD_WEBTHREAD_BASE_H_
diff --git a/third_party/WebKit/public/platform/scheduler/child/webthread_impl_for_worker_scheduler.h b/third_party/WebKit/public/platform/scheduler/child/webthread_impl_for_worker_scheduler.h new file mode 100644 index 0000000..4a8d687 --- /dev/null +++ b/third_party/WebKit/public/platform/scheduler/child/webthread_impl_for_worker_scheduler.h
@@ -0,0 +1,78 @@ +// 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 THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_CHILD_WEBTHREAD_IMPL_FOR_WORKER_SCHEDULER_H_ +#define THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_CHILD_WEBTHREAD_IMPL_FOR_WORKER_SCHEDULER_H_ + +#include "base/threading/thread.h" +#include "public/platform/scheduler/child/webthread_base.h" + +namespace base { +class WaitableEvent; +}; + +namespace blink { +class WebScheduler; +}; + +namespace blink { +namespace scheduler { +class SchedulerTqmDelegate; +class SingleThreadIdleTaskRunner; +class TaskQueue; +class WebSchedulerImpl; +class WebTaskRunnerImpl; +class WorkerScheduler; + +class BLINK_PLATFORM_EXPORT WebThreadImplForWorkerScheduler + : public WebThreadBase, + public base::MessageLoop::DestructionObserver { + public: + explicit WebThreadImplForWorkerScheduler(const char* name); + WebThreadImplForWorkerScheduler(const char* name, + base::Thread::Options options); + ~WebThreadImplForWorkerScheduler() override; + + void Init(); + + // WebThread implementation. + WebScheduler* scheduler() const override; + PlatformThreadId threadId() const override; + WebTaskRunner* getWebTaskRunner() override; + + // WebThreadBase implementation. + base::SingleThreadTaskRunner* GetTaskRunner() const override; + scheduler::SingleThreadIdleTaskRunner* GetIdleTaskRunner() const override; + + // base::MessageLoop::DestructionObserver implementation. + void WillDestroyCurrentMessageLoop() override; + + protected: + base::Thread* thread() const { return thread_.get(); } + + private: + virtual std::unique_ptr<scheduler::WorkerScheduler> CreateWorkerScheduler(); + + void AddTaskObserverInternal( + base::MessageLoop::TaskObserver* observer) override; + void RemoveTaskObserverInternal( + base::MessageLoop::TaskObserver* observer) override; + + void InitOnThread(base::WaitableEvent* completion); + void RestoreTaskRunnerOnThread(base::WaitableEvent* completion); + + std::unique_ptr<base::Thread> thread_; + std::unique_ptr<scheduler::WorkerScheduler> worker_scheduler_; + std::unique_ptr<scheduler::WebSchedulerImpl> web_scheduler_; + scoped_refptr<base::SingleThreadTaskRunner> thread_task_runner_; + scoped_refptr<TaskQueue> task_runner_; + scoped_refptr<scheduler::SingleThreadIdleTaskRunner> idle_task_runner_; + scoped_refptr<SchedulerTqmDelegate> task_runner_delegate_; + std::unique_ptr<WebTaskRunnerImpl> web_task_runner_; +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_CHILD_WEBTHREAD_IMPL_FOR_WORKER_SCHEDULER_H_
diff --git a/third_party/WebKit/public/platform/scheduler/child/worker_scheduler.h b/third_party/WebKit/public/platform/scheduler/child/worker_scheduler.h new file mode 100644 index 0000000..4dd78e2c8 --- /dev/null +++ b/third_party/WebKit/public/platform/scheduler/child/worker_scheduler.h
@@ -0,0 +1,42 @@ +// 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 THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_CHILD_WORKER_SCHEDULER_H_ +#define THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_CHILD_WORKER_SCHEDULER_H_ + +#include <memory> + +#include "base/macros.h" +#include "base/message_loop/message_loop.h" +#include "public/platform/scheduler/child/child_scheduler.h" +#include "public/platform/scheduler/child/single_thread_idle_task_runner.h" +#include "public/platform/WebCommon.h" + +namespace base { +class MessageLoop; +} + +namespace blink { +namespace scheduler { +class SchedulerTqmDelegate; + +class BLINK_PLATFORM_EXPORT WorkerScheduler : public ChildScheduler { + public: + ~WorkerScheduler() override; + static std::unique_ptr<WorkerScheduler> Create( + scoped_refptr<SchedulerTqmDelegate> main_task_runner); + + // Must be called before the scheduler can be used. Does any post construction + // initialization needed such as initializing idle period detection. + virtual void Init() = 0; + + protected: + WorkerScheduler(); + DISALLOW_COPY_AND_ASSIGN(WorkerScheduler); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_CHILD_WORKER_SCHEDULER_H_
diff --git a/third_party/WebKit/public/platform/scheduler/renderer/render_widget_scheduling_state.h b/third_party/WebKit/public/platform/scheduler/renderer/render_widget_scheduling_state.h new file mode 100644 index 0000000..2bd8afc --- /dev/null +++ b/third_party/WebKit/public/platform/scheduler/renderer/render_widget_scheduling_state.h
@@ -0,0 +1,36 @@ +// 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 THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_RENDERER_RENDER_WIDGET_SCHEDULING_STATE_H_ +#define THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_RENDERER_RENDER_WIDGET_SCHEDULING_STATE_H_ + +#include "public/platform/WebCommon.h" + +namespace blink { +namespace scheduler { + +class RenderWidgetSignals; + +class BLINK_PLATFORM_EXPORT RenderWidgetSchedulingState { + public: + void SetHidden(bool hidden); + void SetHasTouchHandler(bool has_touch_handler); + + ~RenderWidgetSchedulingState(); + + private: + friend class RenderWidgetSignals; + + explicit RenderWidgetSchedulingState( + RenderWidgetSignals* render_widget_scheduling_signals); + + RenderWidgetSignals* render_widget_signals_; // NOT OWNED + bool hidden_; + bool has_touch_handler_; +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_RENDERER_RENDER_WIDGET_SCHEDULING_STATE_H_
diff --git a/third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h b/third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h new file mode 100644 index 0000000..2a865e8 --- /dev/null +++ b/third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h
@@ -0,0 +1,189 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_RENDERER_RENDERER_SCHEDULER_H_ +#define THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_RENDERER_RENDERER_SCHEDULER_H_ + +#include <memory> + +#include "base/macros.h" +#include "base/message_loop/message_loop.h" +#include "public/platform/scheduler/child/child_scheduler.h" +#include "public/platform/scheduler/child/single_thread_idle_task_runner.h" +#include "public/platform/scheduler/renderer/render_widget_scheduling_state.h" +#include "public/platform/WebCommon.h" +#include "public/platform/WebInputEvent.h" +#include "public/platform/WebScheduler.h" +#include "v8/include/v8.h" + +namespace base { +namespace trace_event { +class BlameContext; +} +} + +namespace cc { +struct BeginFrameArgs; +} + +namespace blink { +class WebLocalFrame; +class WebThread; +} + +namespace blink { +namespace scheduler { + +class RenderWidgetSchedulingState; + +class BLINK_PLATFORM_EXPORT RendererScheduler : public ChildScheduler { + public: + class BLINK_PLATFORM_EXPORT RAILModeObserver { + public: + virtual ~RAILModeObserver(); + virtual void OnRAILModeChanged(v8::RAILMode rail_mode) = 0; + }; + + ~RendererScheduler() override; + static std::unique_ptr<RendererScheduler> Create(); + + // Returns the compositor task runner. + virtual scoped_refptr<TaskQueue> CompositorTaskRunner() = 0; + + // Creates a WebThread implementation for the renderer main thread. + virtual std::unique_ptr<WebThread> CreateMainThread() = 0; + + // Returns the loading task runner. This queue is intended for tasks related + // to resource dispatch, foreground HTML parsing, etc... + virtual scoped_refptr<TaskQueue> LoadingTaskRunner() = 0; + + // Returns the timer task runner. This queue is intended for DOM Timers. + // TODO(alexclarke): Get rid of this default timer queue. + virtual scoped_refptr<TaskQueue> TimerTaskRunner() = 0; + + // Returns a new loading task runner. This queue is intended for tasks related + // to resource dispatch, foreground HTML parsing, etc... + virtual scoped_refptr<TaskQueue> NewLoadingTaskRunner(const char* name) = 0; + + // Returns a new timer task runner. This queue is intended for DOM Timers. + virtual scoped_refptr<TaskQueue> NewTimerTaskRunner(const char* name) = 0; + + // Returns a task runner for tasks which should never get throttled. + virtual scoped_refptr<TaskQueue> NewUnthrottledTaskRunner( + const char* name) = 0; + + // Returns a new RenderWidgetSchedulingState. The signals from this will be + // used to make scheduling decisions. + virtual std::unique_ptr<RenderWidgetSchedulingState> + NewRenderWidgetSchedulingState() = 0; + + // Called to notify about the start of an extended period where no frames + // need to be drawn. Must be called from the main thread. + virtual void BeginFrameNotExpectedSoon() = 0; + + // Called to notify about the start of a new frame. Must be called from the + // main thread. + virtual void WillBeginFrame(const cc::BeginFrameArgs& args) = 0; + + // Called to notify that a previously begun frame was committed. Must be + // called from the main thread. + virtual void DidCommitFrameToCompositor() = 0; + + // Keep RendererScheduler::InputEventStateToString in sync with this enum. + enum class InputEventState { + EVENT_CONSUMED_BY_COMPOSITOR, + EVENT_FORWARDED_TO_MAIN_THREAD, + }; + static const char* InputEventStateToString(InputEventState input_event_state); + + // Tells the scheduler that the system processed an input event. Called by the + // compositor (impl) thread. Note it's expected that every call to + // DidHandleInputEventOnCompositorThread where |event_state| is + // EVENT_FORWARDED_TO_MAIN_THREAD will be followed by a corresponding call + // to DidHandleInputEventOnMainThread. + virtual void DidHandleInputEventOnCompositorThread( + const WebInputEvent& web_input_event, + InputEventState event_state) = 0; + + // Tells the scheduler that the system processed an input event. Must be + // called from the main thread. + virtual void DidHandleInputEventOnMainThread( + const WebInputEvent& web_input_event) = 0; + + // Tells the scheduler that the system is displaying an input animation (e.g. + // a fling). Called by the compositor (impl) thread. + virtual void DidAnimateForInputOnCompositorThread() = 0; + + // Tells the scheduler that the renderer process has been backgrounded, i.e., + // there are no critical, user facing activities (visual, audio, etc...) + // driven by this process. A stricter condition than |OnRendererHidden()|, the + // process is assumed to be foregrounded when the scheduler is constructed. + // Must be called on the main thread. + virtual void OnRendererBackgrounded() = 0; + + // Tells the scheduler that the renderer process has been foregrounded. + // This is the assumed state when the scheduler is constructed. + // Must be called on the main thread. + virtual void OnRendererForegrounded() = 0; + + // Tells the scheduler that the render process should be suspended. This can + // only be done when the renderer is backgrounded. The renderer will be + // automatically resumed when foregrounded. + virtual void SuspendRenderer() = 0; + + // Tells the scheduler that a navigation task is pending. While any main-frame + // navigation tasks are pending, the scheduler will ensure that loading tasks + // are not blocked even if they are expensive. Must be called on the main + // thread. + virtual void AddPendingNavigation(WebScheduler::NavigatingFrameType type) = 0; + + // Tells the scheduler that a navigation task is no longer pending. + // Must be called on the main thread. + virtual void RemovePendingNavigation( + WebScheduler::NavigatingFrameType type) = 0; + + // Tells the scheduler that a navigation has started. The scheduler will + // prioritize loading tasks for a short duration afterwards. + // Must be called from the main thread. + virtual void OnNavigationStarted() = 0; + + // Returns true if the scheduler has reason to believe that high priority work + // may soon arrive on the main thread, e.g., if gesture events were observed + // recently. + // Must be called from the main thread. + virtual bool IsHighPriorityWorkAnticipated() = 0; + + // Suspends the timer queue and increments the timer queue suspension count. + // May only be called from the main thread. + virtual void SuspendTimerQueue() = 0; + + // Decrements the timer queue suspension count and re-enables the timer queue + // if the suspension count is zero and the current schduler policy allows it. + virtual void ResumeTimerQueue() = 0; + + // Sets whether to allow suspension of timers after the backgrounded signal is + // received via OnRendererBackgrounded. Defaults to disabled. + virtual void SetTimerQueueSuspensionWhenBackgroundedEnabled(bool enabled) = 0; + + // Sets the default blame context to which top level work should be + // attributed in this renderer. |blame_context| must outlive this scheduler. + virtual void SetTopLevelBlameContext( + base::trace_event::BlameContext* blame_context) = 0; + + // The renderer scheduler maintains an estimated RAIL mode[1]. This observer + // can be used to get notified when the mode changes. The observer will be + // called on the main thread and must outlive this class. + // [1] + // https://developers.google.com/web/tools/chrome-devtools/profile/evaluate-performance/rail + virtual void SetRAILModeObserver(RAILModeObserver* observer) = 0; + + protected: + RendererScheduler(); + DISALLOW_COPY_AND_ASSIGN(RendererScheduler); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_RENDERER_RENDERER_SCHEDULER_H_
diff --git a/third_party/WebKit/public/platform/scheduler/test/fake_renderer_scheduler.h b/third_party/WebKit/public/platform/scheduler/test/fake_renderer_scheduler.h new file mode 100644 index 0000000..5706b77 --- /dev/null +++ b/third_party/WebKit/public/platform/scheduler/test/fake_renderer_scheduler.h
@@ -0,0 +1,67 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_TEST_FAKE_RENDERER_SCHEDULER_H_ +#define THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_TEST_FAKE_RENDERER_SCHEDULER_H_ + +#include "base/macros.h" +#include "public/platform/scheduler/renderer/renderer_scheduler.h" + +namespace blink { +namespace scheduler { + +class FakeRendererScheduler : public RendererScheduler { + public: + FakeRendererScheduler(); + ~FakeRendererScheduler() override; + + // RendererScheduler implementation. + std::unique_ptr<WebThread> CreateMainThread() override; + scoped_refptr<TaskQueue> DefaultTaskRunner() override; + scoped_refptr<TaskQueue> CompositorTaskRunner() override; + scoped_refptr<TaskQueue> LoadingTaskRunner() override; + scoped_refptr<SingleThreadIdleTaskRunner> IdleTaskRunner() override; + scoped_refptr<TaskQueue> TimerTaskRunner() override; + scoped_refptr<TaskQueue> NewLoadingTaskRunner(const char* name) override; + scoped_refptr<TaskQueue> NewTimerTaskRunner(const char* name) override; + scoped_refptr<TaskQueue> NewUnthrottledTaskRunner(const char* name) override; + std::unique_ptr<RenderWidgetSchedulingState> NewRenderWidgetSchedulingState() + override; + void WillBeginFrame(const cc::BeginFrameArgs& args) override; + void BeginFrameNotExpectedSoon() override; + void DidCommitFrameToCompositor() override; + void DidHandleInputEventOnCompositorThread( + const WebInputEvent& web_input_event, + InputEventState event_state) override; + void DidHandleInputEventOnMainThread( + const WebInputEvent& web_input_event) override; + void DidAnimateForInputOnCompositorThread() override; + void OnRendererBackgrounded() override; + void OnRendererForegrounded() override; + void SuspendRenderer() override; + void AddPendingNavigation(WebScheduler::NavigatingFrameType type) override; + void RemovePendingNavigation(WebScheduler::NavigatingFrameType type) override; + void OnNavigationStarted() override; + bool IsHighPriorityWorkAnticipated() override; + bool CanExceedIdleDeadlineIfRequired() const override; + bool ShouldYieldForHighPriorityWork() override; + void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer) override; + void RemoveTaskObserver( + base::MessageLoop::TaskObserver* task_observer) override; + void Shutdown() override; + void SuspendTimerQueue() override; + void ResumeTimerQueue() override; + void SetTimerQueueSuspensionWhenBackgroundedEnabled(bool enabled) override; + void SetTopLevelBlameContext( + base::trace_event::BlameContext* blame_context) override; + void SetRAILModeObserver(RAILModeObserver* observer) override; + + private: + DISALLOW_COPY_AND_ASSIGN(FakeRendererScheduler); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_TEST_FAKE_RENDERER_SCHEDULER_H_
diff --git a/third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h b/third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h new file mode 100644 index 0000000..6e99ee31 --- /dev/null +++ b/third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h
@@ -0,0 +1,24 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_TEST_RENDERER_SCHEDULER_TEST_SUPPORT_H_ +#define THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_TEST_RENDERER_SCHEDULER_TEST_SUPPORT_H_ + +#include "base/bind.h" +#include "base/memory/ptr_util.h" + +namespace blink { +namespace scheduler { + +class RendererScheduler; + +std::unique_ptr<RendererScheduler> CreateRendererSchedulerForTests(); + +void RunIdleTasksForTesting(RendererScheduler* scheduler, + const base::Closure& callback); + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_TEST_RENDERER_SCHEDULER_TEST_SUPPORT_H_
diff --git a/third_party/WebKit/public/platform/scheduler/utility/webthread_impl_for_utility_thread.h b/third_party/WebKit/public/platform/scheduler/utility/webthread_impl_for_utility_thread.h new file mode 100644 index 0000000..564f3e11e --- /dev/null +++ b/third_party/WebKit/public/platform/scheduler/utility/webthread_impl_for_utility_thread.h
@@ -0,0 +1,40 @@ +// 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 THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_UTILITY_WEBTHREAD_IMPL_FOR_UTILITY_THREAD_H_ +#define THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_UTILITY_WEBTHREAD_IMPL_FOR_UTILITY_THREAD_H_ + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "public/platform/scheduler/child/webthread_base.h" +#include "public/platform/WebCommon.h" + +namespace blink { +namespace scheduler { + +class BLINK_PLATFORM_EXPORT WebThreadImplForUtilityThread + : public scheduler::WebThreadBase { + public: + WebThreadImplForUtilityThread(); + ~WebThreadImplForUtilityThread() override; + + // WebThread implementation. + WebScheduler* scheduler() const override; + PlatformThreadId threadId() const override; + + // WebThreadBase implementation. + base::SingleThreadTaskRunner* GetTaskRunner() const override; + scheduler::SingleThreadIdleTaskRunner* GetIdleTaskRunner() const override; + + private: + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + PlatformThreadId thread_id_; + + DISALLOW_COPY_AND_ASSIGN(WebThreadImplForUtilityThread); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_UTILITY_WEBTHREAD_IMPL_FOR_UTILITY_THREAD_H_
diff --git a/third_party/WebKit/public/web/WebFrameClient.h b/third_party/WebKit/public/web/WebFrameClient.h index 108c4c7a..ebde5da 100644 --- a/third_party/WebKit/public/web/WebFrameClient.h +++ b/third_party/WebKit/public/web/WebFrameClient.h
@@ -702,6 +702,13 @@ return WebPageVisibilityStateVisible; } + // Overwrites the given URL to use an HTML5 embed if possible. + // An empty URL is returned if the URL is not overriden. + virtual WebURL overrideFlashEmbedWithHTML(const WebURL& url) + { + return WebURL(); + } + protected: virtual ~WebFrameClient() { } };
diff --git a/third_party/WebKit/public/web/WebLocalFrame.h b/third_party/WebKit/public/web/WebLocalFrame.h index e3e687a5..25657a7 100644 --- a/third_party/WebKit/public/web/WebLocalFrame.h +++ b/third_party/WebKit/public/web/WebLocalFrame.h
@@ -240,6 +240,7 @@ virtual void selectRange(const WebPoint& base, const WebPoint& extent) = 0; virtual void selectRange(const WebRange&) = 0; + virtual WebString rangeAsText(const WebRange&) = 0; // Move the current selection to the provided viewport point/points. If the // current selection is editable, the new selection will be restricted to
diff --git a/third_party/WebKit/public/web/WebRange.h b/third_party/WebKit/public/web/WebRange.h index fd5ca00..36dcbea 100644 --- a/third_party/WebKit/public/web/WebRange.h +++ b/third_party/WebKit/public/web/WebRange.h
@@ -31,47 +31,33 @@ #ifndef WebRange_h #define WebRange_h -#include "WebFrame.h" #include "public/platform/WebCommon.h" -#include "public/platform/WebPrivatePtr.h" -#include "public/platform/WebVector.h" namespace blink { class Range; class WebString; +class LocalFrame; -// Provides readonly access to some properties of a DOM range. -class WebRange { +class WebRange final { public: - ~WebRange() { reset(); } + BLINK_EXPORT WebRange(int start, int length); - WebRange() { } - WebRange(const WebRange& r) { assign(r); } - WebRange& operator=(const WebRange& r) - { - assign(r); - return *this; - } + int startOffset() const { return m_start; } + int endOffset() const { return m_end; } + int length() const { return m_end - m_start; } - BLINK_EXPORT void reset(); - BLINK_EXPORT void assign(const WebRange&); - - bool isNull() const { return m_private.isNull(); } - - BLINK_EXPORT int startOffset() const; - BLINK_EXPORT int endOffset() const; - BLINK_EXPORT WebString toPlainText() const; - - BLINK_EXPORT static WebRange fromDocumentRange(WebLocalFrame*, int start, int length); + bool isNull() const { return m_start == -1 && m_end == -1; } #if BLINK_IMPLEMENTATION WebRange(Range*); - operator Range*() const; + + Range* createRange(LocalFrame*) const; #endif private: - WebPrivatePtr<Range> m_private; + int m_start = -1; + int m_end = -1; }; } // namespace blink
diff --git a/third_party/WebKit/public/web/WebRuntimeFeatures.h b/third_party/WebKit/public/web/WebRuntimeFeatures.h index c0df222..f7df2b9 100644 --- a/third_party/WebKit/public/web/WebRuntimeFeatures.h +++ b/third_party/WebKit/public/web/WebRuntimeFeatures.h
@@ -120,6 +120,7 @@ BLINK_EXPORT static void enableXSLT(bool); BLINK_EXPORT static void forceOverlayFullscreenVideo(bool); BLINK_EXPORT static void enableAutoplayMutedVideos(bool); + BLINK_EXPORT static void enableTimerThrottlingForBackgroundTabs(bool); BLINK_EXPORT static void enableCanvas2dDynamicRenderingModeSwitching(bool); BLINK_EXPORT static void enableSendBeaconThrowForBlobWithNonSimpleType(bool); private:
diff --git a/third_party/WebKit/public/web/WebSpellCheckClient.h b/third_party/WebKit/public/web/WebSpellCheckClient.h index bbbd547..a16117c 100644 --- a/third_party/WebKit/public/web/WebSpellCheckClient.h +++ b/third_party/WebKit/public/web/WebSpellCheckClient.h
@@ -33,7 +33,6 @@ #include "../platform/WebString.h" #include "../platform/WebVector.h" -#include "WebTextCheckingType.h" namespace blink { @@ -54,12 +53,6 @@ int& misspelledLength, WebVector<WebString>* optionalSuggestions) { } - // The client should perform spell-checking on the given text. This function will - // enumerate all misspellings at once. - virtual void checkTextOfParagraph(const WebString&, - WebTextCheckingTypeMask mask, - WebVector<WebTextCheckingResult>* results) { } - // Requests asynchronous spelling and grammar checking, whose result should be // returned by passed completion object. virtual void requestCheckingOfText(const WebString& textToCheck, @@ -67,6 +60,10 @@ const WebVector<unsigned>& markerOffsets, WebTextCheckingCompletion* completionCallback) { } + // Clear all stored references to requests, so that it will not become a + // leak source. + virtual void cancelAllPendingRequests() { } + // Show or hide the spelling UI. virtual void showSpellingUI(bool show) { }
diff --git a/third_party/WebKit/public/web/WebSurroundingText.h b/third_party/WebKit/public/web/WebSurroundingText.h index e5315c6..ec456d6 100644 --- a/third_party/WebKit/public/web/WebSurroundingText.h +++ b/third_party/WebKit/public/web/WebSurroundingText.h
@@ -35,6 +35,7 @@ class SurroundingText; class WebNode; class WebRange; +class WebLocalFrame; struct WebPoint; // WebSurroundingText is a Blink API that gives access to the SurroundingText @@ -50,11 +51,10 @@ // position relative to a provided node. // The maximum length of the contents retrieved is defined by maxLength. BLINK_EXPORT void initialize(const WebNode&, const WebPoint&, size_t maxLength); - - // Initializes the object to get the text surrounding a given range. + // Initializes the object with the current selection in a given frame. // The maximum length of the contents retrieved is defined by maxLength. // It does not include the text inside the range. - BLINK_EXPORT void initialize(const WebRange&, size_t maxLength); + BLINK_EXPORT void initializeFromCurrentSelection(WebLocalFrame*, size_t maxLength); // Surrounding text content retrieved. BLINK_EXPORT WebString textContent() const;
diff --git a/third_party/WebKit/public/web/WebTextCheckingType.h b/third_party/WebKit/public/web/WebTextCheckingType.h deleted file mode 100644 index 486cf0eb..0000000 --- a/third_party/WebKit/public/web/WebTextCheckingType.h +++ /dev/null
@@ -1,45 +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 WebTextCheckingType_h -#define WebTextCheckingType_h - -namespace blink { - -enum WebTextCheckingType { - WebTextCheckingTypeSpelling = 1 << 1, - WebTextCheckingTypeGrammar = 1 << 2, -}; - -typedef unsigned WebTextCheckingTypeMask; - -} // namespace blink - -#endif
diff --git a/third_party/android_protobuf/BUILD.gn b/third_party/android_protobuf/BUILD.gn index c7d03b8d..bddd967b 100644 --- a/third_party/android_protobuf/BUILD.gn +++ b/third_party/android_protobuf/BUILD.gn
@@ -150,6 +150,9 @@ android_library("protobuf_nano_javalib") { chromium_code = false java_files = [ + "src/java/src/device/main/java/com/google/protobuf/nano/android/ParcelableExtendableMessageNano.java", + "src/java/src/device/main/java/com/google/protobuf/nano/android/ParcelableMessageNano.java", + "src/java/src/device/main/java/com/google/protobuf/nano/android/ParcelableMessageNanoCreator.java", "src/java/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java", "src/java/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java", "src/java/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java",
diff --git a/third_party/ced/BUILD.gn b/third_party/ced/BUILD.gn index c2ed9a2..a9f51a08 100644 --- a/third_party/ced/BUILD.gn +++ b/third_party/ced/BUILD.gn
@@ -13,14 +13,15 @@ static_library("ced") { sources = [ + # find src -maxdepth 3 ! -type d | egrep '\.(h|cc)$' | grep -v test.cc |\ + # LC_COLLATE=c sort | sed 's/^\(.*\)$/ "\1",/' "src/compact_enc_det/compact_enc_det.cc", - "src/compact_enc_det/compact_enc_det.h", "src/compact_enc_det/compact_enc_det_generated_tables.h", "src/compact_enc_det/compact_enc_det_generated_tables2.h", "src/compact_enc_det/compact_enc_det_hint_code.cc", "src/compact_enc_det/compact_enc_det_hint_code.h", "src/util/basictypes.h", - "src/util/build_config.h", + "src/util/case_insensitive_hash.h", "src/util/commandlineflags.h", "src/util/encodings/encodings.cc", "src/util/encodings/encodings.h", @@ -33,7 +34,9 @@ "src/util/string_util.h", "src/util/varsetter.h", ] - + public = [ + "src/compact_enc_det/compact_enc_det.h", + ] configs -= [ "//build/config/compiler:chromium_code" ] configs += [ "//build/config/compiler:no_chromium_code" ] @@ -57,6 +60,7 @@ "src/compact_enc_det/compact_enc_det_fuzz_test.cc", "src/compact_enc_det/compact_enc_det_unittest.cc", "src/compact_enc_det/detail_head_string.inc", + "src/util/encodings/encodings_unittest.cc", ] if (is_win) {
diff --git a/third_party/ced/ced.gyp b/third_party/ced/ced.gyp index cb42521..11237529 100644 --- a/third_party/ced/ced.gyp +++ b/third_party/ced/ced.gyp
@@ -4,6 +4,7 @@ { 'includes': [ + 'ced.gypi', '../../build/win_precompile.gypi', ], 'targets': [ @@ -14,26 +15,7 @@ 'src', ], 'sources': [ - "src/compact_enc_det/compact_enc_det.cc", - "src/compact_enc_det/compact_enc_det.h", - "src/compact_enc_det/compact_enc_det_generated_tables.h", - "src/compact_enc_det/compact_enc_det_generated_tables2.h", - "src/compact_enc_det/compact_enc_det_hint_code.cc", - "src/compact_enc_det/compact_enc_det_hint_code.h", - "src/compact_enc_det/detail_head_string.inc", - "src/util/basictypes.h", - "src/util/build_config.h", - "src/util/commandlineflags.h", - "src/util/encodings/encodings.cc", - "src/util/encodings/encodings.h", - "src/util/encodings/encodings.pb.h", - "src/util/languages/languages.cc", - "src/util/languages/languages.h", - "src/util/languages/languages.pb.h", - "src/util/logging.h", - "src/util/port.h", - "src/util/string_util.h", - "src/util/varsetter.h", + '<@(ced_sources)', ], 'direct_dependent_settings': { 'include_dirs': [ @@ -41,6 +23,9 @@ ], }, 'conditions': [ + ['OS == "ios"', { + 'toolsets': ['host', 'target'], + }], ['OS=="win"', { 'direct_dependent_settings': { 'defines': [ @@ -69,8 +54,10 @@ '<(DEPTH)', ], 'sources': [ - "src/compact_enc_det/compact_enc_det_fuzz_test.cc", - "src/compact_enc_det/compact_enc_det_unittest.cc", + 'src/compact_enc_det/compact_enc_det_fuzz_test.cc', + 'src/compact_enc_det/compact_enc_det_unittest.cc', + 'src/compact_enc_det/detail_head_string.inc', + 'src/util/encodings/encodings_unittest.cc', ], }, ],
diff --git a/third_party/ced/ced.gypi b/third_party/ced/ced.gypi new file mode 100644 index 0000000..12984fb0 --- /dev/null +++ b/third_party/ced/ced.gypi
@@ -0,0 +1,31 @@ +# 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. + +{ + 'variables': { + 'ced_sources': [ + # find src -maxdepth 3 ! -type d | egrep '\.(h|cc)$' | grep -v test.cc | \ + # LC_COLLATE=c sort | sed "s/^\(.*\)$/ '\1',/" + 'src/compact_enc_det/compact_enc_det.cc', + 'src/compact_enc_det/compact_enc_det.h', + 'src/compact_enc_det/compact_enc_det_generated_tables2.h', + 'src/compact_enc_det/compact_enc_det_generated_tables.h', + 'src/compact_enc_det/compact_enc_det_hint_code.cc', + 'src/compact_enc_det/compact_enc_det_hint_code.h', + 'src/util/basictypes.h', + 'src/util/case_insensitive_hash.h', + 'src/util/commandlineflags.h', + 'src/util/encodings/encodings.cc', + 'src/util/encodings/encodings.h', + 'src/util/encodings/encodings.pb.h', + 'src/util/languages/languages.cc', + 'src/util/languages/languages.h', + 'src/util/languages/languages.pb.h', + 'src/util/logging.h', + 'src/util/port.h', + 'src/util/string_util.h', + 'src/util/varsetter.h', + ], + } +}
diff --git a/third_party/ced/ced_nacl.gyp b/third_party/ced/ced_nacl.gyp new file mode 100644 index 0000000..54250d1 --- /dev/null +++ b/third_party/ced/ced_nacl.gyp
@@ -0,0 +1,41 @@ +# Copyright (c) 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. + +{ + 'includes': [ + 'ced.gypi', + '../../native_client/build/untrusted.gypi', + ], + 'target_defaults': { + 'pnacl_compile_flags': [ + '-Wno-c++11-narrowing', + '-Wno-unused-variable' + ], + }, + 'targets': [ + { + 'target_name': 'ced_nacl', + 'type': 'none', + 'include_dirs': [ + 'src', + ], + 'variables': { + 'nlib_target': 'libced_nacl.a', + 'build_glibc': 0, + 'build_newlib': 0, + 'build_pnacl_newlib': 1, + }, + 'sources': [ + '<@(ced_sources)', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + 'src', + ], + }, + }, + ], +} + +
diff --git a/third_party/cld/BUILD.gn b/third_party/cld/BUILD.gn new file mode 100644 index 0000000..dcfaf8b --- /dev/null +++ b/third_party/cld/BUILD.gn
@@ -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. + +import("//build/buildflag_header.gni") + +# Specifies which language identification model to use: CLD2 or CLD3. +cld_version = 2 + +buildflag_header("cld_version") { + header = "cld_version.h" + flags = [ "CLD_VERSION=$cld_version" ] +} + +group("cld") { + public_deps = [ + ":cld_version", + ] + if (cld_version == 2) { + public_deps += [ "//third_party/cld_2" ] + } else if (cld_version == 3) { + # TODO(abakalov): Rename to //third_party/cld_3/src/src:cld_3 + public_deps += [ "//third_party/cld_3/src/src:nnet_language_identifier" ] + } else { + assert(false, "CLD version should be 2 or 3") + } +}
diff --git a/third_party/cld/LICENSE b/third_party/cld/LICENSE new file mode 100644 index 0000000..c5899b26 --- /dev/null +++ b/third_party/cld/LICENSE
@@ -0,0 +1,203 @@ +Copyright 2016 Google Inc. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2016, Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.
diff --git a/third_party/cld/OWNERS b/third_party/cld/OWNERS new file mode 100644 index 0000000..99c5de0 --- /dev/null +++ b/third_party/cld/OWNERS
@@ -0,0 +1,2 @@ +andrewhayden@chromium.org +abakalov@chromium.org \ No newline at end of file
diff --git a/third_party/cld/README.chromium b/third_party/cld/README.chromium new file mode 100644 index 0000000..3d2e0e81 --- /dev/null +++ b/third_party/cld/README.chromium
@@ -0,0 +1,17 @@ +Name: Compact Language Detector +Short Name: cld +URL: NA +Version: 0 +License: Apache 2.0 +Security Critical: no + +Description: +The BUILD.gn file in this directory governs which language detector is used. +The options are: +- CLD2 implemented in //third_party/cld_2 +- CLD3 implemented in //third_party/cld_3 + +For more context, see https://bugs.chromium.org/p/webrtc/issues/detail?id=6200 + +Local Modifications: +None.
diff --git a/third_party/libaddressinput/chromium/chrome_metadata_source.cc b/third_party/libaddressinput/chromium/chrome_metadata_source.cc index c54f129..af0dde2 100644 --- a/third_party/libaddressinput/chromium/chrome_metadata_source.cc +++ b/third_party/libaddressinput/chromium/chrome_metadata_source.cc
@@ -59,7 +59,7 @@ getter_(getter) {} ChromeMetadataSource::~ChromeMetadataSource() { - STLDeleteValues(&requests_); + base::STLDeleteValues(&requests_); } void ChromeMetadataSource::Get(const std::string& key,
diff --git a/third_party/libaddressinput/chromium/json.cc b/third_party/libaddressinput/chromium/json.cc index 535173f..f7bc4af 100644 --- a/third_party/libaddressinput/chromium/json.cc +++ b/third_party/libaddressinput/chromium/json.cc
@@ -49,7 +49,7 @@ : owned_(Parse(json, &parser_error_)), dict_(*owned_) {} - ~JsonImpl() { STLDeleteElements(&sub_dicts_); } + ~JsonImpl() { base::STLDeleteElements(&sub_dicts_); } bool parser_error() const { return parser_error_; }
diff --git a/third_party/libvpx/README.chromium b/third_party/libvpx/README.chromium index 8a79be8..f23cd14 100644 --- a/third_party/libvpx/README.chromium +++ b/third_party/libvpx/README.chromium
@@ -5,9 +5,9 @@ License File: source/libvpx/LICENSE Security Critical: yes -Date: Monday July 25 2016 +Date: Friday August 05 2016 Branch: master -Commit: 82070ae9393b1e79559d81fcf1aa89c2e4aa58ee +Commit: 2d1e63d0c50cc0088e6b851ec86fdc79f0476ac8 Description: Contains the sources used to compile libvpx binaries used by Google Chrome and
diff --git a/third_party/libvpx/generate_gypi.sh b/third_party/libvpx/generate_gypi.sh index 9dc5440..09bafdda 100755 --- a/third_party/libvpx/generate_gypi.sh +++ b/third_party/libvpx/generate_gypi.sh
@@ -597,7 +597,8 @@ cd $BASE_DIR/$LIBVPX_SRC_DIR echo echo "Update README.chromium:" -git log -1 --format="%cd%nCommit: %H" --date=format:"Date: %A %B %d %Y" +git --no-pager log -1 --format="%cd%nCommit: %H" \ + --date=format:"Date: %A %B %d %Y" cd $BASE_DIR
diff --git a/third_party/libvpx/libvpx_srcs.gni b/third_party/libvpx/libvpx_srcs.gni index b3d434d..0d6e2b3 100644 --- a/third_party/libvpx/libvpx_srcs.gni +++ b/third_party/libvpx/libvpx_srcs.gni
@@ -872,12 +872,6 @@ libvpx_srcs_arm = [ "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.c", "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.h", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/idct_blk_v6.c", - "//third_party/libvpx/source/libvpx/vp8/common/arm/bilinearfilter_arm.c", - "//third_party/libvpx/source/libvpx/vp8/common/arm/bilinearfilter_arm.h", - "//third_party/libvpx/source/libvpx/vp8/common/arm/dequantize_arm.c", - "//third_party/libvpx/source/libvpx/vp8/common/arm/filter_arm.c", - "//third_party/libvpx/source/libvpx/vp8/common/arm/loopfilter_arm.c", "//third_party/libvpx/source/libvpx/vp8/common/blockd.c", "//third_party/libvpx/source/libvpx/vp8/common/blockd.h", "//third_party/libvpx/source/libvpx/vp8/common/coefupdateprobs.h", @@ -946,7 +940,6 @@ "//third_party/libvpx/source/libvpx/vp8/decoder/onyxd_int.h", "//third_party/libvpx/source/libvpx/vp8/decoder/threading.c", "//third_party/libvpx/source/libvpx/vp8/decoder/treereader.h", - "//third_party/libvpx/source/libvpx/vp8/encoder/arm/dct_arm.c", "//third_party/libvpx/source/libvpx/vp8/encoder/bitstream.c", "//third_party/libvpx/source/libvpx/vp8/encoder/bitstream.h", "//third_party/libvpx/source/libvpx/vp8/encoder/block.h", @@ -1147,7 +1140,6 @@ "//third_party/libvpx/source/libvpx/vpx/vpx_image.h", "//third_party/libvpx/source/libvpx/vpx/vpx_integer.h", "//third_party/libvpx/source/libvpx/vpx_dsp/add_noise.c", - "//third_party/libvpx/source/libvpx/vpx_dsp/arm/subpel_variance_media.c", "//third_party/libvpx/source/libvpx/vpx_dsp/avg.c", "//third_party/libvpx/source/libvpx/vpx_dsp/bitreader.c", "//third_party/libvpx/source/libvpx/vpx_dsp/bitreader.h", @@ -1207,37 +1199,10 @@ "//third_party/libvpx/source/libvpx/vpx_util/vpx_thread.c", "//third_party/libvpx/source/libvpx/vpx_util/vpx_thread.h", ] -libvpx_srcs_arm_assembly = [ - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/bilinearfilter_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/copymem16x16_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/copymem8x4_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/copymem8x8_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/dc_only_idct_add_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/dequant_idct_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/dequantize_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/filter_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/idct_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/iwalsh_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/loopfilter_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/simpleloopfilter_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/sixtappredict8x4_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/encoder/arm/armv6/vp8_short_fdct4x4_armv6.asm", - "//third_party/libvpx/source/libvpx/vp8/encoder/arm/armv6/walsh_v6.asm", - "//third_party/libvpx/source/libvpx/vpx_dsp/arm/bilinear_filter_media.asm", - "//third_party/libvpx/source/libvpx/vpx_dsp/arm/sad_media.asm", - "//third_party/libvpx/source/libvpx/vpx_dsp/arm/variance_halfpixvar16x16_h_media.asm", - "//third_party/libvpx/source/libvpx/vpx_dsp/arm/variance_halfpixvar16x16_hv_media.asm", - "//third_party/libvpx/source/libvpx/vpx_dsp/arm/variance_halfpixvar16x16_v_media.asm", - "//third_party/libvpx/source/libvpx/vpx_dsp/arm/variance_media.asm", -] +libvpx_srcs_arm_assembly = [] libvpx_srcs_arm_neon = [ "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.c", "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.h", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/idct_blk_v6.c", - "//third_party/libvpx/source/libvpx/vp8/common/arm/bilinearfilter_arm.c", - "//third_party/libvpx/source/libvpx/vp8/common/arm/bilinearfilter_arm.h", - "//third_party/libvpx/source/libvpx/vp8/common/arm/dequantize_arm.c", - "//third_party/libvpx/source/libvpx/vp8/common/arm/filter_arm.c", "//third_party/libvpx/source/libvpx/vp8/common/arm/loopfilter_arm.c", "//third_party/libvpx/source/libvpx/vp8/common/arm/neon/bilinearpredict_neon.c", "//third_party/libvpx/source/libvpx/vp8/common/arm/neon/copymem_neon.c", @@ -1322,7 +1287,6 @@ "//third_party/libvpx/source/libvpx/vp8/decoder/onyxd_int.h", "//third_party/libvpx/source/libvpx/vp8/decoder/threading.c", "//third_party/libvpx/source/libvpx/vp8/decoder/treereader.h", - "//third_party/libvpx/source/libvpx/vp8/encoder/arm/dct_arm.c", "//third_party/libvpx/source/libvpx/vp8/encoder/arm/neon/denoising_neon.c", "//third_party/libvpx/source/libvpx/vp8/encoder/arm/neon/fastquantizeb_neon.c", "//third_party/libvpx/source/libvpx/vp8/encoder/arm/neon/shortfdct_neon.c", @@ -1540,9 +1504,9 @@ "//third_party/libvpx/source/libvpx/vpx_dsp/arm/loopfilter_neon.c", "//third_party/libvpx/source/libvpx/vpx_dsp/arm/sad4d_neon.c", "//third_party/libvpx/source/libvpx/vpx_dsp/arm/sad_neon.c", - "//third_party/libvpx/source/libvpx/vpx_dsp/arm/subpel_variance_media.c", "//third_party/libvpx/source/libvpx/vpx_dsp/arm/subpel_variance_neon.c", "//third_party/libvpx/source/libvpx/vpx_dsp/arm/subtract_neon.c", + "//third_party/libvpx/source/libvpx/vpx_dsp/arm/transpose_neon.h", "//third_party/libvpx/source/libvpx/vpx_dsp/arm/variance_neon.c", "//third_party/libvpx/source/libvpx/vpx_dsp/arm/vpx_convolve_neon.c", "//third_party/libvpx/source/libvpx/vpx_dsp/avg.c", @@ -1605,22 +1569,6 @@ "//third_party/libvpx/source/libvpx/vpx_util/vpx_thread.h", ] libvpx_srcs_arm_neon_assembly = [ - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/bilinearfilter_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/copymem16x16_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/copymem8x4_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/copymem8x8_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/dc_only_idct_add_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/dequant_idct_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/dequantize_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/filter_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/idct_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/iwalsh_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/loopfilter_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/simpleloopfilter_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/sixtappredict8x4_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/encoder/arm/armv6/vp8_short_fdct4x4_armv6.asm", - "//third_party/libvpx/source/libvpx/vp8/encoder/arm/armv6/walsh_v6.asm", - "//third_party/libvpx/source/libvpx/vpx_dsp/arm/bilinear_filter_media.asm", "//third_party/libvpx/source/libvpx/vpx_dsp/arm/idct16x16_1_add_neon.asm", "//third_party/libvpx/source/libvpx/vpx_dsp/arm/idct16x16_add_neon.asm", "//third_party/libvpx/source/libvpx/vpx_dsp/arm/idct32x32_1_add_neon.asm", @@ -1634,12 +1582,7 @@ "//third_party/libvpx/source/libvpx/vpx_dsp/arm/loopfilter_4_neon.asm", "//third_party/libvpx/source/libvpx/vpx_dsp/arm/loopfilter_8_neon.asm", "//third_party/libvpx/source/libvpx/vpx_dsp/arm/loopfilter_mb_neon.asm", - "//third_party/libvpx/source/libvpx/vpx_dsp/arm/sad_media.asm", "//third_party/libvpx/source/libvpx/vpx_dsp/arm/save_reg_neon.asm", - "//third_party/libvpx/source/libvpx/vpx_dsp/arm/variance_halfpixvar16x16_h_media.asm", - "//third_party/libvpx/source/libvpx/vpx_dsp/arm/variance_halfpixvar16x16_hv_media.asm", - "//third_party/libvpx/source/libvpx/vpx_dsp/arm/variance_halfpixvar16x16_v_media.asm", - "//third_party/libvpx/source/libvpx/vpx_dsp/arm/variance_media.asm", "//third_party/libvpx/source/libvpx/vpx_dsp/arm/vpx_convolve8_avg_neon_asm.asm", "//third_party/libvpx/source/libvpx/vpx_dsp/arm/vpx_convolve8_neon_asm.asm", "//third_party/libvpx/source/libvpx/vpx_dsp/arm/vpx_convolve_avg_neon_asm.asm", @@ -1648,11 +1591,6 @@ libvpx_srcs_arm_neon_cpu_detect = [ "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.c", "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.h", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/idct_blk_v6.c", - "//third_party/libvpx/source/libvpx/vp8/common/arm/bilinearfilter_arm.c", - "//third_party/libvpx/source/libvpx/vp8/common/arm/bilinearfilter_arm.h", - "//third_party/libvpx/source/libvpx/vp8/common/arm/dequantize_arm.c", - "//third_party/libvpx/source/libvpx/vp8/common/arm/filter_arm.c", "//third_party/libvpx/source/libvpx/vp8/common/arm/loopfilter_arm.c", "//third_party/libvpx/source/libvpx/vp8/common/blockd.c", "//third_party/libvpx/source/libvpx/vp8/common/blockd.h", @@ -1722,7 +1660,6 @@ "//third_party/libvpx/source/libvpx/vp8/decoder/onyxd_int.h", "//third_party/libvpx/source/libvpx/vp8/decoder/threading.c", "//third_party/libvpx/source/libvpx/vp8/decoder/treereader.h", - "//third_party/libvpx/source/libvpx/vp8/encoder/arm/dct_arm.c", "//third_party/libvpx/source/libvpx/vp8/encoder/bitstream.c", "//third_party/libvpx/source/libvpx/vp8/encoder/bitstream.h", "//third_party/libvpx/source/libvpx/vp8/encoder/block.h", @@ -1923,7 +1860,7 @@ "//third_party/libvpx/source/libvpx/vpx/vpx_image.h", "//third_party/libvpx/source/libvpx/vpx/vpx_integer.h", "//third_party/libvpx/source/libvpx/vpx_dsp/add_noise.c", - "//third_party/libvpx/source/libvpx/vpx_dsp/arm/subpel_variance_media.c", + "//third_party/libvpx/source/libvpx/vpx_dsp/arm/transpose_neon.h", "//third_party/libvpx/source/libvpx/vpx_dsp/avg.c", "//third_party/libvpx/source/libvpx/vpx_dsp/bitreader.c", "//third_party/libvpx/source/libvpx/vpx_dsp/bitreader.h", @@ -1984,27 +1921,6 @@ "//third_party/libvpx/source/libvpx/vpx_util/vpx_thread.h", ] libvpx_srcs_arm_neon_cpu_detect_assembly = [ - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/bilinearfilter_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/copymem16x16_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/copymem8x4_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/copymem8x8_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/dc_only_idct_add_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/dequant_idct_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/dequantize_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/filter_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/idct_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/iwalsh_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/loopfilter_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/simpleloopfilter_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/common/arm/armv6/sixtappredict8x4_v6.asm", - "//third_party/libvpx/source/libvpx/vp8/encoder/arm/armv6/vp8_short_fdct4x4_armv6.asm", - "//third_party/libvpx/source/libvpx/vp8/encoder/arm/armv6/walsh_v6.asm", - "//third_party/libvpx/source/libvpx/vpx_dsp/arm/bilinear_filter_media.asm", - "//third_party/libvpx/source/libvpx/vpx_dsp/arm/sad_media.asm", - "//third_party/libvpx/source/libvpx/vpx_dsp/arm/variance_halfpixvar16x16_h_media.asm", - "//third_party/libvpx/source/libvpx/vpx_dsp/arm/variance_halfpixvar16x16_hv_media.asm", - "//third_party/libvpx/source/libvpx/vpx_dsp/arm/variance_halfpixvar16x16_v_media.asm", - "//third_party/libvpx/source/libvpx/vpx_dsp/arm/variance_media.asm", "//third_party/libvpx/source/libvpx/vpx_dsp/arm/idct16x16_1_add_neon.asm", "//third_party/libvpx/source/libvpx/vpx_dsp/arm/idct16x16_add_neon.asm", "//third_party/libvpx/source/libvpx/vpx_dsp/arm/idct32x32_1_add_neon.asm", @@ -2065,8 +1981,6 @@ libvpx_srcs_arm64 = [ "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.c", "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.h", - "//third_party/libvpx/source/libvpx/vp8/common/arm/dequantize_arm.c", - "//third_party/libvpx/source/libvpx/vp8/common/arm/filter_arm.c", "//third_party/libvpx/source/libvpx/vp8/common/arm/loopfilter_arm.c", "//third_party/libvpx/source/libvpx/vp8/common/arm/neon/bilinearpredict_neon.c", "//third_party/libvpx/source/libvpx/vp8/common/arm/neon/copymem_neon.c", @@ -2151,7 +2065,6 @@ "//third_party/libvpx/source/libvpx/vp8/decoder/onyxd_int.h", "//third_party/libvpx/source/libvpx/vp8/decoder/threading.c", "//third_party/libvpx/source/libvpx/vp8/decoder/treereader.h", - "//third_party/libvpx/source/libvpx/vp8/encoder/arm/dct_arm.c", "//third_party/libvpx/source/libvpx/vp8/encoder/arm/neon/denoising_neon.c", "//third_party/libvpx/source/libvpx/vp8/encoder/arm/neon/fastquantizeb_neon.c", "//third_party/libvpx/source/libvpx/vp8/encoder/arm/neon/shortfdct_neon.c", @@ -2382,6 +2295,7 @@ "//third_party/libvpx/source/libvpx/vpx_dsp/arm/sad_neon.c", "//third_party/libvpx/source/libvpx/vpx_dsp/arm/subpel_variance_neon.c", "//third_party/libvpx/source/libvpx/vpx_dsp/arm/subtract_neon.c", + "//third_party/libvpx/source/libvpx/vpx_dsp/arm/transpose_neon.h", "//third_party/libvpx/source/libvpx/vpx_dsp/arm/variance_neon.c", "//third_party/libvpx/source/libvpx/vpx_dsp/arm/vpx_convolve8_avg_neon.c", "//third_party/libvpx/source/libvpx/vpx_dsp/arm/vpx_convolve8_neon.c",
diff --git a/third_party/libvpx/libvpx_srcs_arm.gypi b/third_party/libvpx/libvpx_srcs_arm.gypi index 53c6110..fe032ef 100644 --- a/third_party/libvpx/libvpx_srcs_arm.gypi +++ b/third_party/libvpx/libvpx_srcs_arm.gypi
@@ -7,25 +7,6 @@ 'sources': [ '<(libvpx_source)/vp8/common/alloccommon.c', '<(libvpx_source)/vp8/common/alloccommon.h', - '<(libvpx_source)/vp8/common/arm/armv6/bilinearfilter_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/copymem16x16_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/copymem8x4_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/copymem8x8_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/dc_only_idct_add_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/dequant_idct_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/dequantize_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/filter_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/idct_blk_v6.c', - '<(libvpx_source)/vp8/common/arm/armv6/idct_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/iwalsh_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/loopfilter_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/simpleloopfilter_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/sixtappredict8x4_v6.asm', - '<(libvpx_source)/vp8/common/arm/bilinearfilter_arm.c', - '<(libvpx_source)/vp8/common/arm/bilinearfilter_arm.h', - '<(libvpx_source)/vp8/common/arm/dequantize_arm.c', - '<(libvpx_source)/vp8/common/arm/filter_arm.c', - '<(libvpx_source)/vp8/common/arm/loopfilter_arm.c', '<(libvpx_source)/vp8/common/blockd.c', '<(libvpx_source)/vp8/common/blockd.h', '<(libvpx_source)/vp8/common/coefupdateprobs.h', @@ -94,9 +75,6 @@ '<(libvpx_source)/vp8/decoder/onyxd_int.h', '<(libvpx_source)/vp8/decoder/threading.c', '<(libvpx_source)/vp8/decoder/treereader.h', - '<(libvpx_source)/vp8/encoder/arm/armv6/vp8_short_fdct4x4_armv6.asm', - '<(libvpx_source)/vp8/encoder/arm/armv6/walsh_v6.asm', - '<(libvpx_source)/vp8/encoder/arm/dct_arm.c', '<(libvpx_source)/vp8/encoder/bitstream.c', '<(libvpx_source)/vp8/encoder/bitstream.h', '<(libvpx_source)/vp8/encoder/block.h', @@ -297,13 +275,6 @@ '<(libvpx_source)/vpx/vpx_image.h', '<(libvpx_source)/vpx/vpx_integer.h', '<(libvpx_source)/vpx_dsp/add_noise.c', - '<(libvpx_source)/vpx_dsp/arm/bilinear_filter_media.asm', - '<(libvpx_source)/vpx_dsp/arm/sad_media.asm', - '<(libvpx_source)/vpx_dsp/arm/subpel_variance_media.c', - '<(libvpx_source)/vpx_dsp/arm/variance_halfpixvar16x16_h_media.asm', - '<(libvpx_source)/vpx_dsp/arm/variance_halfpixvar16x16_hv_media.asm', - '<(libvpx_source)/vpx_dsp/arm/variance_halfpixvar16x16_v_media.asm', - '<(libvpx_source)/vpx_dsp/arm/variance_media.asm', '<(libvpx_source)/vpx_dsp/avg.c', '<(libvpx_source)/vpx_dsp/bitreader.c', '<(libvpx_source)/vpx_dsp/bitreader.h',
diff --git a/third_party/libvpx/libvpx_srcs_arm64.gypi b/third_party/libvpx/libvpx_srcs_arm64.gypi index 90b0191..3304ca1 100644 --- a/third_party/libvpx/libvpx_srcs_arm64.gypi +++ b/third_party/libvpx/libvpx_srcs_arm64.gypi
@@ -7,8 +7,6 @@ 'sources': [ '<(libvpx_source)/vp8/common/alloccommon.c', '<(libvpx_source)/vp8/common/alloccommon.h', - '<(libvpx_source)/vp8/common/arm/dequantize_arm.c', - '<(libvpx_source)/vp8/common/arm/filter_arm.c', '<(libvpx_source)/vp8/common/arm/loopfilter_arm.c', '<(libvpx_source)/vp8/common/arm/neon/bilinearpredict_neon.c', '<(libvpx_source)/vp8/common/arm/neon/copymem_neon.c', @@ -93,7 +91,6 @@ '<(libvpx_source)/vp8/decoder/onyxd_int.h', '<(libvpx_source)/vp8/decoder/threading.c', '<(libvpx_source)/vp8/decoder/treereader.h', - '<(libvpx_source)/vp8/encoder/arm/dct_arm.c', '<(libvpx_source)/vp8/encoder/arm/neon/denoising_neon.c', '<(libvpx_source)/vp8/encoder/arm/neon/fastquantizeb_neon.c', '<(libvpx_source)/vp8/encoder/arm/neon/shortfdct_neon.c', @@ -324,6 +321,7 @@ '<(libvpx_source)/vpx_dsp/arm/sad_neon.c', '<(libvpx_source)/vpx_dsp/arm/subpel_variance_neon.c', '<(libvpx_source)/vpx_dsp/arm/subtract_neon.c', + '<(libvpx_source)/vpx_dsp/arm/transpose_neon.h', '<(libvpx_source)/vpx_dsp/arm/variance_neon.c', '<(libvpx_source)/vpx_dsp/arm/vpx_convolve8_avg_neon.c', '<(libvpx_source)/vpx_dsp/arm/vpx_convolve8_neon.c',
diff --git a/third_party/libvpx/libvpx_srcs_arm_neon.gypi b/third_party/libvpx/libvpx_srcs_arm_neon.gypi index fb95e64..6b781c4 100644 --- a/third_party/libvpx/libvpx_srcs_arm_neon.gypi +++ b/third_party/libvpx/libvpx_srcs_arm_neon.gypi
@@ -7,24 +7,6 @@ 'sources': [ '<(libvpx_source)/vp8/common/alloccommon.c', '<(libvpx_source)/vp8/common/alloccommon.h', - '<(libvpx_source)/vp8/common/arm/armv6/bilinearfilter_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/copymem16x16_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/copymem8x4_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/copymem8x8_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/dc_only_idct_add_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/dequant_idct_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/dequantize_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/filter_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/idct_blk_v6.c', - '<(libvpx_source)/vp8/common/arm/armv6/idct_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/iwalsh_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/loopfilter_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/simpleloopfilter_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/sixtappredict8x4_v6.asm', - '<(libvpx_source)/vp8/common/arm/bilinearfilter_arm.c', - '<(libvpx_source)/vp8/common/arm/bilinearfilter_arm.h', - '<(libvpx_source)/vp8/common/arm/dequantize_arm.c', - '<(libvpx_source)/vp8/common/arm/filter_arm.c', '<(libvpx_source)/vp8/common/arm/loopfilter_arm.c', '<(libvpx_source)/vp8/common/arm/neon/bilinearpredict_neon.c', '<(libvpx_source)/vp8/common/arm/neon/copymem_neon.c', @@ -109,9 +91,6 @@ '<(libvpx_source)/vp8/decoder/onyxd_int.h', '<(libvpx_source)/vp8/decoder/threading.c', '<(libvpx_source)/vp8/decoder/treereader.h', - '<(libvpx_source)/vp8/encoder/arm/armv6/vp8_short_fdct4x4_armv6.asm', - '<(libvpx_source)/vp8/encoder/arm/armv6/walsh_v6.asm', - '<(libvpx_source)/vp8/encoder/arm/dct_arm.c', '<(libvpx_source)/vp8/encoder/arm/neon/denoising_neon.c', '<(libvpx_source)/vp8/encoder/arm/neon/fastquantizeb_neon.c', '<(libvpx_source)/vp8/encoder/arm/neon/shortfdct_neon.c', @@ -322,7 +301,6 @@ '<(libvpx_source)/vpx/vpx_integer.h', '<(libvpx_source)/vpx_dsp/add_noise.c', '<(libvpx_source)/vpx_dsp/arm/avg_neon.c', - '<(libvpx_source)/vpx_dsp/arm/bilinear_filter_media.asm', '<(libvpx_source)/vpx_dsp/arm/fwd_txfm_neon.c', '<(libvpx_source)/vpx_dsp/arm/hadamard_neon.c', '<(libvpx_source)/vpx_dsp/arm/idct16x16_1_add_neon.asm', @@ -342,16 +320,11 @@ '<(libvpx_source)/vpx_dsp/arm/loopfilter_mb_neon.asm', '<(libvpx_source)/vpx_dsp/arm/loopfilter_neon.c', '<(libvpx_source)/vpx_dsp/arm/sad4d_neon.c', - '<(libvpx_source)/vpx_dsp/arm/sad_media.asm', '<(libvpx_source)/vpx_dsp/arm/sad_neon.c', '<(libvpx_source)/vpx_dsp/arm/save_reg_neon.asm', - '<(libvpx_source)/vpx_dsp/arm/subpel_variance_media.c', '<(libvpx_source)/vpx_dsp/arm/subpel_variance_neon.c', '<(libvpx_source)/vpx_dsp/arm/subtract_neon.c', - '<(libvpx_source)/vpx_dsp/arm/variance_halfpixvar16x16_h_media.asm', - '<(libvpx_source)/vpx_dsp/arm/variance_halfpixvar16x16_hv_media.asm', - '<(libvpx_source)/vpx_dsp/arm/variance_halfpixvar16x16_v_media.asm', - '<(libvpx_source)/vpx_dsp/arm/variance_media.asm', + '<(libvpx_source)/vpx_dsp/arm/transpose_neon.h', '<(libvpx_source)/vpx_dsp/arm/variance_neon.c', '<(libvpx_source)/vpx_dsp/arm/vpx_convolve8_avg_neon_asm.asm', '<(libvpx_source)/vpx_dsp/arm/vpx_convolve8_neon_asm.asm',
diff --git a/third_party/libvpx/libvpx_srcs_arm_neon_cpu_detect.gypi b/third_party/libvpx/libvpx_srcs_arm_neon_cpu_detect.gypi index 53c6110..8a85f928 100644 --- a/third_party/libvpx/libvpx_srcs_arm_neon_cpu_detect.gypi +++ b/third_party/libvpx/libvpx_srcs_arm_neon_cpu_detect.gypi
@@ -7,24 +7,6 @@ 'sources': [ '<(libvpx_source)/vp8/common/alloccommon.c', '<(libvpx_source)/vp8/common/alloccommon.h', - '<(libvpx_source)/vp8/common/arm/armv6/bilinearfilter_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/copymem16x16_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/copymem8x4_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/copymem8x8_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/dc_only_idct_add_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/dequant_idct_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/dequantize_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/filter_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/idct_blk_v6.c', - '<(libvpx_source)/vp8/common/arm/armv6/idct_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/iwalsh_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/loopfilter_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/simpleloopfilter_v6.asm', - '<(libvpx_source)/vp8/common/arm/armv6/sixtappredict8x4_v6.asm', - '<(libvpx_source)/vp8/common/arm/bilinearfilter_arm.c', - '<(libvpx_source)/vp8/common/arm/bilinearfilter_arm.h', - '<(libvpx_source)/vp8/common/arm/dequantize_arm.c', - '<(libvpx_source)/vp8/common/arm/filter_arm.c', '<(libvpx_source)/vp8/common/arm/loopfilter_arm.c', '<(libvpx_source)/vp8/common/blockd.c', '<(libvpx_source)/vp8/common/blockd.h', @@ -94,9 +76,6 @@ '<(libvpx_source)/vp8/decoder/onyxd_int.h', '<(libvpx_source)/vp8/decoder/threading.c', '<(libvpx_source)/vp8/decoder/treereader.h', - '<(libvpx_source)/vp8/encoder/arm/armv6/vp8_short_fdct4x4_armv6.asm', - '<(libvpx_source)/vp8/encoder/arm/armv6/walsh_v6.asm', - '<(libvpx_source)/vp8/encoder/arm/dct_arm.c', '<(libvpx_source)/vp8/encoder/bitstream.c', '<(libvpx_source)/vp8/encoder/bitstream.h', '<(libvpx_source)/vp8/encoder/block.h', @@ -297,13 +276,7 @@ '<(libvpx_source)/vpx/vpx_image.h', '<(libvpx_source)/vpx/vpx_integer.h', '<(libvpx_source)/vpx_dsp/add_noise.c', - '<(libvpx_source)/vpx_dsp/arm/bilinear_filter_media.asm', - '<(libvpx_source)/vpx_dsp/arm/sad_media.asm', - '<(libvpx_source)/vpx_dsp/arm/subpel_variance_media.c', - '<(libvpx_source)/vpx_dsp/arm/variance_halfpixvar16x16_h_media.asm', - '<(libvpx_source)/vpx_dsp/arm/variance_halfpixvar16x16_hv_media.asm', - '<(libvpx_source)/vpx_dsp/arm/variance_halfpixvar16x16_v_media.asm', - '<(libvpx_source)/vpx_dsp/arm/variance_media.asm', + '<(libvpx_source)/vpx_dsp/arm/transpose_neon.h', '<(libvpx_source)/vpx_dsp/avg.c', '<(libvpx_source)/vpx_dsp/bitreader.c', '<(libvpx_source)/vpx_dsp/bitreader.h',
diff --git a/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vp8_rtcd.h b/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vp8_rtcd.h index 583d77d..0f9388d 100644 --- a/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vp8_rtcd.h +++ b/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vp8_rtcd.h
@@ -27,21 +27,17 @@ #endif void vp8_bilinear_predict16x16_c(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -void vp8_bilinear_predict16x16_armv6(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); void vp8_bilinear_predict16x16_neon(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); RTCD_EXTERN void (*vp8_bilinear_predict16x16)(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); void vp8_bilinear_predict4x4_c(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -void vp8_bilinear_predict4x4_armv6(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -#define vp8_bilinear_predict4x4 vp8_bilinear_predict4x4_armv6 +#define vp8_bilinear_predict4x4 vp8_bilinear_predict4x4_c void vp8_bilinear_predict8x4_c(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -void vp8_bilinear_predict8x4_armv6(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); void vp8_bilinear_predict8x4_neon(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); RTCD_EXTERN void (*vp8_bilinear_predict8x4)(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); void vp8_bilinear_predict8x8_c(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -void vp8_bilinear_predict8x8_armv6(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); void vp8_bilinear_predict8x8_neon(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); RTCD_EXTERN void (*vp8_bilinear_predict8x8)(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); @@ -61,22 +57,18 @@ #define vp8_clear_system_state vp8_clear_system_state_c void vp8_copy_mem16x16_c(unsigned char *src, int src_pitch, unsigned char *dst, int dst_pitch); -void vp8_copy_mem16x16_v6(unsigned char *src, int src_pitch, unsigned char *dst, int dst_pitch); void vp8_copy_mem16x16_neon(unsigned char *src, int src_pitch, unsigned char *dst, int dst_pitch); RTCD_EXTERN void (*vp8_copy_mem16x16)(unsigned char *src, int src_pitch, unsigned char *dst, int dst_pitch); void vp8_copy_mem8x4_c(unsigned char *src, int src_pitch, unsigned char *dst, int dst_pitch); -void vp8_copy_mem8x4_v6(unsigned char *src, int src_pitch, unsigned char *dst, int dst_pitch); void vp8_copy_mem8x4_neon(unsigned char *src, int src_pitch, unsigned char *dst, int dst_pitch); RTCD_EXTERN void (*vp8_copy_mem8x4)(unsigned char *src, int src_pitch, unsigned char *dst, int dst_pitch); void vp8_copy_mem8x8_c(unsigned char *src, int src_pitch, unsigned char *dst, int dst_pitch); -void vp8_copy_mem8x8_v6(unsigned char *src, int src_pitch, unsigned char *dst, int dst_pitch); void vp8_copy_mem8x8_neon(unsigned char *src, int src_pitch, unsigned char *dst, int dst_pitch); RTCD_EXTERN void (*vp8_copy_mem8x8)(unsigned char *src, int src_pitch, unsigned char *dst, int dst_pitch); void vp8_dc_only_idct_add_c(short input, unsigned char *pred, int pred_stride, unsigned char *dst, int dst_stride); -void vp8_dc_only_idct_add_v6(short input, unsigned char *pred, int pred_stride, unsigned char *dst, int dst_stride); void vp8_dc_only_idct_add_neon(short input, unsigned char *pred, int pred_stride, unsigned char *dst, int dst_stride); RTCD_EXTERN void (*vp8_dc_only_idct_add)(short input, unsigned char *pred, int pred_stride, unsigned char *dst, int dst_stride); @@ -89,22 +81,18 @@ RTCD_EXTERN int (*vp8_denoiser_filter_uv)(unsigned char *mc_running_avg, int mc_avg_stride, unsigned char *running_avg, int avg_stride, unsigned char *sig, int sig_stride, unsigned int motion_magnitude, int increase_denoising); void vp8_dequant_idct_add_c(short *input, short *dq, unsigned char *output, int stride); -void vp8_dequant_idct_add_v6(short *input, short *dq, unsigned char *output, int stride); void vp8_dequant_idct_add_neon(short *input, short *dq, unsigned char *output, int stride); RTCD_EXTERN void (*vp8_dequant_idct_add)(short *input, short *dq, unsigned char *output, int stride); void vp8_dequant_idct_add_uv_block_c(short *q, short *dq, unsigned char *dst_u, unsigned char *dst_v, int stride, char *eobs); -void vp8_dequant_idct_add_uv_block_v6(short *q, short *dq, unsigned char *dst_u, unsigned char *dst_v, int stride, char *eobs); void vp8_dequant_idct_add_uv_block_neon(short *q, short *dq, unsigned char *dst_u, unsigned char *dst_v, int stride, char *eobs); RTCD_EXTERN void (*vp8_dequant_idct_add_uv_block)(short *q, short *dq, unsigned char *dst_u, unsigned char *dst_v, int stride, char *eobs); void vp8_dequant_idct_add_y_block_c(short *q, short *dq, unsigned char *dst, int stride, char *eobs); -void vp8_dequant_idct_add_y_block_v6(short *q, short *dq, unsigned char *dst, int stride, char *eobs); void vp8_dequant_idct_add_y_block_neon(short *q, short *dq, unsigned char *dst, int stride, char *eobs); RTCD_EXTERN void (*vp8_dequant_idct_add_y_block)(short *q, short *dq, unsigned char *dst, int stride, char *eobs); void vp8_dequantize_b_c(struct blockd*, short *dqc); -void vp8_dequantize_b_v6(struct blockd*, short *dqc); void vp8_dequantize_b_neon(struct blockd*, short *dqc); RTCD_EXTERN void (*vp8_dequantize_b)(struct blockd*, short *dqc); @@ -128,42 +116,34 @@ #define vp8_full_search_sad vp8_full_search_sad_c void vp8_loop_filter_bh_c(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); -void vp8_loop_filter_bh_armv6(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); void vp8_loop_filter_bh_neon(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); RTCD_EXTERN void (*vp8_loop_filter_bh)(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); void vp8_loop_filter_bv_c(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); -void vp8_loop_filter_bv_armv6(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); void vp8_loop_filter_bv_neon(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); RTCD_EXTERN void (*vp8_loop_filter_bv)(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); void vp8_loop_filter_mbh_c(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); -void vp8_loop_filter_mbh_armv6(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); void vp8_loop_filter_mbh_neon(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); RTCD_EXTERN void (*vp8_loop_filter_mbh)(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); void vp8_loop_filter_mbv_c(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); -void vp8_loop_filter_mbv_armv6(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); void vp8_loop_filter_mbv_neon(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); RTCD_EXTERN void (*vp8_loop_filter_mbv)(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); void vp8_loop_filter_bhs_c(unsigned char *y, int ystride, const unsigned char *blimit); -void vp8_loop_filter_bhs_armv6(unsigned char *y, int ystride, const unsigned char *blimit); void vp8_loop_filter_bhs_neon(unsigned char *y, int ystride, const unsigned char *blimit); RTCD_EXTERN void (*vp8_loop_filter_simple_bh)(unsigned char *y, int ystride, const unsigned char *blimit); void vp8_loop_filter_bvs_c(unsigned char *y, int ystride, const unsigned char *blimit); -void vp8_loop_filter_bvs_armv6(unsigned char *y, int ystride, const unsigned char *blimit); void vp8_loop_filter_bvs_neon(unsigned char *y, int ystride, const unsigned char *blimit); RTCD_EXTERN void (*vp8_loop_filter_simple_bv)(unsigned char *y, int ystride, const unsigned char *blimit); void vp8_loop_filter_simple_horizontal_edge_c(unsigned char *y, int ystride, const unsigned char *blimit); -void vp8_loop_filter_simple_horizontal_edge_armv6(unsigned char *y, int ystride, const unsigned char *blimit); void vp8_loop_filter_mbhs_neon(unsigned char *y, int ystride, const unsigned char *blimit); RTCD_EXTERN void (*vp8_loop_filter_simple_mbh)(unsigned char *y, int ystride, const unsigned char *blimit); void vp8_loop_filter_simple_vertical_edge_c(unsigned char *y, int ystride, const unsigned char *blimit); -void vp8_loop_filter_simple_vertical_edge_armv6(unsigned char *y, int ystride, const unsigned char *blimit); void vp8_loop_filter_mbvs_neon(unsigned char *y, int ystride, const unsigned char *blimit); RTCD_EXTERN void (*vp8_loop_filter_simple_mbv)(unsigned char *y, int ystride, const unsigned char *blimit); @@ -180,22 +160,18 @@ #define vp8_regular_quantize_b vp8_regular_quantize_b_c void vp8_short_fdct4x4_c(short *input, short *output, int pitch); -void vp8_short_fdct4x4_armv6(short *input, short *output, int pitch); void vp8_short_fdct4x4_neon(short *input, short *output, int pitch); RTCD_EXTERN void (*vp8_short_fdct4x4)(short *input, short *output, int pitch); void vp8_short_fdct8x4_c(short *input, short *output, int pitch); -void vp8_short_fdct8x4_armv6(short *input, short *output, int pitch); void vp8_short_fdct8x4_neon(short *input, short *output, int pitch); RTCD_EXTERN void (*vp8_short_fdct8x4)(short *input, short *output, int pitch); void vp8_short_idct4x4llm_c(short *input, unsigned char *pred, int pitch, unsigned char *dst, int dst_stride); -void vp8_short_idct4x4llm_v6_dual(short *input, unsigned char *pred, int pitch, unsigned char *dst, int dst_stride); void vp8_short_idct4x4llm_neon(short *input, unsigned char *pred, int pitch, unsigned char *dst, int dst_stride); RTCD_EXTERN void (*vp8_short_idct4x4llm)(short *input, unsigned char *pred, int pitch, unsigned char *dst, int dst_stride); void vp8_short_inv_walsh4x4_c(short *input, short *output); -void vp8_short_inv_walsh4x4_v6(short *input, short *output); void vp8_short_inv_walsh4x4_neon(short *input, short *output); RTCD_EXTERN void (*vp8_short_inv_walsh4x4)(short *input, short *output); @@ -203,26 +179,21 @@ #define vp8_short_inv_walsh4x4_1 vp8_short_inv_walsh4x4_1_c void vp8_short_walsh4x4_c(short *input, short *output, int pitch); -void vp8_short_walsh4x4_armv6(short *input, short *output, int pitch); void vp8_short_walsh4x4_neon(short *input, short *output, int pitch); RTCD_EXTERN void (*vp8_short_walsh4x4)(short *input, short *output, int pitch); void vp8_sixtap_predict16x16_c(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -void vp8_sixtap_predict16x16_armv6(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); void vp8_sixtap_predict16x16_neon(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); RTCD_EXTERN void (*vp8_sixtap_predict16x16)(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); void vp8_sixtap_predict4x4_c(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -void vp8_sixtap_predict4x4_armv6(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -#define vp8_sixtap_predict4x4 vp8_sixtap_predict4x4_armv6 +#define vp8_sixtap_predict4x4 vp8_sixtap_predict4x4_c void vp8_sixtap_predict8x4_c(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -void vp8_sixtap_predict8x4_armv6(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); void vp8_sixtap_predict8x4_neon(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); RTCD_EXTERN void (*vp8_sixtap_predict8x4)(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); void vp8_sixtap_predict8x8_c(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -void vp8_sixtap_predict8x8_armv6(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); void vp8_sixtap_predict8x8_neon(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); RTCD_EXTERN void (*vp8_sixtap_predict8x8)(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); @@ -238,65 +209,65 @@ (void)flags; - vp8_bilinear_predict16x16 = vp8_bilinear_predict16x16_armv6; + vp8_bilinear_predict16x16 = vp8_bilinear_predict16x16_c; if (flags & HAS_NEON) vp8_bilinear_predict16x16 = vp8_bilinear_predict16x16_neon; - vp8_bilinear_predict8x4 = vp8_bilinear_predict8x4_armv6; + vp8_bilinear_predict8x4 = vp8_bilinear_predict8x4_c; if (flags & HAS_NEON) vp8_bilinear_predict8x4 = vp8_bilinear_predict8x4_neon; - vp8_bilinear_predict8x8 = vp8_bilinear_predict8x8_armv6; + vp8_bilinear_predict8x8 = vp8_bilinear_predict8x8_c; if (flags & HAS_NEON) vp8_bilinear_predict8x8 = vp8_bilinear_predict8x8_neon; - vp8_copy_mem16x16 = vp8_copy_mem16x16_v6; + vp8_copy_mem16x16 = vp8_copy_mem16x16_c; if (flags & HAS_NEON) vp8_copy_mem16x16 = vp8_copy_mem16x16_neon; - vp8_copy_mem8x4 = vp8_copy_mem8x4_v6; + vp8_copy_mem8x4 = vp8_copy_mem8x4_c; if (flags & HAS_NEON) vp8_copy_mem8x4 = vp8_copy_mem8x4_neon; - vp8_copy_mem8x8 = vp8_copy_mem8x8_v6; + vp8_copy_mem8x8 = vp8_copy_mem8x8_c; if (flags & HAS_NEON) vp8_copy_mem8x8 = vp8_copy_mem8x8_neon; - vp8_dc_only_idct_add = vp8_dc_only_idct_add_v6; + vp8_dc_only_idct_add = vp8_dc_only_idct_add_c; if (flags & HAS_NEON) vp8_dc_only_idct_add = vp8_dc_only_idct_add_neon; vp8_denoiser_filter = vp8_denoiser_filter_c; if (flags & HAS_NEON) vp8_denoiser_filter = vp8_denoiser_filter_neon; vp8_denoiser_filter_uv = vp8_denoiser_filter_uv_c; if (flags & HAS_NEON) vp8_denoiser_filter_uv = vp8_denoiser_filter_uv_neon; - vp8_dequant_idct_add = vp8_dequant_idct_add_v6; + vp8_dequant_idct_add = vp8_dequant_idct_add_c; if (flags & HAS_NEON) vp8_dequant_idct_add = vp8_dequant_idct_add_neon; - vp8_dequant_idct_add_uv_block = vp8_dequant_idct_add_uv_block_v6; + vp8_dequant_idct_add_uv_block = vp8_dequant_idct_add_uv_block_c; if (flags & HAS_NEON) vp8_dequant_idct_add_uv_block = vp8_dequant_idct_add_uv_block_neon; - vp8_dequant_idct_add_y_block = vp8_dequant_idct_add_y_block_v6; + vp8_dequant_idct_add_y_block = vp8_dequant_idct_add_y_block_c; if (flags & HAS_NEON) vp8_dequant_idct_add_y_block = vp8_dequant_idct_add_y_block_neon; - vp8_dequantize_b = vp8_dequantize_b_v6; + vp8_dequantize_b = vp8_dequantize_b_c; if (flags & HAS_NEON) vp8_dequantize_b = vp8_dequantize_b_neon; vp8_fast_quantize_b = vp8_fast_quantize_b_c; if (flags & HAS_NEON) vp8_fast_quantize_b = vp8_fast_quantize_b_neon; - vp8_loop_filter_bh = vp8_loop_filter_bh_armv6; + vp8_loop_filter_bh = vp8_loop_filter_bh_c; if (flags & HAS_NEON) vp8_loop_filter_bh = vp8_loop_filter_bh_neon; - vp8_loop_filter_bv = vp8_loop_filter_bv_armv6; + vp8_loop_filter_bv = vp8_loop_filter_bv_c; if (flags & HAS_NEON) vp8_loop_filter_bv = vp8_loop_filter_bv_neon; - vp8_loop_filter_mbh = vp8_loop_filter_mbh_armv6; + vp8_loop_filter_mbh = vp8_loop_filter_mbh_c; if (flags & HAS_NEON) vp8_loop_filter_mbh = vp8_loop_filter_mbh_neon; - vp8_loop_filter_mbv = vp8_loop_filter_mbv_armv6; + vp8_loop_filter_mbv = vp8_loop_filter_mbv_c; if (flags & HAS_NEON) vp8_loop_filter_mbv = vp8_loop_filter_mbv_neon; - vp8_loop_filter_simple_bh = vp8_loop_filter_bhs_armv6; + vp8_loop_filter_simple_bh = vp8_loop_filter_bhs_c; if (flags & HAS_NEON) vp8_loop_filter_simple_bh = vp8_loop_filter_bhs_neon; - vp8_loop_filter_simple_bv = vp8_loop_filter_bvs_armv6; + vp8_loop_filter_simple_bv = vp8_loop_filter_bvs_c; if (flags & HAS_NEON) vp8_loop_filter_simple_bv = vp8_loop_filter_bvs_neon; - vp8_loop_filter_simple_mbh = vp8_loop_filter_simple_horizontal_edge_armv6; + vp8_loop_filter_simple_mbh = vp8_loop_filter_simple_horizontal_edge_c; if (flags & HAS_NEON) vp8_loop_filter_simple_mbh = vp8_loop_filter_mbhs_neon; - vp8_loop_filter_simple_mbv = vp8_loop_filter_simple_vertical_edge_armv6; + vp8_loop_filter_simple_mbv = vp8_loop_filter_simple_vertical_edge_c; if (flags & HAS_NEON) vp8_loop_filter_simple_mbv = vp8_loop_filter_mbvs_neon; - vp8_short_fdct4x4 = vp8_short_fdct4x4_armv6; + vp8_short_fdct4x4 = vp8_short_fdct4x4_c; if (flags & HAS_NEON) vp8_short_fdct4x4 = vp8_short_fdct4x4_neon; - vp8_short_fdct8x4 = vp8_short_fdct8x4_armv6; + vp8_short_fdct8x4 = vp8_short_fdct8x4_c; if (flags & HAS_NEON) vp8_short_fdct8x4 = vp8_short_fdct8x4_neon; - vp8_short_idct4x4llm = vp8_short_idct4x4llm_v6_dual; + vp8_short_idct4x4llm = vp8_short_idct4x4llm_c; if (flags & HAS_NEON) vp8_short_idct4x4llm = vp8_short_idct4x4llm_neon; - vp8_short_inv_walsh4x4 = vp8_short_inv_walsh4x4_v6; + vp8_short_inv_walsh4x4 = vp8_short_inv_walsh4x4_c; if (flags & HAS_NEON) vp8_short_inv_walsh4x4 = vp8_short_inv_walsh4x4_neon; - vp8_short_walsh4x4 = vp8_short_walsh4x4_armv6; + vp8_short_walsh4x4 = vp8_short_walsh4x4_c; if (flags & HAS_NEON) vp8_short_walsh4x4 = vp8_short_walsh4x4_neon; - vp8_sixtap_predict16x16 = vp8_sixtap_predict16x16_armv6; + vp8_sixtap_predict16x16 = vp8_sixtap_predict16x16_c; if (flags & HAS_NEON) vp8_sixtap_predict16x16 = vp8_sixtap_predict16x16_neon; - vp8_sixtap_predict8x4 = vp8_sixtap_predict8x4_armv6; + vp8_sixtap_predict8x4 = vp8_sixtap_predict8x4_c; if (flags & HAS_NEON) vp8_sixtap_predict8x4 = vp8_sixtap_predict8x4_neon; - vp8_sixtap_predict8x8 = vp8_sixtap_predict8x8_armv6; + vp8_sixtap_predict8x8 = vp8_sixtap_predict8x8_c; if (flags & HAS_NEON) vp8_sixtap_predict8x8 = vp8_sixtap_predict8x8_neon; } #endif
diff --git a/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_config.asm b/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_config.asm index 234a428..ce5963f 100644 --- a/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_config.asm +++ b/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_config.asm
@@ -5,8 +5,6 @@ .equ ARCH_MIPS , 0 .equ ARCH_X86 , 0 .equ ARCH_X86_64 , 0 -.equ HAVE_EDSP , 0 -.equ HAVE_MEDIA , 1 .equ HAVE_NEON , 1 .equ HAVE_NEON_ASM , 1 .equ HAVE_MIPS32 , 0
diff --git a/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_config.h b/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_config.h index 0fe7471b..8c6b8050 100644 --- a/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_config.h +++ b/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_config.h
@@ -14,8 +14,6 @@ #define ARCH_MIPS 0 #define ARCH_X86 0 #define ARCH_X86_64 0 -#define HAVE_EDSP 0 -#define HAVE_MEDIA 1 #define HAVE_NEON 1 #define HAVE_NEON_ASM 1 #define HAVE_MIPS32 0
diff --git a/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_dsp_rtcd.h index 36d911c..f0854c5 100644 --- a/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_dsp_rtcd.h +++ b/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_dsp_rtcd.h
@@ -433,7 +433,6 @@ RTCD_EXTERN void (*vpx_minmax_8x8)(const uint8_t *s, int p, const uint8_t *d, int dp, int *min, int *max); unsigned int vpx_mse16x16_c(const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int recon_stride, unsigned int *sse); -unsigned int vpx_mse16x16_media(const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int recon_stride, unsigned int *sse); unsigned int vpx_mse16x16_neon(const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int recon_stride, unsigned int *sse); RTCD_EXTERN unsigned int (*vpx_mse16x16)(const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int recon_stride, unsigned int *sse); @@ -459,7 +458,6 @@ #define vpx_quantize_b_32x32 vpx_quantize_b_32x32_c unsigned int vpx_sad16x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride); -unsigned int vpx_sad16x16_media(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride); unsigned int vpx_sad16x16_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride); RTCD_EXTERN unsigned int (*vpx_sad16x16)(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride); @@ -696,7 +694,6 @@ #define vpx_sub_pixel_avg_variance8x8 vpx_sub_pixel_avg_variance8x8_c uint32_t vpx_sub_pixel_variance16x16_c(const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse); -uint32_t vpx_sub_pixel_variance16x16_media(const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse); uint32_t vpx_sub_pixel_variance16x16_neon(const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse); RTCD_EXTERN uint32_t (*vpx_sub_pixel_variance16x16)(const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse); @@ -736,7 +733,6 @@ #define vpx_sub_pixel_variance8x4 vpx_sub_pixel_variance8x4_c uint32_t vpx_sub_pixel_variance8x8_c(const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse); -uint32_t vpx_sub_pixel_variance8x8_media(const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse); uint32_t vpx_sub_pixel_variance8x8_neon(const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse); RTCD_EXTERN uint32_t (*vpx_sub_pixel_variance8x8)(const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse); @@ -780,7 +776,6 @@ RTCD_EXTERN void (*vpx_v_predictor_8x8)(uint8_t *dst, ptrdiff_t y_stride, const uint8_t *above, const uint8_t *left); unsigned int vpx_variance16x16_c(const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse); -unsigned int vpx_variance16x16_media(const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse); unsigned int vpx_variance16x16_neon(const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse); RTCD_EXTERN unsigned int (*vpx_variance16x16)(const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse); @@ -824,21 +819,17 @@ #define vpx_variance8x4 vpx_variance8x4_c unsigned int vpx_variance8x8_c(const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse); -unsigned int vpx_variance8x8_media(const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse); unsigned int vpx_variance8x8_neon(const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse); RTCD_EXTERN unsigned int (*vpx_variance8x8)(const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse); uint32_t vpx_variance_halfpixvar16x16_h_c(const unsigned char *src_ptr, int source_stride, const unsigned char *ref_ptr, int ref_stride, uint32_t *sse); -uint32_t vpx_variance_halfpixvar16x16_h_media(const unsigned char *src_ptr, int source_stride, const unsigned char *ref_ptr, int ref_stride, uint32_t *sse); -#define vpx_variance_halfpixvar16x16_h vpx_variance_halfpixvar16x16_h_media +#define vpx_variance_halfpixvar16x16_h vpx_variance_halfpixvar16x16_h_c uint32_t vpx_variance_halfpixvar16x16_hv_c(const unsigned char *src_ptr, int source_stride, const unsigned char *ref_ptr, int ref_stride, uint32_t *sse); -uint32_t vpx_variance_halfpixvar16x16_hv_media(const unsigned char *src_ptr, int source_stride, const unsigned char *ref_ptr, int ref_stride, uint32_t *sse); -#define vpx_variance_halfpixvar16x16_hv vpx_variance_halfpixvar16x16_hv_media +#define vpx_variance_halfpixvar16x16_hv vpx_variance_halfpixvar16x16_hv_c uint32_t vpx_variance_halfpixvar16x16_v_c(const unsigned char *src_ptr, int source_stride, const unsigned char *ref_ptr, int ref_stride, uint32_t *sse); -uint32_t vpx_variance_halfpixvar16x16_v_media(const unsigned char *src_ptr, int source_stride, const unsigned char *ref_ptr, int ref_stride, uint32_t *sse); -#define vpx_variance_halfpixvar16x16_v vpx_variance_halfpixvar16x16_v_media +#define vpx_variance_halfpixvar16x16_v vpx_variance_halfpixvar16x16_v_c void vpx_ve_predictor_4x4_c(uint8_t *dst, ptrdiff_t y_stride, const uint8_t *above, const uint8_t *left); #define vpx_ve_predictor_4x4 vpx_ve_predictor_4x4_c @@ -995,9 +986,9 @@ if (flags & HAS_NEON) vpx_lpf_vertical_8_dual = vpx_lpf_vertical_8_dual_neon; vpx_minmax_8x8 = vpx_minmax_8x8_c; if (flags & HAS_NEON) vpx_minmax_8x8 = vpx_minmax_8x8_neon; - vpx_mse16x16 = vpx_mse16x16_media; + vpx_mse16x16 = vpx_mse16x16_c; if (flags & HAS_NEON) vpx_mse16x16 = vpx_mse16x16_neon; - vpx_sad16x16 = vpx_sad16x16_media; + vpx_sad16x16 = vpx_sad16x16_c; if (flags & HAS_NEON) vpx_sad16x16 = vpx_sad16x16_neon; vpx_sad16x16x4d = vpx_sad16x16x4d_c; if (flags & HAS_NEON) vpx_sad16x16x4d = vpx_sad16x16x4d_neon; @@ -1019,13 +1010,13 @@ if (flags & HAS_NEON) vpx_sad8x8 = vpx_sad8x8_neon; vpx_satd = vpx_satd_c; if (flags & HAS_NEON) vpx_satd = vpx_satd_neon; - vpx_sub_pixel_variance16x16 = vpx_sub_pixel_variance16x16_media; + vpx_sub_pixel_variance16x16 = vpx_sub_pixel_variance16x16_c; if (flags & HAS_NEON) vpx_sub_pixel_variance16x16 = vpx_sub_pixel_variance16x16_neon; vpx_sub_pixel_variance32x32 = vpx_sub_pixel_variance32x32_c; if (flags & HAS_NEON) vpx_sub_pixel_variance32x32 = vpx_sub_pixel_variance32x32_neon; vpx_sub_pixel_variance64x64 = vpx_sub_pixel_variance64x64_c; if (flags & HAS_NEON) vpx_sub_pixel_variance64x64 = vpx_sub_pixel_variance64x64_neon; - vpx_sub_pixel_variance8x8 = vpx_sub_pixel_variance8x8_media; + vpx_sub_pixel_variance8x8 = vpx_sub_pixel_variance8x8_c; if (flags & HAS_NEON) vpx_sub_pixel_variance8x8 = vpx_sub_pixel_variance8x8_neon; vpx_subtract_block = vpx_subtract_block_c; if (flags & HAS_NEON) vpx_subtract_block = vpx_subtract_block_neon; @@ -1045,7 +1036,7 @@ if (flags & HAS_NEON) vpx_v_predictor_4x4 = vpx_v_predictor_4x4_neon; vpx_v_predictor_8x8 = vpx_v_predictor_8x8_c; if (flags & HAS_NEON) vpx_v_predictor_8x8 = vpx_v_predictor_8x8_neon; - vpx_variance16x16 = vpx_variance16x16_media; + vpx_variance16x16 = vpx_variance16x16_c; if (flags & HAS_NEON) vpx_variance16x16 = vpx_variance16x16_neon; vpx_variance16x8 = vpx_variance16x8_c; if (flags & HAS_NEON) vpx_variance16x8 = vpx_variance16x8_neon; @@ -1059,7 +1050,7 @@ if (flags & HAS_NEON) vpx_variance64x64 = vpx_variance64x64_neon; vpx_variance8x16 = vpx_variance8x16_c; if (flags & HAS_NEON) vpx_variance8x16 = vpx_variance8x16_neon; - vpx_variance8x8 = vpx_variance8x8_media; + vpx_variance8x8 = vpx_variance8x8_c; if (flags & HAS_NEON) vpx_variance8x8 = vpx_variance8x8_neon; vpx_vector_var = vpx_vector_var_c; if (flags & HAS_NEON) vpx_vector_var = vpx_vector_var_neon;
diff --git a/third_party/libvpx/source/config/linux/arm-neon/vp8_rtcd.h b/third_party/libvpx/source/config/linux/arm-neon/vp8_rtcd.h index d439ee27..e02f0e2 100644 --- a/third_party/libvpx/source/config/linux/arm-neon/vp8_rtcd.h +++ b/third_party/libvpx/source/config/linux/arm-neon/vp8_rtcd.h
@@ -27,21 +27,17 @@ #endif void vp8_bilinear_predict16x16_c(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -void vp8_bilinear_predict16x16_armv6(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); void vp8_bilinear_predict16x16_neon(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); #define vp8_bilinear_predict16x16 vp8_bilinear_predict16x16_neon void vp8_bilinear_predict4x4_c(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -void vp8_bilinear_predict4x4_armv6(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -#define vp8_bilinear_predict4x4 vp8_bilinear_predict4x4_armv6 +#define vp8_bilinear_predict4x4 vp8_bilinear_predict4x4_c void vp8_bilinear_predict8x4_c(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -void vp8_bilinear_predict8x4_armv6(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); void vp8_bilinear_predict8x4_neon(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); #define vp8_bilinear_predict8x4 vp8_bilinear_predict8x4_neon void vp8_bilinear_predict8x8_c(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -void vp8_bilinear_predict8x8_armv6(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); void vp8_bilinear_predict8x8_neon(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); #define vp8_bilinear_predict8x8 vp8_bilinear_predict8x8_neon @@ -61,22 +57,18 @@ #define vp8_clear_system_state vp8_clear_system_state_c void vp8_copy_mem16x16_c(unsigned char *src, int src_pitch, unsigned char *dst, int dst_pitch); -void vp8_copy_mem16x16_v6(unsigned char *src, int src_pitch, unsigned char *dst, int dst_pitch); void vp8_copy_mem16x16_neon(unsigned char *src, int src_pitch, unsigned char *dst, int dst_pitch); #define vp8_copy_mem16x16 vp8_copy_mem16x16_neon void vp8_copy_mem8x4_c(unsigned char *src, int src_pitch, unsigned char *dst, int dst_pitch); -void vp8_copy_mem8x4_v6(unsigned char *src, int src_pitch, unsigned char *dst, int dst_pitch); void vp8_copy_mem8x4_neon(unsigned char *src, int src_pitch, unsigned char *dst, int dst_pitch); #define vp8_copy_mem8x4 vp8_copy_mem8x4_neon void vp8_copy_mem8x8_c(unsigned char *src, int src_pitch, unsigned char *dst, int dst_pitch); -void vp8_copy_mem8x8_v6(unsigned char *src, int src_pitch, unsigned char *dst, int dst_pitch); void vp8_copy_mem8x8_neon(unsigned char *src, int src_pitch, unsigned char *dst, int dst_pitch); #define vp8_copy_mem8x8 vp8_copy_mem8x8_neon void vp8_dc_only_idct_add_c(short input, unsigned char *pred, int pred_stride, unsigned char *dst, int dst_stride); -void vp8_dc_only_idct_add_v6(short input, unsigned char *pred, int pred_stride, unsigned char *dst, int dst_stride); void vp8_dc_only_idct_add_neon(short input, unsigned char *pred, int pred_stride, unsigned char *dst, int dst_stride); #define vp8_dc_only_idct_add vp8_dc_only_idct_add_neon @@ -89,22 +81,18 @@ #define vp8_denoiser_filter_uv vp8_denoiser_filter_uv_neon void vp8_dequant_idct_add_c(short *input, short *dq, unsigned char *output, int stride); -void vp8_dequant_idct_add_v6(short *input, short *dq, unsigned char *output, int stride); void vp8_dequant_idct_add_neon(short *input, short *dq, unsigned char *output, int stride); #define vp8_dequant_idct_add vp8_dequant_idct_add_neon void vp8_dequant_idct_add_uv_block_c(short *q, short *dq, unsigned char *dst_u, unsigned char *dst_v, int stride, char *eobs); -void vp8_dequant_idct_add_uv_block_v6(short *q, short *dq, unsigned char *dst_u, unsigned char *dst_v, int stride, char *eobs); void vp8_dequant_idct_add_uv_block_neon(short *q, short *dq, unsigned char *dst_u, unsigned char *dst_v, int stride, char *eobs); #define vp8_dequant_idct_add_uv_block vp8_dequant_idct_add_uv_block_neon void vp8_dequant_idct_add_y_block_c(short *q, short *dq, unsigned char *dst, int stride, char *eobs); -void vp8_dequant_idct_add_y_block_v6(short *q, short *dq, unsigned char *dst, int stride, char *eobs); void vp8_dequant_idct_add_y_block_neon(short *q, short *dq, unsigned char *dst, int stride, char *eobs); #define vp8_dequant_idct_add_y_block vp8_dequant_idct_add_y_block_neon void vp8_dequantize_b_c(struct blockd*, short *dqc); -void vp8_dequantize_b_v6(struct blockd*, short *dqc); void vp8_dequantize_b_neon(struct blockd*, short *dqc); #define vp8_dequantize_b vp8_dequantize_b_neon @@ -128,42 +116,34 @@ #define vp8_full_search_sad vp8_full_search_sad_c void vp8_loop_filter_bh_c(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); -void vp8_loop_filter_bh_armv6(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); void vp8_loop_filter_bh_neon(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); #define vp8_loop_filter_bh vp8_loop_filter_bh_neon void vp8_loop_filter_bv_c(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); -void vp8_loop_filter_bv_armv6(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); void vp8_loop_filter_bv_neon(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); #define vp8_loop_filter_bv vp8_loop_filter_bv_neon void vp8_loop_filter_mbh_c(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); -void vp8_loop_filter_mbh_armv6(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); void vp8_loop_filter_mbh_neon(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); #define vp8_loop_filter_mbh vp8_loop_filter_mbh_neon void vp8_loop_filter_mbv_c(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); -void vp8_loop_filter_mbv_armv6(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); void vp8_loop_filter_mbv_neon(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); #define vp8_loop_filter_mbv vp8_loop_filter_mbv_neon void vp8_loop_filter_bhs_c(unsigned char *y, int ystride, const unsigned char *blimit); -void vp8_loop_filter_bhs_armv6(unsigned char *y, int ystride, const unsigned char *blimit); void vp8_loop_filter_bhs_neon(unsigned char *y, int ystride, const unsigned char *blimit); #define vp8_loop_filter_simple_bh vp8_loop_filter_bhs_neon void vp8_loop_filter_bvs_c(unsigned char *y, int ystride, const unsigned char *blimit); -void vp8_loop_filter_bvs_armv6(unsigned char *y, int ystride, const unsigned char *blimit); void vp8_loop_filter_bvs_neon(unsigned char *y, int ystride, const unsigned char *blimit); #define vp8_loop_filter_simple_bv vp8_loop_filter_bvs_neon void vp8_loop_filter_simple_horizontal_edge_c(unsigned char *y, int ystride, const unsigned char *blimit); -void vp8_loop_filter_simple_horizontal_edge_armv6(unsigned char *y, int ystride, const unsigned char *blimit); void vp8_loop_filter_mbhs_neon(unsigned char *y, int ystride, const unsigned char *blimit); #define vp8_loop_filter_simple_mbh vp8_loop_filter_mbhs_neon void vp8_loop_filter_simple_vertical_edge_c(unsigned char *y, int ystride, const unsigned char *blimit); -void vp8_loop_filter_simple_vertical_edge_armv6(unsigned char *y, int ystride, const unsigned char *blimit); void vp8_loop_filter_mbvs_neon(unsigned char *y, int ystride, const unsigned char *blimit); #define vp8_loop_filter_simple_mbv vp8_loop_filter_mbvs_neon @@ -180,22 +160,18 @@ #define vp8_regular_quantize_b vp8_regular_quantize_b_c void vp8_short_fdct4x4_c(short *input, short *output, int pitch); -void vp8_short_fdct4x4_armv6(short *input, short *output, int pitch); void vp8_short_fdct4x4_neon(short *input, short *output, int pitch); #define vp8_short_fdct4x4 vp8_short_fdct4x4_neon void vp8_short_fdct8x4_c(short *input, short *output, int pitch); -void vp8_short_fdct8x4_armv6(short *input, short *output, int pitch); void vp8_short_fdct8x4_neon(short *input, short *output, int pitch); #define vp8_short_fdct8x4 vp8_short_fdct8x4_neon void vp8_short_idct4x4llm_c(short *input, unsigned char *pred, int pitch, unsigned char *dst, int dst_stride); -void vp8_short_idct4x4llm_v6_dual(short *input, unsigned char *pred, int pitch, unsigned char *dst, int dst_stride); void vp8_short_idct4x4llm_neon(short *input, unsigned char *pred, int pitch, unsigned char *dst, int dst_stride); #define vp8_short_idct4x4llm vp8_short_idct4x4llm_neon void vp8_short_inv_walsh4x4_c(short *input, short *output); -void vp8_short_inv_walsh4x4_v6(short *input, short *output); void vp8_short_inv_walsh4x4_neon(short *input, short *output); #define vp8_short_inv_walsh4x4 vp8_short_inv_walsh4x4_neon @@ -203,26 +179,21 @@ #define vp8_short_inv_walsh4x4_1 vp8_short_inv_walsh4x4_1_c void vp8_short_walsh4x4_c(short *input, short *output, int pitch); -void vp8_short_walsh4x4_armv6(short *input, short *output, int pitch); void vp8_short_walsh4x4_neon(short *input, short *output, int pitch); #define vp8_short_walsh4x4 vp8_short_walsh4x4_neon void vp8_sixtap_predict16x16_c(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -void vp8_sixtap_predict16x16_armv6(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); void vp8_sixtap_predict16x16_neon(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); #define vp8_sixtap_predict16x16 vp8_sixtap_predict16x16_neon void vp8_sixtap_predict4x4_c(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -void vp8_sixtap_predict4x4_armv6(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -#define vp8_sixtap_predict4x4 vp8_sixtap_predict4x4_armv6 +#define vp8_sixtap_predict4x4 vp8_sixtap_predict4x4_c void vp8_sixtap_predict8x4_c(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -void vp8_sixtap_predict8x4_armv6(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); void vp8_sixtap_predict8x4_neon(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); #define vp8_sixtap_predict8x4 vp8_sixtap_predict8x4_neon void vp8_sixtap_predict8x8_c(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -void vp8_sixtap_predict8x8_armv6(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); void vp8_sixtap_predict8x8_neon(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); #define vp8_sixtap_predict8x8 vp8_sixtap_predict8x8_neon
diff --git a/third_party/libvpx/source/config/linux/arm-neon/vpx_config.asm b/third_party/libvpx/source/config/linux/arm-neon/vpx_config.asm index 8511a15..c61aebc 100644 --- a/third_party/libvpx/source/config/linux/arm-neon/vpx_config.asm +++ b/third_party/libvpx/source/config/linux/arm-neon/vpx_config.asm
@@ -5,8 +5,6 @@ .equ ARCH_MIPS , 0 .equ ARCH_X86 , 0 .equ ARCH_X86_64 , 0 -.equ HAVE_EDSP , 0 -.equ HAVE_MEDIA , 1 .equ HAVE_NEON , 1 .equ HAVE_NEON_ASM , 1 .equ HAVE_MIPS32 , 0
diff --git a/third_party/libvpx/source/config/linux/arm-neon/vpx_config.h b/third_party/libvpx/source/config/linux/arm-neon/vpx_config.h index 6c6eaf0..67bd10fc 100644 --- a/third_party/libvpx/source/config/linux/arm-neon/vpx_config.h +++ b/third_party/libvpx/source/config/linux/arm-neon/vpx_config.h
@@ -14,8 +14,6 @@ #define ARCH_MIPS 0 #define ARCH_X86 0 #define ARCH_X86_64 0 -#define HAVE_EDSP 0 -#define HAVE_MEDIA 1 #define HAVE_NEON 1 #define HAVE_NEON_ASM 1 #define HAVE_MIPS32 0
diff --git a/third_party/libvpx/source/config/linux/arm-neon/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/arm-neon/vpx_dsp_rtcd.h index c39f1463..1a47370 100644 --- a/third_party/libvpx/source/config/linux/arm-neon/vpx_dsp_rtcd.h +++ b/third_party/libvpx/source/config/linux/arm-neon/vpx_dsp_rtcd.h
@@ -433,7 +433,6 @@ #define vpx_minmax_8x8 vpx_minmax_8x8_neon unsigned int vpx_mse16x16_c(const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int recon_stride, unsigned int *sse); -unsigned int vpx_mse16x16_media(const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int recon_stride, unsigned int *sse); unsigned int vpx_mse16x16_neon(const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int recon_stride, unsigned int *sse); #define vpx_mse16x16 vpx_mse16x16_neon @@ -459,7 +458,6 @@ #define vpx_quantize_b_32x32 vpx_quantize_b_32x32_c unsigned int vpx_sad16x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride); -unsigned int vpx_sad16x16_media(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride); unsigned int vpx_sad16x16_neon(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride); #define vpx_sad16x16 vpx_sad16x16_neon @@ -696,7 +694,6 @@ #define vpx_sub_pixel_avg_variance8x8 vpx_sub_pixel_avg_variance8x8_c uint32_t vpx_sub_pixel_variance16x16_c(const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse); -uint32_t vpx_sub_pixel_variance16x16_media(const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse); uint32_t vpx_sub_pixel_variance16x16_neon(const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse); #define vpx_sub_pixel_variance16x16 vpx_sub_pixel_variance16x16_neon @@ -736,7 +733,6 @@ #define vpx_sub_pixel_variance8x4 vpx_sub_pixel_variance8x4_c uint32_t vpx_sub_pixel_variance8x8_c(const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse); -uint32_t vpx_sub_pixel_variance8x8_media(const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse); uint32_t vpx_sub_pixel_variance8x8_neon(const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse); #define vpx_sub_pixel_variance8x8 vpx_sub_pixel_variance8x8_neon @@ -780,7 +776,6 @@ #define vpx_v_predictor_8x8 vpx_v_predictor_8x8_neon unsigned int vpx_variance16x16_c(const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse); -unsigned int vpx_variance16x16_media(const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse); unsigned int vpx_variance16x16_neon(const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse); #define vpx_variance16x16 vpx_variance16x16_neon @@ -824,21 +819,17 @@ #define vpx_variance8x4 vpx_variance8x4_c unsigned int vpx_variance8x8_c(const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse); -unsigned int vpx_variance8x8_media(const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse); unsigned int vpx_variance8x8_neon(const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse); #define vpx_variance8x8 vpx_variance8x8_neon uint32_t vpx_variance_halfpixvar16x16_h_c(const unsigned char *src_ptr, int source_stride, const unsigned char *ref_ptr, int ref_stride, uint32_t *sse); -uint32_t vpx_variance_halfpixvar16x16_h_media(const unsigned char *src_ptr, int source_stride, const unsigned char *ref_ptr, int ref_stride, uint32_t *sse); -#define vpx_variance_halfpixvar16x16_h vpx_variance_halfpixvar16x16_h_media +#define vpx_variance_halfpixvar16x16_h vpx_variance_halfpixvar16x16_h_c uint32_t vpx_variance_halfpixvar16x16_hv_c(const unsigned char *src_ptr, int source_stride, const unsigned char *ref_ptr, int ref_stride, uint32_t *sse); -uint32_t vpx_variance_halfpixvar16x16_hv_media(const unsigned char *src_ptr, int source_stride, const unsigned char *ref_ptr, int ref_stride, uint32_t *sse); -#define vpx_variance_halfpixvar16x16_hv vpx_variance_halfpixvar16x16_hv_media +#define vpx_variance_halfpixvar16x16_hv vpx_variance_halfpixvar16x16_hv_c uint32_t vpx_variance_halfpixvar16x16_v_c(const unsigned char *src_ptr, int source_stride, const unsigned char *ref_ptr, int ref_stride, uint32_t *sse); -uint32_t vpx_variance_halfpixvar16x16_v_media(const unsigned char *src_ptr, int source_stride, const unsigned char *ref_ptr, int ref_stride, uint32_t *sse); -#define vpx_variance_halfpixvar16x16_v vpx_variance_halfpixvar16x16_v_media +#define vpx_variance_halfpixvar16x16_v vpx_variance_halfpixvar16x16_v_c void vpx_ve_predictor_4x4_c(uint8_t *dst, ptrdiff_t y_stride, const uint8_t *above, const uint8_t *left); #define vpx_ve_predictor_4x4 vpx_ve_predictor_4x4_c
diff --git a/third_party/libvpx/source/config/linux/arm/vp8_rtcd.h b/third_party/libvpx/source/config/linux/arm/vp8_rtcd.h index 1be5a1a..ca692f7e 100644 --- a/third_party/libvpx/source/config/linux/arm/vp8_rtcd.h +++ b/third_party/libvpx/source/config/linux/arm/vp8_rtcd.h
@@ -27,20 +27,16 @@ #endif void vp8_bilinear_predict16x16_c(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -void vp8_bilinear_predict16x16_armv6(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -#define vp8_bilinear_predict16x16 vp8_bilinear_predict16x16_armv6 +#define vp8_bilinear_predict16x16 vp8_bilinear_predict16x16_c void vp8_bilinear_predict4x4_c(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -void vp8_bilinear_predict4x4_armv6(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -#define vp8_bilinear_predict4x4 vp8_bilinear_predict4x4_armv6 +#define vp8_bilinear_predict4x4 vp8_bilinear_predict4x4_c void vp8_bilinear_predict8x4_c(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -void vp8_bilinear_predict8x4_armv6(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -#define vp8_bilinear_predict8x4 vp8_bilinear_predict8x4_armv6 +#define vp8_bilinear_predict8x4 vp8_bilinear_predict8x4_c void vp8_bilinear_predict8x8_c(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -void vp8_bilinear_predict8x8_armv6(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -#define vp8_bilinear_predict8x8 vp8_bilinear_predict8x8_armv6 +#define vp8_bilinear_predict8x8 vp8_bilinear_predict8x8_c void vp8_blend_b_c(unsigned char *y, unsigned char *u, unsigned char *v, int y1, int u1, int v1, int alpha, int stride); #define vp8_blend_b vp8_blend_b_c @@ -58,20 +54,16 @@ #define vp8_clear_system_state vp8_clear_system_state_c void vp8_copy_mem16x16_c(unsigned char *src, int src_pitch, unsigned char *dst, int dst_pitch); -void vp8_copy_mem16x16_v6(unsigned char *src, int src_pitch, unsigned char *dst, int dst_pitch); -#define vp8_copy_mem16x16 vp8_copy_mem16x16_v6 +#define vp8_copy_mem16x16 vp8_copy_mem16x16_c void vp8_copy_mem8x4_c(unsigned char *src, int src_pitch, unsigned char *dst, int dst_pitch); -void vp8_copy_mem8x4_v6(unsigned char *src, int src_pitch, unsigned char *dst, int dst_pitch); -#define vp8_copy_mem8x4 vp8_copy_mem8x4_v6 +#define vp8_copy_mem8x4 vp8_copy_mem8x4_c void vp8_copy_mem8x8_c(unsigned char *src, int src_pitch, unsigned char *dst, int dst_pitch); -void vp8_copy_mem8x8_v6(unsigned char *src, int src_pitch, unsigned char *dst, int dst_pitch); -#define vp8_copy_mem8x8 vp8_copy_mem8x8_v6 +#define vp8_copy_mem8x8 vp8_copy_mem8x8_c void vp8_dc_only_idct_add_c(short input, unsigned char *pred, int pred_stride, unsigned char *dst, int dst_stride); -void vp8_dc_only_idct_add_v6(short input, unsigned char *pred, int pred_stride, unsigned char *dst, int dst_stride); -#define vp8_dc_only_idct_add vp8_dc_only_idct_add_v6 +#define vp8_dc_only_idct_add vp8_dc_only_idct_add_c int vp8_denoiser_filter_c(unsigned char *mc_running_avg_y, int mc_avg_y_stride, unsigned char *running_avg_y, int avg_y_stride, unsigned char *sig, int sig_stride, unsigned int motion_magnitude, int increase_denoising); #define vp8_denoiser_filter vp8_denoiser_filter_c @@ -80,20 +72,16 @@ #define vp8_denoiser_filter_uv vp8_denoiser_filter_uv_c void vp8_dequant_idct_add_c(short *input, short *dq, unsigned char *output, int stride); -void vp8_dequant_idct_add_v6(short *input, short *dq, unsigned char *output, int stride); -#define vp8_dequant_idct_add vp8_dequant_idct_add_v6 +#define vp8_dequant_idct_add vp8_dequant_idct_add_c void vp8_dequant_idct_add_uv_block_c(short *q, short *dq, unsigned char *dst_u, unsigned char *dst_v, int stride, char *eobs); -void vp8_dequant_idct_add_uv_block_v6(short *q, short *dq, unsigned char *dst_u, unsigned char *dst_v, int stride, char *eobs); -#define vp8_dequant_idct_add_uv_block vp8_dequant_idct_add_uv_block_v6 +#define vp8_dequant_idct_add_uv_block vp8_dequant_idct_add_uv_block_c void vp8_dequant_idct_add_y_block_c(short *q, short *dq, unsigned char *dst, int stride, char *eobs); -void vp8_dequant_idct_add_y_block_v6(short *q, short *dq, unsigned char *dst, int stride, char *eobs); -#define vp8_dequant_idct_add_y_block vp8_dequant_idct_add_y_block_v6 +#define vp8_dequant_idct_add_y_block vp8_dequant_idct_add_y_block_c void vp8_dequantize_b_c(struct blockd*, short *dqc); -void vp8_dequantize_b_v6(struct blockd*, short *dqc); -#define vp8_dequantize_b vp8_dequantize_b_v6 +#define vp8_dequantize_b vp8_dequantize_b_c int vp8_diamond_search_sad_c(struct macroblock *x, struct block *b, struct blockd *d, union int_mv *ref_mv, union int_mv *best_mv, int search_param, int sad_per_bit, int *num00, struct variance_vtable *fn_ptr, int *mvcost[2], union int_mv *center_mv); #define vp8_diamond_search_sad vp8_diamond_search_sad_c @@ -114,36 +102,28 @@ #define vp8_full_search_sad vp8_full_search_sad_c void vp8_loop_filter_bh_c(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); -void vp8_loop_filter_bh_armv6(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); -#define vp8_loop_filter_bh vp8_loop_filter_bh_armv6 +#define vp8_loop_filter_bh vp8_loop_filter_bh_c void vp8_loop_filter_bv_c(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); -void vp8_loop_filter_bv_armv6(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); -#define vp8_loop_filter_bv vp8_loop_filter_bv_armv6 +#define vp8_loop_filter_bv vp8_loop_filter_bv_c void vp8_loop_filter_mbh_c(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); -void vp8_loop_filter_mbh_armv6(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); -#define vp8_loop_filter_mbh vp8_loop_filter_mbh_armv6 +#define vp8_loop_filter_mbh vp8_loop_filter_mbh_c void vp8_loop_filter_mbv_c(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); -void vp8_loop_filter_mbv_armv6(unsigned char *y, unsigned char *u, unsigned char *v, int ystride, int uv_stride, struct loop_filter_info *lfi); -#define vp8_loop_filter_mbv vp8_loop_filter_mbv_armv6 +#define vp8_loop_filter_mbv vp8_loop_filter_mbv_c void vp8_loop_filter_bhs_c(unsigned char *y, int ystride, const unsigned char *blimit); -void vp8_loop_filter_bhs_armv6(unsigned char *y, int ystride, const unsigned char *blimit); -#define vp8_loop_filter_simple_bh vp8_loop_filter_bhs_armv6 +#define vp8_loop_filter_simple_bh vp8_loop_filter_bhs_c void vp8_loop_filter_bvs_c(unsigned char *y, int ystride, const unsigned char *blimit); -void vp8_loop_filter_bvs_armv6(unsigned char *y, int ystride, const unsigned char *blimit); -#define vp8_loop_filter_simple_bv vp8_loop_filter_bvs_armv6 +#define vp8_loop_filter_simple_bv vp8_loop_filter_bvs_c void vp8_loop_filter_simple_horizontal_edge_c(unsigned char *y, int ystride, const unsigned char *blimit); -void vp8_loop_filter_simple_horizontal_edge_armv6(unsigned char *y, int ystride, const unsigned char *blimit); -#define vp8_loop_filter_simple_mbh vp8_loop_filter_simple_horizontal_edge_armv6 +#define vp8_loop_filter_simple_mbh vp8_loop_filter_simple_horizontal_edge_c void vp8_loop_filter_simple_vertical_edge_c(unsigned char *y, int ystride, const unsigned char *blimit); -void vp8_loop_filter_simple_vertical_edge_armv6(unsigned char *y, int ystride, const unsigned char *blimit); -#define vp8_loop_filter_simple_mbv vp8_loop_filter_simple_vertical_edge_armv6 +#define vp8_loop_filter_simple_mbv vp8_loop_filter_simple_vertical_edge_c int vp8_mbblock_error_c(struct macroblock *mb, int dc); #define vp8_mbblock_error vp8_mbblock_error_c @@ -158,43 +138,34 @@ #define vp8_regular_quantize_b vp8_regular_quantize_b_c void vp8_short_fdct4x4_c(short *input, short *output, int pitch); -void vp8_short_fdct4x4_armv6(short *input, short *output, int pitch); -#define vp8_short_fdct4x4 vp8_short_fdct4x4_armv6 +#define vp8_short_fdct4x4 vp8_short_fdct4x4_c void vp8_short_fdct8x4_c(short *input, short *output, int pitch); -void vp8_short_fdct8x4_armv6(short *input, short *output, int pitch); -#define vp8_short_fdct8x4 vp8_short_fdct8x4_armv6 +#define vp8_short_fdct8x4 vp8_short_fdct8x4_c void vp8_short_idct4x4llm_c(short *input, unsigned char *pred, int pitch, unsigned char *dst, int dst_stride); -void vp8_short_idct4x4llm_v6_dual(short *input, unsigned char *pred, int pitch, unsigned char *dst, int dst_stride); -#define vp8_short_idct4x4llm vp8_short_idct4x4llm_v6_dual +#define vp8_short_idct4x4llm vp8_short_idct4x4llm_c void vp8_short_inv_walsh4x4_c(short *input, short *output); -void vp8_short_inv_walsh4x4_v6(short *input, short *output); -#define vp8_short_inv_walsh4x4 vp8_short_inv_walsh4x4_v6 +#define vp8_short_inv_walsh4x4 vp8_short_inv_walsh4x4_c void vp8_short_inv_walsh4x4_1_c(short *input, short *output); #define vp8_short_inv_walsh4x4_1 vp8_short_inv_walsh4x4_1_c void vp8_short_walsh4x4_c(short *input, short *output, int pitch); -void vp8_short_walsh4x4_armv6(short *input, short *output, int pitch); -#define vp8_short_walsh4x4 vp8_short_walsh4x4_armv6 +#define vp8_short_walsh4x4 vp8_short_walsh4x4_c void vp8_sixtap_predict16x16_c(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -void vp8_sixtap_predict16x16_armv6(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -#define vp8_sixtap_predict16x16 vp8_sixtap_predict16x16_armv6 +#define vp8_sixtap_predict16x16 vp8_sixtap_predict16x16_c void vp8_sixtap_predict4x4_c(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -void vp8_sixtap_predict4x4_armv6(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -#define vp8_sixtap_predict4x4 vp8_sixtap_predict4x4_armv6 +#define vp8_sixtap_predict4x4 vp8_sixtap_predict4x4_c void vp8_sixtap_predict8x4_c(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -void vp8_sixtap_predict8x4_armv6(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -#define vp8_sixtap_predict8x4 vp8_sixtap_predict8x4_armv6 +#define vp8_sixtap_predict8x4 vp8_sixtap_predict8x4_c void vp8_sixtap_predict8x8_c(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -void vp8_sixtap_predict8x8_armv6(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch); -#define vp8_sixtap_predict8x8 vp8_sixtap_predict8x8_armv6 +#define vp8_sixtap_predict8x8 vp8_sixtap_predict8x8_c void vp8_rtcd(void);
diff --git a/third_party/libvpx/source/config/linux/arm/vpx_config.asm b/third_party/libvpx/source/config/linux/arm/vpx_config.asm index 299b467..df9e9777 100644 --- a/third_party/libvpx/source/config/linux/arm/vpx_config.asm +++ b/third_party/libvpx/source/config/linux/arm/vpx_config.asm
@@ -5,8 +5,6 @@ .equ ARCH_MIPS , 0 .equ ARCH_X86 , 0 .equ ARCH_X86_64 , 0 -.equ HAVE_EDSP , 0 -.equ HAVE_MEDIA , 1 .equ HAVE_NEON , 0 .equ HAVE_NEON_ASM , 0 .equ HAVE_MIPS32 , 0
diff --git a/third_party/libvpx/source/config/linux/arm/vpx_config.h b/third_party/libvpx/source/config/linux/arm/vpx_config.h index 9735b37..ab52e03 100644 --- a/third_party/libvpx/source/config/linux/arm/vpx_config.h +++ b/third_party/libvpx/source/config/linux/arm/vpx_config.h
@@ -14,8 +14,6 @@ #define ARCH_MIPS 0 #define ARCH_X86 0 #define ARCH_X86_64 0 -#define HAVE_EDSP 0 -#define HAVE_MEDIA 1 #define HAVE_NEON 0 #define HAVE_NEON_ASM 0 #define HAVE_MIPS32 0
diff --git a/third_party/libvpx/source/config/linux/arm/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/arm/vpx_dsp_rtcd.h index ef9ac7d..a852ec3 100644 --- a/third_party/libvpx/source/config/linux/arm/vpx_dsp_rtcd.h +++ b/third_party/libvpx/source/config/linux/arm/vpx_dsp_rtcd.h
@@ -365,8 +365,7 @@ #define vpx_minmax_8x8 vpx_minmax_8x8_c unsigned int vpx_mse16x16_c(const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int recon_stride, unsigned int *sse); -unsigned int vpx_mse16x16_media(const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int recon_stride, unsigned int *sse); -#define vpx_mse16x16 vpx_mse16x16_media +#define vpx_mse16x16 vpx_mse16x16_c unsigned int vpx_mse16x8_c(const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int recon_stride, unsigned int *sse); #define vpx_mse16x8 vpx_mse16x8_c @@ -390,8 +389,7 @@ #define vpx_quantize_b_32x32 vpx_quantize_b_32x32_c unsigned int vpx_sad16x16_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride); -unsigned int vpx_sad16x16_media(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride); -#define vpx_sad16x16 vpx_sad16x16_media +#define vpx_sad16x16 vpx_sad16x16_c unsigned int vpx_sad16x16_avg_c(const uint8_t *src_ptr, int src_stride, const uint8_t *ref_ptr, int ref_stride, const uint8_t *second_pred); #define vpx_sad16x16_avg vpx_sad16x16_avg_c @@ -616,8 +614,7 @@ #define vpx_sub_pixel_avg_variance8x8 vpx_sub_pixel_avg_variance8x8_c uint32_t vpx_sub_pixel_variance16x16_c(const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse); -uint32_t vpx_sub_pixel_variance16x16_media(const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse); -#define vpx_sub_pixel_variance16x16 vpx_sub_pixel_variance16x16_media +#define vpx_sub_pixel_variance16x16 vpx_sub_pixel_variance16x16_c uint32_t vpx_sub_pixel_variance16x32_c(const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse); #define vpx_sub_pixel_variance16x32 vpx_sub_pixel_variance16x32_c @@ -653,8 +650,7 @@ #define vpx_sub_pixel_variance8x4 vpx_sub_pixel_variance8x4_c uint32_t vpx_sub_pixel_variance8x8_c(const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse); -uint32_t vpx_sub_pixel_variance8x8_media(const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse); -#define vpx_sub_pixel_variance8x8 vpx_sub_pixel_variance8x8_media +#define vpx_sub_pixel_variance8x8 vpx_sub_pixel_variance8x8_c void vpx_subtract_block_c(int rows, int cols, int16_t *diff_ptr, ptrdiff_t diff_stride, const uint8_t *src_ptr, ptrdiff_t src_stride, const uint8_t *pred_ptr, ptrdiff_t pred_stride); #define vpx_subtract_block vpx_subtract_block_c @@ -687,8 +683,7 @@ #define vpx_v_predictor_8x8 vpx_v_predictor_8x8_c unsigned int vpx_variance16x16_c(const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse); -unsigned int vpx_variance16x16_media(const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse); -#define vpx_variance16x16 vpx_variance16x16_media +#define vpx_variance16x16 vpx_variance16x16_c unsigned int vpx_variance16x32_c(const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse); #define vpx_variance16x32 vpx_variance16x32_c @@ -724,20 +719,16 @@ #define vpx_variance8x4 vpx_variance8x4_c unsigned int vpx_variance8x8_c(const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse); -unsigned int vpx_variance8x8_media(const uint8_t *src_ptr, int source_stride, const uint8_t *ref_ptr, int ref_stride, unsigned int *sse); -#define vpx_variance8x8 vpx_variance8x8_media +#define vpx_variance8x8 vpx_variance8x8_c uint32_t vpx_variance_halfpixvar16x16_h_c(const unsigned char *src_ptr, int source_stride, const unsigned char *ref_ptr, int ref_stride, uint32_t *sse); -uint32_t vpx_variance_halfpixvar16x16_h_media(const unsigned char *src_ptr, int source_stride, const unsigned char *ref_ptr, int ref_stride, uint32_t *sse); -#define vpx_variance_halfpixvar16x16_h vpx_variance_halfpixvar16x16_h_media +#define vpx_variance_halfpixvar16x16_h vpx_variance_halfpixvar16x16_h_c uint32_t vpx_variance_halfpixvar16x16_hv_c(const unsigned char *src_ptr, int source_stride, const unsigned char *ref_ptr, int ref_stride, uint32_t *sse); -uint32_t vpx_variance_halfpixvar16x16_hv_media(const unsigned char *src_ptr, int source_stride, const unsigned char *ref_ptr, int ref_stride, uint32_t *sse); -#define vpx_variance_halfpixvar16x16_hv vpx_variance_halfpixvar16x16_hv_media +#define vpx_variance_halfpixvar16x16_hv vpx_variance_halfpixvar16x16_hv_c uint32_t vpx_variance_halfpixvar16x16_v_c(const unsigned char *src_ptr, int source_stride, const unsigned char *ref_ptr, int ref_stride, uint32_t *sse); -uint32_t vpx_variance_halfpixvar16x16_v_media(const unsigned char *src_ptr, int source_stride, const unsigned char *ref_ptr, int ref_stride, uint32_t *sse); -#define vpx_variance_halfpixvar16x16_v vpx_variance_halfpixvar16x16_v_media +#define vpx_variance_halfpixvar16x16_v vpx_variance_halfpixvar16x16_v_c void vpx_ve_predictor_4x4_c(uint8_t *dst, ptrdiff_t y_stride, const uint8_t *above, const uint8_t *left); #define vpx_ve_predictor_4x4 vpx_ve_predictor_4x4_c
diff --git a/third_party/libvpx/source/config/linux/arm64/vpx_config.asm b/third_party/libvpx/source/config/linux/arm64/vpx_config.asm index e9338acf..8343637a 100644 --- a/third_party/libvpx/source/config/linux/arm64/vpx_config.asm +++ b/third_party/libvpx/source/config/linux/arm64/vpx_config.asm
@@ -5,8 +5,6 @@ .equ ARCH_MIPS , 0 .equ ARCH_X86 , 0 .equ ARCH_X86_64 , 0 -.equ HAVE_EDSP , 0 -.equ HAVE_MEDIA , 0 .equ HAVE_NEON , 1 .equ HAVE_NEON_ASM , 0 .equ HAVE_MIPS32 , 0
diff --git a/third_party/libvpx/source/config/linux/arm64/vpx_config.h b/third_party/libvpx/source/config/linux/arm64/vpx_config.h index 55267563..2f910b0c 100644 --- a/third_party/libvpx/source/config/linux/arm64/vpx_config.h +++ b/third_party/libvpx/source/config/linux/arm64/vpx_config.h
@@ -14,8 +14,6 @@ #define ARCH_MIPS 0 #define ARCH_X86 0 #define ARCH_X86_64 0 -#define HAVE_EDSP 0 -#define HAVE_MEDIA 0 #define HAVE_NEON 1 #define HAVE_NEON_ASM 0 #define HAVE_MIPS32 0
diff --git a/third_party/libvpx/source/config/linux/generic/vpx_config.asm b/third_party/libvpx/source/config/linux/generic/vpx_config.asm index ae37fb01..235a971 100644 --- a/third_party/libvpx/source/config/linux/generic/vpx_config.asm +++ b/third_party/libvpx/source/config/linux/generic/vpx_config.asm
@@ -5,8 +5,6 @@ .equ ARCH_MIPS , 0 .equ ARCH_X86 , 0 .equ ARCH_X86_64 , 0 -.equ HAVE_EDSP , 0 -.equ HAVE_MEDIA , 0 .equ HAVE_NEON , 0 .equ HAVE_NEON_ASM , 0 .equ HAVE_MIPS32 , 0
diff --git a/third_party/libvpx/source/config/linux/generic/vpx_config.h b/third_party/libvpx/source/config/linux/generic/vpx_config.h index 5172288..e60ffbc 100644 --- a/third_party/libvpx/source/config/linux/generic/vpx_config.h +++ b/third_party/libvpx/source/config/linux/generic/vpx_config.h
@@ -14,8 +14,6 @@ #define ARCH_MIPS 0 #define ARCH_X86 0 #define ARCH_X86_64 0 -#define HAVE_EDSP 0 -#define HAVE_MEDIA 0 #define HAVE_NEON 0 #define HAVE_NEON_ASM 0 #define HAVE_MIPS32 0
diff --git a/third_party/libvpx/source/config/linux/ia32/vpx_config.asm b/third_party/libvpx/source/config/linux/ia32/vpx_config.asm index a57d1828..30bb869e 100644 --- a/third_party/libvpx/source/config/linux/ia32/vpx_config.asm +++ b/third_party/libvpx/source/config/linux/ia32/vpx_config.asm
@@ -2,8 +2,6 @@ %define ARCH_MIPS 0 %define ARCH_X86 1 %define ARCH_X86_64 0 -%define HAVE_EDSP 0 -%define HAVE_MEDIA 0 %define HAVE_NEON 0 %define HAVE_NEON_ASM 0 %define HAVE_MIPS32 0
diff --git a/third_party/libvpx/source/config/linux/ia32/vpx_config.h b/third_party/libvpx/source/config/linux/ia32/vpx_config.h index b5df366..55636cc8 100644 --- a/third_party/libvpx/source/config/linux/ia32/vpx_config.h +++ b/third_party/libvpx/source/config/linux/ia32/vpx_config.h
@@ -14,8 +14,6 @@ #define ARCH_MIPS 0 #define ARCH_X86 1 #define ARCH_X86_64 0 -#define HAVE_EDSP 0 -#define HAVE_MEDIA 0 #define HAVE_NEON 0 #define HAVE_NEON_ASM 0 #define HAVE_MIPS32 0
diff --git a/third_party/libvpx/source/config/linux/mips64el/vpx_config.h b/third_party/libvpx/source/config/linux/mips64el/vpx_config.h index bbddd5c..744d7b2a 100644 --- a/third_party/libvpx/source/config/linux/mips64el/vpx_config.h +++ b/third_party/libvpx/source/config/linux/mips64el/vpx_config.h
@@ -14,8 +14,6 @@ #define ARCH_MIPS 1 #define ARCH_X86 0 #define ARCH_X86_64 0 -#define HAVE_EDSP 0 -#define HAVE_MEDIA 0 #define HAVE_NEON 0 #define HAVE_NEON_ASM 0 #define HAVE_MIPS32 0
diff --git a/third_party/libvpx/source/config/linux/mipsel/vpx_config.h b/third_party/libvpx/source/config/linux/mipsel/vpx_config.h index e2795e7..3506a034 100644 --- a/third_party/libvpx/source/config/linux/mipsel/vpx_config.h +++ b/third_party/libvpx/source/config/linux/mipsel/vpx_config.h
@@ -14,8 +14,6 @@ #define ARCH_MIPS 1 #define ARCH_X86 0 #define ARCH_X86_64 0 -#define HAVE_EDSP 0 -#define HAVE_MEDIA 0 #define HAVE_NEON 0 #define HAVE_NEON_ASM 0 #define HAVE_MIPS32 1
diff --git a/third_party/libvpx/source/config/linux/x64/vpx_config.asm b/third_party/libvpx/source/config/linux/x64/vpx_config.asm index ec3bcd3..9bb58ca1 100644 --- a/third_party/libvpx/source/config/linux/x64/vpx_config.asm +++ b/third_party/libvpx/source/config/linux/x64/vpx_config.asm
@@ -2,8 +2,6 @@ %define ARCH_MIPS 0 %define ARCH_X86 0 %define ARCH_X86_64 1 -%define HAVE_EDSP 0 -%define HAVE_MEDIA 0 %define HAVE_NEON 0 %define HAVE_NEON_ASM 0 %define HAVE_MIPS32 0
diff --git a/third_party/libvpx/source/config/linux/x64/vpx_config.h b/third_party/libvpx/source/config/linux/x64/vpx_config.h index f8f69509..cbc16566 100644 --- a/third_party/libvpx/source/config/linux/x64/vpx_config.h +++ b/third_party/libvpx/source/config/linux/x64/vpx_config.h
@@ -14,8 +14,6 @@ #define ARCH_MIPS 0 #define ARCH_X86 0 #define ARCH_X86_64 1 -#define HAVE_EDSP 0 -#define HAVE_MEDIA 0 #define HAVE_NEON 0 #define HAVE_NEON_ASM 0 #define HAVE_MIPS32 0
diff --git a/third_party/libvpx/source/config/mac/ia32/vpx_config.asm b/third_party/libvpx/source/config/mac/ia32/vpx_config.asm index a57d1828..30bb869e 100644 --- a/third_party/libvpx/source/config/mac/ia32/vpx_config.asm +++ b/third_party/libvpx/source/config/mac/ia32/vpx_config.asm
@@ -2,8 +2,6 @@ %define ARCH_MIPS 0 %define ARCH_X86 1 %define ARCH_X86_64 0 -%define HAVE_EDSP 0 -%define HAVE_MEDIA 0 %define HAVE_NEON 0 %define HAVE_NEON_ASM 0 %define HAVE_MIPS32 0
diff --git a/third_party/libvpx/source/config/mac/ia32/vpx_config.h b/third_party/libvpx/source/config/mac/ia32/vpx_config.h index b5df366..55636cc8 100644 --- a/third_party/libvpx/source/config/mac/ia32/vpx_config.h +++ b/third_party/libvpx/source/config/mac/ia32/vpx_config.h
@@ -14,8 +14,6 @@ #define ARCH_MIPS 0 #define ARCH_X86 1 #define ARCH_X86_64 0 -#define HAVE_EDSP 0 -#define HAVE_MEDIA 0 #define HAVE_NEON 0 #define HAVE_NEON_ASM 0 #define HAVE_MIPS32 0
diff --git a/third_party/libvpx/source/config/mac/x64/vpx_config.asm b/third_party/libvpx/source/config/mac/x64/vpx_config.asm index ec3bcd3..9bb58ca1 100644 --- a/third_party/libvpx/source/config/mac/x64/vpx_config.asm +++ b/third_party/libvpx/source/config/mac/x64/vpx_config.asm
@@ -2,8 +2,6 @@ %define ARCH_MIPS 0 %define ARCH_X86 0 %define ARCH_X86_64 1 -%define HAVE_EDSP 0 -%define HAVE_MEDIA 0 %define HAVE_NEON 0 %define HAVE_NEON_ASM 0 %define HAVE_MIPS32 0
diff --git a/third_party/libvpx/source/config/mac/x64/vpx_config.h b/third_party/libvpx/source/config/mac/x64/vpx_config.h index f8f69509..cbc16566 100644 --- a/third_party/libvpx/source/config/mac/x64/vpx_config.h +++ b/third_party/libvpx/source/config/mac/x64/vpx_config.h
@@ -14,8 +14,6 @@ #define ARCH_MIPS 0 #define ARCH_X86 0 #define ARCH_X86_64 1 -#define HAVE_EDSP 0 -#define HAVE_MEDIA 0 #define HAVE_NEON 0 #define HAVE_NEON_ASM 0 #define HAVE_MIPS32 0
diff --git a/third_party/libvpx/source/config/nacl/vpx_config.asm b/third_party/libvpx/source/config/nacl/vpx_config.asm index ae37fb01..235a971 100644 --- a/third_party/libvpx/source/config/nacl/vpx_config.asm +++ b/third_party/libvpx/source/config/nacl/vpx_config.asm
@@ -5,8 +5,6 @@ .equ ARCH_MIPS , 0 .equ ARCH_X86 , 0 .equ ARCH_X86_64 , 0 -.equ HAVE_EDSP , 0 -.equ HAVE_MEDIA , 0 .equ HAVE_NEON , 0 .equ HAVE_NEON_ASM , 0 .equ HAVE_MIPS32 , 0
diff --git a/third_party/libvpx/source/config/nacl/vpx_config.h b/third_party/libvpx/source/config/nacl/vpx_config.h index 5172288..e60ffbc 100644 --- a/third_party/libvpx/source/config/nacl/vpx_config.h +++ b/third_party/libvpx/source/config/nacl/vpx_config.h
@@ -14,8 +14,6 @@ #define ARCH_MIPS 0 #define ARCH_X86 0 #define ARCH_X86_64 0 -#define HAVE_EDSP 0 -#define HAVE_MEDIA 0 #define HAVE_NEON 0 #define HAVE_NEON_ASM 0 #define HAVE_MIPS32 0
diff --git a/third_party/libvpx/source/config/vpx_version.h b/third_party/libvpx/source/config/vpx_version.h index f3ab22be..0abfdabd 100644 --- a/third_party/libvpx/source/config/vpx_version.h +++ b/third_party/libvpx/source/config/vpx_version.h
@@ -1,7 +1,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 6 #define VERSION_PATCH 0 -#define VERSION_EXTRA "201-g82070ae" +#define VERSION_EXTRA "278-g2d1e63d" #define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH)) -#define VERSION_STRING_NOSP "v1.6.0-201-g82070ae" -#define VERSION_STRING " v1.6.0-201-g82070ae" +#define VERSION_STRING_NOSP "v1.6.0-278-g2d1e63d" +#define VERSION_STRING " v1.6.0-278-g2d1e63d"
diff --git a/third_party/libvpx/source/config/win/ia32/vpx_config.asm b/third_party/libvpx/source/config/win/ia32/vpx_config.asm index a80158a..065a797f 100644 --- a/third_party/libvpx/source/config/win/ia32/vpx_config.asm +++ b/third_party/libvpx/source/config/win/ia32/vpx_config.asm
@@ -2,8 +2,6 @@ %define ARCH_MIPS 0 %define ARCH_X86 1 %define ARCH_X86_64 0 -%define HAVE_EDSP 0 -%define HAVE_MEDIA 0 %define HAVE_NEON 0 %define HAVE_NEON_ASM 0 %define HAVE_MIPS32 0
diff --git a/third_party/libvpx/source/config/win/ia32/vpx_config.h b/third_party/libvpx/source/config/win/ia32/vpx_config.h index 37b721c1..03a4861 100644 --- a/third_party/libvpx/source/config/win/ia32/vpx_config.h +++ b/third_party/libvpx/source/config/win/ia32/vpx_config.h
@@ -14,8 +14,6 @@ #define ARCH_MIPS 0 #define ARCH_X86 1 #define ARCH_X86_64 0 -#define HAVE_EDSP 0 -#define HAVE_MEDIA 0 #define HAVE_NEON 0 #define HAVE_NEON_ASM 0 #define HAVE_MIPS32 0
diff --git a/third_party/libvpx/source/config/win/x64/vpx_config.asm b/third_party/libvpx/source/config/win/x64/vpx_config.asm index 11eb837..c254c98 100644 --- a/third_party/libvpx/source/config/win/x64/vpx_config.asm +++ b/third_party/libvpx/source/config/win/x64/vpx_config.asm
@@ -2,8 +2,6 @@ %define ARCH_MIPS 0 %define ARCH_X86 0 %define ARCH_X86_64 1 -%define HAVE_EDSP 0 -%define HAVE_MEDIA 0 %define HAVE_NEON 0 %define HAVE_NEON_ASM 0 %define HAVE_MIPS32 0
diff --git a/third_party/libvpx/source/config/win/x64/vpx_config.h b/third_party/libvpx/source/config/win/x64/vpx_config.h index 03ffe3f1..b74c752 100644 --- a/third_party/libvpx/source/config/win/x64/vpx_config.h +++ b/third_party/libvpx/source/config/win/x64/vpx_config.h
@@ -14,8 +14,6 @@ #define ARCH_MIPS 0 #define ARCH_X86 0 #define ARCH_X86_64 1 -#define HAVE_EDSP 0 -#define HAVE_MEDIA 0 #define HAVE_NEON 0 #define HAVE_NEON_ASM 0 #define HAVE_MIPS32 0
diff --git a/third_party/polymer/v1_0/components-chromium/paper-dropdown-menu/bower.json b/third_party/polymer/v1_0/components-chromium/paper-dropdown-menu/bower.json index 4b0dcfd..855a50d 100644 --- a/third_party/polymer/v1_0/components-chromium/paper-dropdown-menu/bower.json +++ b/third_party/polymer/v1_0/components-chromium/paper-dropdown-menu/bower.json
@@ -1,6 +1,6 @@ { "name": "paper-dropdown-menu", - "version": "1.3.3", + "version": "1.3.4", "description": "An element that works similarly to a native browser select", "authors": [ "The Polymer Authors"
diff --git a/third_party/polymer/v1_0/components-chromium/paper-dropdown-menu/paper-dropdown-menu-light.html b/third_party/polymer/v1_0/components-chromium/paper-dropdown-menu/paper-dropdown-menu-light.html index dde7919..5044dce 100644 --- a/third_party/polymer/v1_0/components-chromium/paper-dropdown-menu/paper-dropdown-menu-light.html +++ b/third_party/polymer/v1_0/components-chromium/paper-dropdown-menu/paper-dropdown-menu-light.html
@@ -184,6 +184,9 @@ :host([no-label-float]) label { top: 8px; + /* Since the label doesn't need to float, remove the animation duration + which slows down visibility changes (i.e. when a selection is made) */ + transition-duration: 0s; } label.label-is-floating { @@ -192,7 +195,7 @@ } label.label-is-hidden { - display: none; + visibility: hidden; } :host([focused]) label.label-is-floating {
diff --git a/third_party/polymer/v1_0/components_summary.txt b/third_party/polymer/v1_0/components_summary.txt index 7aedabc..250eb72 100644 --- a/third_party/polymer/v1_0/components_summary.txt +++ b/third_party/polymer/v1_0/components_summary.txt
@@ -1,427 +1,366 @@ Name: app-layout -Version: 0.9.2 Repository: git://github.com/PolymerElements/app-layout.git -Tag: v0.9.2 +Tree: v0.9.2 Revision: e4453ca78c83677938041885023d79ce92d03a3a Tree link: https://github.com/PolymerElements/app-layout/tree/v0.9.2 Name: app-route -Version: 0.9.2 Repository: git://github.com/PolymerElements/app-route.git -Tag: v0.9.2 +Tree: v0.9.2 Revision: c97dd0f01593b4cfd9ef7bba7dfe004f8b42c1c0 Tree link: https://github.com/PolymerElements/app-route/tree/v0.9.2 Name: font-roboto -Version: 1.0.1 Repository: git://github.com/PolymerElements/font-roboto.git -Tag: v1.0.1 +Tree: v1.0.1 Revision: 21ce9b51a417fa9995cf6606e886aba0728f70a1 Tree link: https://github.com/PolymerElements/font-roboto/tree/v1.0.1 Name: iron-a11y-announcer -Version: 1.0.5 Repository: git://github.com/PolymerElements/iron-a11y-announcer.git -Tag: v1.0.5 +Tree: v1.0.5 Revision: 2432d39a1693ccd728cbe7eb55810063737d3403 Tree link: https://github.com/PolymerElements/iron-a11y-announcer/tree/v1.0.5 Name: iron-a11y-keys -Version: 1.0.6 Repository: git://github.com/PolymerElements/iron-a11y-keys.git -Tag: v1.0.6 +Tree: v1.0.6 Revision: aa9374f069b942dfabcaabb587cbb00b0dd28c63 Tree link: https://github.com/PolymerElements/iron-a11y-keys/tree/v1.0.6 Name: iron-a11y-keys-behavior -Version: 1.1.7 Repository: git://github.com/PolymerElements/iron-a11y-keys-behavior.git -Tag: v1.1.7 +Tree: v1.1.7 Revision: cde403dee704a1d3ea5f7cb49067f0eab31a8afa Tree link: https://github.com/PolymerElements/iron-a11y-keys-behavior/tree/v1.1.7 Name: iron-autogrow-textarea -Version: 1.0.13 Repository: git://github.com/PolymerElements/iron-autogrow-textarea.git -Tag: v1.0.13 +Tree: v1.0.13 Revision: 399cfdbb3fac0c7b61d14a8cf8402c0195b0ff04 Tree link: https://github.com/PolymerElements/iron-autogrow-textarea/tree/v1.0.13 Name: iron-behaviors -Version: 1.0.17 Repository: git://github.com/PolymerElements/iron-behaviors.git -Tag: v1.0.17 +Tree: v1.0.17 Revision: ef8e89b5f0aa4e8a6b51ca6491ea453bf395f94f Tree link: https://github.com/PolymerElements/iron-behaviors/tree/v1.0.17 Name: iron-checked-element-behavior -Version: 1.0.5 Repository: git://github.com/PolymerElements/iron-checked-element-behavior.git -Tag: v1.0.5 +Tree: v1.0.5 Revision: c70add47a9af62d30746587e8a1303fb390787c6 Tree link: https://github.com/PolymerElements/iron-checked-element-behavior/tree/v1.0.5 Name: iron-collapse -Version: 1.2.0 Repository: git://github.com/PolymerElements/iron-collapse.git -Tag: v1.2.0 +Tree: v1.2.0 Revision: 3743d45099a50d8f79c06a99991f65d839441d5a Tree link: https://github.com/PolymerElements/iron-collapse/tree/v1.2.0 Name: iron-dropdown -Version: 1.5.1 Repository: git://github.com/PolymerElements/iron-dropdown.git -Tag: v1.5.1 +Tree: v1.5.1 Revision: 3b89a43719e82aeb8ea5362f9f0d2974ed059189 Tree link: https://github.com/PolymerElements/iron-dropdown/tree/v1.5.1 Name: iron-fit-behavior -Version: 1.2.5 Repository: git://github.com/PolymerElements/iron-fit-behavior.git -Tag: v1.2.5 +Tree: v1.2.5 Revision: 8bc774b9376882ae5ba09f9e007764c6ee9fbbca Tree link: https://github.com/PolymerElements/iron-fit-behavior/tree/v1.2.5 Name: iron-flex-layout -Version: 1.3.1 Repository: git://github.com/PolymerElements/iron-flex-layout.git -Tag: v1.3.1 +Tree: v1.3.1 Revision: 6d88f29f3a7181daa2a5c7f678de44f0a0e6a717 Tree link: https://github.com/PolymerElements/iron-flex-layout/tree/v1.3.1 Name: iron-form-element-behavior -Version: 1.0.6 Repository: git://github.com/PolymerElements/iron-form-element-behavior.git -Tag: v1.0.6 +Tree: v1.0.6 Revision: cf9e09ded62daf3363852ce98260aaad1ed0fae1 Tree link: https://github.com/PolymerElements/iron-form-element-behavior/tree/v1.0.6 Name: iron-icon -Version: 1.0.9 Repository: git://github.com/PolymerElements/iron-icon.git -Tag: v1.0.9 +Tree: v1.0.9 Revision: f6fb241901377e30e2c9c6cd47e3e8e8beb6574d Tree link: https://github.com/PolymerElements/iron-icon/tree/v1.0.9 Name: iron-icons -Version: 1.1.3 Repository: git://github.com/PolymerElements/iron-icons.git -Tag: v1.1.3 +Tree: v1.1.3 Revision: c13869b57a9464dfc3a1f26e89858f8be37e7441 Tree link: https://github.com/PolymerElements/iron-icons/tree/v1.1.3 Name: iron-iconset-svg -Version: 1.0.9 Repository: git://github.com/PolymerElements/iron-iconset-svg.git -Tag: v1.0.9 +Tree: v1.0.9 Revision: ce9b2ea1f73d936cffdd05f3fe34b1f69d1d32db Tree link: https://github.com/PolymerElements/iron-iconset-svg/tree/v1.0.9 Name: iron-input -Version: 1.0.10 Repository: git://github.com/PolymerElements/iron-input.git -Tag: 1.0.10 +Tree: 1.0.10 Revision: 01d17407672ad8033ee447c9c7a65162f13c8f49 Tree link: https://github.com/PolymerElements/iron-input/tree/1.0.10 Name: iron-list -Version: 1.3.5 Repository: git://github.com/PolymerElements/iron-list.git -Tag: v1.3.5 +Tree: v1.3.5 Revision: 4713a5dc86da222167e3467531a187b239885547 Tree link: https://github.com/PolymerElements/iron-list/tree/v1.3.5 Name: iron-location -Version: 0.8.8 Repository: git://github.com/PolymerElements/iron-location.git -Tag: v0.8.8 +Tree: v0.8.8 Revision: ab65525d349f13c467653a200711202eeae17ff0 Tree link: https://github.com/PolymerElements/iron-location/tree/v0.8.8 Name: iron-media-query -Version: 1.0.8 Repository: git://github.com/PolymerElements/iron-media-query.git -Tag: v1.0.8 +Tree: v1.0.8 Revision: 3f916be171af7a3e03eb019acdfea71055d3c744 Tree link: https://github.com/PolymerElements/iron-media-query/tree/v1.0.8 Name: iron-menu-behavior -Version: 1.1.9 Repository: git://github.com/PolymerElements/iron-menu-behavior.git -Tag: v1.1.9 +Tree: v1.1.9 Revision: d7d82ae11aac17ec7ebd7e468e5ce179a1d964bd Tree link: https://github.com/PolymerElements/iron-menu-behavior/tree/v1.1.9 Name: iron-meta -Version: 1.1.1 Repository: git://github.com/PolymerElements/iron-meta.git -Tag: v1.1.1 +Tree: v1.1.1 Revision: e171ee234b482219c9514e6f9551df48ef48bd9f Tree link: https://github.com/PolymerElements/iron-meta/tree/v1.1.1 Name: iron-overlay-behavior -Version: 1.8.6 Repository: git://github.com/PolymerElements/iron-overlay-behavior.git -Tag: v1.8.6 +Tree: v1.8.6 Revision: 4b579d7e47a19b3c1e5a65ee631bd432230b3610 Tree link: https://github.com/PolymerElements/iron-overlay-behavior/tree/v1.8.6 Name: iron-pages -Version: 1.0.8 Repository: git://github.com/PolymerElements/iron-pages.git -Tag: v1.0.8 +Tree: v1.0.8 Revision: 1399d2d51a0ce50edd2c79a6d37419967509bf2c Tree link: https://github.com/PolymerElements/iron-pages/tree/v1.0.8 Name: iron-range-behavior -Version: 1.0.6 Repository: git://github.com/PolymerElements/iron-range-behavior.git -Tag: v1.0.6 +Tree: v1.0.6 Revision: 1317604307387599725b80b63cbd293102ea2db0 Tree link: https://github.com/PolymerElements/iron-range-behavior/tree/v1.0.6 Name: iron-resizable-behavior -Version: 1.0.5 Repository: git://github.com/PolymerElements/iron-resizable-behavior.git -Tag: v1.0.5 +Tree: v1.0.5 Revision: 354f287922e497b79797348b31596eebaccb9761 Tree link: https://github.com/PolymerElements/iron-resizable-behavior/tree/v1.0.5 Name: iron-scroll-target-behavior -Version: 1.0.8 Repository: git://github.com/PolymerElements/iron-scroll-target-behavior.git -Tag: v1.0.8 +Tree: v1.0.8 Revision: 4c66bc9869b6475dc1d8b59419a0148bf46d9493 Tree link: https://github.com/PolymerElements/iron-scroll-target-behavior/tree/v1.0.8 Name: iron-scroll-threshold -Version: 1.0.2 Repository: git://github.com/PolymerElements/iron-scroll-threshold.git -Tag: v1.0.2 +Tree: v1.0.2 Revision: 3b0ded11ea87703a4f1ef48cea93226fb0e71ef1 Tree link: https://github.com/PolymerElements/iron-scroll-threshold/tree/v1.0.2 Name: iron-selector -Version: 1.5.2 Repository: git://github.com/PolymerElements/iron-selector.git -Tag: v1.5.2 +Tree: v1.5.2 Revision: 18e8e12dcd9a4560de480562f65935feed334b86 Tree link: https://github.com/PolymerElements/iron-selector/tree/v1.5.2 Name: iron-test-helpers -Version: 1.2.5 Repository: git://github.com/PolymerElements/iron-test-helpers.git -Tag: v1.2.5 +Tree: v1.2.5 Revision: a6a123f1330e8e146def1b947b4db0b951003fc0 Tree link: https://github.com/PolymerElements/iron-test-helpers/tree/v1.2.5 Name: iron-validatable-behavior -Version: 1.1.1 Repository: git://github.com/PolymerElements/iron-validatable-behavior.git -Tag: v1.1.1 +Tree: v1.1.1 Revision: 2ecd3f411e298733b29f1660f75cb9b03ea31d77 Tree link: https://github.com/PolymerElements/iron-validatable-behavior/tree/v1.1.1 Name: neon-animation -Version: 1.2.4 Repository: git://github.com/PolymerElements/neon-animation.git -Tag: v1.2.4 +Tree: v1.2.4 Revision: bd4f50c9a84023363e80513e10456a18232b21a7 Tree link: https://github.com/PolymerElements/neon-animation/tree/v1.2.4 Name: paper-behaviors -Version: 1.0.12 Repository: git://github.com/PolymerElements/paper-behaviors.git -Tag: v1.0.12 +Tree: v1.0.12 Revision: 424919089ce3a68dfac1de17e6a56f4e09048e95 Tree link: https://github.com/PolymerElements/paper-behaviors/tree/v1.0.12 Name: paper-button -Version: 1.0.13 Repository: git://github.com/PolymerElements/paper-button.git -Tag: v1.0.13 +Tree: v1.0.13 Revision: 649ac0c09fa74b5af258cb6debebba811024f7cc Tree link: https://github.com/PolymerElements/paper-button/tree/v1.0.13 Name: paper-checkbox -Version: 1.3.0 Repository: git://github.com/PolymerElements/paper-checkbox.git -Tag: v1.3.0 +Tree: v1.3.0 Revision: 47e05d17eeca4e9f3a06ef59a86ae9739fa84022 Tree link: https://github.com/PolymerElements/paper-checkbox/tree/v1.3.0 Name: paper-dialog -Version: 1.1.0 Repository: git://github.com/PolymerElements/paper-dialog.git -Tag: v1.1.0 +Tree: v1.1.0 Revision: 7f31fa918fbd562b516eb262f1ed527dcaf7b7c0 Tree link: https://github.com/PolymerElements/paper-dialog/tree/v1.1.0 Name: paper-dialog-behavior -Version: 1.2.7 Repository: git://github.com/PolymerElements/paper-dialog-behavior.git -Tag: v1.2.7 +Tree: v1.2.7 Revision: decc77ca55c0381cf01d7409ddf1eb966543e84e Tree link: https://github.com/PolymerElements/paper-dialog-behavior/tree/v1.2.7 Name: paper-drawer-panel -Version: 1.0.10 Repository: git://github.com/PolymerElements/paper-drawer-panel.git -Tag: v1.0.10 +Tree: v1.0.10 Revision: 34c1d82dc3048dff33c83047bfaa95414e36d673 Tree link: https://github.com/PolymerElements/paper-drawer-panel/tree/v1.0.10 Name: paper-dropdown-menu -Version: 1.3.3 Repository: git://github.com/PolymerElements/paper-dropdown-menu.git -Tag: v1.3.3 -Revision: 3684eba30503adb1ae2f395e917f7e5ed1ae38cd -Tree link: https://github.com/PolymerElements/paper-dropdown-menu/tree/v1.3.3 +Tree: v1.3.4 +Revision: 208e1c1df91ae941d0fc772acaf143e6e4f013dd +Tree link: https://github.com/PolymerElements/paper-dropdown-menu/tree/v1.3.4 Name: paper-fab -Version: 1.2.0 Repository: git://github.com/PolymerElements/paper-fab.git -Tag: v1.2.0 +Tree: v1.2.0 Revision: 691638ca9b922411926b916a592f01a5f25c1af8 Tree link: https://github.com/PolymerElements/paper-fab/tree/v1.2.0 Name: paper-header-panel -Version: 1.1.6 Repository: git://github.com/PolymerElements/paper-header-panel.git -Tag: v1.1.6 +Tree: v1.1.6 Revision: 3bf4e4f22eb12dd98039bad0eaaa942c2e869961 Tree link: https://github.com/PolymerElements/paper-header-panel/tree/v1.1.6 Name: paper-icon-button -Version: 1.1.2 Repository: git://github.com/PolymerElements/paper-icon-button.git -Tag: v1.1.2 +Tree: v1.1.2 Revision: 0a6c65f73765d6f6ae6cfe90ddc9905a2cf45f20 Tree link: https://github.com/PolymerElements/paper-icon-button/tree/v1.1.2 Name: paper-input -Version: 1.1.17 Repository: git://github.com/PolymerElements/paper-input.git -Tag: v1.1.17 +Tree: v1.1.17 Revision: 61d482886c58324b682cea3c605695c31154e084 Tree link: https://github.com/PolymerElements/paper-input/tree/v1.1.17 Name: paper-item -Version: 1.2.1 Repository: git://github.com/PolymerElements/paper-item.git -Tag: v1.2.1 +Tree: v1.2.1 Revision: 1eab91333b318ae19e315866575b2dddd38e6abc Tree link: https://github.com/PolymerElements/paper-item/tree/v1.2.1 Name: paper-listbox -Version: 1.1.2 Repository: git://github.com/PolymerelEments/paper-listbox.git -Tag: v1.1.2 +Tree: v1.1.2 Revision: b0fde50f57db3e8e4926e9d046be9d3c159a2bff Tree link: https://github.com/PolymerelEments/paper-listbox/tree/v1.1.2 Name: paper-material -Version: 1.0.6 Repository: git://github.com/PolymerElements/paper-material.git -Tag: v1.0.6 +Tree: v1.0.6 Revision: 6aef0896fcbc25f9f5bd1dd55f7679e6ab7f92ad Tree link: https://github.com/PolymerElements/paper-material/tree/v1.0.6 Name: paper-menu -Version: 1.2.2 Repository: git://github.com/PolymerElements/paper-menu.git -Tag: v1.2.2 +Tree: v1.2.2 Revision: f31a1dbc5b594a84c8c01eca0f23f9bcb8f6ba76 Tree link: https://github.com/PolymerElements/paper-menu/tree/v1.2.2 Name: paper-menu-button -Version: 1.5.1 Repository: git://github.com/PolymerElements/paper-menu-button.git -Tag: v1.5.1 +Tree: v1.5.1 Revision: 1a4d0a04177782beaf7a6c855ad10cf545da338f Tree link: https://github.com/PolymerElements/paper-menu-button/tree/v1.5.1 Name: paper-progress -Version: 1.0.10 Repository: git://github.com/PolymerElements/paper-progress.git -Tag: v1.0.10 +Tree: v1.0.10 Revision: dfdde2b02947fb2dfd3f2d303ec17f7f4919348c Tree link: https://github.com/PolymerElements/paper-progress/tree/v1.0.10 Name: paper-radio-button -Version: 1.2.1 Repository: git://github.com/PolymerElements/paper-radio-button.git -Tag: v1.2.1 +Tree: v1.2.1 Revision: d0839a28a638882f40216437d6878af0085d1df8 Tree link: https://github.com/PolymerElements/paper-radio-button/tree/v1.2.1 Name: paper-radio-group -Version: 1.2.0 Repository: git://github.com/PolymerElements/paper-radio-group.git -Tag: v1.2.0 +Tree: v1.2.0 Revision: 1505d1a57fbeabcb779de3e9f0e9857acd8b5f13 Tree link: https://github.com/PolymerElements/paper-radio-group/tree/v1.2.0 Name: paper-ripple -Version: 1.0.8 Repository: git://github.com/PolymerElements/paper-ripple.git -Tag: v1.0.8 +Tree: v1.0.8 Revision: eb1c01cac162b7ce7e78760d5c0df61c9a5c2974 Tree link: https://github.com/PolymerElements/paper-ripple/tree/v1.0.8 Name: paper-slider -Version: 1.0.11 Repository: git://github.com/PolymerElements/paper-slider.git -Tag: v1.0.11 +Tree: v1.0.11 Revision: 855e3ed20d12b4545175317536adca7897928537 Tree link: https://github.com/PolymerElements/paper-slider/tree/v1.0.11 Name: paper-spinner -Version: 1.2.0 Repository: git://github.com/PolymerElements/paper-spinner.git -Tag: v1.2.0 +Tree: v1.2.0 Revision: 66dc50a940aa9a3a067137defe1712aa85de6f35 Tree link: https://github.com/PolymerElements/paper-spinner/tree/v1.2.0 Name: paper-styles -Version: 1.1.4 Repository: git://github.com/PolymerElements/paper-styles.git -Tag: v1.1.4 +Tree: v1.1.4 Revision: 885bbd74db88dab4fb5dc229cdf994c55fb2b31b Tree link: https://github.com/PolymerElements/paper-styles/tree/v1.1.4 Name: paper-tabs -Version: 1.6.2 Repository: git://github.com/PolymerElements/paper-tabs.git -Tag: v1.6.2 +Tree: v1.6.2 Revision: fc3df3875f97cbcee8cfa8f4895d86a4fd2925c7 Tree link: https://github.com/PolymerElements/paper-tabs/tree/v1.6.2 Name: paper-toggle-button -Version: 1.1.2 Repository: git://github.com/PolymerElements/paper-toggle-button.git -Tag: v1.1.2 +Tree: v1.1.2 Revision: 18d90a3e164fcac6bd985fdaeba771873b1bc5df Tree link: https://github.com/PolymerElements/paper-toggle-button/tree/v1.1.2 Name: paper-toolbar -Version: 1.1.6 Repository: git://github.com/PolymerElements/paper-toolbar.git -Tag: v1.1.6 +Tree: v1.1.6 Revision: 39b8ad381bd4ba7834ed8f30a938b49810b9204f Tree link: https://github.com/PolymerElements/paper-toolbar/tree/v1.1.6 Name: paper-tooltip -Version: 1.1.2 Repository: git://github.com/PolymerElements/paper-tooltip.git -Tag: v1.1.2 +Tree: v1.1.2 Revision: 6be894127678900f6e506b56fc9622ab768c03aa Tree link: https://github.com/PolymerElements/paper-tooltip/tree/v1.1.2 Name: polymer -Version: 1.6.1 Repository: git://github.com/Polymer/polymer.git -Tag: v1.6.1 +Tree: v1.6.1 Revision: 1f197d9d7874b1e5808b2a5c26f34446a7d912fc Tree link: https://github.com/Polymer/polymer/tree/v1.6.1
diff --git a/third_party/polymer/v1_0/create_components_summary.py b/third_party/polymer/v1_0/create_components_summary.py index a8184db..922930761 100644 --- a/third_party/polymer/v1_0/create_components_summary.py +++ b/third_party/polymer/v1_0/create_components_summary.py
@@ -2,35 +2,59 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import os import json +import os +import re + COMPONENTS_DIR = 'components' COMPONENT_SUMMARY =\ """Name: %(name)s -Version: %(version)s Repository: %(repository)s -Tag: %(tag)s +Tree: %(tree)s Revision: %(revision)s -Tree link: %(tree)s +Tree link: %(tree_link)s """ -for entry in sorted(os.listdir(COMPONENTS_DIR)): - component_path = os.path.join(COMPONENTS_DIR, entry) - if not os.path.isdir(component_path): - continue - bower_path = os.path.join(component_path, '.bower.json') - if not os.path.isfile(bower_path): - raise Exception('%s is not a file.' % bower_path) - with open(bower_path) as stream: - info = json.load(stream) + +def PrintSummary(info): repository = info['_source'] - tree = 'https%s/tree/%s' % (repository[3:-4], info['_resolution']['tag']) + resolution = info['_resolution'] + tree = GetTreeishName(resolution) + # Convert to web link. + repository_web = re.sub('^git:', 'https:', re.sub('\.git$', '', repository)) + # Specify tree to browse to. + tree_link = repository_web + '/tree/' + tree print COMPONENT_SUMMARY % { 'name': info['name'], - 'version': info['version'], 'repository': repository, - 'tag': info['_resolution']['tag'], - 'revision': info['_resolution']['commit'], - 'tree': tree + 'tree': tree, + 'revision': resolution['commit'], + 'tree_link': tree_link } + + +def GetTreeishName(resolution): + """Gets the name of the tree-ish (branch, tag or commit).""" + if resolution['type'] == 'branch': + return resolution['branch'] + if resolution['type'] in ('version', 'tag'): + return resolution['tag'] + return resolution['commit'] + + +def main(): + for entry in sorted(os.listdir(COMPONENTS_DIR)): + component_path = os.path.join(COMPONENTS_DIR, entry) + if not os.path.isdir(component_path): + continue + bower_path = os.path.join(component_path, '.bower.json') + if not os.path.isfile(bower_path): + raise Exception('%s is not a file.' % bower_path) + with open(bower_path) as stream: + info = json.load(stream) + PrintSummary(info) + + +if __name__ == '__main__': + main()
diff --git a/tools/battor_agent/battor_agent.cc b/tools/battor_agent/battor_agent.cc index f17c4d5..6fc6ea17 100644 --- a/tools/battor_agent/battor_agent.cc +++ b/tools/battor_agent/battor_agent.cc
@@ -248,7 +248,7 @@ case Action::READ_CALIBRATION_FRAME: case Action::READ_DATA_FRAME: case Action::READ_CURRENT_SAMPLE: - if (++num_read_attempts_ > kMaxReadAttempts) { + if (num_read_attempts_++ > kMaxReadAttempts) { CompleteCommand(BATTOR_ERROR_RECEIVE_ERROR); return; }
diff --git a/tools/battor_agent/battor_agent_unittest.cc b/tools/battor_agent/battor_agent_unittest.cc index 8b2358bf..0239649 100644 --- a/tools/battor_agent/battor_agent_unittest.cc +++ b/tools/battor_agent/battor_agent_unittest.cc
@@ -355,7 +355,7 @@ TEST_F(BattOrAgentTest, StartTracingFailsIfInitAckReadFails) { RunStartTracingTo(BattOrAgentState::INIT_SENT); - for (int i = 0; i < 20; i++) { + for (int i = 0; i < 21; i++) { OnMessageRead(false, BATTOR_MESSAGE_TYPE_CONTROL_ACK, nullptr); // Bytes will be sent because INIT will be retried. @@ -369,7 +369,7 @@ TEST_F(BattOrAgentTest, StartTracingFailsIfInitWrongAckRead) { RunStartTracingTo(BattOrAgentState::INIT_SENT); - for (int i = 0; i < 20; i++) { + for (int i = 0; i < 21; i++) { OnMessageRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK, ToCharVector(kStartTracingAck)); @@ -569,7 +569,7 @@ TEST_F(BattOrAgentTest, StopTracingFailsIfEEPROMReadFails) { RunStopTracingTo(BattOrAgentState::EEPROM_REQUEST_SENT); - for (int i = 0; i < 20; i++) { + for (int i = 0; i < 21; i++) { OnMessageRead(false, BATTOR_MESSAGE_TYPE_CONTROL_ACK, nullptr); } @@ -616,7 +616,7 @@ RunStopTracingTo(BattOrAgentState::SAMPLES_REQUEST_SENT); // We attempt the read a max of 20 times: send that many failures. - for (int i = 0; i < 20; i++) { + for (int i = 0; i < 21; i++) { OnMessageRead(false, BATTOR_MESSAGE_TYPE_SAMPLES, nullptr); } @@ -642,7 +642,7 @@ RunStopTracingTo(BattOrAgentState::CALIBRATION_FRAME_RECEIVED); // We attempt the read a max of 20 times: send that many failures. - for (int i = 0; i < 20; i++) { + for (int i = 0; i < 21; i++) { OnMessageRead(false, BATTOR_MESSAGE_TYPE_SAMPLES, nullptr); }
diff --git a/tools/battor_agent/battor_connection_impl.cc b/tools/battor_agent/battor_connection_impl.cc index cf33c2a..849637bf 100644 --- a/tools/battor_agent/battor_connection_impl.cc +++ b/tools/battor_agent/battor_connection_impl.cc
@@ -228,9 +228,17 @@ return; } - LogSerial(StringPrintf( - "%d more bytes read: %s.", bytes_read, - CharArrayToString(pending_read_buffer_->data(), bytes_read).c_str())); + if (pending_read_message_type_ == BATTOR_MESSAGE_TYPE_SAMPLES) { + // If we're reading samples, don't log every byte that we receive. This + // exacerbates a problem on Mac wherein we can't process sample frames + // quickly enough to prevent the serial buffer from overflowing, causing us + // to drop frames. + LogSerial(StringPrintf("%d more bytes read.", bytes_read)); + } else { + LogSerial(StringPrintf( + "%d more bytes read: %s.", bytes_read, + CharArrayToString(pending_read_buffer_->data(), bytes_read).c_str())); + } already_read_buffer_.insert(already_read_buffer_.end(), pending_read_buffer_->data(),
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_benchmark.py b/tools/chrome_proxy/integration_tests/chrome_proxy_benchmark.py index 04740c5..70aa55b 100644 --- a/tools/chrome_proxy/integration_tests/chrome_proxy_benchmark.py +++ b/tools/chrome_proxy/integration_tests/chrome_proxy_benchmark.py
@@ -10,6 +10,21 @@ DESKTOP_PLATFORMS = ['mac', 'linux', 'win', 'chromeos'] WEBVIEW_PLATFORMS = ['android-webview', 'android-webview-shell'] + +class ChromeProxyBypassOnTimeout(ChromeProxyBenchmark): + """Check that the proxy bypasses when origin times out. + + If the origin site does not make an HTTP response in a reasonable + amount of time, the proxy should bypass. + """ + tag = 'timeout_bypass' + test = measurements.ChromeProxyBypassOnTimeout + page_set = pagesets.BypassOnTimeoutStorySet + + @classmethod + def Name(cls): + return 'chrome_proxy_benchmark.timeout_bypass.timeout_bypass' + class ChromeProxyClientType(ChromeProxyBenchmark): tag = 'client_type' test = measurements.ChromeProxyClientType @@ -316,4 +331,4 @@ @classmethod def Name(cls): - return 'chrome_proxy_benchmark.pingback' \ No newline at end of file + return 'chrome_proxy_benchmark.pingback'
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_measurements.py b/tools/chrome_proxy/integration_tests/chrome_proxy_measurements.py index 7c05b95..59903dd 100644 --- a/tools/chrome_proxy/integration_tests/chrome_proxy_measurements.py +++ b/tools/chrome_proxy/integration_tests/chrome_proxy_measurements.py
@@ -13,6 +13,20 @@ from telemetry.core import exceptions, util from telemetry.page import page_test +class ChromeProxyBypassOnTimeout(ChromeProxyValidation): + """Checks the client bypasses when endpoint site times out.""" + + def __init__(self): + super(ChromeProxyBypassOnTimeout, self).__init__( + restart_after_each_page=True, + metrics=metrics.ChromeProxyMetric()) + + def CustomizeBrowserOptions(self, options): + super(ChromeProxyBypassOnTimeout, self).CustomizeBrowserOptions( + options) + + def AddResults(self, tab, results): + self._metrics.AddResultsForBypassOnTimeout(tab, results) class ChromeProxyDataSaving(page_test.PageTest): """Chrome proxy data saving measurement.""" @@ -677,4 +691,4 @@ '--enable-stats-collection-bindings') def AddResults(self, tab, results): - self._metrics.AddResultsForPingback(tab, results) \ No newline at end of file + self._metrics.AddResultsForPingback(tab, results)
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_metrics.py b/tools/chrome_proxy/integration_tests/chrome_proxy_metrics.py index 9c12daa1c..56ef213 100644 --- a/tools/chrome_proxy/integration_tests/chrome_proxy_metrics.py +++ b/tools/chrome_proxy/integration_tests/chrome_proxy_metrics.py
@@ -872,6 +872,27 @@ results.AddValue(scalar.ScalarValue( results.current_page, 'succeeded_sum', 'count', succeeded)) + def AddResultsForBypassOnTimeout(self, tab, results): + bypass_count = 0 + # Wait maximum of 120 seconds for test to complete. Should complete soon + # after 90 second test server delay in case of failure, and much sooner in + # case of success. + tab.WaitForDocumentReadyStateToBeComplete(timeout=120) + for resp in self.IterResponses(tab): + if resp.HasChromeProxyViaHeader() and not resp.response.url.endswith( + 'favicon.ico'): + r = resp.response + raise ChromeProxyMetricException, ( + 'Response for %s should not have via header after HTTP timeout.\n' + 'Reponse: status=(%d)\nHeaders:\n %s' % ( + r.url, r.status, r.headers)) + elif not resp.response.url.endswith('favicon.ico'): + bypass_count += 1 + if bypass_count == 0: + raise ChromeProxyMetricException('No pages were tested!') + results.AddValue(scalar.ScalarValue( + results.current_page, 'bypass', 'count', bypass_count)) + PROXIED = 'proxied' DIRECT = 'direct'
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/http_timeout.py b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/http_timeout.py new file mode 100644 index 0000000..e7587a77 --- /dev/null +++ b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/http_timeout.py
@@ -0,0 +1,26 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +from telemetry.page import page as page_module +from telemetry import story + + +class BypassOnTimeoutPage(page_module.Page): + + def __init__(self, url, page_set): + super(BypassOnTimeoutPage, self).__init__(url=url, page_set=page_set) + + +class BypassOnTimeoutStorySet(story.StorySet): + """This site takes 60s to respond when being accessed by proxy.""" + + def __init__(self): + super(BypassOnTimeoutStorySet, self).__init__() + + urls_list = [ + 'http://chromeproxy-test.appspot.com/blackhole' + ] + + for url in urls_list: + self.AddStory(BypassOnTimeoutPage(url, self))
diff --git a/tools/chrome_proxy/testserver/app.yaml b/tools/chrome_proxy/testserver/app.yaml index a73e1ee9..6ee8284 100644 --- a/tools/chrome_proxy/testserver/app.yaml +++ b/tools/chrome_proxy/testserver/app.yaml
@@ -2,8 +2,6 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -application: chromeproxy-test -version: 1 runtime: go api_version: go1
diff --git a/tools/chrome_proxy/testserver/server.go b/tools/chrome_proxy/testserver/server.go index 698e45c..0861fab3 100644 --- a/tools/chrome_proxy/testserver/server.go +++ b/tools/chrome_proxy/testserver/server.go
@@ -35,12 +35,15 @@ "net/http" "os" "strconv" + "strings" + "time" ) func init() { http.HandleFunc("/requestHeader", requestHeader) http.HandleFunc("/resource", resource) http.HandleFunc("/default", defaultResponse) + http.HandleFunc("/blackhole", blackholeProxy) } // requestHander returns request headers in response body as text. @@ -82,6 +85,19 @@ } } +// blackholePoxy delays 90 seconds for proxied responses, in order to test if +// the proxy will timeout on the site. Responds immediately to any other request. +func blackholeProxy(w http.ResponseWriter, r *http.Request) { + if strings.Contains(r.Header.Get("via"), "Chrome-Compression-Proxy") { + // Causes timeout on proxy, will then send BLOCK_ONCE. + // Appspot will 502 traffic at 120 seconds with no response. + time.Sleep(90 * time.Second); + w.Write([]byte("You are proxy")); + } else { + w.Write([]byte("You are direct")); + } +} + type override struct { status int header http.Header
diff --git a/tools/copyright_scanner/third_party_files_whitelist.txt b/tools/copyright_scanner/third_party_files_whitelist.txt index d1a304f..e6d125b 100644 --- a/tools/copyright_scanner/third_party_files_whitelist.txt +++ b/tools/copyright_scanner/third_party_files_whitelist.txt
@@ -248,3 +248,9 @@ components/test_runner/helper/layout_test_helper_mac.mm # Bundles of existing code. chrome/browser/resources/md_downloads/vulcanized.html +# Generated config files, which are checked in outside of the third-party +# library they configure. Copyright The open-vcdiff Authors; Apache2 license. +sdch/ios/config.h +sdch/linux/config.h +sdch/mac/config.h +sdch/win/config.h
diff --git a/tools/gn/bootstrap/bootstrap.py b/tools/gn/bootstrap/bootstrap.py index fa81d10..aab92c2 100755 --- a/tools/gn/bootstrap/bootstrap.py +++ b/tools/gn/bootstrap/bootstrap.py
@@ -373,6 +373,7 @@ 'base/base_switches.cc', 'base/callback_internal.cc', 'base/command_line.cc', + 'base/debug/activity_tracker.cc', 'base/debug/alias.cc', 'base/debug/stack_trace.cc', 'base/debug/task_annotator.cc',
diff --git a/tools/gn/function_toolchain.cc b/tools/gn/function_toolchain.cc index 852d25a5..69ca961c 100644 --- a/tools/gn/function_toolchain.cc +++ b/tools/gn/function_toolchain.cc
@@ -321,9 +321,8 @@ "\n" " When you specify a target using an alternate toolchain, the master\n" " build configuration file is re-interpreted in the context of that\n" - " toolchain (see \"gn help toolchain\"). The toolchain_args allows you\n" - " to control the arguments passed into this alternate invocation of\n" - " the build.\n" + " toolchain. toolchain_args allows you to control the arguments\n" + " passed into this alternate invocation of the build.\n" "\n" " Any default system arguments or arguments passed in via \"gn args\"\n" " will also be passed to the alternate invocation unless explicitly\n"
diff --git a/tools/gn/operators.cc b/tools/gn/operators.cc index ac6a37f..9ac18bf 100644 --- a/tools/gn/operators.cc +++ b/tools/gn/operators.cc
@@ -209,6 +209,33 @@ *err = Err(*name_token_, "Undefined identifier."); } +// Computes an error message for overwriting a nonempty list/scope with another. +Err MakeOverwriteError(const BinaryOpNode* op_node, + const Value& old_value) { + std::string type_name; + std::string empty_def; + + if (old_value.type() == Value::LIST) { + type_name = "list"; + empty_def = "[]"; + } else if (old_value.type() == Value::SCOPE) { + type_name = "scope"; + empty_def = "{}"; + } else { + NOTREACHED(); + } + + Err result(op_node->left()->GetRange(), + "Replacing nonempty " + type_name + ".", + "This overwrites a previously-defined nonempty " + type_name + + "with another nonempty " + type_name + "."); + result.AppendSubErr(Err(old_value, "for previous definition", + "Did you mean to append/modify instead? If you really want to overwrite, " + "do:\n" + " foo = " + empty_def + "\nbefore reassigning.")); + return result; +} + // ----------------------------------------------------------------------------- Err MakeIncompatibleTypeError(const BinaryOpNode* op_node, @@ -297,31 +324,23 @@ Err* err) { const Value* old_value = dest->GetExistingValue(); if (old_value) { - // Throw an error when overwriting a nonempty list with another nonempty - // list item. This is to detect the case where you write - // defines = ["FOO"] - // and you overwrote inherited ones, when instead you mean to append: - // defines += ["FOO"] - if (old_value->type() == Value::LIST && - !old_value->list_value().empty() && - right.type() == Value::LIST && - !right.list_value().empty()) { - *err = Err(op_node->left()->GetRange(), "Replacing nonempty list.", - std::string("This overwrites a previously-defined nonempty list ") + - "(length " + - base::IntToString(static_cast<int>(old_value->list_value().size())) - + ")."); - err->AppendSubErr(Err(*old_value, "for previous definition", - "with another one (length " + - base::IntToString(static_cast<int>(right.list_value().size())) + - "). Did you mean " + - "\"+=\" to append instead? If you\nreally want to do this, do\n" - " foo = []\nbefore reassigning.")); + // Check for overwriting nonempty scopes or lists with other nonempty + // scopes or lists. This prevents mistakes that clobber a value rather than + // appending to it. For cases where a user meant to clear a value, allow + // overwriting a nonempty list/scope with an empty one, which can then be + // modified. + if (old_value->type() == Value::LIST && right.type() == Value::LIST && + !old_value->list_value().empty() && !right.list_value().empty()) { + *err = MakeOverwriteError(op_node, *old_value); + return Value(); + } else if (old_value->type() == Value::SCOPE && + right.type() == Value::SCOPE && + old_value->scope_value()->HasValues(Scope::SEARCH_CURRENT) && + right.scope_value()->HasValues(Scope::SEARCH_CURRENT)) { + *err = MakeOverwriteError(op_node, *old_value); return Value(); } } - if (err->has_error()) - return Value(); Value* written_value = dest->SetValue(std::move(right), op_node->right());
diff --git a/tools/gn/operators_unittest.cc b/tools/gn/operators_unittest.cc index e2c396c4..4fa3d11 100644 --- a/tools/gn/operators_unittest.cc +++ b/tools/gn/operators_unittest.cc
@@ -26,15 +26,6 @@ return v.string_value() == s; } -// Returns a list populated with a single literal Value corresponding to the -// given token. The token must outlive the list (since the list will just -// copy the reference). -std::unique_ptr<ListNode> ListWithLiteral(const Token& token) { - std::unique_ptr<ListNode> list(new ListNode); - list->append_item(std::unique_ptr<ParseNode>(new LiteralNode(token))); - return list; -} - // This parse node is for passing to tests. It returns a canned value for // Execute(). class TestParseNode : public ParseNode { @@ -59,6 +50,54 @@ Value value_; }; +// Sets up a BinaryOpNode for testing. +class TestBinaryOpNode : public BinaryOpNode { + public: + // Input token value string must outlive class. + TestBinaryOpNode(Token::Type op_token_type, + const char* op_token_value) + : BinaryOpNode(), + op_token_ownership_(Location(), op_token_type, op_token_value) { + set_op(op_token_ownership_); + } + + void SetLeftToValue(const Value& value) { + set_left(std::unique_ptr<ParseNode>(new TestParseNode(value))); + } + + // Sets the left-hand side of the operator to an identifier node, this is + // used for testing assignments. Input string must outlive class. + void SetLeftToIdentifier(const char* identifier) { + left_identifier_token_ownership_ = + Token(Location(), Token::IDENTIFIER, identifier); + set_left(std::unique_ptr<ParseNode>( + new IdentifierNode(left_identifier_token_ownership_))); + } + + void SetRightToValue(const Value& value) { + set_right(std::unique_ptr<ParseNode>(new TestParseNode(value))); + } + void SetRightToListOfValue(const Value& value) { + Value list(nullptr, Value::LIST); + list.list_value().push_back(value); + set_right(std::unique_ptr<ParseNode>(new TestParseNode(list))); + } + void SetRightToListOfValue(const Value& value1, const Value& value2) { + Value list(nullptr, Value::LIST); + list.list_value().push_back(value1); + list.list_value().push_back(value2); + set_right(std::unique_ptr<ParseNode>(new TestParseNode(list))); + } + + private: + // The base class takes the Token by reference, this manages the lifetime. + Token op_token_ownership_; + + // When setting the left to an identifier, this manages the lifetime of + // the identifier token. + Token left_identifier_token_ownership_; +}; + } // namespace TEST(Operators, SourcesAppend) { @@ -70,15 +109,8 @@ setup.scope()->SetValue(sources, Value(nullptr, Value::LIST), nullptr); // Set up the operator. - BinaryOpNode node; - const char token_value[] = "+="; - Token op(Location(), Token::PLUS_EQUALS, token_value); - node.set_op(op); - - // Append to the sources variable. - Token identifier_token(Location(), Token::IDENTIFIER, sources); - node.set_left( - std::unique_ptr<ParseNode>(new IdentifierNode(identifier_token))); + TestBinaryOpNode node(Token::PLUS_EQUALS, "+="); + node.SetLeftToIdentifier(sources); // Set up the filter on the scope to remove everything ending with "rm" std::unique_ptr<PatternList> pattern_list(new PatternList); @@ -86,31 +118,25 @@ setup.scope()->set_sources_assignment_filter(std::move(pattern_list)); // Append an integer. - const char integer_value[] = "5"; - Token integer(Location(), Token::INTEGER, integer_value); - node.set_right(ListWithLiteral(integer)); + node.SetRightToListOfValue(Value(nullptr, static_cast<int64_t>(5))); node.Execute(setup.scope(), &err); EXPECT_FALSE(err.has_error()); // Append a string that doesn't match the pattern, it should get appended. - const char string_1_value[] = "\"good\""; - Token string_1(Location(), Token::STRING, string_1_value); - node.set_right(ListWithLiteral(string_1)); + const char string1[] = "good"; + node.SetRightToListOfValue(Value(nullptr, string1)); node.Execute(setup.scope(), &err); EXPECT_FALSE(err.has_error()); // Append a string that does match the pattern, it should be a no-op. - const char string_2_value[] = "\"foo-rm\""; - Token string_2(Location(), Token::STRING, string_2_value); - node.set_right(ListWithLiteral(string_2)); + const char string2[] = "foo-rm"; + node.SetRightToListOfValue(Value(nullptr, string2)); node.Execute(setup.scope(), &err); EXPECT_FALSE(err.has_error()); // Append a list with the two strings from above. - ListNode list; - list.append_item(std::unique_ptr<ParseNode>(new LiteralNode(string_1))); - list.append_item(std::unique_ptr<ParseNode>(new LiteralNode(string_2))); - ExecuteBinaryOperator(setup.scope(), &node, node.left(), &list, &err); + node.SetRightToListOfValue(Value(nullptr, string1), Value(nullptr, string2)); + node.Execute(setup.scope(), &err); EXPECT_FALSE(err.has_error()); // The sources variable in the scope should now have: [ 5, "good", "good" ] @@ -133,23 +159,14 @@ const char foo[] = "foo"; setup.scope()->SetValue(foo, Value(nullptr, Value::LIST), nullptr); - // Set up the operator. - BinaryOpNode node; - const char token_value[] = "+="; - Token op(Location(), Token::PLUS_EQUALS, token_value); - node.set_op(op); - - // Append to the foo variable. - Token identifier_token(Location(), Token::IDENTIFIER, foo); - node.set_left( - std::unique_ptr<ParseNode>(new IdentifierNode(identifier_token))); + // Set up the operator to append to "foo". + TestBinaryOpNode node(Token::PLUS_EQUALS, "+="); + node.SetLeftToIdentifier(foo); // Append a list with a list, the result should be a nested list. - std::unique_ptr<ListNode> outer_list(new ListNode); - const char twelve_str[] = "12"; - Token twelve(Location(), Token::INTEGER, twelve_str); - outer_list->append_item(ListWithLiteral(twelve)); - node.set_right(std::move(outer_list)); + Value inner_list(nullptr, Value::LIST); + inner_list.list_value().push_back(Value(nullptr, static_cast<int64_t>(12))); + node.SetRightToListOfValue(inner_list); Value ret = ExecuteBinaryOperator(setup.scope(), &node, node.left(), node.right(), &err); @@ -177,7 +194,7 @@ EXPECT_TRUE(err.has_error()); err = Err(); - node.set_right(std::unique_ptr<ParseNode>(new LiteralNode(twelve))); + node.SetRightToValue(Value(nullptr, static_cast<int64_t>(12))); ExecuteBinaryOperator(setup.scope(), &node, node.left(), node.right(), &err); EXPECT_TRUE(err.has_error()); } @@ -194,26 +211,14 @@ test_list.list_value().push_back(Value(nullptr, foo_str)); // Set up "var" with an the test list. - const char var_str[] = "var"; - setup.scope()->SetValue(var_str, test_list, nullptr); + const char var[] = "var"; + setup.scope()->SetValue(var, test_list, nullptr); - // Set up the operator. - BinaryOpNode node; - const char token_value[] = "-="; - Token op(Location(), Token::MINUS_EQUALS, token_value); - node.set_op(op); - - // Do -= on the var. - Token identifier_token(Location(), Token::IDENTIFIER, var_str); - node.set_left( - std::unique_ptr<ParseNode>(new IdentifierNode(identifier_token))); + TestBinaryOpNode node(Token::MINUS_EQUALS, "-="); + node.SetLeftToIdentifier(var); // Subtract a list consisting of "foo". - Value foo_list(nullptr, Value::LIST); - foo_list.list_value().push_back(Value(nullptr, foo_str)); - std::unique_ptr<ParseNode> outer_list(new TestParseNode(foo_list)); - node.set_right(std::move(outer_list)); - + node.SetRightToListOfValue(Value(nullptr, foo_str)); Value result = ExecuteBinaryOperator( setup.scope(), &node, node.left(), node.right(), &err); EXPECT_FALSE(err.has_error()); @@ -224,7 +229,7 @@ // The "var" variable should have been updated. Both instances of "foo" are // deleted. - const Value* new_value = setup.scope()->GetValue(var_str); + const Value* new_value = setup.scope()->GetValue(var); ASSERT_TRUE(new_value); ASSERT_EQ(Value::LIST, new_value->type()); ASSERT_EQ(1u, new_value->list_value().size()); @@ -236,16 +241,9 @@ Err err; TestWithScope setup; - // Set up the operator. - BinaryOpNode node; - const char token_value[] = "&&"; - Token op(Location(), Token::BOOLEAN_AND, token_value); - node.set_op(op); - - // Set the left to false. - const char false_str[] = "false"; - Token false_tok(Location(), Token::FALSE_TOKEN, false_str); - node.set_left(std::unique_ptr<ParseNode>(new LiteralNode(false_tok))); + // Set a && operator with the left to false. + TestBinaryOpNode node(Token::BOOLEAN_AND, "&&"); + node.SetLeftToValue(Value(nullptr, false)); // Set right as foo, but don't define a value for it. const char foo[] = "foo"; @@ -262,16 +260,9 @@ Err err; TestWithScope setup; - // Set up the operator. - BinaryOpNode node; - const char token_value[] = "||"; - Token op(Location(), Token::BOOLEAN_OR, token_value); - node.set_op(op); - - // Set the left to false. - const char false_str[] = "true"; - Token false_tok(Location(), Token::TRUE_TOKEN, false_str); - node.set_left(std::unique_ptr<ParseNode>(new LiteralNode(false_tok))); + // Set a || operator with the left to true. + TestBinaryOpNode node(Token::BOOLEAN_OR, "||"); + node.SetLeftToValue(Value(nullptr, true)); // Set right as foo, but don't define a value for it. const char foo[] = "foo"; @@ -283,3 +274,59 @@ node.right(), &err); EXPECT_FALSE(err.has_error()); } + +// Overwriting nonempty lists and scopes with other nonempty lists and scopes +// should be disallowed. +TEST(Operators, NonemptyOverwriting) { + Err err; + TestWithScope setup; + + // Set up "foo" with a nonempty list. + const char foo[] = "foo"; + Value old_value(nullptr, Value::LIST); + old_value.list_value().push_back(Value(nullptr, "string")); + setup.scope()->SetValue(foo, old_value, nullptr); + + TestBinaryOpNode node(Token::EQUAL, "="); + node.SetLeftToIdentifier(foo); + + // Assigning a nonempty list should fail. + node.SetRightToListOfValue(Value(nullptr, "string")); + node.Execute(setup.scope(), &err); + ASSERT_TRUE(err.has_error()); + EXPECT_EQ("Replacing nonempty list.", err.message()); + err = Err(); + + // Assigning an empty list should succeed. + node.SetRightToValue(Value(nullptr, Value::LIST)); + node.Execute(setup.scope(), &err); + ASSERT_FALSE(err.has_error()); + const Value* new_value = setup.scope()->GetValue(foo); + ASSERT_TRUE(new_value); + ASSERT_EQ(Value::LIST, new_value->type()); + ASSERT_TRUE(new_value->list_value().empty()); + + // Set up "foo" with a nonempty scope. + const char bar[] = "bar"; + old_value = Value( + nullptr, std::unique_ptr<Scope>(new Scope(setup.settings()))); + old_value.scope_value()->SetValue(bar, Value(nullptr, "bar"), nullptr); + setup.scope()->SetValue(foo, old_value, nullptr); + + // Assigning a nonempty scope should fail (re-use old_value copy). + node.SetRightToValue(old_value); + node.Execute(setup.scope(), &err); + ASSERT_TRUE(err.has_error()); + EXPECT_EQ("Replacing nonempty scope.", err.message()); + err = Err(); + + // Assigning an empty list should succeed. + node.SetRightToValue( + Value(nullptr, std::unique_ptr<Scope>(new Scope(setup.settings())))); + node.Execute(setup.scope(), &err); + ASSERT_FALSE(err.has_error()); + new_value = setup.scope()->GetValue(foo); + ASSERT_TRUE(new_value); + ASSERT_EQ(Value::SCOPE, new_value->type()); + ASSERT_FALSE(new_value->scope_value()->HasValues(Scope::SEARCH_CURRENT)); +}
diff --git a/tools/gn/scope.cc b/tools/gn/scope.cc index 7e7c201..fbe73f44 100644 --- a/tools/gn/scope.cc +++ b/tools/gn/scope.cc
@@ -71,6 +71,11 @@ mutable_containing_ = nullptr; } +bool Scope::HasValues(SearchNested search_nested) const { + DCHECK(search_nested == SEARCH_CURRENT); + return !values_.empty(); +} + const Value* Scope::GetValue(const base::StringPiece& ident, bool counts_as_used) { // First check for programmatically-provided values.
diff --git a/tools/gn/scope.h b/tools/gn/scope.h index 3d36712..b87afcd 100644 --- a/tools/gn/scope.h +++ b/tools/gn/scope.h
@@ -125,6 +125,14 @@ // self-sufficient. void DetachFromContaining(); + // Returns true if the scope has any values set. This does not check other + // things that may be set like templates or defaults. + // + // Currently this does not search nested scopes and this will assert if you + // want to search nested scopes. The enum is passed so the callers are + // unambiguous about nested scope handling. This can be added if needed. + bool HasValues(SearchNested search_nested) const; + // Returns NULL if there's no such value. // // counts_as_used should be set if the variable is being read in a way that @@ -133,16 +141,6 @@ bool counts_as_used); const Value* GetValue(const base::StringPiece& ident) const; - // If the value exists in the current scope, destrictively moves it into the - // return value. If it exists in a containing scope, copies it. - // - // This is for implementing modify-write operations where we want to read - // the existing value and plan to immediately overwrite it. If the value is - // in a containing scope, we never want to touch it (all writes go to the - // current scope), but if it's in the current scope, avoid the copy since it - // will be overwritten anyway. - //Value DestructiveMoveOut(const base::StringPiece& ident); - // Returns the requested value as a mutable one if possible. If the value // is not found in a mutable scope, then returns null. Note that the value // could still exist in a const scope, so GetValue() could still return
diff --git a/tools/ipc_fuzzer/message_lib/all_messages.h b/tools/ipc_fuzzer/message_lib/all_messages.h index 739c446d..13e93d1a 100644 --- a/tools/ipc_fuzzer/message_lib/all_messages.h +++ b/tools/ipc_fuzzer/message_lib/all_messages.h
@@ -24,7 +24,6 @@ #include "components/pdf/common/pdf_message_generator.h" #include "components/spellcheck/common/spellcheck_message_generator.h" #include "components/tracing/common/tracing_messages.h" -#include "components/translate/content/common/translate_messages.h" #include "components/visitedlink/common/visitedlink_message_generator.h" #include "content/common/all_messages.h" #include "extensions/common/extension_message_generator.h"
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index 9c8e72ecc..142a2372 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -710,11 +710,13 @@ # but it's not clear if that's actually used anywhere. 'win': 'gn_official_x86', 'win-asan': 'gn_official_syzyasan_x86', + 'win-clang': 'gn_official_clang_x86', 'win-pgo': [ 'gn_official_chrome_pgo_phase_1_x86', 'gn_official_chrome_pgo_phase_2_x86', ], 'win64': 'gn_official_x64', + 'win64-clang': 'gn_official_clang_x64', 'win64-pgo': [ 'gn_official_chrome_pgo_phase_1_x64', 'gn_official_chrome_pgo_phase_2_x64', @@ -1237,6 +1239,14 @@ 'gn', 'official', ], + 'gn_official_clang_x64': [ + 'gn', 'clang', 'official', 'x64', + ], + + 'gn_official_clang_x86': [ + 'gn', 'clang', 'official', 'x86', + ], + 'gn_official_x86': [ 'gn', 'official', 'x86', ],
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index 820924f..be49f69 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -3547,6 +3547,13 @@ </description> </action> +<action name="DownloadNotification.Button_Annotate"> + <owner>derat@chromium.org</owner> + <description> + User pushes "Annotate" button on download notification. + </description> +</action> + <action name="DownloadNotification.Button_Cancel"> <owner>yoshiki@chromium.org</owner> <description> @@ -12380,6 +12387,16 @@ </description> </action> +<action name="PasswordManager_LoginFollowingAutofill"> + <owner>vabr@chromium.org</owner> + <owner>vasilii@chromium.org</owner> + <description> + The user logged in successfully with a credential originally filled by + Chrome, and either did not change the stored password at all, or authorized + Chrome to update it with the current password value. + </description> +</action> + <action name="PasswordManager_LoginPassed"> <owner>vasilii@chromium.org</owner> <description> @@ -12399,6 +12416,15 @@ <description>Please enter the description of this user action.</description> </action> +<action name="PasswordManager_SyncCredentialFilledAndLoginSuccessfull"> + <owner>vabr@chromium.org</owner> + <owner>vasilii@chromium.org</owner> + <description> + Counts the number of times when Chrome fills the user's sync account + credentials, and the user logs in successfully after submitting them. + </description> +</action> + <action name="PasswordManager_SyncCredentialShown"> <owner>gcasto@chromium.org</owner> <owner>vabr@chromium.org</owner> @@ -12415,6 +12441,7 @@ Counts the number of times a user submits an autofilled credential which matches their sync account. </description> + <obsolete>Counted the wrong thing, http://crbug.com/635428</obsolete> </action> <action name="PasswordManager_UsedNonDefaultUsername">
diff --git a/tools/metrics/histograms/find_unmapped_histograms.py b/tools/metrics/histograms/find_unmapped_histograms.py index d1787026..25f0cb2 100644 --- a/tools/metrics/histograms/find_unmapped_histograms.py +++ b/tools/metrics/histograms/find_unmapped_histograms.py
@@ -124,7 +124,9 @@ names that might vary during a single run of the app. Returns: - A set containing any found literal histogram names. + A tuple of + a set containing any found literal histogram names, and + a set mapping histogram name to first filename:line where it was found """ logging.info('Scanning Chromium source for histograms...') @@ -136,14 +138,14 @@ filenames = set([location.split(':')[0] for location in locations]) histograms = set() + location_map = dict() for filename in filenames: contents = '' with open(filename, 'r') as f: contents = f.read() - matches = set(HISTOGRAM_REGEX.findall(contents)) - for histogram in matches: - histogram = collapseAdjacentCStrings(histogram) + for match in HISTOGRAM_REGEX.finditer(contents): + histogram = collapseAdjacentCStrings(match.group(1)) # Must begin and end with a quotation mark. if not histogram or histogram[0] != '"' or histogram[-1] != '"': @@ -156,9 +158,12 @@ logNonLiteralHistogram(filename, histogram) continue - histograms.add(histogram_stripped) + if histogram_stripped not in histograms: + histograms.add(histogram_stripped) + line_number = contents[:match.start()].count('\n') + 1 + location_map[histogram_stripped] = '%s:%d' % (filename, line_number) - return histograms + return histograms, location_map def readXmlHistograms(histograms_file_location): @@ -212,6 +217,11 @@ '--root-directory) [optional, defaults to "%s"]' % default_extra_histograms_path, metavar='FILE') + parser.add_option( + '--verbose', action='store_true', dest='verbose', default=False, + help=( + 'print file position information with histograms ' + + '[optional, defaults to %default]')) (options, args) = parser.parse_args() if args: @@ -225,7 +235,7 @@ except EnvironmentError as e: logging.error("Could not change to root directory: %s", e) sys.exit(1) - chromium_histograms = readChromiumHistograms() + chromium_histograms, location_map = readChromiumHistograms() xml_histograms = readXmlHistograms(options.histograms_file_location) unmapped_histograms = chromium_histograms - xml_histograms @@ -241,7 +251,11 @@ logging.info('Histograms in Chromium but not in XML files:') logging.info('-------------------------------------------------') for histogram in sorted(unmapped_histograms): - logging.info(' %s - %s', histogram, hashHistogramName(histogram)) + if options.verbose: + logging.info('%s: %s - %s', location_map[histogram], histogram, + hashHistogramName(histogram)) + else: + logging.info(' %s - %s', histogram, hashHistogramName(histogram)) else: logging.info('Success! No unmapped histograms found.')
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 5b9a378..4334e50 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -3912,6 +3912,32 @@ </summary> </histogram> +<histogram name="Blink.ScriptValueSerializer.DOMWrapperCount" units="objects"> + <owner>platform-architecture-dev@chromium.org</owner> + <summary> + Number of DOM wrappers serialized as part of an object passed to + postMessage, IndexedDB, or another API that serializes script values. + </summary> +</histogram> + +<histogram name="Blink.ScriptValueSerializer.JSObjectCount" units="objects"> + <owner>platform-architecture-dev@chromium.org</owner> + <summary> + Number of JavaScript objects (other than DOM wrappers) serialized as part of + an object passed to postMessage, IndexedDB, or another API that serializes + script values. + </summary> +</histogram> + +<histogram name="Blink.ScriptValueSerializer.PrimitiveCount" units="values"> + <owner>platform-architecture-dev@chromium.org</owner> + <summary> + Number of primitive values (numbers, strings, etc.) serialized as part of an + object passed to postMessage, IndexedDB, or another API that serializes + script values. + </summary> +</histogram> + <histogram name="Blink.SharedBuffer.FailedLock" enum="ResourceType"> <owner>hiroshige@chromium.org</owner> <summary> @@ -23614,6 +23640,10 @@ <histogram name="Memory.CompressibleStringCount" enum="CompressibleStringCountType"> + <obsolete> + Deprecated as of Aug 2016. CompressibleString has been reverted once at + https://crrev.com/2227933002. + </obsolete> <owner>hajimehoshi@chromium.org</owner> <summary> This records the frequency with which JavaScript source strings are @@ -35579,7 +35609,10 @@ <histogram name="NewTabPage.Snippets.FetchTime" units="ms"> <owner>mastiz@chromium.org</owner> - <summary>Time spent fetching snippets.</summary> + <summary> + Time spent fetching snippets. Only recorded for fetch attempts that resulted + in an actual network request. + </summary> </histogram> <histogram name="NewTabPage.Snippets.IncompleteSnippetsAfterFetch" @@ -35850,6 +35883,16 @@ </summary> </histogram> +<histogram name="Notifications.Database.DeleteBeforeWriteResult" + enum="NotificationDatabaseStatus"> + <owner>peter@chromium.org</owner> + <summary> + Records the result status codes of deleting notification data from the Web + Notification database that share their tag (replacement identifier) with a + notification that's about to be shown. + </summary> +</histogram> + <histogram name="Notifications.Database.DeleteResult" enum="NotificationDatabaseStatus"> <owner>peter@chromium.org</owner> @@ -38055,6 +38098,32 @@ </summary> </histogram> +<histogram name="PageLoad.Experimental.Cache.RequestPercent.ParseStop" + units="%"> + <owner>csharrison@chromium.org</owner> + <summary> + The percent of subresources loaded from cache for the given page load. + Recorded at the end of HTML parsing. + </summary> +</histogram> + +<histogram name="PageLoad.Experimental.Cache.TotalRequests.ParseStop" + units="requests"> + <owner>csharrison@chromium.org</owner> + <summary> + The number of subresources a given page finished loading from cache at parse + stop. + </summary> +</histogram> + +<histogram name="PageLoad.Experimental.TotalRequests.ParseStop" + units="requests"> + <owner>csharrison@chromium.org</owner> + <summary> + The number of subresources a given page finished loading at parse stop. + </summary> +</histogram> + <histogram name="PageLoad.Internal.ClientRedirect.FirstPaintToNavigation" units="ms"> <owner>bmcquade@chromium.org</owner> @@ -39418,6 +39487,15 @@ </summary> </histogram> +<histogram name="PaymentRequest.SelectedPaymentMethod" + enum="PaymentRequestPaymentMethods"> + <owner>sebsg@chromium.org</owner> + <summary> + Tracks what payment method was used to complete a transaction in Payment + Request. + </summary> +</histogram> + <histogram name="PDF.DocumentFeature" enum="PDFFeatures"> <owner>tsergeant@chromium.org</owner> <summary> @@ -39528,6 +39606,30 @@ </summary> </histogram> +<histogram name="Permissions.Prompt.DismissCount"> + <owner>dominickn@chromium.org</owner> + <summary> + This metric, recorded at the time of a permission prompt dismissal, records + the total number of prompt dismissal events for this origin since the last + time the user cleared their history or site data, inclusive of the current + dismissal. Every event in a bucket larger than 1 in this histogram will also + have an event in each smaller bucket. The suffix of the histogram indicates + which particular permission. + </summary> +</histogram> + +<histogram name="Permissions.Prompt.IgnoreCount"> + <owner>dominickn@chromium.org</owner> + <summary> + This metric, recorded at the time of a permission prompt ignore, records the + total number of prompt ignore events for this origin since the last time the + user cleared their history or site data, inclusive of the current ignore. + Every event in a bucket larger than 1 in this histogram will also have an + event in each smaller bucket. The suffix of the histogram indicates which + particular permission. + </summary> +</histogram> + <histogram name="Permissions.Prompt.MergedBubbleAccepted" enum="PermissionRequestType"> <owner>benwells@chromium.org</owner> @@ -42692,6 +42794,14 @@ </summary> </histogram> +<histogram name="Plugin.Flash.YouTubeRewrite" enum="YouTubeRewriteStatus"> + <owner>mlamouri@chromium.org</owner> + <owner>kdsilva@google.org</owner> + <summary> + Records the YouTube Flash embed rewrite status when attempted. + </summary> +</histogram> + <histogram name="Plugin.FlashNavigateUsage" enum="FlashNavigateUsageType"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <summary>Record usage of PPB_Flash.Navigate() Pepper API.</summary> @@ -42742,13 +42852,24 @@ <histogram name="Plugin.PowerSaver.PeripheralHeuristic" enum="PluginPowerSaverPeripheralHeuristicDecision"> + <obsolete> + Deprecated in favor of Plugin.PowerSaver.PeripheralHeuristicFinalDecision. + </obsolete> <owner>tommycli@chromium.org</owner> <summary> - Record the initial decision of the Plugin Power Saver peripheral content - heuristic. For each plugin instance, this heuristic decides whether the - plugin instance is essential content or peripheral. All same-origin content - is essential. Cross-origin content is peripheral if it is small and not on - the origin whitelist. + Records each decision of the Plugin Power Saver peripheral content + heuristic. This UMA is counted once per peripheral query, and may count a + single plugin instance multiple times as it is resized. + </summary> +</histogram> + +<histogram name="Plugin.PowerSaver.PeripheralHeuristicInitialDecision" + enum="PluginPowerSaverPeripheralHeuristicDecision"> + <owner>tommycli@chromium.org</owner> + <summary> + Records the initial decision of the Plugin Power Saver peripheral content + heuristic for each plugin instance. This is recorded once per plugin + instance. </summary> </histogram> @@ -42806,6 +42927,11 @@ </summary> </histogram> +<histogram name="Plugin.RequestObjectResult" enum="BooleanSuccess"> + <owner>mlamouri@chromium.org</owner> + <summary>Result of HTMLPluginElement::requestObject in Blink.</summary> +</histogram> + <histogram name="Plugin.SyncMessageTime" units="ms"> <obsolete> Deprecated due to NPAPI removal. @@ -46575,6 +46701,16 @@ </summary> </histogram> +<histogram name="Renderer4.IdealContentsScale"> + <owner>vmpstr@chromium.org</owner> + <summary> + The contents scale at which picture layer impl should be rasterized in order + to appear crisp. This is also known as ideal contents scale. This value is + recorded any time the ideal contents scale changes. Some examples of this + are pinch-zoom and JavaScript transform changes. + </summary> +</histogram> + <histogram name="Renderer4.InvalidationRegionApproximateRectCount" units="rects"> <owner>wiltzius@chromium.org</owner> @@ -47485,6 +47621,9 @@ <histogram name="ResourcePrefetchPredictor.ResourceStatus" enum="ResourcePrefetchPredictorResourceStatus"> + <obsolete> + Deprecated 08/2016 with the removal of the recording code. + </obsolete> <owner>zhenw@chromium.org</owner> <summary> The distribution of the reasons for which subresources are ignored during @@ -60417,6 +60556,23 @@ <summary>Language of page detected by CLD2.</summary> </histogram> +<histogram name="Translate.CLD3.LanguageDetected" enum="CLD3LanguageCode"> + <owner>abakalov@chromium.org</owner> + <summary> + Language of the input page detected by CLD3. This information is logged on + every page load. + </summary> +</histogram> + +<histogram name="Translate.CLD3.LanguagePercentage" units="%"> + <owner>abakalov@chromium.org</owner> + <summary> + Percentage of the bytes that are associated with the most popular language + on the input page. Only recorded if the detection returned a + "known" result. + </summary> +</histogram> + <histogram name="Translate.ContentLanguage" enum="TranslateLanguage"> <owner>kenjibaheux@google.com</owner> <summary> @@ -69146,6 +69302,7 @@ <int value="19" label="RenderPassDrawQuad has background filters."/> <int value="20" label="RenderPassDrawQuad has a mask."/> <int value="21" label="RenderPassDrawQuad has unconvertable filters."/> + <int value="22" label="RenderPassDrawQuad has a sorting context id."/> </enum> <enum name="CanvasContextType" type="int"> @@ -70134,6 +70291,105 @@ <int value="613" label="X_Takri"/> </enum> +<enum name="CLD3LanguageCode" type="int"> + <summary> + Hash values for the languages supported by CLD3. Each of these values is + computed by casting the output of base::HashMetricName(language_string_id) + to base::HistogramBase::Sample. + </summary> + <int value="-2132740958" label="gl"/> + <int value="-2092490813" label="fa"/> + <int value="-2084324285" label="iw"/> + <int value="-2070680532" label="hi"/> + <int value="-2070250592" label="zu"/> + <int value="-2042178987" label="si"/> + <int value="-2041104386" label="mi"/> + <int value="-2014954614" label="so"/> + <int value="-1999171202" label="lv"/> + <int value="-1994870905" label="lt"/> + <int value="-1855113037" label="vi"/> + <int value="-1828586117" label="de"/> + <int value="-1823968882" label="zh"/> + <int value="-1791051166" label="ha"/> + <int value="-1760672594" label="mr"/> + <int value="-1696927720" label="la"/> + <int value="-1690250140" label="ja"/> + <int value="-1532548885" label="pa"/> + <int value="-1284862637" label="ru"/> + <int value="-1273588087" label="kn"/> + <int value="-1048980531" label="ur"/> + <int value="-1042449480" label="cy"/> + <int value="-1033645590" label="fil"/> + <int value="-1025520269" label="az"/> + <int value="-1000295094" label="no"/> + <int value="-887258309" label="hu"/> + <int value="-862298602" label="st"/> + <int value="-750267977" label="bg"/> + <int value="-742603342" label="ca"/> + <int value="-734032818" label="km"/> + <int value="-659007214" label="el"/> + <int value="-647197922" label="ceb"/> + <int value="-645438410" label="my"/> + <int value="-644560085" label="su"/> + <int value="-598481752" label="et"/> + <int value="-426630965" label="ga"/> + <int value="-415677801" label="it"/> + <int value="-403118581" label="sw"/> + <int value="-342591258" label="sq"/> + <int value="-219674420" label="ta"/> + <int value="-181870943" label="bn"/> + <int value="-110306666" label="sr"/> + <int value="-78164291" label="kk"/> + <int value="-74147910" label="en"/> + <int value="-35182995" label="fi"/> + <int value="-5034744" label="ny"/> + <int value="42532257" label="id"/> + <int value="64053359" label="eu"/> + <int value="114573335" label="es"/> + <int value="121688617" label="eo"/> + <int value="124739394" label="lo"/> + <int value="132594104" label="be"/> + <int value="134866094" label="ka"/> + <int value="142313505" label="ro"/> + <int value="145030010" label="gu"/> + <int value="162326141" label="sl"/> + <int value="183952636" label="mg"/> + <int value="191168946" label="mk"/> + <int value="357286655" label="af"/> + <int value="461111861" label="mt"/> + <int value="462869158" label="hy"/> + <int value="470982931" label="sv"/> + <int value="522435458" label="hr"/> + <int value="526531379" label="ml"/> + <int value="538270200" label="uk"/> + <int value="596295208" label="bs"/> + <int value="673577439" label="cs"/> + <int value="796588925" label="yo"/> + <int value="804120371" label="jv"/> + <int value="873647701" label="th"/> + <int value="910795716" label="ne"/> + <int value="925733725" label="ms"/> + <int value="1092864716" label="ht"/> + <int value="1110169461" label="hmn"/> + <int value="1119752109" label="te"/> + <int value="1140816756" label="ar"/> + <int value="1166708194" label="is"/> + <int value="1214473765" label="unknown"/> + <int value="1311313702" label="pt"/> + <int value="1312638242" label="pl"/> + <int value="1437205305" label="uz"/> + <int value="1482920614" label="yi"/> + <int value="1483760478" label="tg"/> + <int value="1552733612" label="da"/> + <int value="1638257274" label="sk"/> + <int value="1670494558" label="ko"/> + <int value="1704315002" label="fr"/> + <int value="1853848431" label="tr"/> + <int value="2039992295" label="ig"/> + <int value="2087142539" label="mn"/> + <int value="2119087611" label="nl"/> +</enum> + <enum name="ClearDataSiteBlacklistReason" type="int"> <int value="0" label="Durable"/> <int value="1" label="Notifications"/> @@ -70533,6 +70789,10 @@ </enum> <enum name="CompressibleStringCountType" type="int"> + <obsolete> + Dprecated as of Aug 2016. CompressibleString has been reverted once at + https://crrev.com/2227933002. + </obsolete> <int value="0" label="Compressed in a background tab"/> <int value="1" label="Decompressed in a background or a foreground tab"/> </enum> @@ -72268,6 +72528,14 @@ <int value="2" label="OnGetFontFiles: GetFontFamily failed"/> <int value="3" label="InitializeDirectWrite: GetSystemFontCollection failed"/> <int value="4" label="MapCharacters: could not find family"/> + <int value="5" label="AddFilesforFont: create font face failed"/> + <int value="6" label="AddFilesforFont: get font file count failed"/> + <int value="7" label="AddFilesforFont: get font files failed"/> + <int value="8" label="AddFilesforFont: get loader failed"/> + <int value="9" label="AddFilesforFont: QueryInterface failed"/> + <int value="10" label="AddLocalFile: get reference key failed"/> + <int value="11" label="AddLocalFile: get path length failed"/> + <int value="12" label="AddLocalFile: get path failed"/> </enum> <enum name="DistillableType" type="int"> @@ -78110,6 +78378,7 @@ <int value="1497" label="ChromeLoadTimesWasAlternateProtocolAvailable"/> <int value="1498" label="ChromeLoadTimesConnectionInfo"/> <int value="1499" label="ChromeLoadTimesUnknown"/> + <int value="1500" label="SVGViewElement"/> </enum> <enum name="FetchRequestMode" type="int"> @@ -82968,6 +83237,7 @@ <int value="-474322576" label="disable-quick-unlock-pin"/> <int value="-462205750" label="enable-service-worker-sync"/> <int value="-455203267" label="use_new_features_summary"/> + <int value="-449465495" label="disable-browser-task-scheduler"/> <int value="-430360431" label="disable-password-generation"/> <int value="-418868128" label="enable-experimental-web-platform-features"/> <int value="-396994784" label="enable-vr-shell"/> @@ -83008,6 +83278,7 @@ <int value="-158197254" label="enable-credential-manager-api"/> <int value="-147283486" label="enable-network-portal-notification"/> <int value="-146552997" label="enable-affiliation-based-matching"/> + <int value="-122492389" label="enable-browser-task-scheduler"/> <int value="-102537270" label="extension-content-verification"/> <int value="-99781021" label="disable-roboto-font-ui"/> <int value="-88822940" label="ssl-version-min"/> @@ -87518,6 +87789,12 @@ <int value="8" label="Other"/> </enum> +<enum name="PaymentRequestPaymentMethods" type="int"> + <int value="0" label="Autofill credit cards"/> + <int value="1" label="Android Pay"/> + <int value="2" label="Other Payment App"/> +</enum> + <enum name="PaymentRequestRequestedInformation" type="int"> <int value="0" label="None"/> <int value="1" label="Email"/> @@ -89384,6 +89661,7 @@ <int value="4" label="ReadyToPersist"/> <int value="5" label="Persist"/> <int value="6" label="ExternalCacheHit"/> + <int value="7" label="ResetWaitForDataReady"/> </enum> <enum name="QuicDiskCacheEntryState" type="int"> @@ -89402,6 +89680,8 @@ <int value="7" label="READY_TO_PERSIST_FAILURE"/> <int value="8" label="PERSIST_NO_BACKEND_FAILURE"/> <int value="9" label="WRITE_FAILURE"/> + <int value="10" label="NO_FAILURE"/> + <int value="11" label="PARSE_DATA_DECODE_FAILURE"/> </enum> <enum name="QuicErrorCodes" type="int"> @@ -95451,6 +95731,7 @@ label="Chooser insta-closed because user or enterprise policy has disabled it"/> <int value="16" label="Web Bluetooth kill switch enabled"/> + <int value="17" label="Web Bluetooth chooser event handler invalid"/> </enum> <enum name="WebCertVerifyAgreement" type="int"> @@ -95944,6 +96225,19 @@ <int value="1" label="XMLHttpRequestSendArrayBufferView"/> </enum> +<enum name="YouTubeRewriteStatus" type="int"> + <int value="0" label="Success">Embed was properly rewritten.</int> + <int value="1" label="Success, params were rewritten"> + Embed was rewritten but the params had to be fixed. + </int> + <int value="2" label="Success, had JS API enabled"> + Embed was rewritten even though JS API was enabled (Android only). + </int> + <int value="3" label="Embed not rewritten, JS API enabled"> + Embed was not rewritten because JS API was enabled. + </int> +</enum> + </enums> <!-- Histogram suffixes list --> @@ -99753,6 +100047,7 @@ <suffix name="NoBackend" label="DiskCache didn't have a backend"/> <suffix name="DiskCache" label="DiskCache backend is using disk cache."/> <suffix name="MemoryCache" label="DiskCache backend is using memory cache."/> + <suffix name="PropertiesBasedCache" label="Preferences based cache is used."/> <suffix name="WaitForDataReady" label="Tracks the last failure reason until WaitForDataReady or its callback is executed. This is recorded when data is ready in @@ -100066,6 +100361,7 @@ <suffix name="async_loading" label="Offline async loaded pages"/> <suffix name="custom_tabs" label="Offline custom tabs"/> <suffix name="download" label="Offline downloaded pages"/> + <suffix name="ntp_suggestions" label="Offline ntp suggestions"/> <affected-histogram name="OfflinePages.Background.OfflinerRequestStatus"/> <affected-histogram name="OfflinePages.DeletePage.AccessCount"/> <affected-histogram name="OfflinePages.DeletePage.LastOpenToCreated"/> @@ -100609,6 +100905,8 @@ <affected-histogram name="Permissions.Action"/> <affected-histogram name="Permissions.Action.InsecureOrigin"/> <affected-histogram name="Permissions.Action.SecureOrigin"/> + <affected-histogram name="Permissions.Prompt.DismissCount"/> + <affected-histogram name="Permissions.Prompt.IgnoreCount"/> <affected-histogram name="Permissions.Requested.CrossOrigin"/> </histogram_suffixes>
diff --git a/tools/origin_trials/generate_token.py b/tools/origin_trials/generate_token.py index 1dca546..268f4567 100755 --- a/tools/origin_trials/generate_token.py +++ b/tools/origin_trials/generate_token.py
@@ -35,6 +35,9 @@ # This script generates Version 2 tokens. VERSION = "\x02" +# Default key file, relative to script_dir. +DEFAULT_KEY_FILE = 'eftest.key' + def HostnameFromArg(arg): """Determines whether a string represents a valid hostname. @@ -98,6 +101,8 @@ struct.pack(">I",len(data)) + data) def main(): + default_key_file_absolute = os.path.join(script_dir, DEFAULT_KEY_FILE) + parser = argparse.ArgumentParser( description="Generate tokens for enabling experimental APIs") parser.add_argument("origin", @@ -111,7 +116,7 @@ "RuntimeFeatures.in") parser.add_argument("--key-file", help="Ed25519 private key file to sign the token with", - default="eftest.key") + default=default_key_file_absolute) expiry_group = parser.add_mutually_exclusive_group() expiry_group.add_argument("--expire-days", help="Days from now when the token should exipire",
diff --git a/tools/perf/benchmarks/benchmark_smoke_unittest.py b/tools/perf/benchmarks/benchmark_smoke_unittest.py index 76d0206..29650aa 100644 --- a/tools/perf/benchmarks/benchmark_smoke_unittest.py +++ b/tools/perf/benchmarks/benchmark_smoke_unittest.py
@@ -15,6 +15,7 @@ from telemetry import benchmark as benchmark_module from telemetry.core import discover +from telemetry import decorators from telemetry.internal.browser import browser_finder from telemetry.testing import options_for_unittests from telemetry.testing import progress_reporter @@ -133,13 +134,29 @@ # test from the class. We should probably discover all of the tests # in a class, and then throw the ones we don't need away instead. + # TODO(aiolos): remove try after all telemetry-side changes land. + try: + decorators.IS_UPDATED_DECORATORS + except AttributeError: + enabled_benchmark_attr = '_enabled_strings' + enabled_method_attr = '_enabled_strings' + disabled_benchmark_attr = '_disabled_strings' + disabled_method_attr = '_disabled_strings' + else: + disabled_benchmark_attr = decorators.DisabledAttributeName(benchmark) + disabled_method_attr = decorators.DisabledAttributeName(method) + enabled_benchmark_attr = decorators.EnabledAttributeName(benchmark) + enabled_method_attr = decorators.EnabledAttributeName(method) # Merge decorators. - for attribute in ['_enabled_strings', '_disabled_strings']: + def MergeDecorators(method_attribute, benchmark_attribute): # Do set union of attributes to eliminate duplicates. - merged_attributes = getattr(method, attribute, set()).union( - getattr(benchmark, attribute, set())) + merged_attributes = getattr(method, method_attribute, set()).union( + getattr(benchmark, benchmark_attribute, set())) if merged_attributes: - setattr(method, attribute, merged_attributes) + setattr(method, method_attribute, merged_attributes) + + MergeDecorators(disabled_method_attr, disabled_benchmark_attr) + MergeDecorators(enabled_method_attr, enabled_benchmark_attr) setattr(BenchmarkSmokeTest, benchmark.Name(), method)
diff --git a/tools/perf/benchmarks/dromaeo.py b/tools/perf/benchmarks/dromaeo.py index 3749f123..a0f296e 100644 --- a/tools/perf/benchmarks/dromaeo.py +++ b/tools/perf/benchmarks/dromaeo.py
@@ -239,7 +239,7 @@ return 'dromaeo.jslibeventprototype' -# win: http://crbug.com/479796, http://crbug.com/529330, http://crbug.com/598705 +# win: http://crbug.com/479796, http://crbug.com/598705 # android: http://crbug.com/503138 # linux: http://crbug.com/583075 @benchmark.Disabled('win-reference', 'android', 'linux')
diff --git a/tools/perf/core/minidump_unittest.py b/tools/perf/core/minidump_unittest.py index 13c49d31..4caf97f 100644 --- a/tools/perf/core/minidump_unittest.py +++ b/tools/perf/core/minidump_unittest.py
@@ -19,8 +19,9 @@ crash_minidump_path = self._browser.GetMostRecentMinidumpPath() #self.assertIsNotNone(crash_minidump_path) - logging.info('testSymbolizeMinidump: most recent path = ' - + crash_minidump_path) + if crash_minidump_path is not None: + logging.info('testSymbolizeMinidump: most recent path = ' + + crash_minidump_path) all_paths = self._browser.GetAllMinidumpPaths() logging.info('testSymbolizeMinidump: all paths ' + ''.join(all_paths)) all_unsymbolized_paths = self._browser.GetAllUnsymbolizedMinidumpPaths() @@ -41,7 +42,6 @@ @decorators.Isolated @decorators.Enabled('mac') - @decorators.Disabled('mac') # crbug.com/634156 def testMultipleCrashMinidumps(self): # Wait for the browser to restart fully before crashing self._LoadPageThenWait('var cat = "dog";', 'cat') @@ -49,8 +49,9 @@ first_crash_path = self._browser.GetMostRecentMinidumpPath() #self.assertIsNotNone(first_crash_path) - logging.info('testMultipleCrashMinidumps: first crash most recent path' - + first_crash_path) + if first_crash_path is not None: + logging.info('testMultipleCrashMinidumps: first crash most recent path' + + first_crash_path) all_paths = self._browser.GetAllMinidumpPaths() logging.info('testMultipleCrashMinidumps: first crash all paths: ' + ''.join(all_paths)) @@ -70,8 +71,9 @@ self._browser.tabs.New().Navigate('chrome://gpucrash', timeout=5) second_crash_path = self._browser.GetMostRecentMinidumpPath() #self.assertIsNotNone(second_crash_path) - logging.info('testMultipleCrashMinidumps: second crash most recent path' - + second_crash_path) + if second_crash_path is not None: + logging.info('testMultipleCrashMinidumps: second crash most recent path' + + second_crash_path) second_crash_all_paths = self._browser.GetAllMinidumpPaths() logging.info('testMultipleCrashMinidumps: second crash all paths: ' + ''.join(second_crash_all_paths))
diff --git a/tools/perf/page_sets/data/system_health_mobile.json b/tools/perf/page_sets/data/system_health_mobile.json index 58e2899..3ec07256 100644 --- a/tools/perf/page_sets/data/system_health_mobile.json +++ b/tools/perf/page_sets/data/system_health_mobile.json
@@ -43,9 +43,6 @@ "system_health_mobile_006.wpr": [ "load:news:cnn" ], - "system_health_mobile_007.wpr": [ - "load:social:facebook" - ], "system_health_mobile_008.wpr": [ "load:news:hackernews" ], @@ -92,6 +89,7 @@ "browse:news:reddit" ], "system_health_mobile_028.wpr": [ + "load:social:facebook", "browse:social:facebook" ], "system_health_mobile_029.wpr": [ @@ -106,7 +104,8 @@ "browse:media:youtube" ], "system_health_mobile_040.wpr": [ - "browse:media:facebook" + "load:media:facebook_photos", + "browse:media:facebook_photos" ] }, "description": "Describes the Web Page Replay archives for a story set. Don't edit by hand! Use record_wpr for updating."
diff --git a/tools/perf/page_sets/data/system_health_mobile_007.wpr.sha1 b/tools/perf/page_sets/data/system_health_mobile_007.wpr.sha1 deleted file mode 100644 index 24408df..0000000 --- a/tools/perf/page_sets/data/system_health_mobile_007.wpr.sha1 +++ /dev/null
@@ -1 +0,0 @@ -eda06f1a8e7783a84c9ee72a88553fac2048a081 \ No newline at end of file
diff --git a/tools/perf/page_sets/mac_gpu_sites.py b/tools/perf/page_sets/mac_gpu_sites.py index fc900b1..4a3a625e 100644 --- a/tools/perf/page_sets/mac_gpu_sites.py +++ b/tools/perf/page_sets/mac_gpu_sites.py
@@ -80,10 +80,24 @@ shared_page_state_class=shared_page_state_class) +class TrivialFullscreenVideoPage(page_module.Page): + + def __init__(self, page_set, shared_page_state_class): + super(TrivialFullscreenVideoPage, self).__init__( + url='file://trivial_sites/trivial_fullscreen_video.html', + page_set=page_set, + name=self.__class__.__name__ + shared_page_state_class.__name__, + shared_page_state_class=shared_page_state_class) + + def RunPageInteractions(self, action_runner): + action_runner.PressKey("Return") + + class MacGpuTrivialPagesStorySet(story.StorySet): def __init__(self): - super(MacGpuTrivialPagesStorySet, self).__init__() + super(MacGpuTrivialPagesStorySet, self).__init__( + cloud_storage_bucket=story.PUBLIC_BUCKET) self.AddStory(TrivialScrollingPage(self, shared_page_state.SharedPageState)) self.AddStory(TrivialBlinkingCursorPage( self, shared_page_state.SharedPageState)) @@ -91,18 +105,22 @@ self.AddStory(TrivialWebGLPage(self, shared_page_state.SharedPageState)) self.AddStory(TrivialBlurAnimationPage( self, shared_page_state.SharedPageState)) + self.AddStory(TrivialFullscreenVideoPage( + self, shared_page_state.SharedPageState)) self.AddStory(TrivialScrollingPage(self, _NoOverlaysSharedPageState)) self.AddStory(TrivialBlinkingCursorPage(self, _NoOverlaysSharedPageState)) self.AddStory(TrivialCanvasPage(self, _NoOverlaysSharedPageState)) self.AddStory(TrivialWebGLPage(self, _NoOverlaysSharedPageState)) self.AddStory(TrivialBlurAnimationPage(self, _NoOverlaysSharedPageState)) + self.AddStory(TrivialFullscreenVideoPage(self, _NoOverlaysSharedPageState)) self.AddStory(TrivialScrollingPage(self, _NoGpuSharedPageState)) self.AddStory(TrivialBlinkingCursorPage(self, _NoGpuSharedPageState)) self.AddStory(TrivialCanvasPage(self, _NoGpuSharedPageState)) self.AddStory(TrivialWebGLPage(self, _NoWebGLImageChromiumSharedPageState)) self.AddStory(TrivialBlurAnimationPage(self, _NoGpuSharedPageState)) + self.AddStory(TrivialFullscreenVideoPage(self, _NoGpuSharedPageState)) @property def allow_mixed_story_states(self):
diff --git a/tools/perf/page_sets/system_health/browsing_stories.py b/tools/perf/page_sets/system_health/browsing_stories.py index 25bf5b8..5ad8150 100644 --- a/tools/perf/page_sets/system_health/browsing_stories.py +++ b/tools/perf/page_sets/system_health/browsing_stories.py
@@ -280,8 +280,8 @@ ITEM_SELECTOR_INDEX = 3 -class FacebookMobileStory(_MediaBrowsingStory): - NAME = 'browse:media:facebook' +class FacebookPhotosMediaStory(_MediaBrowsingStory): + NAME = 'browse:media:facebook_photos' URL = ( 'https://m.facebook.com/rihanna/photos/a.207477806675.138795.10092511675/10153911739606676/?type=3&source=54&ref=page_internal') ITEM_SELECTOR = '._57-r.touchable' @@ -289,13 +289,9 @@ IS_SINGLE_PAGE_APP = True ITEM_SELECTOR_INDEX = 0 - def _Login(self, action_runner): - action_runner.Navigate('https://m.facebook.com/rihanna') - action_runner.tab.WaitForDocumentReadyStateToBeComplete() - -class FacebookDesktopStory(_MediaBrowsingStory): - NAME = 'browse:media:facebook' +class FacebookPhotosDesktopStory(_MediaBrowsingStory): + NAME = 'browse:media:facebook_photos' URL = ( 'https://www.facebook.com/rihanna/photos/a.207477806675.138795.10092511675/10153911739606676/?type=3&theater') ITEM_SELECTOR = '.snowliftPager.next' @@ -303,7 +299,3 @@ # theater viewer. SUPPORTED_PLATFORMS = platforms.NO_PLATFORMS IS_SINGLE_PAGE_APP = True - - def _Login(self, action_runner): - action_runner.Navigate('https://www.facebook.com/rihanna') - action_runner.tab.WaitForDocumentReadyStateToBeComplete()
diff --git a/tools/perf/page_sets/system_health/loading_stories.py b/tools/perf/page_sets/system_health/loading_stories.py index 90b2dabf..961ccb4 100644 --- a/tools/perf/page_sets/system_health/loading_stories.py +++ b/tools/perf/page_sets/system_health/loading_stories.py
@@ -232,7 +232,7 @@ URL = 'https://www.9gag.com/' -class LoadFlickr(_LoadingStory): +class LoadFlickrStory(_LoadingStory): NAME = 'load:media:flickr' URL = 'https://www.flickr.com/photos/tags/farm' @@ -244,11 +244,27 @@ !== null''') -class LoadImgur(_LoadingStory): +class LoadImgurStory(_LoadingStory): NAME = 'load:media:imgur' URL = 'http://imgur.com/gallery/5UlBN' +class LoadFacebookPhotosMobileStory(_LoadingStory): + NAME = 'load:media:facebook_photos' + URL = ( + 'https://m.facebook.com/rihanna/photos/a.207477806675.138795.10092511675/10153911739606676/?type=3&source=54&ref=page_internal') + SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY + + +class LoadFacebookPhotosDesktopStory(_LoadingStory): + NAME = 'load:media:facebook_photos' + URL = ( + 'https://www.facebook.com/rihanna/photos/a.207477806675.138795.10092511675/10153911739606676/?type=3&theater') + # Recording currently does not work. The page gets stuck in the + # theater viewer. + SUPPORTED_PLATFORMS = platforms.NO_PLATFORMS + + ################################################################################ # Online tools (documents, emails, storage, ...). ################################################################################ @@ -263,7 +279,7 @@ class _LoadGmailBaseStory(_LoadingStory): NAME = 'load:tools:gmail' URL = 'https://mail.google.com/mail/' - SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY + ABSTRACT_STORY = True def _Login(self, action_runner): google_login.LoginGoogleAccount(action_runner, 'googletest',
diff --git a/tools/perf/page_sets/system_health/system_health_story.py b/tools/perf/page_sets/system_health/system_health_story.py index 5d916bc..1642e44 100644 --- a/tools/perf/page_sets/system_health/system_health_story.py +++ b/tools/perf/page_sets/system_health/system_health_story.py
@@ -23,11 +23,7 @@ story set. This field is NOT inherited by subclasses (that's why it's defined on the metaclass). """ - return cls.__dict__.get('__ABSTRACT_STORY__', False) - - @ABSTRACT_STORY.setter - def ABSTRACT_STORY(cls, ABSTRACT_STORY): - cls.__dict__['__ABSTRACT_STORY__'] = ABSTRACT_STORY + return cls.__dict__.get('ABSTRACT_STORY', False) class SystemHealthStory(page.Page):
diff --git a/tools/perf/page_sets/trivial_sites/road_trip_640_480.mp4.sha1 b/tools/perf/page_sets/trivial_sites/road_trip_640_480.mp4.sha1 new file mode 100644 index 0000000..a5ecc247 --- /dev/null +++ b/tools/perf/page_sets/trivial_sites/road_trip_640_480.mp4.sha1
@@ -0,0 +1 @@ +0a225539a4d8c0ed4c2a8a01f12f4611e4fa6566 \ No newline at end of file
diff --git a/tools/perf/page_sets/trivial_sites/trivial_fullscreen_video.html b/tools/perf/page_sets/trivial_sites/trivial_fullscreen_video.html new file mode 100644 index 0000000..4b32ddec --- /dev/null +++ b/tools/perf/page_sets/trivial_sites/trivial_fullscreen_video.html
@@ -0,0 +1,37 @@ +<!doctype html> +<html> +<head> + <style type="text/css"> + /* Make the video stretch to fill the screen. */ + :-webkit-full-screen #fullscreenvideo { + width: 100%; + height: 100%; + } + </style> +</head> +<body> + <!--This video was obtained from + https://videos.pexels.com/videos/adventure-trip-481. It is licensed under + Creative Commons Zero, which does not require attribution.--> + <video controls src="road_trip_640_480.mp4" width="640" + height="480" id="fullscreenvideo" autoplay="autoplay"> +</body> +<script> + var videoElement = document.getElementById("fullscreenvideo"); + + function toggleFullScreen() { + if (!document.webkitFullScreen) { + videoElement.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT); + } else { + document.webkitCancelFullScreen(); + } + } + + // Pressing "Return" causes the video to enter fullscreen. + document.addEventListener("keydown", function(e) { + if (e.keyCode == 13) { + toggleFullScreen(); + } + }, false); +</script> +</html>
diff --git a/ui/android/java/src/org/chromium/ui/UiUtils.java b/ui/android/java/src/org/chromium/ui/UiUtils.java index b81b994..4522ec45 100644 --- a/ui/android/java/src/org/chromium/ui/UiUtils.java +++ b/ui/android/java/src/org/chromium/ui/UiUtils.java
@@ -333,4 +333,16 @@ ? ContentUriUtils.getContentUriFromFile(context, file) : Uri.fromFile(file); } + + /** + * Removes the view from its parent {@link ViewGroup}. No-op if the {@link View} is not yet + * attached to the view hierarchy. + * + * @param view The view to be removed from the parent. + */ + public static void removeViewFromParent(View view) { + ViewGroup parent = (ViewGroup) view.getParent(); + if (parent == null) return; + parent.removeView(view); + } }
diff --git a/ui/android/view_android.cc b/ui/android/view_android.cc index 4e969e2..259aed6e 100644 --- a/ui/android/view_android.cc +++ b/ui/android/view_android.cc
@@ -16,6 +16,7 @@ namespace ui { using base::android::JavaRef; +using base::android::ScopedJavaLocalRef; ViewAndroid::ScopedAnchorView::ScopedAnchorView( JNIEnv* env,
diff --git a/ui/app_list/views/app_list_item_view.cc b/ui/app_list/views/app_list_item_view.cc index 66814a7e..e605141 100644 --- a/ui/app_list/views/app_list_item_view.cc +++ b/ui/app_list/views/app_list_item_view.cc
@@ -18,7 +18,6 @@ #include "ui/base/dragdrop/drag_utils.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" -#include "ui/base/ui_base_switches_util.h" #include "ui/compositor/layer.h" #include "ui/compositor/scoped_layer_animation_settings.h" #include "ui/gfx/animation/throb_animation.h" @@ -427,14 +426,14 @@ } break; case ui::ET_GESTURE_TAP_DOWN: - if (::switches::IsTouchFeedbackEnabled() && state() != STATE_DISABLED) { + if (state() != STATE_DISABLED) { SetState(STATE_PRESSED); event->SetHandled(); } break; case ui::ET_GESTURE_TAP: case ui::ET_GESTURE_TAP_CANCEL: - if (::switches::IsTouchFeedbackEnabled() && state() != STATE_DISABLED) + if (state() != STATE_DISABLED) SetState(STATE_NORMAL); break; case ui::ET_GESTURE_LONG_PRESS:
diff --git a/ui/app_list/views/page_switcher.cc b/ui/app_list/views/page_switcher.cc index 0dbdebb..4950c00 100644 --- a/ui/app_list/views/page_switcher.cc +++ b/ui/app_list/views/page_switcher.cc
@@ -10,7 +10,6 @@ #include "third_party/skia/include/core/SkPath.h" #include "ui/app_list/app_list_constants.h" #include "ui/app_list/pagination_model.h" -#include "ui/base/ui_base_switches_util.h" #include "ui/gfx/animation/throb_animation.h" #include "ui/gfx/canvas.h" #include "ui/gfx/skia_util.h" @@ -66,9 +65,6 @@ void OnGestureEvent(ui::GestureEvent* event) override { CustomButton::OnGestureEvent(event); - if (!switches::IsTouchFeedbackEnabled()) - return; - if (event->type() == ui::ET_GESTURE_TAP_DOWN) SetState(views::CustomButton::STATE_HOVERED); else if (event->type() == ui::ET_GESTURE_TAP_CANCEL ||
diff --git a/ui/aura/client/aura_constants.cc b/ui/aura/client/aura_constants.cc index 804993f..82fb587f 100644 --- a/ui/aura/client/aura_constants.cc +++ b/ui/aura/client/aura_constants.cc
@@ -9,6 +9,7 @@ DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(AURA_EXPORT, bool) DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(AURA_EXPORT, ui::ModalType) +DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(AURA_EXPORT, gfx::ImageSkia*) DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(AURA_EXPORT, gfx::Rect*) DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(AURA_EXPORT, ui::InputMethod*) DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(AURA_EXPORT, ui::WindowShowState) @@ -28,16 +29,17 @@ DEFINE_WINDOW_PROPERTY_KEY(bool, kConstrainedWindowKey, false); DEFINE_WINDOW_PROPERTY_KEY(bool, kDrawAttentionKey, false); DEFINE_WINDOW_PROPERTY_KEY(bool, kExcludeFromMruKey, false); -DEFINE_WINDOW_PROPERTY_KEY(Window*, kHostWindowKey, NULL); +DEFINE_WINDOW_PROPERTY_KEY(Window*, kHostWindowKey, nullptr); DEFINE_WINDOW_PROPERTY_KEY(ui::ModalType, kModalKey, ui::MODAL_TYPE_NONE); // gfx::Rect object for RestoreBoundsKey property is owned by the window // and will be freed automatically. -DEFINE_OWNED_WINDOW_PROPERTY_KEY(gfx::Rect, kRestoreBoundsKey, NULL); +DEFINE_OWNED_WINDOW_PROPERTY_KEY(gfx::Rect, kRestoreBoundsKey, nullptr); DEFINE_WINDOW_PROPERTY_KEY( ui::WindowShowState, kRestoreShowStateKey, ui::SHOW_STATE_DEFAULT); DEFINE_WINDOW_PROPERTY_KEY( ui::WindowShowState, kShowStateKey, ui::SHOW_STATE_DEFAULT); DEFINE_WINDOW_PROPERTY_KEY(int, kTopViewInset, 0); +DEFINE_OWNED_WINDOW_PROPERTY_KEY(gfx::ImageSkia, kWindowIconKey, nullptr); } // namespace client } // namespace aura
diff --git a/ui/aura/client/aura_constants.h b/ui/aura/client/aura_constants.h index 17523dab..9675a67 100644 --- a/ui/aura/client/aura_constants.h +++ b/ui/aura/client/aura_constants.h
@@ -71,6 +71,9 @@ // the web contents for app windows and varies for fullscreen windows. AURA_EXPORT extern const aura::WindowProperty<int>* const kTopViewInset; +// A property key to store window icon. +AURA_EXPORT extern const WindowProperty<gfx::ImageSkia*>* const kWindowIconKey; + // Alphabetical sort. } // namespace client
diff --git a/ui/aura/window_tree_host_platform.cc b/ui/aura/window_tree_host_platform.cc index 78396432..02bb8f7 100644 --- a/ui/aura/window_tree_host_platform.cc +++ b/ui/aura/window_tree_host_platform.cc
@@ -65,6 +65,7 @@ WindowTreeHostPlatform::~WindowTreeHostPlatform() { DestroyCompositor(); DestroyDispatcher(); + window_->Close(); } ui::EventSource* WindowTreeHostPlatform::GetEventSource() {
diff --git a/ui/base/clipboard/clipboard_mac.mm b/ui/base/clipboard/clipboard_mac.mm index f3a4c43..8c42c0b 100644 --- a/ui/base/clipboard/clipboard_mac.mm +++ b/ui/base/clipboard/clipboard_mac.mm
@@ -39,11 +39,9 @@ @"org.chromium.pepper-custom-data"; NSPasteboard* GetPasteboard() { - // The pasteboard should not be nil in a UI session, but this handy DCHECK - // can help track down problems if someone tries using clipboard code outside - // of a UI session. + // The pasteboard can always be nil, since there is a finite amount of storage + // that must be shared between all pasteboards. NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; - DCHECK(pasteboard); return pasteboard; } @@ -227,11 +225,12 @@ types->push_back(base::UTF8ToUTF16(kMimeTypeHTML)); if (IsFormatAvailable(Clipboard::GetRtfFormatType(), type)) types->push_back(base::UTF8ToUTF16(kMimeTypeRTF)); - if ([NSImage canInitWithPasteboard:GetPasteboard()]) + + NSPasteboard* pb = GetPasteboard(); + if (pb && [NSImage canInitWithPasteboard:pb]) types->push_back(base::UTF8ToUTF16(kMimeTypePNG)); *contains_filenames = false; - NSPasteboard* pb = GetPasteboard(); if ([[pb types] containsObject:kWebCustomDataPboardType]) { NSData* data = [pb dataForType:kWebCustomDataPboardType]; if ([data length]) @@ -320,7 +319,8 @@ initWithContentsOfURL:[NSURL fileURLWithPath:[paths lastObject]]]); } } else { - image.reset([[NSImage alloc] initWithPasteboard:pb]); + if (pb) + image.reset([[NSImage alloc] initWithPasteboard:pb]); } } @catch (id exception) { }
diff --git a/ui/base/resource/resource_bundle_android.cc b/ui/base/resource/resource_bundle_android.cc index bec09a3..82623155 100644 --- a/ui/base/resource/resource_bundle_android.cc +++ b/ui/base/resource/resource_bundle_android.cc
@@ -128,7 +128,7 @@ g_locale_paks_in_apk = value; } -void LoadMainAndroidPackFile(const char* path_within_apk, +bool LoadMainAndroidPackFile(const char* path_within_apk, const base::FilePath& disk_file_path) { if (LoadFromApkOrFile(path_within_apk, &disk_file_path, @@ -137,7 +137,9 @@ ResourceBundle::GetSharedInstance().AddDataPackFromFileRegion( base::File(g_resources_pack_fd), g_resources_pack_region, SCALE_FACTOR_NONE); + return true; } + return false; } int GetMainAndroidPackFd(base::MemoryMappedFile::Region* out_region) {
diff --git a/ui/base/resource/resource_bundle_android.h b/ui/base/resource/resource_bundle_android.h index e975a39f..be7da363 100644 --- a/ui/base/resource/resource_bundle_android.h +++ b/ui/base/resource/resource_bundle_android.h
@@ -14,8 +14,8 @@ namespace ui { // Loads "resources.apk" from the .apk. Falls back to loading from disk, which -// is necessary for tests. -UI_BASE_EXPORT void LoadMainAndroidPackFile( +// is necessary for tests. Returns true if it succeeds, false otherwise. +UI_BASE_EXPORT bool LoadMainAndroidPackFile( const char* path_within_apk, const base::FilePath& disk_file_path);
diff --git a/ui/base/ui_base_switches.cc b/ui/base/ui_base_switches.cc index 9bdc967..915d6335 100644 --- a/ui/base/ui_base_switches.cc +++ b/ui/base/ui_base_switches.cc
@@ -40,9 +40,6 @@ // Disables touch event based drag and drop. const char kDisableTouchDragDrop[] = "disable-touch-drag-drop"; -// Disables additional visual feedback to touch input. -const char kDisableTouchFeedback[] = "disable-touch-feedback"; - // Enables large icons on the New Tab page. const char kEnableIconNtp[] = "enable-icon-ntp";
diff --git a/ui/base/ui_base_switches.h b/ui/base/ui_base_switches.h index 1d37d7b..08b349df 100644 --- a/ui/base/ui_base_switches.h +++ b/ui/base/ui_base_switches.h
@@ -28,7 +28,6 @@ UI_BASE_EXPORT extern const char kDisableIconNtp[]; UI_BASE_EXPORT extern const char kDisableTouchAdjustment[]; UI_BASE_EXPORT extern const char kDisableTouchDragDrop[]; -UI_BASE_EXPORT extern const char kDisableTouchFeedback[]; UI_BASE_EXPORT extern const char kEnableIconNtp[]; UI_BASE_EXPORT extern const char kEnableTouchDragDrop[]; UI_BASE_EXPORT extern const char kLang[];
diff --git a/ui/base/ui_base_switches_util.cc b/ui/base/ui_base_switches_util.cc index aecf2630..000d1a0 100644 --- a/ui/base/ui_base_switches_util.cc +++ b/ui/base/ui_base_switches_util.cc
@@ -20,11 +20,4 @@ #endif } -bool IsTouchFeedbackEnabled() { - static bool touch_feedback_enabled = - !base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kDisableTouchFeedback); - return touch_feedback_enabled; -} - } // namespace switches
diff --git a/ui/base/ui_base_switches_util.h b/ui/base/ui_base_switches_util.h index 14ca97c..612a5be 100644 --- a/ui/base/ui_base_switches_util.h +++ b/ui/base/ui_base_switches_util.h
@@ -11,7 +11,6 @@ UI_BASE_EXPORT bool IsLinkDisambiguationPopupEnabled(); UI_BASE_EXPORT bool IsTouchDragDropEnabled(); -UI_BASE_EXPORT bool IsTouchFeedbackEnabled(); } // namespace switches
diff --git a/ui/compositor/DEPS b/ui/compositor/DEPS index cf468de..4e0f1bf 100644 --- a/ui/compositor/DEPS +++ b/ui/compositor/DEPS
@@ -2,6 +2,7 @@ "+cc", "-cc/blink", "+gpu/command_buffer/client/gles2_interface.h", + "+services/ui/public/cpp", "+skia/ext/refptr.h", "+third_party/skia", "+ui/gfx",
diff --git a/ui/compositor/clip_recorder.cc b/ui/compositor/clip_recorder.cc index d2078f5f..1c0eb55 100644 --- a/ui/compositor/clip_recorder.cc +++ b/ui/compositor/clip_recorder.cc
@@ -17,59 +17,47 @@ namespace ui { ClipRecorder::ClipRecorder(const PaintContext& context) - : context_(context), num_closers_(0) {} + : context_(context), num_closers_(0) { + } ClipRecorder::~ClipRecorder() { for (int i = num_closers_ - 1; i >= 0; --i) { - const gfx::Rect& bounds_in_layer = bounds_in_layer_[i]; switch (closers_[i]) { case CLIP_RECT: - context_.list_->CreateAndAppendItem<cc::EndClipDisplayItem>( - bounds_in_layer); + context_.list_->CreateAndAppendPairedEndItem<cc::EndClipDisplayItem>(); break; case CLIP_PATH: - context_.list_->CreateAndAppendItem<cc::EndClipPathDisplayItem>( - bounds_in_layer); + context_.list_ + ->CreateAndAppendPairedEndItem<cc::EndClipPathDisplayItem>(); break; } } } -void ClipRecorder::RecordCloser(const gfx::Rect& bounds_in_layer, - Closer closer) { +void ClipRecorder::RecordCloser(Closer closer) { DCHECK_LT(num_closers_, kMaxOpCount); - closers_[num_closers_] = closer; - bounds_in_layer_[num_closers_++] = bounds_in_layer; -} - -static gfx::Rect PathToEnclosingRect(const gfx::Path& path) { - return gfx::ToEnclosingRect(gfx::SkRectToRectF(path.getBounds())); + closers_[num_closers_++] = closer; } void ClipRecorder::ClipRect(const gfx::Rect& clip_rect) { bool antialias = false; - gfx::Rect clip_in_layer_space = context_.ToLayerSpaceRect(clip_rect); - context_.list_->CreateAndAppendItem<cc::ClipDisplayItem>( - clip_in_layer_space, clip_rect, std::vector<SkRRect>(), antialias); - RecordCloser(clip_in_layer_space, CLIP_RECT); + context_.list_->CreateAndAppendPairedBeginItem<cc::ClipDisplayItem>( + clip_rect, std::vector<SkRRect>(), antialias); + RecordCloser(CLIP_RECT); } void ClipRecorder::ClipPath(const gfx::Path& clip_path) { bool antialias = false; - gfx::Rect clip_in_layer_space = - context_.ToLayerSpaceRect(PathToEnclosingRect(clip_path)); - context_.list_->CreateAndAppendItem<cc::ClipPathDisplayItem>( - clip_in_layer_space, clip_path, SkRegion::kIntersect_Op, antialias); - RecordCloser(clip_in_layer_space, CLIP_PATH); + context_.list_->CreateAndAppendPairedBeginItem<cc::ClipPathDisplayItem>( + clip_path, SkRegion::kIntersect_Op, antialias); + RecordCloser(CLIP_PATH); } void ClipRecorder::ClipPathWithAntiAliasing(const gfx::Path& clip_path) { bool antialias = true; - gfx::Rect clip_in_layer_space = - context_.ToLayerSpaceRect(PathToEnclosingRect(clip_path)); - context_.list_->CreateAndAppendItem<cc::ClipPathDisplayItem>( - clip_in_layer_space, clip_path, SkRegion::kIntersect_Op, antialias); - RecordCloser(clip_in_layer_space, CLIP_PATH); + context_.list_->CreateAndAppendPairedBeginItem<cc::ClipPathDisplayItem>( + clip_path, SkRegion::kIntersect_Op, antialias); + RecordCloser(CLIP_PATH); } } // namespace ui
diff --git a/ui/compositor/clip_recorder.h b/ui/compositor/clip_recorder.h index e1e4790..52f1596 100644 --- a/ui/compositor/clip_recorder.h +++ b/ui/compositor/clip_recorder.h
@@ -16,7 +16,6 @@ namespace gfx { class Path; -class Size; } namespace ui { @@ -41,14 +40,13 @@ CLIP_PATH, }; - void RecordCloser(const gfx::Rect& bounds_in_layer, Closer); + void RecordCloser(Closer); const PaintContext& context_; // If someone needs to do more than this many operations with a single // ClipRecorder then we'll increase this. enum : int { kMaxOpCount = 4 }; Closer closers_[kMaxOpCount]; - gfx::Rect bounds_in_layer_[kMaxOpCount]; int num_closers_; DISALLOW_COPY_AND_ASSIGN(ClipRecorder);
diff --git a/ui/compositor/compositing_recorder.cc b/ui/compositor/compositing_recorder.cc index fd255c73..1c488e0 100644 --- a/ui/compositor/compositing_recorder.cc +++ b/ui/compositor/compositing_recorder.cc
@@ -12,27 +12,23 @@ namespace ui { CompositingRecorder::CompositingRecorder(const PaintContext& context, - const gfx::Size& size_in_context, uint8_t alpha, bool lcd_text_requires_opaque_layer) : context_(context), - bounds_in_layer_(context.ToLayerSpaceBounds(size_in_context)), saved_(alpha < 255) { if (!saved_) return; - context_.list_->CreateAndAppendItem<cc::CompositingDisplayItem>( - bounds_in_layer_, alpha, SkXfermode::kSrcOver_Mode, - nullptr /* no bounds */, nullptr /* no color filter */, - lcd_text_requires_opaque_layer); + context_.list_->CreateAndAppendPairedBeginItem<cc::CompositingDisplayItem>( + alpha, SkXfermode::kSrcOver_Mode, nullptr /* no bounds */, + nullptr /* no color filter */, lcd_text_requires_opaque_layer); } CompositingRecorder::~CompositingRecorder() { if (!saved_) return; - context_.list_->CreateAndAppendItem<cc::EndCompositingDisplayItem>( - bounds_in_layer_); + context_.list_->CreateAndAppendPairedEndItem<cc::EndCompositingDisplayItem>(); } } // namespace ui
diff --git a/ui/compositor/compositing_recorder.h b/ui/compositor/compositing_recorder.h index 86267d0..78817f9 100644 --- a/ui/compositor/compositing_recorder.h +++ b/ui/compositor/compositing_recorder.h
@@ -9,11 +9,6 @@ #include "base/macros.h" #include "ui/compositor/compositor_export.h" -#include "ui/gfx/geometry/rect.h" - -namespace gfx { -class Size; -} namespace ui { class PaintContext; @@ -33,14 +28,12 @@ // only be used in cases where the text is known to be rendered opaquely on an // opaque background before compositing. CompositingRecorder(const PaintContext& context, - const gfx::Size& size_in_context, uint8_t alpha, bool lcd_text_requires_opaque_layer); ~CompositingRecorder(); private: const PaintContext& context_; - const gfx::Rect bounds_in_layer_; bool saved_; DISALLOW_COPY_AND_ASSIGN(CompositingRecorder);
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc index ee97043..84f9831 100644 --- a/ui/compositor/compositor.cc +++ b/ui/compositor/compositor.cc
@@ -80,6 +80,9 @@ : context_factory_(context_factory), root_layer_(NULL), widget_(gfx::kNullAcceleratedWidget), +#if defined(USE_AURA) + window_(nullptr), +#endif widget_valid_(false), output_surface_requested_(false), surface_id_allocator_(new cc::SurfaceIdAllocator( @@ -427,6 +430,17 @@ return widget_; } +#if defined(USE_AURA) +void Compositor::SetWindow(ui::Window* window) { + window_ = window; +} + +ui::Window* Compositor::window() const { + DCHECK(window_); + return window_; +} +#endif + scoped_refptr<CompositorVSyncManager> Compositor::vsync_manager() const { return vsync_manager_; }
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h index 1fa1bfc..f918f97 100644 --- a/ui/compositor/compositor.h +++ b/ui/compositor/compositor.h
@@ -16,6 +16,7 @@ #include "base/observer_list.h" #include "base/single_thread_task_runner.h" #include "base/time/time.h" +#include "build/build_config.h" #include "cc/output/begin_frame_args.h" #include "cc/surfaces/surface_sequence.h" #include "cc/trees/layer_tree_host_client.h" @@ -68,6 +69,10 @@ class Reflector; class Texture; +#if defined(USE_AURA) +class Window; +#endif + const int kCompositorLockTimeoutMs = 67; class COMPOSITOR_EXPORT ContextFactoryObserver { @@ -282,6 +287,12 @@ gfx::AcceleratedWidget ReleaseAcceleratedWidget(); gfx::AcceleratedWidget widget() const; +#if defined(USE_AURA) + // Sets the window for the compositor to render into on mus+ash. + void SetWindow(ui::Window* window); + ui::Window* window() const; +#endif + // Returns the vsync manager for this compositor. scoped_refptr<CompositorVSyncManager> vsync_manager() const; @@ -385,6 +396,9 @@ base::ObserverList<CompositorAnimationObserver> animation_observer_list_; gfx::AcceleratedWidget widget_; +#if defined(USE_AURA) + ui::Window* window_; +#endif std::unordered_map<uint32_t, uint32_t> surface_clients_; bool widget_valid_; bool output_surface_requested_;
diff --git a/ui/compositor/paint_cache.cc b/ui/compositor/paint_cache.cc index ba3855a..9feaca0 100644 --- a/ui/compositor/paint_cache.cc +++ b/ui/compositor/paint_cache.cc
@@ -21,8 +21,8 @@ return false; DCHECK(context.list_); gfx::Rect bounds_in_layer = context.ToLayerSpaceBounds(size_in_context); - context.list_->CreateAndAppendItem<cc::DrawingDisplayItem>(bounds_in_layer, - display_item_); + context.list_->CreateAndAppendDrawingItem<cc::DrawingDisplayItem>( + bounds_in_layer, display_item_); return true; }
diff --git a/ui/compositor/paint_recorder.cc b/ui/compositor/paint_recorder.cc index 76ea8ff..2c01e5c4 100644 --- a/ui/compositor/paint_recorder.cc +++ b/ui/compositor/paint_recorder.cc
@@ -42,9 +42,8 @@ context_.inside_paint_recorder_ = false; #endif const auto& item = - context_.list_->CreateAndAppendItem<cc::DrawingDisplayItem>( - bounds_in_layer_, - context_.recorder_->finishRecordingAsPicture()); + context_.list_->CreateAndAppendDrawingItem<cc::DrawingDisplayItem>( + bounds_in_layer_, context_.recorder_->finishRecordingAsPicture()); if (cache_) cache_->SetCache(item); }
diff --git a/ui/compositor/transform_recorder.cc b/ui/compositor/transform_recorder.cc index 5867a54..cdacadb9 100644 --- a/ui/compositor/transform_recorder.cc +++ b/ui/compositor/transform_recorder.cc
@@ -15,16 +15,13 @@ TransformRecorder::~TransformRecorder() { if (transformed_) - context_.list_->CreateAndAppendItem<cc::EndTransformDisplayItem>( - bounds_in_layer_); + context_.list_->CreateAndAppendPairedEndItem<cc::EndTransformDisplayItem>(); } -void TransformRecorder::Transform(const gfx::Transform& transform, - const gfx::Size& size_in_context) { +void TransformRecorder::Transform(const gfx::Transform& transform) { DCHECK(!transformed_); - bounds_in_layer_ = context_.ToLayerSpaceBounds(size_in_context); - context_.list_->CreateAndAppendItem<cc::TransformDisplayItem>( - bounds_in_layer_, transform); + context_.list_->CreateAndAppendPairedBeginItem<cc::TransformDisplayItem>( + transform); transformed_ = true; }
diff --git a/ui/compositor/transform_recorder.h b/ui/compositor/transform_recorder.h index c02738e8..97c632be 100644 --- a/ui/compositor/transform_recorder.h +++ b/ui/compositor/transform_recorder.h
@@ -7,7 +7,6 @@ #include "base/macros.h" #include "ui/compositor/compositor_export.h" -#include "ui/gfx/geometry/rect.h" namespace cc { class DisplayItem; @@ -15,7 +14,6 @@ } namespace gfx { -class Size; class Transform; } @@ -31,14 +29,10 @@ explicit TransformRecorder(const PaintContext& context); ~TransformRecorder(); - // |size_in_context| is the size in the paint context's space surrounding - // everything that's visible. - void Transform(const gfx::Transform& transform, - const gfx::Size& size_in_context); + void Transform(const gfx::Transform& transform); private: const PaintContext& context_; - gfx::Rect bounds_in_layer_; bool transformed_; DISALLOW_COPY_AND_ASSIGN(TransformRecorder);
diff --git a/ui/display/types/BUILD.gn b/ui/display/types/BUILD.gn index 6b5d1e3..8b1f6a8 100644 --- a/ui/display/types/BUILD.gn +++ b/ui/display/types/BUILD.gn
@@ -20,6 +20,7 @@ deps = [ "//base", + "//ui/gfx:memory_buffer", "//ui/gfx/geometry", ] }
diff --git a/ui/display/types/DEPS b/ui/display/types/DEPS index f2fc77d6..b9a60fa 100644 --- a/ui/display/types/DEPS +++ b/ui/display/types/DEPS
@@ -1,5 +1,6 @@ include_rules = [ "-ui", "+ui/display/types", + "+ui/gfx/buffer_types.h", "+ui/gfx/geometry", ]
diff --git a/ui/display/types/display_snapshot.cc b/ui/display/types/display_snapshot.cc index eb310a9..b833237 100644 --- a/ui/display/types/display_snapshot.cc +++ b/ui/display/types/display_snapshot.cc
@@ -56,4 +56,9 @@ DisplaySnapshot::~DisplaySnapshot() {} +// static +gfx::BufferFormat DisplaySnapshot::PrimaryFormat() { + return gfx::BufferFormat::BGRX_8888; +} + } // namespace ui
diff --git a/ui/display/types/display_snapshot.h b/ui/display/types/display_snapshot.h index a4654e2..58cdb398 100644 --- a/ui/display/types/display_snapshot.h +++ b/ui/display/types/display_snapshot.h
@@ -13,6 +13,7 @@ #include "base/macros.h" #include "ui/display/types/display_constants.h" #include "ui/display/types/display_mode.h" +#include "ui/gfx/buffer_types.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/size.h" @@ -77,6 +78,9 @@ // Used when no product id known. static const int64_t kInvalidProductID = -1; + // Return the buffer format to be used for the primary plane buffer. + static gfx::BufferFormat PrimaryFormat(); + protected: // Display id for this output. int64_t display_id_;
diff --git a/ui/events/latency_info.cc b/ui/events/latency_info.cc index 8a5ac1b6a..a5cb1ec 100644 --- a/ui/events/latency_info.cc +++ b/ui/events/latency_info.cc
@@ -359,13 +359,10 @@ void LatencyInfo::RemoveLatency(LatencyComponentType type) { LatencyMap::iterator it = latency_components_.begin(); while (it != latency_components_.end()) { - if (it->first.first == type) { - LatencyMap::iterator tmp = it; - ++it; - latency_components_.erase(tmp); - } else { + if (it->first.first == type) + it = latency_components_.erase(it); + else it++; - } } }
diff --git a/ui/events/latency_info_unittest.cc b/ui/events/latency_info_unittest.cc index e279863..51f328e 100644 --- a/ui/events/latency_info_unittest.cc +++ b/ui/events/latency_info_unittest.cc
@@ -67,4 +67,17 @@ EXPECT_EQ(component.event_time.ToInternalValue(), (100 * 2 + 200 * 3) / 5); } +TEST(LatencyInfoTest, RemoveLatency) { + LatencyInfo info; + info.AddLatencyNumber(INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0, 0); + info.AddLatencyNumber(INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 1, 0); + info.AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0); + + info.RemoveLatency(INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT); + + EXPECT_FALSE(info.FindLatency(INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0, 0)); + EXPECT_FALSE(info.FindLatency(INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 1, 0)); + EXPECT_TRUE(info.FindLatency(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0)); +} + } // namespace ui
diff --git a/ui/file_manager/file_manager/foreground/css/file_manager.css b/ui/file_manager/file_manager/foreground/css/file_manager.css index 39e7d2ca..e8926a3 100644 --- a/ui/file_manager/file_manager/foreground/css/file_manager.css +++ b/ui/file_manager/file_manager/foreground/css/file_manager.css
@@ -1087,20 +1087,27 @@ /* A single directory name in the list of path breadcrumbs. */ .breadcrumbs .breadcrumb-path { - -webkit-margin-end: 0; /* An arrow is used as a spacer instead. */ box-sizing: border-box; cursor: pointer; flex: none; font-size: 14px; font-weight: 500; + margin: 0; min-width: 0; padding: 0 9px; text-transform: none; white-space: nowrap; } -.breadcrumbs .breadcrumb-path:not(:first-child) { - -webkit-margin-start: 0; /* An arrow is used as a spacer instead. */ +.breadcrumbs .breadcrumb-path:first-child { + /* -webkit-margin-start isn't proper + because folder names should be ltr even in RTL languages. */ + margin-left: 8px; +} + +html[dir='rtl'] .breadcrumbs .breadcrumb-path:first-child { + margin-left: 0; + margin-right: 8px; } .breadcrumbs .breadcrumb-path:active {
diff --git a/ui/file_manager/file_manager/foreground/elements/files_quick_view.css b/ui/file_manager/file_manager/foreground/elements/files_quick_view.css index 04ab61bd..b19a617 100644 --- a/ui/file_manager/file_manager/foreground/elements/files_quick_view.css +++ b/ui/file_manager/file_manager/foreground/elements/files_quick_view.css
@@ -21,10 +21,6 @@ width: 100%; } -video { - min-width: 192px; -} - #video-poster { max-height: 100%; max-width: 100%; @@ -34,12 +30,6 @@ box-shadow: 0 0 0 2px rgba(191, 191, 191, 0.5); } -video::-webkit-media-controls-fullscreen-button, -audio::-webkit-media-controls-volume-slider, -video::-webkit-media-controls-volume-slider { - display: none; -} - #audio-artwork { height: 300px; margin: 0 auto; @@ -66,6 +56,11 @@ margin-right: 320px; } +:host-context(html[dir='rtl']) #contentPanel[metadata-box-active] { + margin-right: auto; + margin-left: 320px; +} + #metadata-button { background: -webkit-image-set( url(../images/files/ui/quick_view/info_outline.png) 1x, @@ -123,6 +118,11 @@ right: 0px; } +:host-context(html[dir='rtl']) #buttons { + right: auto; + left: 0px +} + paper-button, files-icon-button { border-radius: 2px; @@ -148,6 +148,11 @@ right: 0; } +:host-context(html[dir='rtl']) #metadata-box { + right: auto; + left: 0; +} + ::-webkit-scrollbar { width: 10px; }
diff --git a/ui/file_manager/file_manager/foreground/elements/files_quick_view.html b/ui/file_manager/file_manager/foreground/elements/files_quick_view.html index 4011d96..41e79e6 100644 --- a/ui/file_manager/file_manager/foreground/elements/files_quick_view.html +++ b/ui/file_manager/file_manager/foreground/elements/files_quick_view.html
@@ -10,7 +10,7 @@ <link rel="import" href="chrome://resources/polymer/v1_0/paper-toolbar/paper-toolbar.html"> <link rel="import" href="files_icon_button.html"> <link rel="import" href="files_metadata_box.html"> -<link rel="import" href="files_safe_img.html"> +<link rel="import" href="files_safe_media.html"> <link rel="import" href="files_tooltip.html"> <link rel="import" href="icons.html"> @@ -33,34 +33,32 @@ <div class='close-on-click' id="innerContentPanel" tabindex="0"> <template is="dom-if" if="[[isImage_(type)]]"> <div class="close-on-click" hidden="[[!contentUrl]]"> - <files-safe-img class="content" src="[[contentUrl]]"></files-safe-img> + <files-safe-media type="image" class="content" src="[[contentUrl]]"></files-safe-media> </div> <template is="dom-if" if="[[!contentUrl]]"> <div generic-thumbnail="image"></div> <div class="no-preivew" i18n-content="QUICK_VIEW_NO_PREVIEW_AVAILABLE"></div> </template> </template> + <!-- Video --> + <files-safe-media type="video" class="content" controls autoplay="[[autoplay]]" src="[[videoUrl_(contentUrl, type)]]" poster="[[videoPoster]]" hidden="[[!isVideo_(type)]]"></files-safe-media> <template is="dom-if" if="[[isVideo_(type)]]"> - <template is="dom-if" if="[[contentUrl]]"> - <video class="content" controls autoplay="[[autoplay]]" src="[[contentUrl]]" poster="[[videoPoster]]"></video> - </template> <template is="dom-if" if="[[!contentUrl]]"> <div class="thumbnail" hidden="[[!videoPoster]]"> - <files-safe-img id="video-poster" src="[[videoPoster]]"></files-safe-img> + <files-safe-media type="image" id="video-poster" src="[[videoPoster]]"></files-safe-media> </div> <div hidden="[[videoPoster]]" generic-thumbnail="video"></div> <div class="no-preview" i18n-content="QUICK_VIEW_NO_PLAYBACK_AVAILABLE"></div> </template> </template> + <!-- Audio --> <template is="dom-if" if="[[isAudio_(type)]]"> - <template is="dom-if" if="[[audioArtwork]]"> - <files-safe-img id="audio-artwork" src="[[audioArtwork]]"></files-safe-img> - </template> - <template is="dom-if" if="[[contentUrl]]"> - <div> - <audio autoplay="[[autoplay]]" controls src="[[contentUrl]]"></audio> - </div> - </template> + <files-safe-media type="image" id="audio-artwork" src="[[audioArtwork]]" hidden="[[!audioArtwork]]"></files-safe-media> + </template> + <div> + <files-safe-media type="audio" autoplay="[[autoplay]]" controls src="[[audioUrl_(contentUrl, type)]]" hidden="[[!isAudio_(type)]]"></files-safe-media> + </div> + <template is="dom-if" if="[[isAudio_(type)]]"> <template is="dom-if" if="[[!contentUrl]]"> <div generic-thumbnail="audio"></div> <div class="no-preivew" i18n-content="QUICK_VIEW_NO_PLAYBACK_AVAILABLE"></div>
diff --git a/ui/file_manager/file_manager/foreground/elements/files_quick_view.js b/ui/file_manager/file_manager/foreground/elements/files_quick_view.js index 9094af0..098912da 100644 --- a/ui/file_manager/file_manager/foreground/elements/files_quick_view.js +++ b/ui/file_manager/file_manager/foreground/elements/files_quick_view.js
@@ -26,7 +26,7 @@ listeners: { 'iron-overlay-closed': 'clear', - 'files-safe-img-tap-outside': 'close', + 'files-safe-media-tap-outside': 'close', }, // Clears fields. @@ -115,6 +115,17 @@ }, /** + * @param {string} contentUrl + * @param {string} type + * @return {string} + * + * @private + */ + videoUrl_: function(contentUrl, type) { + return this.isVideo_(type) ? contentUrl : ""; + }, + + /** * @param {string} type * @return {boolean} * @@ -125,6 +136,17 @@ }, /** + * @param {string} contentUrl + * @param {string} type + * @return {string} + * + * @private + */ + audioUrl_: function(contentUrl, type) { + return this.isAudio_(type) ? contentUrl : ""; + }, + + /** * @param {string} type * @return {boolean} *
diff --git a/ui/file_manager/file_manager/foreground/elements/files_safe_audio_webview_content.css b/ui/file_manager/file_manager/foreground/elements/files_safe_audio_webview_content.css new file mode 100644 index 0000000..e514dbb --- /dev/null +++ b/ui/file_manager/file_manager/foreground/elements/files_safe_audio_webview_content.css
@@ -0,0 +1,34 @@ +/* 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. */ + +#content { + bottom: 0; + left: 0; + margin: 0 auto; + max-height: 100%; + max-width: 100%; + padding: 0; + position: absolute; + right: 0; + top: 0; +} + +img { + background-color: white; + background-image: + linear-gradient(45deg, #efefef 25%, transparent 25%, transparent 75%, + #efefef 75%, #efefef), + linear-gradient(45deg, #efefef 25%, transparent 25%, transparent 75%, + #efefef 75%, #efefef); + background-position: 0 0, 10px 10px; + background-size: 21px 21px; +} + +#content[hidden] { + display: none; +} + +audio::-webkit-media-controls-volume-slider { + display: none; +}
diff --git a/ui/file_manager/file_manager/foreground/elements/files_safe_audio_webview_content.html b/ui/file_manager/file_manager/foreground/elements/files_safe_audio_webview_content.html new file mode 100644 index 0000000..96af49a --- /dev/null +++ b/ui/file_manager/file_manager/foreground/elements/files_safe_audio_webview_content.html
@@ -0,0 +1,15 @@ +<!-- 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. +--> + +<!DOCTYPE HTML> +<html> + <head> + <link rel="stylesheet" type="text/css" href="files_safe_audio_webview_content.css"> + </head> + <body> + <audio id="content" controls autoplay></audio> + <script src="files_safe_audio_webview_content.js"></script> + </body> +</html>
diff --git a/ui/file_manager/file_manager/foreground/elements/files_safe_audio_webview_content.js b/ui/file_manager/file_manager/foreground/elements/files_safe_audio_webview_content.js new file mode 100644 index 0000000..53bcfdb6 --- /dev/null +++ b/ui/file_manager/file_manager/foreground/elements/files_safe_audio_webview_content.js
@@ -0,0 +1,39 @@ +// 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. + +window.onload = function() { + var FILES_APP_ORIGIN = 'chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj'; + var messageSource; + + var content = document.getElementById('content'); + + window.addEventListener('message', function(event) { + // TODO(oka): Fix FOUC problem. When webview is first created and receives + // the first message, sometimes the body size is smaller than the outer + // window for a moment and it causes flush of unstyled content. + if (event.origin !== FILES_APP_ORIGIN) { + console.error('Unknown origin: ' + event.origin); + return; + } + messageSource = event.source; + content.src = event.data; + }); + + document.addEventListener('contextmenu', function(e) { + e.preventDefault(); + return false; + }); + + document.addEventListener('click', function(e) { + var data; + if (e.target === content) { + data = 'tap-inside'; + } else { + data = 'tap-outside'; + } + + if (messageSource) + messageSource.postMessage(data, FILES_APP_ORIGIN); + }); +};
diff --git a/ui/file_manager/file_manager/foreground/elements/files_safe_img_webview_content.css b/ui/file_manager/file_manager/foreground/elements/files_safe_img_webview_content.css index c939cf69..a1c91e75 100644 --- a/ui/file_manager/file_manager/foreground/elements/files_safe_img_webview_content.css +++ b/ui/file_manager/file_manager/foreground/elements/files_safe_img_webview_content.css
@@ -3,7 +3,6 @@ * found in the LICENSE file. */ #content { - background-color: transparent; bottom: 0; left: 0; margin: auto; @@ -15,6 +14,17 @@ top: 0; } +img { + background-color: white; + background-image: + linear-gradient(45deg, #efefef 25%, transparent 25%, transparent 75%, + #efefef 75%, #efefef), + linear-gradient(45deg, #efefef 25%, transparent 25%, transparent 75%, + #efefef 75%, #efefef); + background-position: 0 0, 10px 10px; + background-size: 21px 21px; +} + #content[hidden] { display: none; }
diff --git a/ui/file_manager/file_manager/foreground/elements/files_safe_media.html b/ui/file_manager/file_manager/foreground/elements/files_safe_media.html new file mode 100644 index 0000000..29a6528 --- /dev/null +++ b/ui/file_manager/file_manager/foreground/elements/files_safe_media.html
@@ -0,0 +1,26 @@ +<!-- 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. +--> + +<dom-module id="files-safe-media"> + <style> + #content { + height: 100%; + width: 100%; + } + #content.audio { + height: 32px; + } + webview { + display: inline-block; + height: 100%; + width: 100%; + } + </style> + <template> + <div id="content" class$="[[type]]"></div> + </template> +</dom-module> + +<script src="files_safe_media.js"></script>
diff --git a/ui/file_manager/file_manager/foreground/elements/files_safe_media.js b/ui/file_manager/file_manager/foreground/elements/files_safe_media.js new file mode 100644 index 0000000..beaf05f --- /dev/null +++ b/ui/file_manager/file_manager/foreground/elements/files_safe_media.js
@@ -0,0 +1,88 @@ +// 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. + +var FILES_APP_ORIGIN = 'chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj'; + +/** + * Polymer element to render a media securely inside webview. + * When tapped, files-safe-media-tap-inside or + * files-safe-media-tap-outside events are fired depending on the position + * of the tap. + */ +var FilesSafeMedia = Polymer({ + is: 'files-safe-media', + + properties: { + // URL accessible from webview. + src: { + type: String, + observer: 'onSrcChange_', + reflectToAttribute: true + }, + type: { + type: String, + readonly: true, + } + }, + + listeners: {'src-changed': 'onSrcChange_'}, + + /** + * @return {string} + */ + sourceFile_: function() { + switch (this.type) { + case 'image': + return 'foreground/elements/files_safe_img_webview_content.html'; + case 'audio': + return 'foreground/elements/files_safe_audio_webview_content.html'; + case 'video': + return 'foreground/elements/files_safe_video_webview_content.html'; + default: + console.error('Unsupported type: ' + this.type); + return ''; + } + }, + + onSrcChange_: function() { + if (!this.src && this.webview_) { + // Remove webview to clean up unnecessary processes. + Polymer.dom(this.$.content).removeChild(this.webview_); + this.webview_ = null; + } else if (this.src && !this.webview_) { + // Create webview node only if src exists to save resouces. + var webview = document.createElement('webview'); + this.webview_ = webview; + webview.partition = 'trusted'; + webview.allowtransparency = 'true'; + Polymer.dom(this.$.content).appendChild(webview); + webview.addEventListener( + 'contentload', this.onSrcChange_.bind(this)); + webview.src = this.sourceFile_(); + } else if (this.src && this.webview_.contentWindow) { + this.webview_.contentWindow.postMessage(this.src, FILES_APP_ORIGIN); + } + }, + + created: function() { + /** + * @type {HTMLElement} + */ + this.webview_ = null; + }, + + ready: function() { + window.addEventListener('message', function(event) { + if (event.origin !== FILES_APP_ORIGIN) { + console.log('Unknown origin.'); + return; + } + if (event.data === 'tap-inside') { + this.fire('files-safe-media-tap-inside'); + } else if (event.data === 'tap-outside') { + this.fire('files-safe-media-tap-outside'); + } + }.bind(this)); + } +});
diff --git a/ui/file_manager/file_manager/foreground/elements/files_safe_video_webview_content.css b/ui/file_manager/file_manager/foreground/elements/files_safe_video_webview_content.css new file mode 100644 index 0000000..2be4d05 --- /dev/null +++ b/ui/file_manager/file_manager/foreground/elements/files_safe_video_webview_content.css
@@ -0,0 +1,36 @@ +/* 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. */ + +#content { + bottom: 0; + left: 0; + margin: auto; + min-width: 192px; + max-height: 100%; + max-width: 100%; + padding: 0; + position: absolute; + right: 0; + top: 0; +} + +img { + background-color: white; + background-image: + linear-gradient(45deg, #efefef 25%, transparent 25%, transparent 75%, + #efefef 75%, #efefef), + linear-gradient(45deg, #efefef 25%, transparent 25%, transparent 75%, + #efefef 75%, #efefef); + background-position: 0 0, 10px 10px; + background-size: 21px 21px; +} + +#content[hidden] { + display: none; +} + +video::-webkit-media-controls-fullscreen-button, +video::-webkit-media-controls-volume-slider { + display: none; +}
diff --git a/ui/file_manager/file_manager/foreground/elements/files_safe_video_webview_content.html b/ui/file_manager/file_manager/foreground/elements/files_safe_video_webview_content.html new file mode 100644 index 0000000..b5c7daf --- /dev/null +++ b/ui/file_manager/file_manager/foreground/elements/files_safe_video_webview_content.html
@@ -0,0 +1,15 @@ +<!-- 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. +--> + +<!DOCTYPE HTML> +<html> + <head> + <link rel="stylesheet" type="text/css" href="files_safe_video_webview_content.css"> + </head> + <body> + <video id="content" autoplay controls></video> + <script src="files_safe_video_webview_content.js"></script> + </body> +</html>
diff --git a/ui/file_manager/file_manager/foreground/elements/files_safe_video_webview_content.js b/ui/file_manager/file_manager/foreground/elements/files_safe_video_webview_content.js new file mode 100644 index 0000000..53bcfdb6 --- /dev/null +++ b/ui/file_manager/file_manager/foreground/elements/files_safe_video_webview_content.js
@@ -0,0 +1,39 @@ +// 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. + +window.onload = function() { + var FILES_APP_ORIGIN = 'chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj'; + var messageSource; + + var content = document.getElementById('content'); + + window.addEventListener('message', function(event) { + // TODO(oka): Fix FOUC problem. When webview is first created and receives + // the first message, sometimes the body size is smaller than the outer + // window for a moment and it causes flush of unstyled content. + if (event.origin !== FILES_APP_ORIGIN) { + console.error('Unknown origin: ' + event.origin); + return; + } + messageSource = event.source; + content.src = event.data; + }); + + document.addEventListener('contextmenu', function(e) { + e.preventDefault(); + return false; + }); + + document.addEventListener('click', function(e) { + var data; + if (e.target === content) { + data = 'tap-inside'; + } else { + data = 'tap-outside'; + } + + if (messageSource) + messageSource.postMessage(data, FILES_APP_ORIGIN); + }); +};
diff --git a/ui/file_manager/file_manager/foreground/js/quick_view_controller.js b/ui/file_manager/file_manager/foreground/js/quick_view_controller.js index d859d5fe..d3d655a 100644 --- a/ui/file_manager/file_manager/foreground/js/quick_view_controller.js +++ b/ui/file_manager/file_manager/foreground/js/quick_view_controller.js
@@ -233,6 +233,15 @@ filePath: entry.name, }; + /** + * @type function(!FileEntry): !Promise<!File> + */ + var getFile = function(entry) { + return new Promise(function(resolve, reject) { + entry.file(resolve, reject); + }); + }; + if (type === 'image') { if (item.externalFileUrl) { if (item.thumbnailUrl) { @@ -244,11 +253,9 @@ }.bind(this)); } } else { - return new Promise(function(resolve, reject) { - entry.file(function(file) { - params.contentUrl = URL.createObjectURL(file); - resolve(params); - }); + return getFile(entry).then(function(file) { + params.contentUrl = URL.createObjectURL(file); + return params; }); } } else if (type === 'video') { @@ -263,26 +270,37 @@ }); } } else { - params.contentUrl = entry.toURL(); params.autoplay = true; if (item.thumbnailUrl) { params.videoPoster = item.thumbnailUrl; } + return getFile(entry).then(function(file) { + params.contentUrl = URL.createObjectURL(file); + return params; + }); } } else if (type === 'audio') { if (item.externalFileUrl) { // If the file is in Drive, we ask user to open it with external app. } else { - params.contentUrl = entry.toURL(); params.autoplay = true; - return this.metadataModel_.get([entry], ['contentThumbnailUrl']) - .then(function(entry, items) { + return Promise + .all([ + this.metadataModel_.get([entry], ['contentThumbnailUrl']), + getFile(entry) + ]) + .then(function(values) { + /** @type {!Array<!MetadataItem>} */ + var items = values[0]; + /** @type {!File} */ + var file = values[1]; var item = items[0]; if (item.contentThumbnailUrl) { params.audioArtwork = item.contentThumbnailUrl; } + params.contentUrl = URL.createObjectURL(file); return params; - }.bind(this, entry)); + }); } } return Promise.resolve(params);
diff --git a/ui/file_manager/file_manager/manifest.json b/ui/file_manager/file_manager/manifest.json index 5f89ee0..470f0ae9 100644 --- a/ui/file_manager/file_manager/manifest.json +++ b/ui/file_manager/file_manager/manifest.json
@@ -51,7 +51,11 @@ "webview": { "partitions": [{ "name": "trusted", - "accessible_resources": ["foreground/elements/files_safe_img_webview_content.*"] + "accessible_resources": [ + "foreground/elements/files_safe_audio_webview_content.*", + "foreground/elements/files_safe_img_webview_content.*", + "foreground/elements/files_safe_video_webview_content.*" + ] }] }, "file_browser_handlers": [
diff --git a/ui/file_manager/file_manager_resources.grd b/ui/file_manager/file_manager_resources.grd index 50220d2..0bd8e70 100644 --- a/ui/file_manager/file_manager_resources.grd +++ b/ui/file_manager/file_manager_resources.grd
@@ -63,11 +63,17 @@ <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_QUICK_PREVIEW_JS" file="file_manager/foreground/elements/files_quick_view.js" type="BINDATA" /> <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_RIPPLE_HTML" file="file_manager/foreground/elements/files_ripple.html" type="BINDATA" /> <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_RIPPLE_JS" file="file_manager/foreground/elements/files_ripple.js" type="BINDATA" /> - <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_SAFE_IMG_HTML" file="file_manager/foreground/elements/files_safe_img.html" type="BINDATA" /> - <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_SAFE_IMG_JS" file="file_manager/foreground/elements/files_safe_img.js" type="BINDATA" /> + <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_SAFE_AUDIO_WEBVIEW_CONTENT_CSS" file="file_manager/foreground/elements/files_safe_audio_webview_content.css" flattenhtml="true" type="BINDATA" /> + <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_SAFE_AUDIO_WEBVIEW_CONTENT_HTML" file="file_manager/foreground/elements/files_safe_audio_webview_content.html" type="BINDATA" /> + <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_SAFE_AUDIO_WEBVIEW_CONTENT_JS" file="file_manager/foreground/elements/files_safe_audio_webview_content.js" type="BINDATA" /> + <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_SAFE_IMG_WEBVIEW_CONTENT_CSS" file="file_manager/foreground/elements/files_safe_img_webview_content.css" flattenhtml="true" type="BINDATA" /> <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_SAFE_IMG_WEBVIEW_CONTENT_HTML" file="file_manager/foreground/elements/files_safe_img_webview_content.html" type="BINDATA" /> <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_SAFE_IMG_WEBVIEW_CONTENT_JS" file="file_manager/foreground/elements/files_safe_img_webview_content.js" type="BINDATA" /> - <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_SAFE_IMG_WEBVIEW_CONTENT_CSS" file="file_manager/foreground/elements/files_safe_img_webview_content.css" flattenhtml="true" type="BINDATA" /> + <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_SAFE_MEDIA_HTML" file="file_manager/foreground/elements/files_safe_media.html" type="BINDATA" /> + <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_SAFE_MEDIA_JS" file="file_manager/foreground/elements/files_safe_media.js" type="BINDATA" /> + <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_SAFE_VIDEO_WEBVIEW_CONTENT_CSS" file="file_manager/foreground/elements/files_safe_video_webview_content.css" flattenhtml="true" type="BINDATA" /> + <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_SAFE_VIDEO_WEBVIEW_CONTENT_HTML" file="file_manager/foreground/elements/files_safe_video_webview_content.html" type="BINDATA" /> + <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_SAFE_VIDEO_WEBVIEW_CONTENT_JS" file="file_manager/foreground/elements/files_safe_video_webview_content.js" type="BINDATA" /> <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_TOAST_HTML" file="file_manager/foreground/elements/files_toast.html" type="BINDATA" /> <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_TOAST_JS" file="file_manager/foreground/elements/files_toast.js" type="BINDATA" /> <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_TOGGLE_RIPPLE_HTML" file="file_manager/foreground/elements/files_toggle_ripple.html" type="BINDATA" />
diff --git a/ui/file_manager/gallery/js/slide_mode.js b/ui/file_manager/gallery/js/slide_mode.js index 54ccfc1..a749191 100644 --- a/ui/file_manager/gallery/js/slide_mode.js +++ b/ui/file_manager/gallery/js/slide_mode.js
@@ -927,6 +927,9 @@ * @param {string} keyID Key of the KeyboardEvent. */ SlideMode.prototype.advanceWithKeyboard = function(keyID) { + if (this.getItemCount_() === 0) + return; + var prev = (keyID === 'ArrowUp' || keyID === 'ArrowLeft' || keyID === 'MediaTrackPrevious');
diff --git a/ui/gfx/gfx.gyp b/ui/gfx/gfx.gyp index 620e37a..5b4410a 100644 --- a/ui/gfx/gfx.gyp +++ b/ui/gfx/gfx.gyp
@@ -82,7 +82,7 @@ '<(DEPTH)/third_party/icu/icu.gyp:icui18n', '<(DEPTH)/third_party/icu/icu.gyp:icuuc', '<(DEPTH)/third_party/libpng/libpng.gyp:libpng', - '<(DEPTH)//third_party/qcms/qcms.gyp:qcms", + '<(DEPTH)//third_party/qcms/qcms.gyp:qcms', '<(DEPTH)/third_party/zlib/zlib.gyp:zlib', 'gfx_geometry', 'gfx_range',
diff --git a/ui/gfx/mojo/transform.mojom b/ui/gfx/mojo/transform.mojom index 5d6103d..c613fec1 100644 --- a/ui/gfx/mojo/transform.mojom +++ b/ui/gfx/mojo/transform.mojom
@@ -7,5 +7,5 @@ // See ui/gfx/transform.h. struct Transform { // Column major order. - array<float, 16> matrix; + array<float, 16>? matrix; };
diff --git a/ui/gfx/mojo/transform_struct_traits.h b/ui/gfx/mojo/transform_struct_traits.h index a55122e..d3fb630 100644 --- a/ui/gfx/mojo/transform_struct_traits.h +++ b/ui/gfx/mojo/transform_struct_traits.h
@@ -15,6 +15,8 @@ struct ArrayTraits<SkMatrix44> { using Element = float; + static bool IsNull(const SkMatrix44& input) { return input.isIdentity(); } + static size_t GetSize(const SkMatrix44& input) { return 16; } static float GetAt(const SkMatrix44& input, size_t index) { @@ -32,6 +34,10 @@ static bool Read(gfx::mojom::TransformDataView data, gfx::Transform* out) { ArrayDataView<float> matrix; data.GetMatrixDataView(&matrix); + if (matrix.is_null()) { + out->MakeIdentity(); + return true; + } out->matrix().setColMajorf(matrix.data()); return true; }
diff --git a/ui/gfx/vector_icons/system_menu_arrow_right.1x.icon b/ui/gfx/vector_icons/system_menu_arrow_right.1x.icon new file mode 100644 index 0000000..30ee32c --- /dev/null +++ b/ui/gfx/vector_icons/system_menu_arrow_right.1x.icon
@@ -0,0 +1,10 @@ +// 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. + +CANVAS_DIMENSIONS, 20, +MOVE_TO, 8, 14, +R_LINE_TO, 4, -4, +R_LINE_TO, -4, -4, +CLOSE, +END
diff --git a/ui/gfx/vector_icons/system_menu_arrow_right.icon b/ui/gfx/vector_icons/system_menu_arrow_right.icon new file mode 100644 index 0000000..2dc5eac --- /dev/null +++ b/ui/gfx/vector_icons/system_menu_arrow_right.icon
@@ -0,0 +1,10 @@ +// 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. + +CANVAS_DIMENSIONS, 40, +MOVE_TO, 16, 28, +R_LINE_TO, 8, -8, +R_LINE_TO, -8, -8, +CLOSE, +END
diff --git a/ui/gfx/vector_icons/system_menu_bluetooth.1x.icon b/ui/gfx/vector_icons/system_menu_bluetooth.1x.icon new file mode 100644 index 0000000..12eb297 --- /dev/null +++ b/ui/gfx/vector_icons/system_menu_bluetooth.1x.icon
@@ -0,0 +1,32 @@ +// 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. + +CANVAS_DIMENSIONS, 20, +MOVE_TO, 10.5f, 1.5f, +R_H_LINE_TO, -1, +V_LINE_TO, 8, +LINE_TO, 5.69f, 4.17f, +LINE_TO, 4.5f, 5.34f, +LINE_TO, 9.5f, 10, +R_LINE_TO, -5, 4.66f, +R_LINE_TO, 1.19f, 1.09f, +LINE_TO, 9.5f, 12, +R_V_LINE_TO, 6.5f, +R_H_LINE_TO, 1, +R_LINE_TO, 4.5f, -5, +R_LINE_TO, -3.5f, -3.5f, +LINE_TO, 15, 6.5f, +R_LINE_TO, -4.5f, -5, +CLOSE, +R_MOVE_TO, 0.77f, 3.36f, +R_LINE_TO, 1.59f, 1.57f, +R_LINE_TO, -1.59f, 1.57f, +V_LINE_TO, 4.86f, +CLOSE, +R_MOVE_TO, 0, 10.28f, +R_V_LINE_TO, -3.13f, +R_LINE_TO, 1.59f, 1.57f, +R_LINE_TO, -1.59f, 1.57f, +CLOSE, +END
diff --git a/ui/gfx/vector_icons/system_menu_bluetooth.icon b/ui/gfx/vector_icons/system_menu_bluetooth.icon new file mode 100644 index 0000000..613ea32e --- /dev/null +++ b/ui/gfx/vector_icons/system_menu_bluetooth.icon
@@ -0,0 +1,32 @@ +// 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. + +CANVAS_DIMENSIONS, 40, +MOVE_TO, 21, 3, +R_H_LINE_TO, -2, +R_V_LINE_TO, 13, +R_LINE_TO, -7.61f, -7.67f, +LINE_TO, 9, 10.68f, +LINE_TO, 19, 20, +LINE_TO, 9, 29.32f, +R_LINE_TO, 2.39f, 2.18f, +LINE_TO, 19, 24, +R_V_LINE_TO, 13, +R_H_LINE_TO, 2, +R_LINE_TO, 9, -10, +R_LINE_TO, -7, -7, +R_LINE_TO, 7, -7, +R_LINE_TO, -9, -10, +CLOSE, +R_MOVE_TO, 1.55f, 6.72f, +R_LINE_TO, 3.18f, 3.13f, +R_LINE_TO, -3.18f, 3.13f, +V_LINE_TO, 9.72f, +CLOSE, +R_MOVE_TO, 0, 20.57f, +R_V_LINE_TO, -6.27f, +R_LINE_TO, 3.18f, 3.13f, +R_LINE_TO, -3.18f, 3.13f, +CLOSE, +END
diff --git a/ui/gfx/vector_icons/system_menu_bluetooth_disabled.1x.icon b/ui/gfx/vector_icons/system_menu_bluetooth_disabled.1x.icon new file mode 100644 index 0000000..1ccee625 --- /dev/null +++ b/ui/gfx/vector_icons/system_menu_bluetooth_disabled.1x.icon
@@ -0,0 +1,35 @@ +// 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. + +CANVAS_DIMENSIONS, 20, +MOVE_TO, 12.84f, 6.43f, +R_LINE_TO, -1.3f, 1.33f, +R_LINE_TO, 1.15f, 1.18f, +LINE_TO, 14.89f, 6.5f, +R_LINE_TO, -4.39f, -5, +R_H_LINE_TO, -0.97f, +R_V_LINE_TO, 4.25f, +R_LINE_TO, 1.79f, 1.78f, +V_LINE_TO, 4.86f, +R_LINE_TO, 1.53f, 1.57f, +CLOSE, +MOVE_TO, 4, 4.51f, +LINE_TO, 9.53f, 10, +R_LINE_TO, -4.71f, 4.66f, +R_LINE_TO, 1.15f, 1.18f, +LINE_TO, 9.53f, 12, +R_V_LINE_TO, 6.5f, +R_H_LINE_TO, 0.98f, +R_LINE_TO, 3.49f, -3.74f, +R_LINE_TO, 1.87f, 1.91f, +LINE_TO, 17, 15.49f, +LINE_TO, 5.15f, 3.33f, +LINE_TO, 4, 4.51f, +CLOSE, +R_MOVE_TO, 7.31f, 7.5f, +R_LINE_TO, 1.53f, 1.57f, +R_LINE_TO, -1.53f, 1.57f, +R_V_LINE_TO, -3.13f, +CLOSE, +END
diff --git a/ui/gfx/vector_icons/system_menu_bluetooth_disabled.icon b/ui/gfx/vector_icons/system_menu_bluetooth_disabled.icon new file mode 100644 index 0000000..c2c0029 --- /dev/null +++ b/ui/gfx/vector_icons/system_menu_bluetooth_disabled.icon
@@ -0,0 +1,35 @@ +// 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. + +CANVAS_DIMENSIONS, 40, +MOVE_TO, 25.68f, 12.85f, +R_LINE_TO, -2.6f, 2.67f, +R_LINE_TO, 2.29f, 2.35f, +LINE_TO, 29.78f, 13, +LINE_TO, 21, 3, +R_H_LINE_TO, -1.95f, +R_V_LINE_TO, 8.5f, +R_LINE_TO, 3.58f, 3.55f, +V_LINE_TO, 9.72f, +R_LINE_TO, 3.06f, 3.13f, +CLOSE, +MOVE_TO, 8, 9.02f, +LINE_TO, 19.05f, 20, +R_LINE_TO, -9.43f, 9.32f, +R_LINE_TO, 2.29f, 2.35f, +LINE_TO, 19.05f, 24, +R_V_LINE_TO, 13, +H_LINE_TO, 21, +R_LINE_TO, 6.97f, -7.48f, +R_LINE_TO, 3.74f, 3.82f, +LINE_TO, 34, 30.98f, +LINE_TO, 10.29f, 6.67f, +LINE_TO, 8, 9.02f, +CLOSE, +R_MOVE_TO, 14.63f, 15, +R_LINE_TO, 3.06f, 3.13f, +R_LINE_TO, -3.05f, 3.13f, +R_V_LINE_TO, -6.27f, +CLOSE, +END
diff --git a/ui/gfx/vector_icons_sources.gypi b/ui/gfx/vector_icons_sources.gypi index beeb7d93..ff315fb8 100644 --- a/ui/gfx/vector_icons_sources.gypi +++ b/ui/gfx/vector_icons_sources.gypi
@@ -134,6 +134,12 @@ 'vector_icons/supervisor_account.icon', 'vector_icons/sync_problem.icon', 'vector_icons/system_menu_accessibility.icon', + 'vector_icons/system_menu_arrow_right.1x.icon', + 'vector_icons/system_menu_arrow_right.icon', + 'vector_icons/system_menu_bluetooth.1x.icon', + 'vector_icons/system_menu_bluetooth.icon', + 'vector_icons/system_menu_bluetooth_disabled.1x.icon', + 'vector_icons/system_menu_bluetooth_disabled.icon', 'vector_icons/system_menu_caps_lock.icon', 'vector_icons/system_menu_rotation_lock_auto.icon', 'vector_icons/system_menu_rotation_lock_locked.icon',
diff --git a/ui/gfx/win/direct_manipulation.cc b/ui/gfx/win/direct_manipulation.cc index ee50937e..f391f07 100644 --- a/ui/gfx/win/direct_manipulation.cc +++ b/ui/gfx/win/direct_manipulation.cc
@@ -22,7 +22,10 @@ DirectManipulationHelper::DirectManipulationHelper() {} -DirectManipulationHelper::~DirectManipulationHelper() {} +DirectManipulationHelper::~DirectManipulationHelper() { + if (view_port_outer_) + view_port_outer_->Abandon(); +} void DirectManipulationHelper::Initialize(HWND window) { DCHECK(::IsWindow(window));
diff --git a/ui/login/account_picker/user_pod_row.js b/ui/login/account_picker/user_pod_row.js index d14bb17..dfb2b3a 100644 --- a/ui/login/account_picker/user_pod_row.js +++ b/ui/login/account_picker/user_pod_row.js
@@ -3424,7 +3424,8 @@ if (this.focusedPod_) { var targetTag = e.target.tagName; if (e.target == this.focusedPod_.passwordElement || - e.target == this.focusedPod_.pinKeyboard.inputElement || + (this.focusedPod_.pinKeyboard && + e.target == this.focusedPod_.pinKeyboard.inputElement) || (targetTag != 'INPUT' && targetTag != 'BUTTON' && targetTag != 'A')) {
diff --git a/ui/message_center/views/message_view.cc b/ui/message_center/views/message_view.cc index 847d5a9..622b18a5 100644 --- a/ui/message_center/views/message_view.cc +++ b/ui/message_center/views/message_view.cc
@@ -7,7 +7,6 @@ #include "ui/accessibility/ax_view_state.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/models/simple_menu_model.h" -#include "ui/base/ui_base_switches_util.h" #include "ui/compositor/scoped_layer_animation_settings.h" #include "ui/gfx/canvas.h" #include "ui/gfx/shadow_value.h" @@ -234,8 +233,6 @@ } void MessageView::SetDrawBackgroundAsActive(bool active) { - if (!switches::IsTouchFeedbackEnabled()) - return; background_view_->background()-> SetNativeControlColor(active ? kHoveredButtonBackgroundColor : kNotificationBackgroundColor);
diff --git a/ui/ozone/demo/surfaceless_gl_renderer.cc b/ui/ozone/demo/surfaceless_gl_renderer.cc index f7d6b8f..f1e5792 100644 --- a/ui/ozone/demo/surfaceless_gl_renderer.cc +++ b/ui/ozone/demo/surfaceless_gl_renderer.cc
@@ -9,6 +9,7 @@ #include "base/bind.h" #include "base/macros.h" #include "base/trace_event/trace_event.h" +#include "ui/display/types/display_snapshot.h" #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_context.h" #include "ui/gl/gl_image.h" @@ -39,14 +40,14 @@ glGenFramebuffersEXT(1, &gl_fb_); glGenTextures(1, &gl_tex_); + gfx::BufferFormat format = ui::DisplaySnapshot::PrimaryFormat(); scoped_refptr<NativePixmap> pixmap = OzonePlatform::GetInstance() ->GetSurfaceFactoryOzone() - ->CreateNativePixmap(widget, size, gfx::BufferFormat::BGRX_8888, - gfx::BufferUsage::SCANOUT); + ->CreateNativePixmap(widget, size, format, gfx::BufferUsage::SCANOUT); scoped_refptr<ui::GLImageOzoneNativePixmap> image( new ui::GLImageOzoneNativePixmap(size, GL_RGB)); - if (!image->Initialize(pixmap.get(), gfx::BufferFormat::BGRX_8888)) { + if (!image->Initialize(pixmap.get(), format)) { LOG(ERROR) << "Failed to create GLImage"; return false; }
diff --git a/ui/ozone/platform/drm/client_native_pixmap_factory_gbm.cc b/ui/ozone/platform/drm/client_native_pixmap_factory_gbm.cc index 12b9550..335f80b 100644 --- a/ui/ozone/platform/drm/client_native_pixmap_factory_gbm.cc +++ b/ui/ozone/platform/drm/client_native_pixmap_factory_gbm.cc
@@ -48,7 +48,8 @@ format == gfx::BufferFormat::BGRX_8888 || format == gfx::BufferFormat::YVU_420; case gfx::BufferUsage::SCANOUT: - return format == gfx::BufferFormat::BGRX_8888; + return format == gfx::BufferFormat::BGRX_8888 || + format == gfx::BufferFormat::RGBX_8888; case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE: case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE_PERSISTENT: { #if defined(OS_CHROMEOS)
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane.cc b/ui/ozone/platform/drm/gpu/hardware_display_plane.cc index bf0f1bb..54f59188 100644 --- a/ui/ozone/platform/drm/gpu/hardware_display_plane.cc +++ b/ui/ozone/platform/drm/gpu/hardware_display_plane.cc
@@ -66,6 +66,7 @@ if (is_dummy) { type_ = kDummy; supported_formats_.push_back(DRM_FORMAT_XRGB8888); + supported_formats_.push_back(DRM_FORMAT_XBGR8888); return true; }
diff --git a/ui/ozone/platform/drm/gpu/screen_manager.cc b/ui/ozone/platform/drm/gpu/screen_manager.cc index 37e4afc..6908b12 100644 --- a/ui/ozone/platform/drm/gpu/screen_manager.cc +++ b/ui/ozone/platform/drm/gpu/screen_manager.cc
@@ -10,6 +10,7 @@ #include "base/memory/ptr_util.h" #include "third_party/skia/include/core/SkCanvas.h" +#include "ui/display/types/display_snapshot.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" @@ -341,9 +342,10 @@ return *primary; } + gfx::BufferFormat format = ui::DisplaySnapshot::PrimaryFormat(); scoped_refptr<DrmDevice> drm = controller->GetAllocationDrmDevice(); - scoped_refptr<ScanoutBuffer> buffer = buffer_generator_->Create( - drm, gfx::BufferFormat::BGRA_8888, bounds.size()); + scoped_refptr<ScanoutBuffer> buffer = + buffer_generator_->Create(drm, format, bounds.size()); if (!buffer) { LOG(ERROR) << "Failed to create scanout buffer"; return OverlayPlane(nullptr, 0, gfx::OVERLAY_TRANSFORM_INVALID, gfx::Rect(),
diff --git a/ui/ozone/platform/drm/host/drm_device_handle.cc b/ui/ozone/platform/drm/host/drm_device_handle.cc index 40f62f1..26db609 100644 --- a/ui/ozone/platform/drm/host/drm_device_handle.cc +++ b/ui/ozone/platform/drm/host/drm_device_handle.cc
@@ -12,11 +12,18 @@ #include "base/files/file_path.h" #include "base/posix/eintr_wrapper.h" #include "base/threading/thread_restrictions.h" +#include "base/time/time.h" namespace ui { namespace { +// Sleep this many milliseconds before retrying after authentication fails. +const int kAuthFailSleepMs = 100; + +// Log a warning after failing to authenticate for this many milliseconds. +const int kLogAuthFailDelayMs = 1000; + bool Authenticate(int fd) { drm_magic_t magic; memset(&magic, 0, sizeof(magic)); @@ -42,7 +49,10 @@ // used a label and is otherwise unvalidated. CHECK(dev_path.DirName() == base::FilePath("/dev/dri")); base::ThreadRestrictions::AssertIOAllowed(); - bool print_warning = true; + + int num_auth_attempts = 0; + bool logged_warning = false; + const base::TimeTicks start_time = base::TimeTicks::Now(); while (true) { file_.reset(); int fd = HANDLE_EINTR(open(dev_path.value().c_str(), O_RDWR | O_CLOEXEC)); @@ -54,16 +64,25 @@ file_.reset(fd); sys_path_ = sys_path; + num_auth_attempts++; if (Authenticate(file_.get())) break; - LOG_IF(WARNING, print_warning) << "Failed to authenticate " - << dev_path.value(); - print_warning = false; - usleep(100000); + // To avoid spamming the logs, hold off before logging a warning (some + // failures are expected at first) and only log a single message. + if (!logged_warning && + (base::TimeTicks::Now() - start_time).InMilliseconds() >= + kLogAuthFailDelayMs) { + LOG(WARNING) << "Failed to authenticate " << dev_path.value() + << " within " << kLogAuthFailDelayMs << " ms"; + logged_warning = true; + } + usleep(kAuthFailSleepMs * 1000); } - VLOG(1) << "Succeeded authenticating " << dev_path.value(); + VLOG(1) << "Succeeded authenticating " << dev_path.value() << " in " + << (base::TimeTicks::Now() - start_time).InMilliseconds() << " ms " + << "with " << num_auth_attempts << " attempt(s)"; return true; }
diff --git a/ui/strings/ui_strings.grd b/ui/strings/ui_strings.grd index 93125bf..e14c19d 100644 --- a/ui/strings/ui_strings.grd +++ b/ui/strings/ui_strings.grd
@@ -588,6 +588,9 @@ <message name="IDS_MESSAGE_CENTER_NOTIFICATION_BUTTON_COPY_SCREENSHOT_TO_CLIPBOARD" desc="The button label for the screenshot notification which copies the screenshot image to clipboard on click."> Copy to clipboard </message> + <message name="IDS_MESSAGE_CENTER_NOTIFICATION_BUTTON_ANNOTATE_SCREENSHOT" desc="The label for the screenshot notification button that opens Google Keep to annotate the screenhsot."> + Annotate in Google Keep + </message> <message name="IDS_MESSAGE_CENTER_NOTIFIER_HATS_NAME" desc="The name of hats notifier that is a system component"> Hats </message>
diff --git a/ui/views/cocoa/bridged_content_view.mm b/ui/views/cocoa/bridged_content_view.mm index 38c06a4..80243f8 100644 --- a/ui/views/cocoa/bridged_content_view.mm +++ b/ui/views/cocoa/bridged_content_view.mm
@@ -437,10 +437,11 @@ if (textInputClient_ && ![self activeMenuController]) { // If a single character is inserted by keyDown's call to // interpretKeyEvents: then use InsertChar() to allow editing events to be - // merged. We use ui::VKEY_UNKOWN as the key code since it's not feasible to - // determine the correct key code for each unicode character. Also a correct - // keycode is not needed in the current context. Send ui::EF_NONE as the key - // modifier since |text| already accounts for the pressed key modifiers. + // merged. We use ui::VKEY_UNKNOWN as the key code since it's not feasible + // to determine the correct key code for each unicode character. Also a + // correct keycode is not needed in the current context. Send ui::EF_NONE as + // the key modifier since |text| already accounts for the pressed key + // modifiers. // Also, note we don't use |keyDownEvent_| to generate the synthetic // ui::KeyEvent since for text inserted using an IME, [keyDownEvent_ @@ -762,8 +763,10 @@ // Selection movement and scrolling. - (void)moveForward:(id)sender { - IsTextRTL(textInputClient_) ? [self moveLeft:sender] - : [self moveRight:sender]; + [self handleAction:ui::TextEditCommand::MOVE_FORWARD + keyCode:ui::VKEY_UNKNOWN + domCode:ui::DomCode::NONE + eventFlags:0]; } - (void)moveRight:(id)sender { @@ -774,8 +777,10 @@ } - (void)moveBackward:(id)sender { - IsTextRTL(textInputClient_) ? [self moveRight:sender] - : [self moveLeft:sender]; + [self handleAction:ui::TextEditCommand::MOVE_BACKWARD + keyCode:ui::VKEY_UNKNOWN + domCode:ui::DomCode::NONE + eventFlags:0]; } - (void)moveLeft:(id)sender { @@ -800,13 +805,17 @@ } - (void)moveWordForward:(id)sender { - IsTextRTL(textInputClient_) ? [self moveWordLeft:sender] - : [self moveWordRight:sender]; + [self handleAction:ui::TextEditCommand::MOVE_WORD_FORWARD + keyCode:ui::VKEY_UNKNOWN + domCode:ui::DomCode::NONE + eventFlags:0]; } - (void)moveWordBackward:(id)sender { - IsTextRTL(textInputClient_) ? [self moveWordRight:sender] - : [self moveWordLeft:sender]; + [self handleAction:ui::TextEditCommand::MOVE_WORD_BACKWARD + keyCode:ui::VKEY_UNKNOWN + domCode:ui::DomCode::NONE + eventFlags:0]; } - (void)moveToBeginningOfLine:(id)sender { @@ -824,22 +833,28 @@ } - (void)moveToBeginningOfParagraph:(id)sender { - [self moveToBeginningOfLine:sender]; + [self handleAction:ui::TextEditCommand::MOVE_TO_BEGINNING_OF_PARAGRAPH + keyCode:ui::VKEY_UNKNOWN + domCode:ui::DomCode::NONE + eventFlags:0]; } - (void)moveToEndOfParagraph:(id)sender { - [self moveToEndOfLine:sender]; + [self handleAction:ui::TextEditCommand::MOVE_TO_END_OF_PARAGRAPH + keyCode:ui::VKEY_UNKNOWN + domCode:ui::DomCode::NONE + eventFlags:0]; } - (void)moveToEndOfDocument:(id)sender { - [self handleAction:ui::TextEditCommand::MOVE_TO_END_OF_LINE + [self handleAction:ui::TextEditCommand::MOVE_TO_END_OF_DOCUMENT keyCode:ui::VKEY_END domCode:ui::DomCode::END eventFlags:ui::EF_CONTROL_DOWN]; } - (void)moveToBeginningOfDocument:(id)sender { - [self handleAction:ui::TextEditCommand::MOVE_TO_BEGINNING_OF_LINE + [self handleAction:ui::TextEditCommand::MOVE_TO_BEGINNING_OF_DOCUMENT keyCode:ui::VKEY_HOME domCode:ui::DomCode::HOME eventFlags:ui::EF_CONTROL_DOWN]; @@ -860,23 +875,32 @@ } - (void)moveBackwardAndModifySelection:(id)sender { - IsTextRTL(textInputClient_) ? [self moveRightAndModifySelection:sender] - : [self moveLeftAndModifySelection:sender]; + [self handleAction:ui::TextEditCommand::MOVE_BACKWARD_AND_MODIFY_SELECTION + keyCode:ui::VKEY_UNKNOWN + domCode:ui::DomCode::NONE + eventFlags:0]; } - (void)moveForwardAndModifySelection:(id)sender { - IsTextRTL(textInputClient_) ? [self moveLeftAndModifySelection:sender] - : [self moveRightAndModifySelection:sender]; + [self handleAction:ui::TextEditCommand::MOVE_FORWARD_AND_MODIFY_SELECTION + keyCode:ui::VKEY_UNKNOWN + domCode:ui::DomCode::NONE + eventFlags:0]; } - (void)moveWordForwardAndModifySelection:(id)sender { - IsTextRTL(textInputClient_) ? [self moveWordLeftAndModifySelection:sender] - : [self moveWordRightAndModifySelection:sender]; + [self handleAction:ui::TextEditCommand::MOVE_WORD_FORWARD_AND_MODIFY_SELECTION + keyCode:ui::VKEY_UNKNOWN + domCode:ui::DomCode::NONE + eventFlags:0]; } - (void)moveWordBackwardAndModifySelection:(id)sender { - IsTextRTL(textInputClient_) ? [self moveWordRightAndModifySelection:sender] - : [self moveWordLeftAndModifySelection:sender]; + [self + handleAction:ui::TextEditCommand::MOVE_WORD_BACKWARD_AND_MODIFY_SELECTION + keyCode:ui::VKEY_UNKNOWN + domCode:ui::DomCode::NONE + eventFlags:0]; } - (void)moveUpAndModifySelection:(id)sender { @@ -912,24 +936,32 @@ } - (void)moveToBeginningOfParagraphAndModifySelection:(id)sender { - [self moveToBeginningOfLineAndModifySelection:sender]; + [self handleAction:ui::TextEditCommand:: + MOVE_TO_BEGINNING_OF_PARAGRAPH_AND_MODIFY_SELECTION + keyCode:ui::VKEY_UNKNOWN + domCode:ui::DomCode::NONE + eventFlags:0]; } - (void)moveToEndOfParagraphAndModifySelection:(id)sender { - [self moveToEndOfLineAndModifySelection:sender]; + [self handleAction:ui::TextEditCommand:: + MOVE_TO_END_OF_PARAGRAPH_AND_MODIFY_SELECTION + keyCode:ui::VKEY_UNKNOWN + domCode:ui::DomCode::NONE + eventFlags:0]; } - (void)moveToEndOfDocumentAndModifySelection:(id)sender { - [self - handleAction:ui::TextEditCommand::MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION - keyCode:ui::VKEY_END - domCode:ui::DomCode::END - eventFlags:ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN]; + [self handleAction:ui::TextEditCommand:: + MOVE_TO_END_OF_DOCUMENT_AND_MODIFY_SELECTION + keyCode:ui::VKEY_END + domCode:ui::DomCode::END + eventFlags:ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN]; } - (void)moveToBeginningOfDocumentAndModifySelection:(id)sender { [self handleAction:ui::TextEditCommand:: - MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION + MOVE_TO_BEGINNING_OF_DOCUMENT_AND_MODIFY_SELECTION keyCode:ui::VKEY_HOME domCode:ui::DomCode::HOME eventFlags:ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN]; @@ -1085,11 +1117,17 @@ } - (void)deleteToBeginningOfParagraph:(id)sender { - [self deleteToBeginningOfLine:sender]; + [self handleAction:ui::TextEditCommand::DELETE_TO_BEGINNING_OF_PARAGRAPH + keyCode:ui::VKEY_UNKNOWN + domCode:ui::DomCode::NONE + eventFlags:0]; } - (void)deleteToEndOfParagraph:(id)sender { - [self deleteToEndOfLine:sender]; + [self handleAction:ui::TextEditCommand::DELETE_TO_END_OF_PARAGRAPH + keyCode:ui::VKEY_UNKNOWN + domCode:ui::DomCode::NONE + eventFlags:0]; } - (void)yank:(id)sender {
diff --git a/ui/views/cocoa/bridged_native_widget_unittest.mm b/ui/views/cocoa/bridged_native_widget_unittest.mm index b864134..0db6aa98 100644 --- a/ui/views/cocoa/bridged_native_widget_unittest.mm +++ b/ui/views/cocoa/bridged_native_widget_unittest.mm
@@ -19,6 +19,8 @@ #import "testing/gtest_mac.h" #import "ui/base/cocoa/window_size_constants.h" #include "ui/base/ime/input_method.h" +#include "ui/base/material_design/material_design_controller.h" +#include "ui/base/test/material_design_controller_test_api.h" #include "ui/events/test/cocoa_test_event_utils.h" #import "ui/gfx/mac/coordinate_conversion.h" #import "ui/gfx/test/ui_cocoa_test_helper.h" @@ -239,6 +241,7 @@ // Overridden from testing::Test: void SetUp() override { ui::CocoaTest::SetUp(); + ui::MaterialDesignController::Initialize(); init_params_.native_widget = native_widget_mac_; @@ -258,6 +261,11 @@ native_widget_mac_->GetWidget()->Init(init_params_); } + void TearDown() override { + ui::test::MaterialDesignControllerTestAPI::Uninitialize(); + ui::CocoaTest::TearDown(); + } + protected: std::unique_ptr<Widget> widget_; MockNativeWidgetMac* native_widget_mac_; // Weak. Owned by |widget_|.
diff --git a/ui/views/controls/button/menu_button.cc b/ui/views/controls/button/menu_button.cc index b891849..4b562c5e 100644 --- a/ui/views/controls/button/menu_button.cc +++ b/ui/views/controls/button/menu_button.cc
@@ -9,7 +9,6 @@ #include "ui/base/dragdrop/drag_drop_types.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" -#include "ui/base/ui_base_switches_util.h" #include "ui/display/screen.h" #include "ui/events/event.h" #include "ui/events/event_constants.h" @@ -256,17 +255,15 @@ SetState(Button::STATE_NORMAL); return; } - if (switches::IsTouchFeedbackEnabled()) { - if (event->type() == ui::ET_GESTURE_TAP_DOWN) { - event->SetHandled(); - if (pressed_lock_count_ == 0) - SetState(Button::STATE_HOVERED); - } else if (state() == Button::STATE_HOVERED && - (event->type() == ui::ET_GESTURE_TAP_CANCEL || - event->type() == ui::ET_GESTURE_END) && - pressed_lock_count_ == 0) { - SetState(Button::STATE_NORMAL); - } + if (event->type() == ui::ET_GESTURE_TAP_DOWN) { + event->SetHandled(); + if (pressed_lock_count_ == 0) + SetState(Button::STATE_HOVERED); + } else if (state() == Button::STATE_HOVERED && + (event->type() == ui::ET_GESTURE_TAP_CANCEL || + event->type() == ui::ET_GESTURE_END) && + pressed_lock_count_ == 0) { + SetState(Button::STATE_NORMAL); } } LabelButton::OnGestureEvent(event);
diff --git a/ui/views/controls/focusable_border.cc b/ui/views/controls/focusable_border.cc index a4e76ff1..2274b3cd 100644 --- a/ui/views/controls/focusable_border.cc +++ b/ui/views/controls/focusable_border.cc
@@ -10,6 +10,7 @@ #include "ui/gfx/canvas.h" #include "ui/gfx/color_palette.h" #include "ui/gfx/geometry/insets.h" +#include "ui/gfx/scoped_canvas.h" #include "ui/gfx/skia_util.h" #include "ui/native_theme/native_theme.h" #include "ui/views/controls/textfield/textfield.h" @@ -45,18 +46,27 @@ paint.setStyle(SkPaint::kStroke_Style); paint.setColor(GetCurrentColor(view)); - SkPath path; if (ui::MaterialDesignController::IsSecondaryUiMaterial()) { - path.moveTo(Textfield::kTextPadding, view.height() - 1); - path.rLineTo(view.width() - Textfield::kTextPadding * 2, 0); - path.offset(0.5f, 0.5f); - paint.setStrokeWidth(SkIntToScalar(1)); + gfx::ScopedCanvas scoped(canvas); + float dsf = canvas->UndoDeviceScaleFactor(); + gfx::RectF rect((gfx::Rect(view.GetLocalBounds()))); + rect = ScaleRect(rect, dsf, dsf); + rect.Inset(gfx::InsetsF(0.5f)); + SkPath path; + float corner_radius_px = kCornerRadiusDp * dsf; + path.addRoundRect(gfx::RectFToSkRect(rect), corner_radius_px, + corner_radius_px); + const int kStrokeWidthPx = 1; + paint.setStrokeWidth(SkIntToScalar(kStrokeWidthPx)); + paint.setAntiAlias(true); + canvas->DrawPath(path, paint); } else { + SkPath path; path.addRect(gfx::RectToSkRect(view.GetLocalBounds()), SkPath::kCW_Direction); paint.setStrokeWidth(SkIntToScalar(2)); + canvas->DrawPath(path, paint); } - canvas->DrawPath(path, paint); } gfx::Insets FocusableBorder::GetInsets() const {
diff --git a/ui/views/controls/focusable_border.h b/ui/views/controls/focusable_border.h index 862049ab..08613125 100644 --- a/ui/views/controls/focusable_border.h +++ b/ui/views/controls/focusable_border.h
@@ -20,6 +20,8 @@ // A Border class to draw a focused border around a field (e.g textfield). class VIEWS_EXPORT FocusableBorder : public Border { public: + static constexpr float kCornerRadiusDp = 1.5f; + FocusableBorder(); ~FocusableBorder() override;
diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc index 94c530ff..7fc2220 100644 --- a/ui/views/controls/menu/menu_controller.cc +++ b/ui/views/controls/menu/menu_controller.cc
@@ -1398,8 +1398,11 @@ ui::Accelerator accelerator(ui::VKEY_RETURN, ui::EF_NONE); hot_view->AcceleratorPressed(accelerator); - CustomButton* button = static_cast<CustomButton*>(hot_view); - SetHotTrackedButton(button); + // An accelerator may have canceled the menu after activation. + if (GetActiveInstance()) { + CustomButton* button = static_cast<CustomButton*>(hot_view); + SetHotTrackedButton(button); + } return true; }
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc index be796b2..1f940c5 100644 --- a/ui/views/controls/textfield/textfield.cc +++ b/ui/views/controls/textfield/textfield.cc
@@ -17,6 +17,7 @@ #include "ui/base/dragdrop/drag_utils.h" #include "ui/base/ime/input_method.h" #include "ui/base/ime/text_edit_commands.h" +#include "ui/base/material_design/material_design_controller.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/ui_base_switches_util.h" #include "ui/compositor/canvas_painter.h" @@ -1732,12 +1733,18 @@ void Textfield::UpdateBackgroundColor() { const SkColor color = GetBackgroundColor(); - set_background(Background::CreateSolidBackground(color)); + if (ui::MaterialDesignController::IsSecondaryUiMaterial()) { + set_background(Background::CreateBackgroundPainter( + true, Painter::CreateSolidRoundRectPainter( + color, FocusableBorder::kCornerRadiusDp))); + } else { + set_background(Background::CreateSolidBackground(color)); + } // Disable subpixel rendering when the background color is transparent // because it draws incorrect colors around the glyphs in that case. // See crbug.com/115198 GetRenderText()->set_subpixel_rendering_suppressed( - SkColorGetA(color) != 0xFF); + SkColorGetA(color) != SK_AlphaOPAQUE); SchedulePaint(); }
diff --git a/ui/views/examples/textfield_example.cc b/ui/views/examples/textfield_example.cc index ffcf464..11ca35e 100644 --- a/ui/views/examples/textfield_example.cc +++ b/ui/views/examples/textfield_example.cc
@@ -8,6 +8,7 @@ #include "base/strings/utf_string_conversions.h" #include "ui/events/event.h" +#include "ui/gfx/color_palette.h" #include "ui/gfx/range/range.h" #include "ui/gfx/render_text.h" #include "ui/views/controls/button/label_button.h" @@ -46,6 +47,8 @@ read_only_->SetReadOnly(true); read_only_->SetText(ASCIIToUTF16("read only")); show_password_ = new LabelButton(this, ASCIIToUTF16("Show password")); + set_background_ = + new LabelButton(this, ASCIIToUTF16("Set non-default background")); clear_all_ = new LabelButton(this, ASCIIToUTF16("Clear All")); append_ = new LabelButton(this, ASCIIToUTF16("Append")); set_ = new LabelButton(this, ASCIIToUTF16("Set")); @@ -61,25 +64,23 @@ 0.2f, GridLayout::USE_PREF, 0, 0); column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0.8f, GridLayout::USE_PREF, 0, 0); - layout->StartRow(0, 0); - layout->AddView(new Label(ASCIIToUTF16("Name:"))); - layout->AddView(name_); - layout->StartRow(0, 0); - layout->AddView(new Label(ASCIIToUTF16("Password:"))); - layout->AddView(password_); - layout->StartRow(0, 0); - layout->AddView(new Label(ASCIIToUTF16("Read Only:"))); - layout->AddView(read_only_); - layout->StartRow(0, 0); - layout->AddView(show_password_); - layout->StartRow(0, 0); - layout->AddView(clear_all_); - layout->StartRow(0, 0); - layout->AddView(append_); - layout->StartRow(0, 0); - layout->AddView(set_); - layout->StartRow(0, 0); - layout->AddView(set_style_); + + auto MakeRow = [layout](View* view1, View* view2) { + layout->StartRowWithPadding(0, 0, 0, 5); + layout->AddView(view1); + if (view2) + layout->AddView(view2); + }; + MakeRow(new Label(ASCIIToUTF16("Name:")), name_); + MakeRow(new Label(ASCIIToUTF16("Password:")), password_); + MakeRow(new Label(ASCIIToUTF16("Read Only:")), read_only_); + MakeRow(new Label(ASCIIToUTF16("Name:")), nullptr); + MakeRow(show_password_, nullptr); + MakeRow(set_background_, nullptr); + MakeRow(clear_all_, nullptr); + MakeRow(append_, nullptr); + MakeRow(set_, nullptr); + MakeRow(set_style_, nullptr); } void TextfieldExample::ContentsChanged(Textfield* sender, @@ -107,6 +108,8 @@ void TextfieldExample::ButtonPressed(Button* sender, const ui::Event& event) { if (sender == show_password_) { PrintStatus("Password [%s]", UTF16ToUTF8(password_->text()).c_str()); + } else if (sender == set_background_) { + password_->SetBackgroundColor(gfx::kGoogleRed300); } else if (sender == clear_all_) { base::string16 empty; name_->SetText(empty);
diff --git a/ui/views/examples/textfield_example.h b/ui/views/examples/textfield_example.h index 90ec331..638d337 100644 --- a/ui/views/examples/textfield_example.h +++ b/ui/views/examples/textfield_example.h
@@ -48,6 +48,7 @@ // Various buttons to control textfield. LabelButton* show_password_; + LabelButton* set_background_; LabelButton* clear_all_; LabelButton* append_; LabelButton* set_;
diff --git a/ui/views/mus/BUILD.gn b/ui/views/mus/BUILD.gn index 72110d44..81f8198 100644 --- a/ui/views/mus/BUILD.gn +++ b/ui/views/mus/BUILD.gn
@@ -33,8 +33,6 @@ "screen_mus.cc", "screen_mus.h", "screen_mus_delegate.h", - "surface_binding.cc", - "surface_binding.h", "surface_context_factory.cc", "surface_context_factory.h", "window_manager_connection.cc",
diff --git a/ui/views/mus/native_widget_mus.cc b/ui/views/mus/native_widget_mus.cc index e786f15f..c325827a 100644 --- a/ui/views/mus/native_widget_mus.cc +++ b/ui/views/mus/native_widget_mus.cc
@@ -21,7 +21,6 @@ #include "services/ui/public/interfaces/window_tree.mojom.h" #include "ui/aura/client/default_capture_client.h" #include "ui/aura/client/window_tree_client.h" -#include "ui/aura/env.h" #include "ui/aura/layout_manager.h" #include "ui/aura/mus/mus_util.h" #include "ui/aura/window.h" @@ -34,7 +33,6 @@ #include "ui/gfx/path.h" #include "ui/native_theme/native_theme_aura.h" #include "ui/platform_window/platform_window_delegate.h" -#include "ui/views/mus/surface_context_factory.h" #include "ui/views/mus/window_manager_constants_converters.h" #include "ui/views/mus/window_manager_frame_values.h" #include "ui/views/mus/window_tree_host_mus.h" @@ -516,8 +514,7 @@ : window_(window), last_cursor_(ui::mojom::Cursor::CURSOR_NULL), native_widget_delegate_(delegate), - is_parallel_widget_in_window_manager_(surface_type == - ui::mojom::SurfaceType::UNDERLAY), + surface_type_(surface_type), show_state_before_fullscreen_(ui::mojom::ShowState::DEFAULT), ownership_(Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET), content_(new aura::Window(this)), @@ -528,19 +525,7 @@ // TODO(fsamuel): Figure out lifetime of |window_|. aura::SetMusWindow(content_, window_); window->SetLocalProperty(kNativeWidgetMusKey, this); - - // WindowTreeHost creates the compositor using the ContextFactory from - // aura::Env. Install |context_factory_| there so that |context_factory_| is - // picked up. - ui::ContextFactory* default_context_factory = - aura::Env::GetInstance()->context_factory(); - if (!default_context_factory) { - context_factory_.reset(new SurfaceContextFactory(window_, surface_type)); - aura::Env::GetInstance()->set_context_factory(context_factory_.get()); - } - window_tree_host_.reset(new WindowTreeHostMus(this, window_)); - aura::Env::GetInstance()->set_context_factory(default_context_factory); } NativeWidgetMus::~NativeWidgetMus() { @@ -569,11 +554,16 @@ } // static -Widget* NativeWidgetMus::GetWidgetForWindow(ui::Window* window) { - if (!window) - return nullptr; +NativeWidgetMus* NativeWidgetMus::GetForWindow(ui::Window* window) { + DCHECK(window); NativeWidgetMus* native_widget = window->GetLocalProperty(kNativeWidgetMusKey); + return native_widget; +} + +// static +Widget* NativeWidgetMus::GetWidgetForWindow(ui::Window* window) { + NativeWidgetMus* native_widget = GetForWindow(window); if (!native_widget) return nullptr; return native_widget->GetWidget(); @@ -702,7 +692,7 @@ aura::client::SetScreenPositionClient(hosted_window, screen_position_client_.get()); - // TODO(erg): Remove this check when ash/mus/frame/move_event_handler.cc's + // TODO(erg): Remove this check when ash/mus/move_event_handler.cc's // direct usage of ui::Window::SetPredefinedCursor() is switched to a // private method on WindowManagerClient. if (!is_parallel_widget_in_window_manager()) { @@ -1042,7 +1032,7 @@ } void NativeWidgetMus::SetAlwaysOnTop(bool always_on_top) { - if (window_) { + if (window_ && !is_parallel_widget_in_window_manager()) { window_->SetSharedProperty<bool>( ui::mojom::WindowManager::kAlwaysOnTop_Property, always_on_top); }
diff --git a/ui/views/mus/native_widget_mus.h b/ui/views/mus/native_widget_mus.h index 2bd29b5..4f47a751 100644 --- a/ui/views/mus/native_widget_mus.h +++ b/ui/views/mus/native_widget_mus.h
@@ -51,7 +51,6 @@ } namespace views { -class SurfaceContextFactory; class WidgetDelegate; // An implementation of NativeWidget that binds to a ui::Window. Because Aura @@ -80,9 +79,13 @@ // Notifies all widgets the frame constants changed in some way. static void NotifyFrameChanged(ui::WindowTreeClient* client); + // Returns the native widget for a ui::Window, or null if there is none. + static NativeWidgetMus* GetForWindow(ui::Window* window); + // Returns the widget for a ui::Window, or null if there is none. static Widget* GetWidgetForWindow(ui::Window* window); + ui::mojom::SurfaceType surface_type() const { return surface_type_; } ui::Window* window() { return window_; } WindowTreeHostMus* window_tree_host() { return window_tree_host_.get(); } @@ -235,7 +238,7 @@ // Returns true if this NativeWidgetMus exists on the window manager side // to provide the frame decorations. bool is_parallel_widget_in_window_manager() { - return is_parallel_widget_in_window_manager_; + return surface_type_ == ui::mojom::SurfaceType::UNDERLAY; } void set_last_cursor(ui::mojom::Cursor cursor) { last_cursor_ = cursor; } @@ -254,7 +257,7 @@ internal::NativeWidgetDelegate* native_widget_delegate_; - const bool is_parallel_widget_in_window_manager_; + const ui::mojom::SurfaceType surface_type_; ui::mojom::ShowState show_state_before_fullscreen_; // See class documentation for Widget in widget.h for a note about ownership. @@ -270,7 +273,6 @@ std::map<std::string, void*> native_window_properties_; // Aura configuration. - std::unique_ptr<SurfaceContextFactory> context_factory_; std::unique_ptr<WindowTreeHostMus> window_tree_host_; aura::Window* content_; std::unique_ptr<wm::FocusController> focus_client_;
diff --git a/ui/views/mus/surface_binding.cc b/ui/views/mus/surface_binding.cc deleted file mode 100644 index 659766ae..0000000 --- a/ui/views/mus/surface_binding.cc +++ /dev/null
@@ -1,117 +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 "ui/views/mus/surface_binding.h" - -#include <stdint.h> - -#include <map> -#include <utility> - -#include "base/bind.h" -#include "base/lazy_instance.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/threading/thread_local.h" -#include "cc/output/compositor_frame.h" -#include "cc/output/output_surface.h" -#include "cc/output/output_surface_client.h" -#include "cc/output/software_output_device.h" -#include "cc/resources/shared_bitmap_manager.h" -#include "mojo/public/cpp/bindings/binding.h" -#include "services/ui/public/cpp/context_provider.h" -#include "services/ui/public/cpp/output_surface.h" -#include "services/ui/public/cpp/window.h" -#include "services/ui/public/cpp/window_tree_client.h" -#include "ui/views/mus/window_tree_host_mus.h" - -namespace views { - -// PerClientState -------------------------------------------------------------- - -// State needed per WindowTreeClient. Provides the real implementation of -// CreateOutputSurface. SurfaceBinding obtains a pointer to the -// PerClientState appropriate for the WindowTreeClient. PerClientState is -// stored in a thread local map. When no more refereces to a PerClientState -// remain the PerClientState is deleted and the underlying map cleaned up. -class SurfaceBinding::PerClientState : public base::RefCounted<PerClientState> { - public: - static PerClientState* Get(ui::WindowTreeClient* client); - - std::unique_ptr<cc::OutputSurface> CreateOutputSurface( - ui::Window* window, - ui::mojom::SurfaceType type); - - private: - typedef std::map<ui::WindowTreeClient*, PerClientState*> ClientToStateMap; - - friend class base::RefCounted<PerClientState>; - - explicit PerClientState(ui::WindowTreeClient* client); - ~PerClientState(); - - static base::LazyInstance< - base::ThreadLocalPointer<ClientToStateMap>>::Leaky window_states; - - ui::WindowTreeClient* client_; - - DISALLOW_COPY_AND_ASSIGN(PerClientState); -}; - -// static -base::LazyInstance<base::ThreadLocalPointer< - SurfaceBinding::PerClientState::ClientToStateMap>>::Leaky - SurfaceBinding::PerClientState::window_states; - -// static -SurfaceBinding::PerClientState* SurfaceBinding::PerClientState::Get( - ui::WindowTreeClient* client) { - ClientToStateMap* window_map = window_states.Pointer()->Get(); - if (!window_map) { - window_map = new ClientToStateMap; - window_states.Pointer()->Set(window_map); - } - if (!(*window_map)[client]) - (*window_map)[client] = new PerClientState(client); - return (*window_map)[client]; -} - -std::unique_ptr<cc::OutputSurface> -SurfaceBinding::PerClientState::CreateOutputSurface( - ui::Window* window, - ui::mojom::SurfaceType surface_type) { - scoped_refptr<cc::ContextProvider> context_provider(new ui::ContextProvider); - return base::WrapUnique(new ui::OutputSurface( - context_provider, window->RequestSurface(surface_type))); -} - -SurfaceBinding::PerClientState::PerClientState(ui::WindowTreeClient* client) - : client_(client) {} - -SurfaceBinding::PerClientState::~PerClientState() { - ClientToStateMap* window_map = window_states.Pointer()->Get(); - DCHECK(window_map); - DCHECK_EQ(this, (*window_map)[client_]); - window_map->erase(client_); - if (window_map->empty()) { - delete window_map; - window_states.Pointer()->Set(nullptr); - } -} - -// SurfaceBinding -------------------------------------------------------------- - -SurfaceBinding::SurfaceBinding(ui::Window* window, - ui::mojom::SurfaceType surface_type) - : window_(window), - surface_type_(surface_type), - state_(PerClientState::Get(window->window_tree())) {} - -SurfaceBinding::~SurfaceBinding() {} - -std::unique_ptr<cc::OutputSurface> SurfaceBinding::CreateOutputSurface() { - return state_ ? state_->CreateOutputSurface(window_, surface_type_) : nullptr; -} - -} // namespace views
diff --git a/ui/views/mus/surface_binding.h b/ui/views/mus/surface_binding.h deleted file mode 100644 index 08340df..0000000 --- a/ui/views/mus/surface_binding.h +++ /dev/null
@@ -1,51 +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 UI_VIEWS_MUS_SURFACE_BINDING_H_ -#define UI_VIEWS_MUS_SURFACE_BINDING_H_ - -#include <memory> - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "services/ui/public/interfaces/window_tree.mojom.h" -#include "ui/views/mus/mus_export.h" - -namespace cc { -class OutputSurface; -} - -namespace ui { -class Window; -} - -namespace views { - -// SurfaceBinding is responsible for managing the connections necessary to -// bind a Window to the surfaces service. -// Internally SurfaceBinding manages one connection (and related structures) per -// WindowTree. That is, all Windows from a particular WindowTree share the same -// connection. -class VIEWS_MUS_EXPORT SurfaceBinding { - public: - SurfaceBinding(ui::Window* window, ui::mojom::SurfaceType surface_type); - ~SurfaceBinding(); - - // Creates an OutputSurface that renders to the Window supplied to the - // constructor. - std::unique_ptr<cc::OutputSurface> CreateOutputSurface(); - - private: - class PerClientState; - - ui::Window* window_; - const ui::mojom::SurfaceType surface_type_; - scoped_refptr<PerClientState> state_; - - DISALLOW_COPY_AND_ASSIGN(SurfaceBinding); -}; - -} // namespace views - -#endif // UI_VIEWS_MUS_SURFACE_BINDING_H_
diff --git a/ui/views/mus/surface_context_factory.cc b/ui/views/mus/surface_context_factory.cc index 046a6075..08fb8c6 100644 --- a/ui/views/mus/surface_context_factory.cc +++ b/ui/views/mus/surface_context_factory.cc
@@ -8,9 +8,11 @@ #include "cc/output/output_surface.h" #include "cc/resources/shared_bitmap_manager.h" #include "cc/surfaces/surface_id_allocator.h" +#include "services/ui/public/cpp/output_surface.h" #include "services/ui/public/cpp/window.h" #include "ui/compositor/reflector.h" #include "ui/gl/gl_bindings.h" +#include "ui/views/mus/native_widget_mus.h" namespace views { namespace { @@ -26,20 +28,19 @@ } // namespace -SurfaceContextFactory::SurfaceContextFactory( - ui::Window* window, - ui::mojom::SurfaceType surface_type) - : surface_binding_(window, surface_type), next_surface_id_namespace_(1u) {} +SurfaceContextFactory::SurfaceContextFactory() + : next_surface_id_namespace_(1u) {} SurfaceContextFactory::~SurfaceContextFactory() {} void SurfaceContextFactory::CreateOutputSurface( base::WeakPtr<ui::Compositor> compositor) { - // NOTIMPLEMENTED(); - std::unique_ptr<cc::OutputSurface> surface = - surface_binding_.CreateOutputSurface(); - if (surface) - compositor->SetOutputSurface(std::move(surface)); + ui::Window* window = compositor->window(); + NativeWidgetMus* native_widget = NativeWidgetMus::GetForWindow(window); + ui::mojom::SurfaceType surface_type = native_widget->surface_type(); + std::unique_ptr<cc::OutputSurface> surface( + new ui::OutputSurface(window->RequestSurface(surface_type))); + compositor->SetOutputSurface(std::move(surface)); } std::unique_ptr<ui::Reflector> SurfaceContextFactory::CreateReflector(
diff --git a/ui/views/mus/surface_context_factory.h b/ui/views/mus/surface_context_factory.h index d5ead5dd..442c39e 100644 --- a/ui/views/mus/surface_context_factory.h +++ b/ui/views/mus/surface_context_factory.h
@@ -13,18 +13,12 @@ #include "services/ui/public/interfaces/window_tree.mojom.h" #include "ui/compositor/compositor.h" #include "ui/views/mus/mus_export.h" -#include "ui/views/mus/surface_binding.h" - -namespace ui { -class Window; -} namespace views { class VIEWS_MUS_EXPORT SurfaceContextFactory : public ui::ContextFactory { public: - SurfaceContextFactory(ui::Window* window, - ui::mojom::SurfaceType surface_type); + SurfaceContextFactory(); ~SurfaceContextFactory() override; private: @@ -57,7 +51,6 @@ void AddObserver(ui::ContextFactoryObserver* observer) override {} void RemoveObserver(ui::ContextFactoryObserver* observer) override {} - SurfaceBinding surface_binding_; uint32_t next_surface_id_namespace_; ui::RasterThreadHelper raster_thread_helper_; ui::MojoGpuMemoryBufferManager gpu_memory_buffer_manager_;
diff --git a/ui/views/mus/window_manager_connection.cc b/ui/views/mus/window_manager_connection.cc index fccfb9e..1aa43ce 100644 --- a/ui/views/mus/window_manager_connection.cc +++ b/ui/views/mus/window_manager_connection.cc
@@ -18,12 +18,13 @@ #include "services/ui/public/cpp/window_tree_client.h" #include "services/ui/public/interfaces/event_matcher.mojom.h" #include "services/ui/public/interfaces/window_tree.mojom.h" +#include "ui/aura/env.h" #include "ui/views/mus/clipboard_mus.h" #include "ui/views/mus/native_widget_mus.h" #include "ui/views/mus/os_exchange_data_provider_mus.h" #include "ui/views/mus/screen_mus.h" +#include "ui/views/mus/surface_context_factory.h" #include "ui/views/pointer_watcher.h" -#include "ui/views/touch_event_watcher.h" #include "ui/views/views_delegate.h" namespace views { @@ -98,48 +99,31 @@ ui::mojom::SurfaceType::DEFAULT); } -void WindowManagerConnection::AddPointerWatcher(PointerWatcher* watcher) { - // TODO(riajiang): Support multiple event matchers (crbug.com/627146). - DCHECK(!HasTouchEventWatcher()); +void WindowManagerConnection::AddPointerWatcher(PointerWatcher* watcher, + bool want_moves) { + // Pointer watchers cannot be added multiple times. + DCHECK(!pointer_watchers_.HasObserver(watcher)); + // TODO(jamescook): Support adding pointer watchers with different + // |want_moves| values by tracking whether the set as a whole wants moves. + // This will involve sending observed move events to a subset of the + // watchers. (crbug.com/627146) + DCHECK(!HasPointerWatcher() || want_moves == pointer_watcher_want_moves_); + pointer_watcher_want_moves_ = want_moves; + bool had_watcher = HasPointerWatcher(); pointer_watchers_.AddObserver(watcher); if (!had_watcher) { - // Start a watcher for pointer down. - // TODO(jamescook): Extend event observers to handle multiple event types. - ui::mojom::EventMatcherPtr matcher = ui::mojom::EventMatcher::New(); - matcher->type_matcher = ui::mojom::EventTypeMatcher::New(); - matcher->type_matcher->type = ui::mojom::EventType::POINTER_DOWN; - client_->SetEventObserver(std::move(matcher)); + // First PointerWatcher added, start the watcher on the window server. + client_->StartPointerWatcher(want_moves); } } void WindowManagerConnection::RemovePointerWatcher(PointerWatcher* watcher) { pointer_watchers_.RemoveObserver(watcher); if (!HasPointerWatcher()) { - // Last PointerWatcher removed, stop the event observer. - client_->SetEventObserver(nullptr); - } -} - -void WindowManagerConnection::AddTouchEventWatcher(TouchEventWatcher* watcher) { - // TODO(riajiang): Support multiple event matchers (crbug.com/627146). - DCHECK(!HasPointerWatcher()); - bool had_watcher = HasTouchEventWatcher(); - touch_event_watchers_.AddObserver(watcher); - if (!had_watcher) { - ui::mojom::EventMatcherPtr matcher = ui::mojom::EventMatcher::New(); - matcher->pointer_kind_matcher = ui::mojom::PointerKindMatcher::New(); - matcher->pointer_kind_matcher->pointer_kind = ui::mojom::PointerKind::TOUCH; - client_->SetEventObserver(std::move(matcher)); - } -} - -void WindowManagerConnection::RemoveTouchEventWatcher( - TouchEventWatcher* watcher) { - touch_event_watchers_.RemoveObserver(watcher); - if (!HasTouchEventWatcher()) { - // Last TouchEventWatcher removed, stop the event observer. - client_->SetEventObserver(nullptr); + // Last PointerWatcher removed, stop the watcher on the window server. + client_->StopPointerWatcher(); + pointer_watcher_want_moves_ = false; } } @@ -150,10 +134,15 @@ WindowManagerConnection::WindowManagerConnection( shell::Connector* connector, const shell::Identity& identity) - : connector_(connector), identity_(identity) { + : connector_(connector), + identity_(identity), + pointer_watcher_want_moves_(false) { lazy_tls_ptr.Pointer()->Set(this); gpu_service_ = ui::GpuService::Initialize(connector); + compositor_context_factory_.reset(new views::SurfaceContextFactory()); + aura::Env::GetInstance()->set_context_factory( + compositor_context_factory_.get()); client_.reset(new ui::WindowTreeClient(this, nullptr, nullptr)); client_->ConnectViaWindowTreeFactory(connector_); @@ -180,15 +169,6 @@ return !!iterator.GetNext(); } -bool WindowManagerConnection::HasTouchEventWatcher() { - // Check to see if we really have any observers left. This doesn't use - // base::ObserverList<>::might_have_observers() because that returns true - // during iteration over the list even when the last observer is removed. - base::ObserverList<TouchEventWatcher>::Iterator iterator( - &touch_event_watchers_); - return !!iterator.GetNext(); -} - void WindowManagerConnection::OnEmbed(ui::Window* root) {} void WindowManagerConnection::OnDidDestroyClient(ui::WindowTreeClient* client) { @@ -199,10 +179,9 @@ } } -void WindowManagerConnection::OnEventObserved(const ui::Event& event, - ui::Window* target) { - if (!event.IsLocatedEvent()) - return; +void WindowManagerConnection::OnPointerEventObserved( + const ui::PointerEvent& event, + ui::Window* target) { Widget* target_widget = nullptr; if (target) { ui::Window* root = target->GetRoot(); @@ -213,23 +192,9 @@ // to store screen coordinates. Screen coordinates really should be returned // separately. See http://crbug.com/608547 gfx::Point location_in_screen = event.AsLocatedEvent()->root_location(); - if (HasPointerWatcher()) { - if (event.type() == ui::ET_MOUSE_PRESSED) { - FOR_EACH_OBSERVER(PointerWatcher, pointer_watchers_, - OnMousePressed(*event.AsMouseEvent(), - location_in_screen, target_widget)); - } else if (event.type() == ui::ET_TOUCH_PRESSED) { - FOR_EACH_OBSERVER(PointerWatcher, pointer_watchers_, - OnTouchPressed(*event.AsTouchEvent(), - location_in_screen, target_widget)); - } - } else if (HasTouchEventWatcher()) { - if (event.IsTouchEvent() || event.IsTouchPointerEvent()) { - FOR_EACH_OBSERVER( - TouchEventWatcher, touch_event_watchers_, - OnTouchEventObserved(*event.AsLocatedEvent(), target_widget)); - } - } + FOR_EACH_OBSERVER( + PointerWatcher, pointer_watchers_, + OnPointerEventObserved(event, location_in_screen, target_widget)); } void WindowManagerConnection::OnWindowManagerFrameValuesChanged() {
diff --git a/ui/views/mus/window_manager_connection.h b/ui/views/mus/window_manager_connection.h index 71c894f..4c7f050 100644 --- a/ui/views/mus/window_manager_connection.h +++ b/ui/views/mus/window_manager_connection.h
@@ -33,8 +33,8 @@ class ClipboardMus; class NativeWidget; class PointerWatcher; -class TouchEventWatcher; class ScreenMus; +class SurfaceContextFactory; namespace internal { class NativeWidgetDelegate; } @@ -72,12 +72,9 @@ const Widget::InitParams& init_params, internal::NativeWidgetDelegate* delegate); - void AddPointerWatcher(PointerWatcher* watcher); + void AddPointerWatcher(PointerWatcher* watcher, bool want_moves); void RemovePointerWatcher(PointerWatcher* watcher); - void AddTouchEventWatcher(TouchEventWatcher* watcher); - void RemoveTouchEventWatcher(TouchEventWatcher* watcher); - const std::set<ui::Window*>& GetRoots() const; private: @@ -88,12 +85,12 @@ // Returns true if there is one or more watchers for this client. bool HasPointerWatcher(); - bool HasTouchEventWatcher(); // ui::WindowTreeClientDelegate: void OnEmbed(ui::Window* root) override; void OnDidDestroyClient(ui::WindowTreeClient* client) override; - void OnEventObserved(const ui::Event& event, ui::Window* target) override; + void OnPointerEventObserved(const ui::PointerEvent& event, + ui::Window* target) override; // ScreenMusDelegate: void OnWindowManagerFrameValuesChanged() override; @@ -107,9 +104,10 @@ std::unique_ptr<ScreenMus> screen_; std::unique_ptr<ui::WindowTreeClient> client_; std::unique_ptr<ui::GpuService> gpu_service_; + std::unique_ptr<SurfaceContextFactory> compositor_context_factory_; // Must be empty on destruction. base::ObserverList<PointerWatcher, true> pointer_watchers_; - base::ObserverList<TouchEventWatcher, true> touch_event_watchers_; + bool pointer_watcher_want_moves_; DISALLOW_COPY_AND_ASSIGN(WindowManagerConnection); };
diff --git a/ui/views/mus/window_manager_connection_unittest.cc b/ui/views/mus/window_manager_connection_unittest.cc index e84d9ea..16415890 100644 --- a/ui/views/mus/window_manager_connection_unittest.cc +++ b/ui/views/mus/window_manager_connection_unittest.cc
@@ -11,7 +11,6 @@ #include "ui/events/event.h" #include "ui/views/pointer_watcher.h" #include "ui/views/test/scoped_views_test_helper.h" -#include "ui/views/touch_event_watcher.h" namespace views { namespace { @@ -21,194 +20,138 @@ TestPointerWatcher() {} ~TestPointerWatcher() override {} - bool mouse_pressed() const { return mouse_pressed_; } - bool touch_pressed() const { return touch_pressed_; } + ui::PointerEvent* last_event_observed() { return last_event_observed_.get(); } - void Reset() { - mouse_pressed_ = false; - touch_pressed_ = false; - } + void Reset() { last_event_observed_.reset(); } // PointerWatcher: - void OnMousePressed(const ui::MouseEvent& event, - const gfx::Point& location_in_screen, - Widget* target) override { - mouse_pressed_ = true; - } - void OnTouchPressed(const ui::TouchEvent& event, - const gfx::Point& location_in_screen, - Widget* target) override { - touch_pressed_ = true; + void OnPointerEventObserved(const ui::PointerEvent& event, + const gfx::Point& location_in_screen, + Widget* target) override { + last_event_observed_.reset(new ui::PointerEvent(event)); } private: - bool mouse_pressed_ = false; - bool touch_pressed_ = false; + std::unique_ptr<ui::PointerEvent> last_event_observed_; DISALLOW_COPY_AND_ASSIGN(TestPointerWatcher); }; } // namespace -namespace { - -class TestTouchEventWatcher : public TouchEventWatcher { - public: - TestTouchEventWatcher() {} - ~TestTouchEventWatcher() override {} - - bool touch_observed() const { return touch_observed_; } - - void Reset() { touch_observed_ = false; } - - // TouchEventWatcher: - void OnTouchEventObserved(const ui::LocatedEvent& event, - Widget* target) override { - touch_observed_ = true; - } - - private: - bool touch_observed_ = false; - - DISALLOW_COPY_AND_ASSIGN(TestTouchEventWatcher); -}; - -} // namespace - class WindowManagerConnectionTest : public testing::Test { public: WindowManagerConnectionTest() {} ~WindowManagerConnectionTest() override {} - void OnEventObserved(const ui::Event& event) { - WindowManagerConnection::Get()->OnEventObserved(event, nullptr); + void OnPointerEventObserved(const ui::PointerEvent& event) { + WindowManagerConnection::Get()->OnPointerEventObserved(event, nullptr); } private: DISALLOW_COPY_AND_ASSIGN(WindowManagerConnectionTest); }; -TEST_F(WindowManagerConnectionTest, PointerWatcher) { +TEST_F(WindowManagerConnectionTest, PointerWatcherNoMove) { base::MessageLoop message_loop(base::MessageLoop::TYPE_UI); ScopedViewsTestHelper helper; WindowManagerConnection* connection = WindowManagerConnection::Get(); ASSERT_TRUE(connection); - ui::MouseEvent mouse_pressed(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), - base::TimeTicks(), ui::EF_NONE, 0); - ui::TouchEvent touch_pressed(ui::ET_TOUCH_PRESSED, gfx::Point(), 1, - base::TimeTicks()); - ui::KeyEvent key_pressed(ui::ET_KEY_PRESSED, ui::VKEY_A, 0); - // PointerWatchers receive mouse events. + ui::PointerEvent pointer_event_down( + ui::ET_POINTER_DOWN, gfx::Point(), gfx::Point(), ui::EF_NONE, 1, + ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH), + base::TimeTicks()); + ui::PointerEvent pointer_event_up( + ui::ET_POINTER_UP, gfx::Point(), gfx::Point(), ui::EF_NONE, 1, + ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE), + base::TimeTicks()); + + // PointerWatchers receive pointer down events. TestPointerWatcher watcher1; - connection->AddPointerWatcher(&watcher1); - OnEventObserved(mouse_pressed); - EXPECT_TRUE(watcher1.mouse_pressed()); + connection->AddPointerWatcher(&watcher1, false); + OnPointerEventObserved(pointer_event_down); + EXPECT_EQ(ui::ET_POINTER_DOWN, watcher1.last_event_observed()->type()); watcher1.Reset(); - // PointerWatchers receive touch events. - OnEventObserved(touch_pressed); - EXPECT_TRUE(watcher1.touch_pressed()); - watcher1.Reset(); - - // PointerWatchers do not trigger for key events. - OnEventObserved(key_pressed); - EXPECT_FALSE(watcher1.mouse_pressed()); - EXPECT_FALSE(watcher1.touch_pressed()); + // PointerWatchers receive pointer up events. + OnPointerEventObserved(pointer_event_up); + EXPECT_EQ(ui::ET_POINTER_UP, watcher1.last_event_observed()->type()); watcher1.Reset(); // Two PointerWatchers can both receive a single observed event. TestPointerWatcher watcher2; - connection->AddPointerWatcher(&watcher2); - OnEventObserved(mouse_pressed); - EXPECT_TRUE(watcher1.mouse_pressed()); - EXPECT_TRUE(watcher2.mouse_pressed()); + connection->AddPointerWatcher(&watcher2, false); + OnPointerEventObserved(pointer_event_down); + EXPECT_EQ(ui::ET_POINTER_DOWN, watcher1.last_event_observed()->type()); + EXPECT_EQ(ui::ET_POINTER_DOWN, watcher2.last_event_observed()->type()); watcher1.Reset(); watcher2.Reset(); // Removing the first PointerWatcher stops sending events to it. connection->RemovePointerWatcher(&watcher1); - OnEventObserved(mouse_pressed); - EXPECT_FALSE(watcher1.mouse_pressed()); - EXPECT_TRUE(watcher2.mouse_pressed()); + OnPointerEventObserved(pointer_event_down); + EXPECT_FALSE(watcher1.last_event_observed()); + EXPECT_EQ(ui::ET_POINTER_DOWN, watcher2.last_event_observed()->type()); watcher1.Reset(); watcher2.Reset(); // Removing the last PointerWatcher stops sending events to it. connection->RemovePointerWatcher(&watcher2); - OnEventObserved(mouse_pressed); - EXPECT_FALSE(watcher1.mouse_pressed()); - EXPECT_FALSE(watcher1.touch_pressed()); + OnPointerEventObserved(pointer_event_down); + EXPECT_FALSE(watcher1.last_event_observed()); + EXPECT_FALSE(watcher2.last_event_observed()); } -TEST_F(WindowManagerConnectionTest, TouchEventWatcher) { +TEST_F(WindowManagerConnectionTest, PointerWatcherMove) { base::MessageLoop message_loop(base::MessageLoop::TYPE_UI); ScopedViewsTestHelper helper; WindowManagerConnection* connection = WindowManagerConnection::Get(); ASSERT_TRUE(connection); - const ui::EventType kMouseType[] = { - ui::ET_MOUSE_PRESSED, ui::ET_MOUSE_DRAGGED, ui::ET_MOUSE_MOVED, - ui::ET_MOUSE_ENTERED, ui::ET_MOUSE_EXITED, ui::ET_MOUSE_RELEASED}; - const ui::EventType kTouchType[] = {ui::ET_TOUCH_PRESSED, ui::ET_TOUCH_MOVED, - ui::ET_TOUCH_RELEASED, - ui::ET_TOUCH_CANCELLED}; + ui::PointerEvent pointer_event_down( + ui::ET_POINTER_DOWN, gfx::Point(), gfx::Point(), ui::EF_NONE, 1, + ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH), + base::TimeTicks()); + ui::PointerEvent pointer_event_move( + ui::ET_POINTER_MOVED, gfx::Point(), gfx::Point(), ui::EF_NONE, 1, + ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH), + base::TimeTicks()); - TestTouchEventWatcher watcher1; - connection->AddTouchEventWatcher(&watcher1); + // PointerWatchers receive pointer down events. + TestPointerWatcher watcher1; + connection->AddPointerWatcher(&watcher1, true); + OnPointerEventObserved(pointer_event_down); + EXPECT_EQ(ui::ET_POINTER_DOWN, watcher1.last_event_observed()->type()); + watcher1.Reset(); - // TouchEventWatchers do not trigger for mouse events. - for (size_t i = 0; i < arraysize(kMouseType); i++) { - ui::MouseEvent mouse_event(kMouseType[i], gfx::Point(), gfx::Point(), - base::TimeTicks(), 0, 0); - ui::PointerEvent mouse_pointer_event(mouse_event); - EXPECT_TRUE(mouse_pointer_event.IsMousePointerEvent()); - OnEventObserved(mouse_pointer_event); - EXPECT_FALSE(watcher1.touch_observed()); - watcher1.Reset(); - } + // PointerWatchers receive pointer move events. + OnPointerEventObserved(pointer_event_move); + EXPECT_EQ(ui::ET_POINTER_MOVED, watcher1.last_event_observed()->type()); + watcher1.Reset(); - // TouchEventWatchers receive both TouchEvent and TouchPointerEvent. - for (size_t i = 0; i < arraysize(kTouchType); i++) { - ui::TouchEvent touch_event(kTouchType[i], gfx::Point(), 0, - base::TimeTicks()); - EXPECT_TRUE(touch_event.IsTouchEvent()); - OnEventObserved(touch_event); - EXPECT_TRUE(watcher1.touch_observed()); - watcher1.Reset(); - - ui::PointerEvent touch_pointer_event(touch_event); - EXPECT_TRUE(touch_pointer_event.IsTouchPointerEvent()); - OnEventObserved(touch_pointer_event); - EXPECT_TRUE(watcher1.touch_observed()); - watcher1.Reset(); - } - - // Two TouchEventWatchers can both receive a single observed event. - TestTouchEventWatcher watcher2; - connection->AddTouchEventWatcher(&watcher2); - ui::TouchEvent touch_event(ui::ET_TOUCH_PRESSED, gfx::Point(), 0, - base::TimeTicks()); - ui::PointerEvent touch_pointer_event(touch_event); - OnEventObserved(touch_pointer_event); - EXPECT_TRUE(watcher1.touch_observed()); - EXPECT_TRUE(watcher2.touch_observed()); + // Two PointerWatchers can both receive a single observed event. + TestPointerWatcher watcher2; + connection->AddPointerWatcher(&watcher2, true); + OnPointerEventObserved(pointer_event_move); + EXPECT_EQ(ui::ET_POINTER_MOVED, watcher1.last_event_observed()->type()); + EXPECT_EQ(ui::ET_POINTER_MOVED, watcher2.last_event_observed()->type()); watcher1.Reset(); watcher2.Reset(); - // Removing the first TouchEventWatcher stops sending events to it. - connection->RemoveTouchEventWatcher(&watcher1); - OnEventObserved(touch_pointer_event); - EXPECT_FALSE(watcher1.touch_observed()); - EXPECT_TRUE(watcher2.touch_observed()); + // Removing the first PointerWatcher stops sending events to it. + connection->RemovePointerWatcher(&watcher1); + OnPointerEventObserved(pointer_event_move); + EXPECT_FALSE(watcher1.last_event_observed()); + EXPECT_EQ(ui::ET_POINTER_MOVED, watcher2.last_event_observed()->type()); watcher1.Reset(); watcher2.Reset(); - // Removing the last TouchEventWatcher stops sending events to it. - connection->RemoveTouchEventWatcher(&watcher2); - OnEventObserved(touch_pointer_event); - EXPECT_FALSE(watcher1.touch_observed()); - EXPECT_FALSE(watcher2.touch_observed()); + // Removing the last PointerWatcher stops sending events to it. + connection->RemovePointerWatcher(&watcher2); + OnPointerEventObserved(pointer_event_move); + EXPECT_FALSE(watcher1.last_event_observed()); + EXPECT_FALSE(watcher2.last_event_observed()); } } // namespace views
diff --git a/ui/views/mus/window_tree_host_mus.cc b/ui/views/mus/window_tree_host_mus.cc index 64a7fd6..47f51e6 100644 --- a/ui/views/mus/window_tree_host_mus.cc +++ b/ui/views/mus/window_tree_host_mus.cc
@@ -42,6 +42,8 @@ this, false))); // Do not advertise accelerated widget; already set manually. + compositor()->SetWindow(window); + // Initialize the stub platform window bounds to those of the ui::Window. platform_window()->SetBounds(window->bounds());
diff --git a/ui/views/pointer_watcher.h b/ui/views/pointer_watcher.h index 5ca10ef..0081871 100644 --- a/ui/views/pointer_watcher.h +++ b/ui/views/pointer_watcher.h
@@ -13,8 +13,7 @@ } namespace ui { -class MouseEvent; -class TouchEvent; +class PointerEvent; } namespace views { @@ -23,18 +22,18 @@ // An interface for read-only observation of pointer events (in particular, the // events cannot be marked as handled). Only certain event types are supported. // The |target| is the top-level widget that will receive the event, if any. +// To reduce IPC traffic from the window server, move events are not provided +// unless the app specifically requests them. // NOTE: On mus this allows observation of events outside of windows owned // by the current process, in which case the |target| will be null. On mus // event.target() is always null. class VIEWS_EXPORT PointerWatcher { public: PointerWatcher() {} - virtual void OnMousePressed(const ui::MouseEvent& event, - const gfx::Point& location_in_screen, - Widget* target) = 0; - virtual void OnTouchPressed(const ui::TouchEvent& event, - const gfx::Point& location_in_screen, - Widget* target) = 0; + + virtual void OnPointerEventObserved(const ui::PointerEvent& event, + const gfx::Point& location_in_screen, + Widget* target) = 0; protected: virtual ~PointerWatcher() {}
diff --git a/ui/views/test/scoped_views_test_helper.cc b/ui/views/test/scoped_views_test_helper.cc index 155843d..aea9122 100644 --- a/ui/views/test/scoped_views_test_helper.cc +++ b/ui/views/test/scoped_views_test_helper.cc
@@ -29,6 +29,13 @@ platform_test_helper_(PlatformTestHelper::Create()) { // The ContextFactory must exist before any Compositors are created. bool enable_pixel_output = false; +#if defined(USE_AURA) + ui::ContextFactory* old_context_factory = nullptr; + if (PlatformTestHelper::IsMus()) { + old_context_factory = aura::Env::GetInstance()->context_factory(); + DCHECK(old_context_factory); + } +#endif ui::ContextFactory* context_factory = ui::InitializeContextFactoryForTests(enable_pixel_output); views_delegate_->set_context_factory(context_factory); @@ -42,10 +49,11 @@ // ui::InitializeContextFactoryForTests() is only needed for the default // WindowTreeHost instance created by TestScreen. After that, the // context-factory is used when creating Widgets (to set-up the compositor for - // the corresponding ui::Windows). So unset the context-factory, so that - // NativeWidgetMus installs the correct context-factory that can talk to mus. + // the corresponding ui::Windows). So restore the context-factory (which + // WindowManagerConnection would have set up), so that NativeWidgetMus + // installs the correct context-factory that can talk to mus. if (PlatformTestHelper::IsMus()) - aura::Env::GetInstance()->set_context_factory(nullptr); + aura::Env::GetInstance()->set_context_factory(old_context_factory); #endif ui::InitializeInputMethodForTesting();
diff --git a/ui/views/touch_event_watcher.h b/ui/views/touch_event_watcher.h deleted file mode 100644 index e1647de..0000000 --- a/ui/views/touch_event_watcher.h +++ /dev/null
@@ -1,43 +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 UI_VIEWS_TOUCH_EVENT_WATCHER_H_ -#define UI_VIEWS_TOUCH_EVENT_WATCHER_H_ - -#include "base/macros.h" -#include "ui/views/views_export.h" - -namespace gfx { -class Point; -} - -namespace ui { -class LocatedEvent; -} - -namespace views { -class Widget; - -// An interface for read-only observation of touch events (in particular, the -// events cannot be marked as handled). Only touch pointer kind are supported. -// The |target| is the top-level widget that will receive the event, if any. -// NOTE: On mus this allows observation of events outside of windows owned -// by the current process, in which case the |target| will be null. On mus -// event.target() is always null. -class VIEWS_EXPORT TouchEventWatcher { - public: - TouchEventWatcher() {} - virtual void OnTouchEventObserved(const ui::LocatedEvent& event, - Widget* target) = 0; - - protected: - virtual ~TouchEventWatcher() {} - - private: - DISALLOW_COPY_AND_ASSIGN(TouchEventWatcher); -}; - -} // namespace views - -#endif // UI_VIEWS_TOUCH_EVENT_WATCHER_H_
diff --git a/ui/views/view.cc b/ui/views/view.cc index be3bbf5..3da5ce0 100644 --- a/ui/views/view.cc +++ b/ui/views/view.cc
@@ -826,7 +826,7 @@ transform_from_parent.Translate(offset_from_parent.x(), offset_from_parent.y()); transform_from_parent.PreconcatTransform(GetTransform()); - transform_recorder.Transform(transform_from_parent, size()); + transform_recorder.Transform(transform_from_parent); } // Note that the cache is not aware of the offset of the view
diff --git a/ui/views/views.gyp b/ui/views/views.gyp index 181580de..8bdad14 100644 --- a/ui/views/views.gyp +++ b/ui/views/views.gyp
@@ -298,7 +298,6 @@ 'style/platform_style.cc', 'style/platform_style.h', 'style/platform_style_mac.mm', - 'touch_event_watcher.h', 'view.cc', 'view.h', 'view_constants.cc',
diff --git a/ui/views/views_exports.cc b/ui/views/views_exports.cc index 1aeec123..f1ba3f5 100644 --- a/ui/views/views_exports.cc +++ b/ui/views/views_exports.cc
@@ -8,4 +8,3 @@ // the resulting dynamic library. #include "ui/views/pointer_watcher.h" -#include "ui/views/touch_event_watcher.h"
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc index b19ee7f7..4e6799db 100644 --- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc +++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
@@ -651,6 +651,9 @@ const gfx::ImageSkia& app_icon) { if (content_window_) desktop_window_tree_host_->SetWindowIcons(window_icon, app_icon); + + NativeWidgetAura::AssignIconToAuraWindow(content_window_, window_icon, + app_icon); } void DesktopNativeWidgetAura::InitModalType(ui::ModalType modal_type) {
diff --git a/ui/views/widget/desktop_aura/desktop_screen_x11.cc b/ui/views/widget/desktop_aura/desktop_screen_x11.cc index 06335ed..d3d2315b 100644 --- a/ui/views/widget/desktop_aura/desktop_screen_x11.cc +++ b/ui/views/widget/desktop_aura/desktop_screen_x11.cc
@@ -327,6 +327,8 @@ if (!is_connected) continue; + bool is_primary_display = output_id == primary_display_id; + if (output_info->crtc) { gfx::XScopedPtr<XRRCrtcInfo, gfx::XObjectDeleter<XRRCrtcInfo, void, XRRFreeCrtcInfo>> @@ -349,7 +351,9 @@ if (has_work_area) { gfx::Rect intersection_in_pixels = crtc_bounds; - intersection_in_pixels.Intersect(work_area_in_pixels); + if (is_primary_display) { + intersection_in_pixels.Intersect(work_area_in_pixels); + } // SetScaleAndBounds() above does the conversion from pixels to DIP for // us, but set_work_area does not, so we need to do it here. display.set_work_area(gfx::Rect( @@ -374,7 +378,7 @@ break; } - if (output_id == primary_display_id) + if (is_primary_display) primary_display_index_ = displays.size(); displays.push_back(display);
diff --git a/ui/views/widget/native_widget_aura.cc b/ui/views/widget/native_widget_aura.cc index 1f72f3a..5476d77 100644 --- a/ui/views/widget/native_widget_aura.cc +++ b/ui/views/widget/native_widget_aura.cc
@@ -97,6 +97,23 @@ window->set_user_data(native_widget); } +// static +void NativeWidgetAura::AssignIconToAuraWindow(aura::Window* window, + const gfx::ImageSkia& window_icon, + const gfx::ImageSkia& app_icon) { + if (!window) + return; + + if (window_icon.isNull() && app_icon.isNull()) { + window->ClearProperty(aura::client::kWindowIconKey); + return; + } + + window->SetProperty( + aura::client::kWindowIconKey, + new gfx::ImageSkia(!window_icon.isNull() ? window_icon : app_icon)); +} + //////////////////////////////////////////////////////////////////////////////// // NativeWidgetAura, internal::NativeWidgetPrivate implementation: @@ -355,7 +372,7 @@ void NativeWidgetAura::SetWindowIcons(const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) { - // Aura doesn't have window icons. + AssignIconToAuraWindow(window_, window_icon, app_icon); } void NativeWidgetAura::InitModalType(ui::ModalType modal_type) {
diff --git a/ui/views/widget/native_widget_aura.h b/ui/views/widget/native_widget_aura.h index 77a4d38..6e495c2 100644 --- a/ui/views/widget/native_widget_aura.h +++ b/ui/views/widget/native_widget_aura.h
@@ -50,6 +50,11 @@ internal::NativeWidgetPrivate* native_widget, aura::Window* window); + // Assign an icon to aura window. + static void AssignIconToAuraWindow(aura::Window* window, + const gfx::ImageSkia& window_icon, + const gfx::ImageSkia& app_icon); + // Overridden from internal::NativeWidgetPrivate: void InitNativeWidget(const Widget::InitParams& params) override; void OnWidgetInitDone() override;
diff --git a/ui/webui/resources/js/util.js b/ui/webui/resources/js/util.js index 29320580..ee6cd40 100644 --- a/ui/webui/resources/js/util.js +++ b/ui/webui/resources/js/util.js
@@ -216,26 +216,44 @@ if (e.defaultPrevented) return; + var eventPath = e.path; + var anchor = null; + if (eventPath) { + for (var i = 0; i < eventPath.length; i++) { + var element = eventPath[i]; + if (element.tagName === 'A' && element.href) { + anchor = element; + break; + } + } + } + + // Fallback if Event.path is not available. var el = e.target; - if (el.nodeType == Node.ELEMENT_NODE && + if (!anchor && el.nodeType == Node.ELEMENT_NODE && el.webkitMatchesSelector('A, A *')) { while (el.tagName != 'A') { el = el.parentElement; } + anchor = el; + } - if ((el.protocol == 'file:' || el.protocol == 'about:') && - (e.button == 0 || e.button == 1)) { - chrome.send('navigateToUrl', [ - el.href, - el.target, - e.button, - e.altKey, - e.ctrlKey, - e.metaKey, - e.shiftKey - ]); - e.preventDefault(); - } + if (!anchor) + return; + + anchor = /** @type {!HTMLAnchorElement} */(anchor); + if ((anchor.protocol == 'file:' || anchor.protocol == 'about:') && + (e.button == 0 || e.button == 1)) { + chrome.send('navigateToUrl', [ + anchor.href, + anchor.target, + e.button, + e.altKey, + e.ctrlKey, + e.metaKey, + e.shiftKey + ]); + e.preventDefault(); } });